import * as i0 from '@angular/core'; import { Directive, NgModule, Optional, Input, Injectable, Component, ChangeDetectionStrategy, EventEmitter, HostBinding, Output, ContentChildren, PLATFORM_ID, Inject, ViewChild, HostListener, SkipSelf, Renderer2, InjectionToken, ElementRef, ContentChild, ComponentFactoryResolver, KeyValueDiffers, Self, Attribute, LOCALE_ID, ViewContainerRef, NgZone, ChangeDetectorRef, TemplateRef } from '@angular/core'; import * as i5 from '@angular/common'; import { CommonModule, isPlatformBrowser, DOCUMENT, NgForOf, getLocaleDayNames, FormStyle, TranslationWidth, getLocaleMonthNames, getLocaleFirstDayOfWeek, getLocaleDateFormat, FormatWidth } from '@angular/common'; import { ClarityIcons, angleIcon, exclamationCircleIcon, checkCircleIcon, ellipsisHorizontalIcon, windowCloseIcon, eventIcon, calendarIcon, eyeHideIcon, eyeIcon, ellipsisVerticalIcon, viewColumnsIcon, arrowIcon, timesIcon, stepForward2Icon, angleDoubleIcon, filterGridCircleIcon, filterGridIcon, infoCircleIcon, exclamationTriangleIcon, circleIcon, dotCircleIcon, errorStandardIcon, successStandardIcon } from '@cds/core/icon'; import { map, tap, startWith, distinctUntilChanged, filter, skipUntil, debounceTime, takeUntil, take, first, switchMap } from 'rxjs/operators'; import * as i3 from 'rxjs'; import { Subject, BehaviorSubject, Observable, fromEvent, isObservable, of, ReplaySubject, combineLatest, merge } from 'rxjs'; import { trigger, transition, style, animate, state, keyframes } from '@angular/animations'; import * as i1 from '@angular/forms'; import { FormControl, FormGroup, FormsModule, NG_VALIDATORS, SelectMultipleControlValueAccessor } from '@angular/forms'; import { CdkTrapFocus } from '@angular/cdk/a11y'; import { CdkDrag } from '@angular/cdk/drag-drop'; import * as i1$1 from '@angular/router'; import '@cds/core/internal-components/close-button/register.js'; import '@cds/core/icon/register'; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrIconCustomTag { } ClrIconCustomTag.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIconCustomTag, deps: [], target: i0.ɵɵFactoryTarget.Directive }); ClrIconCustomTag.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIconCustomTag, selector: "clr-icon", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIconCustomTag, decorators: [{ type: Directive, args: [{ selector: 'clr-icon', }] }] }); class CdsIconCustomTag { } CdsIconCustomTag.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdsIconCustomTag, deps: [], target: i0.ɵɵFactoryTarget.Directive }); CdsIconCustomTag.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: CdsIconCustomTag, selector: "cds-icon", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdsIconCustomTag, decorators: [{ type: Directive, args: [{ selector: 'cds-icon', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_ICON_DIRECTIVES = [ClrIconCustomTag, CdsIconCustomTag]; class ClrIconModule { } ClrIconModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIconModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrIconModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrIconModule, declarations: [ClrIconCustomTag, CdsIconCustomTag], imports: [CommonModule], exports: [ClrIconCustomTag, CdsIconCustomTag] }); ClrIconModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIconModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIconModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_ICON_DIRECTIVES], exports: [CLR_ICON_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This is an abstract class because we need it to still be a valid token for dependency injection after transpiling. * This does not mean you should extend it, simply implementing it is fine. */ class LoadingListener { } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrLoadingState; (function (ClrLoadingState) { ClrLoadingState[ClrLoadingState["DEFAULT"] = 0] = "DEFAULT"; ClrLoadingState[ClrLoadingState["LOADING"] = 1] = "LOADING"; ClrLoadingState[ClrLoadingState["SUCCESS"] = 2] = "SUCCESS"; ClrLoadingState[ClrLoadingState["ERROR"] = 3] = "ERROR"; })(ClrLoadingState || (ClrLoadingState = {})); class ClrLoading { // We find the first parent that handles something loading constructor(listener) { this.listener = listener; this._loadingState = ClrLoadingState.DEFAULT; } get loadingState() { return this._loadingState; } set loadingState(value) { if (value === true) { value = ClrLoadingState.LOADING; } else if (!value) { value = ClrLoadingState.DEFAULT; } if (value === this._loadingState) { return; } this._loadingState = value; if (this.listener) { this.listener.loadingStateChange(value); } } ngOnDestroy() { this.loadingState = ClrLoadingState.DEFAULT; } } ClrLoading.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoading, deps: [{ token: LoadingListener, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrLoading.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrLoading, selector: "[clrLoading]", inputs: { loadingState: ["clrLoading", "loadingState"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoading, decorators: [{ type: Directive, args: [{ selector: '[clrLoading]', }] }], ctorParameters: function () { return [{ type: LoadingListener, decorators: [{ type: Optional }] }]; }, propDecorators: { loadingState: [{ type: Input, args: ['clrLoading'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class IfExpandService { constructor() { this.expandable = 0; this._loading = false; this._expanded = false; this._expandChange = new Subject(); } get loading() { return this._loading; } set loading(value) { value = !!value; if (value !== this._loading) { this._loading = value; } } get expanded() { return this._expanded; } set expanded(value) { value = !!value; if (value !== this._expanded) { this._expanded = value; this._expandChange.next(value); } } get expandChange() { return this._expandChange.asObservable(); } toggle() { this.expanded = !this._expanded; } loadingStateChange(state) { switch (state) { case ClrLoadingState.LOADING: this.loading = true; break; default: this.loading = false; break; } } } IfExpandService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfExpandService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); IfExpandService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfExpandService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfExpandService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let NB_INSTANCES = 0; function uniqueIdFactory() { return 'clr-id-' + NB_INSTANCES++; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAccordionDescription { } ClrAccordionDescription.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionDescription, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrAccordionDescription.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAccordionDescription, selector: "clr-accordion-description, clr-step-description", host: { properties: { "class.clr-accordion-description": "true" } }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionDescription, decorators: [{ type: Component, args: [{ selector: 'clr-accordion-description, clr-step-description', template: ``, host: { '[class.clr-accordion-description]': 'true' }, changeDetection: ChangeDetectionStrategy.OnPush, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var AccordionStatus; (function (AccordionStatus) { AccordionStatus["Inactive"] = "inactive"; AccordionStatus["Error"] = "error"; AccordionStatus["Complete"] = "complete"; })(AccordionStatus || (AccordionStatus = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const defaultAnimationTiming = '0.2s ease-in-out'; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const panelAnimation = [ trigger('skipInitialRender', [transition(':enter', [])]), trigger('toggle', [ transition('void => *', [ style({ display: 'block', height: 0 }), animate(defaultAnimationTiming, style({ height: '*' })), ]), ]), ]; const stepAnimation = [ trigger('skipInitialRender', [transition(':enter', [])]), trigger('toggle', [ transition('void => *', [ style({ display: 'block', height: 0 }), animate(defaultAnimationTiming, style({ height: '*' })), ]), transition('* => void', [ style({ display: 'block' }), animate(defaultAnimationTiming, style({ height: 0, display: 'none' })), ]), ]), ]; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const commonStringsDefault = { open: 'Open', close: 'Close', show: 'Show', hide: 'Hide', expand: 'Expand', collapse: 'Collapse', more: 'More', select: 'Select', selectAll: 'Select All', previous: 'Previous', next: 'Next', current: 'Jump to current', info: 'Info', success: 'Success', warning: 'Warning', danger: 'Error', rowActions: 'Available actions', pickColumns: 'Manage Columns', showColumns: 'Show Columns', sortColumn: 'Sort Column', firstPage: 'First Page', lastPage: 'Last Page', nextPage: 'Next Page', previousPage: 'Previous Page', currentPage: 'Current Page', totalPages: 'Total Pages', filterItems: 'Filter items', minValue: 'Min value', maxValue: 'Max value', modalContentStart: 'Beginning of Modal Content', modalContentEnd: 'End of Modal Content', showColumnsMenuDescription: 'Show or hide columns menu', allColumnsSelected: 'All columns selected', signpostToggle: 'Signpost Toggle', signpostClose: 'Signpost Close', loading: 'Loading', // Datagrid detailPaneStart: 'Start of row details', detailPaneEnd: 'End of row details', singleSelectionAriaLabel: 'Single selection header', singleActionableAriaLabel: 'Single actionable header', detailExpandableAriaLabel: 'Toggle more row content', datagridFilterAriaLabel: 'Toggle {COLUMN} filter', datagridFilterDialogAriaLabel: 'Filter dialog', columnSeparatorAriaLabel: 'Column resize handle', columnSeparatorDescription: 'Use left or right key to resize the column', // Alert alertCloseButtonAriaLabel: 'Close alert', alertNextAlertAriaLabel: 'Next alert message, {CURRENT} of {COUNT}', alertPreviousAlertAriaLabel: 'Previous alert message, {CURRENT} of {COUNT}', // Date Picker datepickerDialogLabel: 'Choose date', datepickerToggleChooseDateLabel: 'Choose date', datepickerToggleChangeDateLabel: 'Change date, {SELECTED_DATE}', datepickerPreviousMonth: 'Previous month', datepickerCurrentMonth: 'Current month', datepickerNextMonth: 'Next month', datepickerPreviousDecade: 'Previous decade', datepickerNextDecade: 'Next decade', datepickerCurrentDecade: 'Current decade', datepickerSelectMonthText: 'Select month, the current month is {CALENDAR_MONTH}', datepickerSelectYearText: 'Select year, the current year is {CALENDAR_YEAR}', datepickerSelectedLabel: '{FULL_DATE} - Selected', // Stack View stackViewChanged: 'Value changed.', // Responsive Nav responsiveNavToggleOpen: 'Open navigation menu', responsiveNavToggleClose: 'Close navigation menu', responsiveNavOverflowOpen: 'Open navigation overflow menu', responsiveNavOverflowClose: 'Close navigation overflow menu', //Vertical Nav verticalNavToggle: 'Toggle vertical navigation', // Timeline steps timelineStepNotStarted: 'Not started', timelineStepCurrent: 'Current', timelineStepSuccess: 'Completed', timelineStepError: 'Error', timelineStepProcessing: 'In progress', // Combobox comboboxDelete: 'Delete selected option', comboboxSearching: 'Searching for matches for "{INPUT}"', comboboxSelection: 'Selection', comboboxSelected: 'Selected', comboboxNoResults: 'No results', comboboxOpen: 'Show options', // Datagrid expandable rows datagridExpandableBeginningOf: 'Beginning of', datagridExpandableEndOf: 'End of', datagridExpandableRowContent: 'Expandable row content', datagridExpandableRowsHelperText: `Screen reader table commands may not work for viewing expanded content, please use your screen reader's browse mode to read the content exposed by this button`, // Wizard wizardStepSuccess: 'Completed', wizardStepError: 'Error', wizardStepnavAriaLabel: 'Step navigation', /** * Password Input * Screen-reader text for the hide/show password field button */ passwordHide: 'Hide password for {LABEL}', passwordShow: 'Show password for {LABEL}', /** * Datagrid footer; sr-only text after the number of selected rows. */ selectedRows: 'Selected rows', }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrCommonStringsService { constructor() { this._strings = commonStringsDefault; } /** * Access to all of the keys as strings */ get keys() { return this._strings; } /** * Allows you to pass in new overrides for localization */ localize(overrides) { this._strings = { ...this._strings, ...overrides }; } /** * Parse a string with a set of tokens to replace */ parse(source, tokens = {}) { const names = Object.keys(tokens); let output = source; if (names.length) { names.forEach(name => { output = output.replace(`{${name}}`, tokens[name]); }); } return output; } } ClrCommonStringsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonStringsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ClrCommonStringsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonStringsService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonStringsService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var AccordionStrategy; (function (AccordionStrategy) { AccordionStrategy["Default"] = "default"; AccordionStrategy["Multi"] = "multi"; })(AccordionStrategy || (AccordionStrategy = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let accordionCount = 0; class AccordionPanelModel { constructor(id, accordionId) { this.id = id; this.accordionId = accordionId; this.status = AccordionStatus.Inactive; this.index = null; this.disabled = false; this.open = false; this.templateId = `${this.id}-${this.accordionId}`; } } class AccordionModel { constructor() { this.strategy = AccordionStrategy.Default; this.accordionCount = accordionCount++; this._panels = {}; } get panels() { return Object.keys(this._panels).map(id => this._panels[id]); } setStrategy(strategy) { this.strategy = strategy; } updatePanelOrder(ids) { ids.forEach((id, index) => (this._panels[id].index = index)); this.removeOldPanels(ids); } addPanel(id, open = false) { this._panels[id] = new AccordionPanelModel(id, this.accordionCount); this._panels[id].open = open; } togglePanel(panelId, open) { const panelIsOpen = this._panels[panelId].open; const newOpenState = open !== undefined ? open : !panelIsOpen; if (newOpenState && this.strategy === AccordionStrategy.Default) { this.closeAllPanels(); } this._panels[panelId].open = newOpenState; } disablePanel(panelId, disabled) { this._panels[panelId].disabled = disabled; } closeAllPanels() { this.panels.forEach(panel => (this._panels[panel.id].open = false)); } removeOldPanels(ids) { this.panels .filter(panel => ids.find(id => id === panel.id) === undefined) .forEach(panel => delete this._panels[panel.id]); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class AccordionService { constructor() { this.accordion = new AccordionModel(); this._panelsChanges = new BehaviorSubject(this.accordion.panels); } getPanelChanges(panelId) { return this._panelsChanges.pipe(map(panels => panels.find(s => s.id === panelId))); } setStrategy(strategy) { this.accordion.setStrategy(strategy); } addPanel(panelId, open = false) { this.accordion.addPanel(panelId, open); this.emitUpdatedPanels(); } togglePanel(panelId, open) { this.accordion.togglePanel(panelId, open); this.emitUpdatedPanels(); } disablePanel(panelId, disabled) { this.accordion.disablePanel(panelId, disabled); this.emitUpdatedPanels(); } updatePanelOrder(ids) { this.accordion.updatePanelOrder(ids); this.emitUpdatedPanels(); } emitUpdatedPanels() { this._panelsChanges.next(this.accordion.panels); } } AccordionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); AccordionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAccordionPanel { constructor(commonStrings, accordionService, ifExpandService, cdr) { this.commonStrings = commonStrings; this.accordionService = accordionService; this.ifExpandService = ifExpandService; this.cdr = cdr; this.disabled = false; this.panelOpen = false; this.panelOpenChange = new EventEmitter(); this.AccordionStatus = AccordionStatus; this.isAccordion = true; this._id = uniqueIdFactory(); } get id() { return this._id; } set id(value) { this._id = value; } get panelNumber() { return this._panelIndex + 1; } ngOnInit() { this.panel = this.accordionService.getPanelChanges(this.id).pipe(tap(panel => this.emitPanelChange(panel))); this.accordionService.addPanel(this.id, this.panelOpen); this.accordionService.togglePanel(this.id, this.panelOpen); this.accordionService.disablePanel(this.id, this.disabled); } ngOnChanges(changes) { if (this.panel && changes.panelOpen && changes.panelOpen.currentValue !== changes.panelOpen.previousValue) { this.accordionService.togglePanel(this.id, changes.panelOpen.currentValue); } if (this.panel && changes.disabled && changes.disabled.currentValue !== changes.disabled.previousValue) { this.accordionService.disablePanel(this.id, changes.disabled.currentValue); } } togglePanel() { this.accordionService.togglePanel(this.id); } collapsePanelOnAnimationDone(panel) { if (!panel.open) { this.ifExpandService.expanded = false; } } getPanelStateClasses(panel) { return `clr-accordion-panel-${panel.status} ${panel.open ? 'clr-accordion-panel-open' : ''}`; } getAccordionContentId(id) { return `clr-accordion-content-${id}'`; } getAccordionHeaderId(id) { return `clr-accordion-header-${id}`; } emitPanelChange(panel) { if (panel.index !== this._panelIndex) { this._panelIndex = panel.index; // The whole chain of updates leading to this line starts in a ngAfterViewInit subscription in accordion.ts, // listening for DOM changes. It seems to only fails in tests, but as this is not a frequently called code, // I prefer to stay on the safe side and initiate a detection cycle here. this.cdr.detectChanges(); } if (panel.open !== this.panelOpen) { this.panelOpenChange.emit(panel.open); /** * @Note: this line below is needed because we don't want to use another value to track * for changes of the panel. Because we use BehaviorSubject this emit event is trigger on * init (that is not needed - there is no change of the original value) - in some cases this * lead to duplicate events. * * To prevent this we try to emit only when the value is changed and keep the value in sync * even that is used only into the Initial Lifecycle (ngOnInit). */ this.panelOpen = panel.open; } if (panel.open) { this.ifExpandService.expanded = true; } } } ClrAccordionPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionPanel, deps: [{ token: ClrCommonStringsService }, { token: AccordionService }, { token: IfExpandService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); ClrAccordionPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAccordionPanel, selector: "clr-accordion-panel", inputs: { disabled: ["clrAccordionPanelDisabled", "disabled"], panelOpen: ["clrAccordionPanelOpen", "panelOpen"] }, outputs: { panelOpenChange: "clrAccordionPanelOpenChange" }, host: { properties: { "class.clr-accordion-panel": "true", "class.clr-accordion-panel-disabled": "this.disabled" } }, providers: [IfExpandService], queries: [{ propertyName: "accordionDescription", predicate: ClrAccordionDescription }], usesOnChanges: true, ngImport: i0, template: "\n
\n
\n \n \n {{commonStrings.keys.danger}}\n {{commonStrings.keys.success}}\n \n \n \n {{panelNumber}}.\n \n \n \n \n \n \n
\n \n \n
\n \n
\n
\n \n \n
\n", dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }], animations: panelAnimation, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionPanel, decorators: [{ type: Component, args: [{ selector: 'clr-accordion-panel', host: { '[class.clr-accordion-panel]': 'true' }, changeDetection: ChangeDetectionStrategy.OnPush, animations: panelAnimation, providers: [IfExpandService], template: "\n
\n
\n \n \n {{commonStrings.keys.danger}}\n {{commonStrings.keys.success}}\n \n \n \n {{panelNumber}}.\n \n \n \n \n \n \n
\n \n \n
\n \n
\n
\n \n \n
\n" }] }], ctorParameters: function () { return [{ type: ClrCommonStringsService }, { type: AccordionService }, { type: IfExpandService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { disabled: [{ type: Input, args: ['clrAccordionPanelDisabled'] }, { type: HostBinding, args: ['class.clr-accordion-panel-disabled'] }], panelOpen: [{ type: Input, args: ['clrAccordionPanelOpen'] }], panelOpenChange: [{ type: Output, args: ['clrAccordionPanelOpenChange'] }], accordionDescription: [{ type: ContentChildren, args: [ClrAccordionDescription] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAccordion { constructor(accordionService) { this.accordionService = accordionService; this.multiPanel = false; this.subscriptions = []; } ngOnInit() { this.setAccordionStrategy(); } ngOnChanges(changes) { if (changes.multiPanel.currentValue !== changes.multiPanel.previousValue) { this.setAccordionStrategy(); } } ngAfterViewInit() { this.subscriptions.push(this.listenForDOMChanges()); } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } setAccordionStrategy() { const strategy = this.multiPanel ? AccordionStrategy.Multi : AccordionStrategy.Default; this.accordionService.setStrategy(strategy); } listenForDOMChanges() { return this.panels.changes .pipe(startWith(this.panels)) .subscribe((panels) => this.accordionService.updatePanelOrder(panels.toArray().map(p => p.id))); } } ClrAccordion.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordion, deps: [{ token: AccordionService }], target: i0.ɵɵFactoryTarget.Component }); ClrAccordion.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAccordion, selector: "clr-accordion", inputs: { multiPanel: ["clrAccordionMultiPanel", "multiPanel"] }, host: { properties: { "class.clr-accordion": "true" } }, providers: [AccordionService], queries: [{ propertyName: "panels", predicate: ClrAccordionPanel }], usesOnChanges: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordion, decorators: [{ type: Component, args: [{ selector: 'clr-accordion', template: ``, host: { '[class.clr-accordion]': 'true' }, providers: [AccordionService], changeDetection: ChangeDetectionStrategy.OnPush, }] }], ctorParameters: function () { return [{ type: AccordionService }]; }, propDecorators: { multiPanel: [{ type: Input, args: ['clrAccordionMultiPanel'] }], panels: [{ type: ContentChildren, args: [ClrAccordionPanel] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAccordionContent { } ClrAccordionContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionContent, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrAccordionContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAccordionContent, selector: "clr-accordion-content, clr-step-content", ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionContent, decorators: [{ type: Component, args: [{ selector: 'clr-accordion-content, clr-step-content', template: ``, changeDetection: ChangeDetectionStrategy.OnPush, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAccordionTitle { } ClrAccordionTitle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionTitle, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrAccordionTitle.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAccordionTitle, selector: "clr-accordion-title, clr-step-title", host: { properties: { "class.clr-accordion-title": "true" } }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionTitle, decorators: [{ type: Component, args: [{ selector: 'clr-accordion-title, clr-step-title', template: ``, host: { '[class.clr-accordion-title]': 'true' }, changeDetection: ChangeDetectionStrategy.OnPush, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * After a conversation with the Angular core team, it turns out we don't have much of a choice for our * declarative API, we need to fight against change detection and its one-way flow. This is * currently the least dirty solution to do what we want. * * Do not modify or even use this class unless you know exactly what you're doing. * It has the potential to trigger change detection loops or kill app performances. */ class WillyWonka { constructor() { this.disableChocolateCheck = false; this._chocolate = new Subject(); } get chocolate() { return this._chocolate.asObservable(); } ngAfterViewChecked() { if (!this.disableChocolateCheck) { this._chocolate.next(); } } } WillyWonka.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WillyWonka, deps: [], target: i0.ɵɵFactoryTarget.Directive }); WillyWonka.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: WillyWonka, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WillyWonka, decorators: [{ type: Directive }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class OompaLoompa { // FIXME: Request Injector once we move to Angular 4.2+, it'll allow easier refactors constructor(cdr, willyWonka) { this.subscription = willyWonka.chocolate.subscribe(() => { if (this.latestFlavor !== this.flavor) { willyWonka.disableChocolateCheck = true; cdr.detectChanges(); willyWonka.disableChocolateCheck = false; } }); } ngAfterContentChecked() { this.latestFlavor = this.flavor; } ngOnDestroy() { this.subscription.unsubscribe(); } } OompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: WillyWonka }], target: i0.ɵɵFactoryTarget.Directive }); OompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: OompaLoompa, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OompaLoompa, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: WillyWonka }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class AccordionWillyWonka extends WillyWonka { } AccordionWillyWonka.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionWillyWonka, deps: null, target: i0.ɵɵFactoryTarget.Directive }); AccordionWillyWonka.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: AccordionWillyWonka, selector: "clr-accordion", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionWillyWonka, decorators: [{ type: Directive, args: [{ selector: 'clr-accordion', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class AccordionOompaLoompa extends OompaLoompa { constructor(cdr, willyWonka, ifExpandService) { if (!willyWonka) { throw new Error('clr-accordion-panel should only be used inside of clr-accordion'); } super(cdr, willyWonka); this.expand = ifExpandService; } get flavor() { return this.expand.expanded; } } AccordionOompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionOompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: AccordionWillyWonka, optional: true }, { token: IfExpandService }], target: i0.ɵɵFactoryTarget.Directive }); AccordionOompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: AccordionOompaLoompa, selector: "clr-accordion-panel", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AccordionOompaLoompa, decorators: [{ type: Directive, args: [{ selector: 'clr-accordion-panel', }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: AccordionWillyWonka, decorators: [{ type: Optional }] }, { type: IfExpandService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const declarations$1 = [ ClrAccordion, ClrAccordionPanel, ClrAccordionTitle, ClrAccordionDescription, ClrAccordionContent, AccordionOompaLoompa, AccordionWillyWonka, ]; class ClrAccordionModule { constructor() { ClarityIcons.addIcons(angleIcon, exclamationCircleIcon, checkCircleIcon); } } ClrAccordionModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrAccordionModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionModule, declarations: [ClrAccordion, ClrAccordionPanel, ClrAccordionTitle, ClrAccordionDescription, ClrAccordionContent, AccordionOompaLoompa, AccordionWillyWonka], imports: [CommonModule, ClrIconModule], exports: [ClrAccordion, ClrAccordionPanel, ClrAccordionTitle, ClrAccordionDescription, ClrAccordionContent, AccordionOompaLoompa, AccordionWillyWonka] }); ClrAccordionModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionModule, imports: [CommonModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAccordionModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule], declarations: [...declarations$1], exports: [...declarations$1], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function triggerAllFormControlValidation(formGroup) { Object.keys(formGroup.controls).forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { control.markAsTouched(); control.markAsDirty(); control.updateValueAndValidity(); } else if (control instanceof FormGroup) { triggerAllFormControlValidation(control); } }); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class StepperModel extends AccordionModel { constructor() { super(...arguments); this.stepperModelInitialize = false; } get allPanelsCompleted() { return this.panels.length && this.getNumberOfIncompletePanels() === 0 && this.getNumberOfOpenPanels() === 0; } addPanel(id, open = false) { super.addPanel(id, open); this._panels[id].disabled = true; } updatePanelOrder(ids) { super.updatePanelOrder(ids); if (this.stepperModelInitialize === false) { this.openFirstPanel(); } } togglePanel(panelId) { if (this._panels[panelId].status === AccordionStatus.Complete) { this._panels[panelId].open = !this._panels[panelId].open; } } navigateToNextPanel(currentPanelId, currentPanelValid = true) { if (currentPanelValid) { this.completePanel(currentPanelId); this.openNextPanel(this._panels[currentPanelId].id); } else { this.setPanelError(currentPanelId); } } overrideInitialPanel(panelId) { this.panels .filter(() => this._panels[panelId] !== undefined) .forEach(panel => { if (panel.index < this._panels[panelId].index) { this.completePanel(panel.id); } else if (panel.id === panelId) { this._panels[panel.id].open = true; } else { this._panels[panel.id].open = false; } }); } setPanelValid(panelId) { this._panels[panelId].status = AccordionStatus.Complete; } setPanelInvalid(panelId) { this._panels[panelId].status = AccordionStatus.Error; } setPanelsWithErrors(ids) { ids.forEach(id => this.setPanelError(id)); } resetPanels() { /* return stepper to initialize state */ this.stepperModelInitialize = false; this.panels.forEach(p => this.resetPanel(p.id)); this.openFirstPanel(); } getNextPanel(currentPanelId) { return this.panels.find(s => s.index === this._panels[currentPanelId].index + 1); } resetAllFuturePanels(panelId) { this.panels.filter(panel => panel.index >= this._panels[panelId].index).forEach(panel => this.resetPanel(panel.id)); } resetPanel(panelId) { this._panels[panelId].status = AccordionStatus.Inactive; this._panels[panelId].open = false; this._panels[panelId].disabled = true; } openFirstPanel() { const firstPanel = this.getFirstPanel(); /** * You need to call updatePanelOrder first to get the correct order, * else the list of panels will not have `index` set and we won't know * how to find the first panel. */ if (!firstPanel) { return; } this._panels[firstPanel.id].open = true; this._panels[firstPanel.id].disabled = true; this.stepperModelInitialize = true; } completePanel(panelId) { this._panels[panelId].status = AccordionStatus.Complete; this._panels[panelId].disabled = false; this._panels[panelId].open = false; } openNextPanel(currentPanelId) { const nextPanel = this.getNextPanel(currentPanelId); if (nextPanel) { this.resetAllFuturePanels(nextPanel.id); this._panels[nextPanel.id].open = true; this._panels[nextPanel.id].disabled = true; } } setPanelError(panelId) { this.resetAllFuturePanels(panelId); this._panels[panelId].open = true; this._panels[panelId].status = AccordionStatus.Error; } getFirstPanel() { return this.panels.find(panel => panel.index === 0); } getNumberOfIncompletePanels() { return this.panels.reduce((prev, next) => (next.status !== AccordionStatus.Complete ? prev + 1 : prev), 0); } getNumberOfOpenPanels() { return this.panels.reduce((prev, next) => (next.open !== false ? prev + 1 : prev), 0); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class StepperService extends AccordionService { constructor() { super(); this.panelsCompleted = this.getAllCompletedPanelChanges(); this.accordion = new StepperModel(); this._activeStepChanges = new Subject(); this.activeStep = this._activeStepChanges.asObservable(); } resetPanels() { this.accordion.resetPanels(); this.emitUpdatedPanels(); } setPanelValid(panelId) { this.accordion.setPanelValid(panelId); this.emitUpdatedPanels(); } setPanelInvalid(panelId) { this.accordion.setPanelInvalid(panelId); this.emitUpdatedPanels(); } setPanelsWithErrors(ids) { this.accordion.setPanelsWithErrors(ids); this.emitUpdatedPanels(); } navigateToNextPanel(currentPanelId, currentPanelValid = true) { this.accordion.navigateToNextPanel(currentPanelId, currentPanelValid); this.updateNextStep(currentPanelId, currentPanelValid); this.emitUpdatedPanels(); } overrideInitialPanel(panelId) { this.accordion.overrideInitialPanel(panelId); this.emitUpdatedPanels(); } updateNextStep(currentPanelId, currentPanelValid) { const nextPanel = this.accordion.getNextPanel(currentPanelId); if (currentPanelValid && nextPanel) { this._activeStepChanges.next(nextPanel.id); } else if (currentPanelValid) { this._activeStepChanges.next(currentPanelId); } } getAllCompletedPanelChanges() { return this._panelsChanges.pipe(map(() => this.accordion.allPanelsCompleted), distinctUntilChanged()); } } StepperService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); StepperService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperService, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStepperPanel extends ClrAccordionPanel { constructor(platformId, commonStrings, formGroupName, ngModelGroup, stepperService, ifExpandService, cdr) { super(commonStrings, stepperService, ifExpandService, cdr); this.platformId = platformId; this.commonStrings = commonStrings; this.formGroupName = formGroupName; this.ngModelGroup = ngModelGroup; this.stepperService = stepperService; this.isAccordion = false; this.subscriptions = []; } get id() { return this.formGroupName ? this.formGroupName.name.toString() : this.ngModelGroup.name; } set id(_value) { // overriding parent id required empty setter } get formGroup() { return this.formGroupName ? this.formGroupName.control : this.ngModelGroup.control; } ngOnInit() { super.ngOnInit(); this.panel = this.panel.pipe(tap(panel => this.triggerAllFormControlValidationIfError(panel))); this.stepperService.disablePanel(this.id, true); this.listenToFocusChanges(); // not all stepper panels are guaranteed to have a form (i.e. empty template-driven) if (this.formGroup) { // set panel status on form status change only after the form becomes invalid const invalidStatusTrigger = this.formGroup.statusChanges.pipe(filter(status => status === 'INVALID')); this.subscriptions.push(this.formGroup.statusChanges.pipe(skipUntil(invalidStatusTrigger), distinctUntilChanged()).subscribe(status => { if (status === 'VALID') { this.stepperService.setPanelValid(this.id); } else if (status === 'INVALID') { this.stepperService.setPanelInvalid(this.id); } })); } } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } listenToFocusChanges() { this.subscriptions.push(this.stepperService.activeStep .pipe(filter(panelId => isPlatformBrowser(this.platformId) && panelId === this.id)) .subscribe(() => this.headerButton.nativeElement.focus())); } triggerAllFormControlValidationIfError(panel) { if (panel.status === AccordionStatus.Error) { triggerAllFormControlValidation(this.formGroup); } } } ClrStepperPanel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepperPanel, deps: [{ token: PLATFORM_ID }, { token: ClrCommonStringsService }, { token: i1.FormGroupName, optional: true }, { token: i1.NgModelGroup, optional: true }, { token: StepperService }, { token: IfExpandService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); ClrStepperPanel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrStepperPanel, selector: "clr-stepper-panel", host: { properties: { "class.clr-accordion-panel": "true" } }, providers: [IfExpandService], viewQueries: [{ propertyName: "headerButton", first: true, predicate: ["headerButton"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n
\n
\n \n \n {{commonStrings.keys.danger}}\n {{commonStrings.keys.success}}\n \n \n \n {{panelNumber}}.\n \n \n \n \n \n \n
\n \n \n
\n \n
\n
\n \n \n
\n", dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }], animations: stepAnimation, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepperPanel, decorators: [{ type: Component, args: [{ selector: 'clr-stepper-panel', host: { '[class.clr-accordion-panel]': 'true' }, changeDetection: ChangeDetectionStrategy.OnPush, animations: stepAnimation, providers: [IfExpandService], template: "\n
\n
\n \n \n {{commonStrings.keys.danger}}\n {{commonStrings.keys.success}}\n \n \n \n {{panelNumber}}.\n \n \n \n \n \n \n
\n \n \n
\n \n
\n
\n \n \n
\n" }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: ClrCommonStringsService }, { type: i1.FormGroupName, decorators: [{ type: Optional }] }, { type: i1.NgModelGroup, decorators: [{ type: Optional }] }, { type: StepperService }, { type: IfExpandService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { headerButton: [{ type: ViewChild, args: ['headerButton'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrStepButtonType; (function (ClrStepButtonType) { ClrStepButtonType["Next"] = "next"; ClrStepButtonType["Submit"] = "submit"; })(ClrStepButtonType || (ClrStepButtonType = {})); class ClrStepButton { constructor(clrStep, stepperService) { this.clrStep = clrStep; this.stepperService = stepperService; this.type = ClrStepButtonType.Next; this.submitButton = false; } ngOnInit() { this.submitButton = this.type === ClrStepButtonType.Submit; } navigateToNextPanel() { this.stepperService.navigateToNextPanel(this.clrStep.id, this.clrStep.formGroup.valid); } } ClrStepButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepButton, deps: [{ token: ClrStepperPanel }, { token: StepperService }], target: i0.ɵɵFactoryTarget.Directive }); ClrStepButton.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrStepButton, selector: "[clrStepButton]", inputs: { type: ["clrStepButton", "type"] }, host: { listeners: { "click": "navigateToNextPanel()" }, properties: { "class.clr-step-button": "true", "class.btn": "true", "type": "'button'", "class.btn-primary": "this.submitButton" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepButton, decorators: [{ type: Directive, args: [{ selector: '[clrStepButton]', host: { '[class.clr-step-button]': 'true', '[class.btn]': 'true', '[type]': "'button'", }, }] }], ctorParameters: function () { return [{ type: ClrStepperPanel }, { type: StepperService }]; }, propDecorators: { type: [{ type: Input, args: ['clrStepButton'] }], submitButton: [{ type: HostBinding, args: ['class.btn-primary'] }], navigateToNextPanel: [{ type: HostListener, args: ['click'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStepper { constructor(formGroup, ngForm, stepperService) { this.formGroup = formGroup; this.ngForm = ngForm; this.stepperService = stepperService; this.subscriptions = []; } ngOnInit() { if (!this.formGroup && !this.ngForm) { throw new Error('To use stepper a Reactive or Template Form is required.'); } this.form = this.formGroup ? this.formGroup : this.ngForm; this.subscriptions.push(this.listenForPanelsCompleted()); this.subscriptions.push(this.listenForFormResetChanges()); } ngOnChanges(changes) { if (changes.initialPanel.currentValue !== changes.initialPanel.previousValue) { this.stepperService.overrideInitialPanel(this.initialPanel); } } ngAfterViewInit() { this.subscriptions.push(this.listenForDOMChanges()); } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } listenForFormResetChanges() { return fromControlReset(this.form.form).subscribe(() => this.stepperService.resetPanels()); } listenForPanelsCompleted() { return this.stepperService.panelsCompleted.subscribe(panelsCompleted => { if (panelsCompleted && this.form.valid) { this.form.ngSubmit.emit(); } else if (!this.form.valid && this.form.touched) { this.setPanelsWithFormErrors(); } }); } setPanelsWithFormErrors() { const panelsWithErrors = this.panels.reduce((panels, p) => (p.formGroup.invalid ? [...panels, p.id] : panels), []); this.stepperService.setPanelsWithErrors(panelsWithErrors); } listenForDOMChanges() { return this.panels.changes.pipe(startWith(this.panels)).subscribe((panels) => { this.stepperService.updatePanelOrder(panels.toArray().map(p => p.id)); if (this.initialPanel) { this.stepperService.overrideInitialPanel(this.initialPanel); } }); } } ClrStepper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepper, deps: [{ token: i1.FormGroupDirective, optional: true }, { token: i1.NgForm, optional: true }, { token: StepperService }], target: i0.ɵɵFactoryTarget.Component }); ClrStepper.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrStepper, selector: "form[clrStepper]", inputs: { initialPanel: ["clrInitialStep", "initialPanel"] }, host: { properties: { "class.clr-accordion": "true", "class.clr-stepper-forms": "true" } }, providers: [StepperService, { provide: AccordionService, useExisting: StepperService }], queries: [{ propertyName: "panels", predicate: ClrStepperPanel, descendants: true }], usesOnChanges: true, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepper, decorators: [{ type: Component, args: [{ selector: 'form[clrStepper]', template: ``, host: { '[class.clr-accordion]': 'true', '[class.clr-stepper-forms]': 'true', }, providers: [StepperService, { provide: AccordionService, useExisting: StepperService }], changeDetection: ChangeDetectionStrategy.OnPush, }] }], ctorParameters: function () { return [{ type: i1.FormGroupDirective, decorators: [{ type: Optional }] }, { type: i1.NgForm, decorators: [{ type: Optional }] }, { type: StepperService }]; }, propDecorators: { initialPanel: [{ type: Input, args: ['clrInitialStep'] }], panels: [{ type: ContentChildren, args: [ClrStepperPanel, { descendants: true }] }] } }); function fromControlReset(control) { return new Observable(observer => { const unpatchedControlReset = control.reset; control.reset = () => { observer.next(); unpatchedControlReset.apply(control); }; return () => { control.reset = unpatchedControlReset; }; }); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class StepperWillyWonka extends WillyWonka { } StepperWillyWonka.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperWillyWonka, deps: null, target: i0.ɵɵFactoryTarget.Directive }); StepperWillyWonka.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: StepperWillyWonka, selector: "form[clrStepper]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperWillyWonka, decorators: [{ type: Directive, args: [{ selector: 'form[clrStepper]', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class StepperOompaLoompa extends OompaLoompa { constructor(cdr, willyWonka, ifExpandService) { if (!willyWonka) { throw new Error('clr-stepper-panel should only be used inside of clrStepper'); } super(cdr, willyWonka); this.expand = ifExpandService; } get flavor() { return this.expand.expanded; } } StepperOompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperOompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: StepperWillyWonka, optional: true }, { token: IfExpandService }], target: i0.ɵɵFactoryTarget.Directive }); StepperOompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: StepperOompaLoompa, selector: "clr-stepper-panel, [clrStepButton]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StepperOompaLoompa, decorators: [{ type: Directive, args: [{ selector: 'clr-stepper-panel, [clrStepButton]', }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: StepperWillyWonka, decorators: [{ type: Optional }] }, { type: IfExpandService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const declarations = [ClrStepper, ClrStepButton, ClrStepperPanel, StepperOompaLoompa, StepperWillyWonka]; class ClrStepperModule { } ClrStepperModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepperModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrStepperModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrStepperModule, declarations: [ClrStepper, ClrStepButton, ClrStepperPanel, StepperOompaLoompa, StepperWillyWonka], imports: [CommonModule, ClrIconModule, ClrAccordionModule], exports: [ClrStepper, ClrStepButton, ClrStepperPanel, StepperOompaLoompa, StepperWillyWonka, ClrAccordionModule] }); ClrStepperModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepperModule, imports: [CommonModule, ClrIconModule, ClrAccordionModule, ClrAccordionModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStepperModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrAccordionModule], declarations: [...declarations], exports: [...declarations, ClrAccordionModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var Keys; (function (Keys) { Keys["ArrowLeft"] = "ArrowLeft"; Keys["ArrowUp"] = "ArrowUp"; Keys["ArrowRight"] = "ArrowRight"; Keys["ArrowDown"] = "ArrowDown"; Keys["Backspace"] = "Backspace"; Keys["Tab"] = "Tab"; Keys["Enter"] = "Enter"; Keys["Escape"] = "Escape"; Keys["Space"] = "Space"; Keys["Spacebar"] = " "; Keys["Home"] = "Home"; Keys["End"] = "End"; })(Keys || (Keys = {})); var IEKeys; (function (IEKeys) { IEKeys["ArrowUp"] = "Up"; IEKeys["ArrowDown"] = "Down"; IEKeys["ArrowRight"] = "Right"; IEKeys["ArrowLeft"] = "Left"; IEKeys["Space"] = "Spacebar"; IEKeys["Escape"] = "Esc"; })(IEKeys || (IEKeys = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function normalizeKey(key) { if (key === Keys.ArrowUp || key === IEKeys.ArrowUp) { return Keys.ArrowUp; } else if (key === Keys.ArrowDown || key === IEKeys.ArrowDown) { return Keys.ArrowDown; } else if (key === Keys.ArrowRight || key === IEKeys.ArrowRight) { return Keys.ArrowRight; } else if (key === Keys.ArrowLeft || key === IEKeys.ArrowLeft) { return Keys.ArrowLeft; } else if (key === Keys.Space || key === IEKeys.Space) { return Keys.Space; } else if (key === Keys.Escape || key === IEKeys.Escape) { return Keys.Escape; } else { return key; } } function preventArrowKeyScroll(event) { const key = normalizeKey(event.key); if (key === Keys.ArrowUp || key === Keys.ArrowDown || key === Keys.ArrowLeft || key === Keys.ArrowRight) { // prevent element container scroll // MDN references this is really the only way to prevent native browser interactions // https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets event.preventDefault(); } } function isKeyEitherLetterOrNumber(event) { const char = event.key; // Only letter characters differ when they switch between lowercase and uppercase, whether it's an English or non-English letter. return char.toLowerCase() !== char.toUpperCase() || (char >= '0' && char <= '9'); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // Popovers might need to ignore click events on an element // (eg: popover opens on focus on an input field. Clicks should be ignored in this case) class ClrPopoverToggleService { constructor() { this._open = false; this._openChange = new Subject(); this._openEventChange = new Subject(); this._popoverAligned = new Subject(); this._popoverVisible = new Subject(); } get openChange() { return this._openChange.asObservable(); } get popoverVisible() { return this._popoverVisible.asObservable(); } get openEvent() { return this._openEvent; } set openEvent(event) { this._openEvent = event; this._openEventChange.next(event); } get open() { return this._open; } set open(value) { value = !!value; if (this._open !== value) { this._open = value; this._openChange.next(value); } } // For compatibility with legacy IfOpenService based implementations get originalEvent() { return this._openEvent; } get popoverAligned() { return this._popoverAligned.asObservable(); } getEventChange() { return this._openEventChange.asObservable(); } /** * Sometimes, we need to remember the event that triggered the toggling to avoid loops. * This is for instance the case of components that open on a click, but close on a click outside. */ toggleWithEvent(event) { preventArrowKeyScroll(event); this.openEvent = event; this.open = !this.open; } popoverVisibleEmit(visible) { this._popoverVisible.next(visible); } popoverAlignedEmit(popoverNode) { this._popoverAligned.next(popoverNode); } } ClrPopoverToggleService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverToggleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ClrPopoverToggleService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverToggleService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverToggleService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // https://github.com/angular/angular/issues/20351#issuecomment-344009887 /** @dynamic */ class ClrPopoverEventsService { constructor(renderer, smartOpenService, document) { this.renderer = renderer; this.smartOpenService = smartOpenService; this.document = document; this.outsideClickClose = true; this.scrollToClose = true; this.subscriptions = []; this.subscriptions.push(smartOpenService.openChange.subscribe(open => { if (open) { this.addEscapeListener(); this.addClickListener(); this.addScrollListener(); } else { this.removeAllEventListeners(); } }), smartOpenService.getEventChange().subscribe(event => { // Remember the event that was used to open the content this.ignoredEvent = event; })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); this.removeAllEventListeners(); } addScrollListener() { if (this.scrollToClose) { this.documentScroller = fromEvent(this.document, 'scroll', { capture: true }); this.scrollSubscription = this.documentScroller .pipe(filter(this.testForSmartPopoverContentContainer)) .subscribe(() => { this.smartOpenService.open = false; this.setAnchorFocus(); }); } else { // I think this is where dynamic re-positioning will be added // Instead of testing like we do in the close pipe below // we need to switch positioning to use an observable and then // debounce the scroll events to recalculate content position in a performant way // For now, ignore scrolling events. return; } } removeScrollListener() { if (this.documentScroller) { this.scrollSubscription.unsubscribe(); delete this.documentScroller; } } addClickListener() { if (this.outsideClickClose) { this.documentClickListener = this.renderer.listen(this.document, 'click', (event) => { if (event === this.ignoredEvent) { // Here we ignore the opening click event (w/o this content opens and immediately closes. delete this.ignoredEvent; } else { this.smartOpenService.open = false; // Rather than a complex change to the focus trap I put focus on the element that was clicked const clickedElement = event.target; clickedElement.focus(); } }); } } removeClickListener() { if (this.outsideClickClose) { delete this.ignoredEvent; if (this.documentClickListener) { this.documentClickListener(); delete this.documentClickListener; } } } addEscapeListener() { this.escapeListener = this.renderer.listen(this.document, 'keydown.escape', () => { this.smartOpenService.open = false; this.setAnchorFocus(); }); } removeEscapeListener() { if (this.escapeListener) { this.escapeListener(); delete this.escapeListener; } } setCloseFocus() { this.closeButtonRef.nativeElement.focus(); } setAnchorFocus() { this.anchorButtonRef.nativeElement.focus(); } testForSmartPopoverContentContainer(event) { // Filter for the documentScroller observable event targets let target = event.target; // Walk up the DOM tree until we get to the element that is a direct child of the body. while (target.classList && target.parentElement.localName !== 'body') { target = target.parentElement; } // Target is the child element of body where the scroll events originated. // Return false and prevent the popover content container from closing for any scroll events inside a popover // content container. if (target.classList) { // check scroll events to see if they are happening in popover content or elsewhere return target.classList.contains('clr-popover-content') ? false : true; } else { // prevents it from closing right after first opening return false; } } removeAllEventListeners() { this.removeScrollListener(); this.removeClickListener(); this.removeEscapeListener(); } } ClrPopoverEventsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverEventsService, deps: [{ token: i0.Renderer2 }, { token: ClrPopoverToggleService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); ClrPopoverEventsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverEventsService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverEventsService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: ClrPopoverToggleService }, { type: HTMLDocument, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverAnchor { constructor(smartEventService, element) { smartEventService.anchorButtonRef = element; } } ClrPopoverAnchor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverAnchor, deps: [{ token: ClrPopoverEventsService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrPopoverAnchor.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]", host: { properties: { "class.clr-anchor": "true" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverAnchor, decorators: [{ type: Directive, args: [{ selector: '[clrPopoverAnchor]', host: { '[class.clr-anchor]': 'true', }, }] }], ctorParameters: function () { return [{ type: ClrPopoverEventsService }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverCloseButton { constructor(elementRef, smartEventsService, smartOpenService) { this.elementRef = elementRef; this.smartEventsService = smartEventsService; this.smartOpenService = smartOpenService; this.closeChange = new EventEmitter(); this.subscriptions = []; this.subscriptions.push(smartOpenService.openChange.pipe(filter(value => !value)).subscribe(() => { this.closeChange.next(); })); } handleClick(event) { this.smartOpenService.toggleWithEvent(event); this.smartEventsService.setAnchorFocus(); } ngAfterViewInit() { this.smartEventsService.closeButtonRef = this.elementRef; this.smartEventsService.setCloseFocus(); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrPopoverCloseButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverCloseButton, deps: [{ token: i0.ElementRef }, { token: ClrPopoverEventsService }, { token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Directive }); ClrPopoverCloseButton.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrPopoverCloseButton, selector: "[clrPopoverCloseButton]", outputs: { closeChange: "clrPopoverOnCloseChange" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class.clr-smart-close-button": "true" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverCloseButton, decorators: [{ type: Directive, args: [{ selector: '[clrPopoverCloseButton]', host: { '[class.clr-smart-close-button]': 'true', }, }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ClrPopoverEventsService }, { type: ClrPopoverToggleService }]; }, propDecorators: { closeChange: [{ type: Output, args: ['clrPopoverOnCloseChange'] }], handleClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrAxis; (function (ClrAxis) { ClrAxis[ClrAxis["VERTICAL"] = 0] = "VERTICAL"; ClrAxis[ClrAxis["HORIZONTAL"] = 1] = "HORIZONTAL"; })(ClrAxis || (ClrAxis = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrAlignment; (function (ClrAlignment) { ClrAlignment[ClrAlignment["START"] = 0] = "START"; ClrAlignment[ClrAlignment["CENTER"] = 0.5] = "CENTER"; ClrAlignment[ClrAlignment["END"] = 1] = "END"; })(ClrAlignment || (ClrAlignment = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrViewportViolation; (function (ClrViewportViolation) { ClrViewportViolation[ClrViewportViolation["BOTTOM"] = 0] = "BOTTOM"; ClrViewportViolation[ClrViewportViolation["LEFT"] = 1] = "LEFT"; ClrViewportViolation[ClrViewportViolation["RIGHT"] = 2] = "RIGHT"; ClrViewportViolation[ClrViewportViolation["TOP"] = 3] = "TOP"; })(ClrViewportViolation || (ClrViewportViolation = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const flipSides = position => { return { ...position, side: -1 * position.side, }; }; // This could be used in more advanced positioning algorithms. // flipAxisFlipSideAndNudgeContent(flipAxis, flipSide, nudge, nudgeForward?): ClrTransform {...} // I would like to keep it for now. const flipAxis = position => { return { ...position, axis: position.axis === 0 ? 1 : 0, }; }; const nudgeContent = (position, forward) => { const nextAlignment = position.content + (forward ? 0.5 : -0.5); if (nextAlignment < 0 || nextAlignment > 1) { return position; } else { return { ...position, content: nextAlignment, }; } }; function flipSidesAndNudgeContent(flip, nudge, nudgeBack) { return (position) => nudge(flip(position), nudgeBack); } function align(position, anchor, content) { let xDiff = anchor.left; let yDiff = anchor.top; // When ClrAxis is VERTICAL BEFORE = left, AFTER = right // When ClrAxis is HORIZONTAL BEFORE is top, AFTER is bottom switch (position.axis + position.side) { case -1: { // ClrAxis.VERTICAL + ClrSide.BEFORE xDiff += alignHorizontal(position, anchor, content); yDiff -= content.height; // pull content up to the top of the anchor break; } case 1: { // ClrAxis.VERTICAL + ClrSide.AFTER xDiff += alignHorizontal(position, anchor, content); yDiff += anchor.height; // push the content down to below the anchor break; } case 0: { // ClrAxis.HORIZONTAL + ClrSide.BEFORE xDiff -= content.width; // pull the content left of the anchor yDiff += alignVertical(position, anchor, content); break; } case 2: { // ClrAxis.HORIZONTAL + ClrSide.AFTER xDiff += anchor.width; // push the content right of of the anchor yDiff += alignVertical(position, anchor, content); break; } default: { break; } } return { xOffset: xDiff, yOffset: yDiff }; } function alignHorizontal(position, anchor, content) { let horizontalOffset = 0; // horizontal offset for the anchor position switch (position.anchor /*calculate for the anchor alignment*/) { case ClrAlignment.START: { // nothing to calculate here break; } case ClrAlignment.CENTER: { horizontalOffset += anchor.width / 2; // push content over 1/2 anchor width break; } case ClrAlignment.END: { horizontalOffset += anchor.width; // push content over width of the anchor break; } default: { break; } } // horizontal offsets for anchor alignment switch (position.content // calculate for the content alignment ) { case ClrAlignment.START: { // Nothing to calculate here break; } case ClrAlignment.CENTER: { horizontalOffset -= content.width / 2; // pull content left by a value of 1/2 content width break; } case ClrAlignment.END: { // subtract the width of currentContent from horizontalOffset to pull it back horizontalOffset -= content.width; break; } default: { break; } } return horizontalOffset; } function alignVertical(position, anchor, content) { // y axis offsets for anchor alignment let verticalOffset = 0; // Calculate y offset for anchor position switch (position.anchor) { case ClrAlignment.START: { // nothing to calculate here break; } case ClrAlignment.CENTER: { verticalOffset += anchor.height / 2; // push content down to the middle of the anchor rect break; } case ClrAlignment.END: { verticalOffset += anchor.height; // push content down to the bottom of the anchor break; } default: { break; } } // Calculate y offsets for content alignment switch (position.content) { case ClrAlignment.START: { // aligned to the top of the content rect break; } case ClrAlignment.CENTER: { verticalOffset -= content.height / 2; // pull content back up to the middle of the content rect break; } case ClrAlignment.END: { verticalOffset -= content.height; // pull content back up to the bottom of the content rect break; } default: { break; } } return verticalOffset; } function testVisibility(offset, content) { const violations = []; const mockCoords = { bottom: offset.yOffset + content.height, left: offset.xOffset, right: offset.xOffset + content.width, top: offset.yOffset, }; if (!(mockCoords.top >= 0)) { violations.push(ClrViewportViolation.TOP); } if (!(mockCoords.left >= 0)) { violations.push(ClrViewportViolation.LEFT); } if (!(mockCoords.bottom <= (window.innerHeight || document.documentElement.clientHeight))) { violations.push(ClrViewportViolation.BOTTOM); } if (!(mockCoords.right <= (window.innerWidth || document.documentElement.clientWidth))) { violations.push(ClrViewportViolation.RIGHT); } return violations; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverPositionService { constructor(eventService, platformId) { this.eventService = eventService; this.platformId = platformId; this._shouldRealign = new Subject(); this.shouldRealign = this._shouldRealign.asObservable(); } realign() { this._shouldRealign.next(); } alignContent(content) { if (!isPlatformBrowser(this.platformId)) { // Only position when in a browser. // Default to the browser origin and prevent getBoundingClientRect from running. return { xOffset: 0, yOffset: 0, }; } this.currentAnchorCoords = this.eventService.anchorButtonRef.nativeElement.getBoundingClientRect(); this.currentContentCoords = content.getBoundingClientRect(); this.contentOffsets = align(this.position, this.currentAnchorCoords, this.currentContentCoords); const visibilityViolations = testVisibility(this.contentOffsets, this.currentContentCoords); /** * Calculate the sum of viewport errors. This calculation is used below with the provided Axis in the given * ClrPopoverPosition. Its worth putting the ClrViewportViolation enum values here: * * BOTTOM = 0, * LEFT = 1, * RIGHT = 2, * TOP = 3, * * So, this.visibilityViolations.length tells us how many sides of the viewport that the popover content was * clipped on. We can only help when the content has an issue on one or two sides. * errorSum is calculated to determine _how_ to change the position. Looking at both the axis and the number * of violations I can use the errorSum to determine how to transform the position (on the fly) and adjust * where it can be improved. * * Note, more than 3 viewport violations and there isn't anything we can do to help. Also when there are two * violations, we can't help if the violations are TOP+BOTTOM || LEFT+RIGHT => There is no transformation we * can make to the position that will help. * * Some examples: * There is only one error and Primary axis is VERTICAL * - this.handleVerticalAxisOneViolation has a switch that will use the error sum to apply the correct * transform to the position based on the reduction of visibilityViolations. * * There are two errors and Primary axis is HORIZONTAL * - handleHorizontalAxisTwoViolations has a switch that uses the error sum to apply both transforms needed to * improve the content position based on the reduction of visibilityViolations. */ const errorSum = visibilityViolations.reduce((count, current) => { return count + current; }, 0); if (visibilityViolations.length === 1 && this.position.axis === ClrAxis.VERTICAL) { // When primary axis is VERTICAL and there is one viewport violation this.handleVerticalAxisOneViolation(errorSum); } else if (visibilityViolations.length === 1 && this.position.axis === ClrAxis.HORIZONTAL) { // When primary axis is HORIZONTAL and there is one viewport violation this.handleHorizontalAxisOneViolation(errorSum); } else if (visibilityViolations.length === 2 && this.position.axis === ClrAxis.VERTICAL) { // When primary axis is VERTICAL and there are two viewport violations this.handleVerticalAxisTwoViolations(errorSum); } else if (visibilityViolations.length === 2 && this.position.axis === ClrAxis.HORIZONTAL) { // When primary axis is HORIZONTAL and there are two viewport violations this.handleHorizontalAxisTwoViolations(errorSum); } /** * Adjusts popover position based on scroll value by adding the negative 'top' value of currentContentCoords to yOffset for proper alignment. * - The negative value means that the 'top' of the content is scrolled out of view at the top of the viewport. */ if (this.currentContentCoords.top < 0) { this.contentOffsets.yOffset += Math.abs(this.currentContentCoords.top); } /** * This detects the condition where the popover is flipped because it would violate the bottom of the viewport, but flipping it results in the * popover rendering above the top of the body (y coordinate outside the body). In that event, it should be rendered within the body * as much as possible, so this logic sets the top of popover to render touching the top of the body. */ if (this.contentOffsets.yOffset + this.currentAnchorCoords.y < 0) { this.contentOffsets.yOffset = 0 - this.currentContentCoords.top; } return this.contentOffsets; } handleVerticalAxisOneViolation(errorSum) { switch (errorSum) { case 0: case 3: { // BOTTOM(0) or TOP(3) are primary violations and we can just flip sides this.contentOffsets = align(flipSides(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } case 1: { // LEFT(1) is secondary and needs to nudge content right this.contentOffsets = align(this.position, this.currentAnchorCoords, this.currentContentCoords); /** * Even with the nudge we still have a problem. We need to check if the content is going to be clipped */ if (this.contentOffsets.xOffset < 0) { this.contentOffsets.xOffset = 10; } break; } case 2: { // RIGHT(2) is secondary and needs to nudge content left this.contentOffsets = align(nudgeContent(this.position, true), this.currentAnchorCoords, this.currentContentCoords); break; } default: { break; } } } handleVerticalAxisTwoViolations(errorSum) { switch (errorSum) { // We know there are two violations. We can use the errorSum to determine which combination of sides were // violated and handle appropriately. case 5: { // TOP(3)+RIGHT(2) is case 5. We need to flip sides and nudge the content to the left const flipAndNudgeLeft = flipSidesAndNudgeContent(flipSides, nudgeContent, true); this.contentOffsets = align(flipAndNudgeLeft(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } case 4: { //TOP(3)+LEFT(1) is case 4, we need to flip sides and nudge content to the right const flipAndNudgeRight = flipSidesAndNudgeContent(flipSides, nudgeContent, false); this.contentOffsets = align(flipAndNudgeRight(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } case 3: { // TOP(3)+BOTTOM(0) || left(1)+RIGHT(2) is case 3. There is nothing we can do position wise to improve the // placement for this content. break; } case 2: { // BOTTOM(0)+RIGHT(2) is case 2. We need to flip sides and nudge the content to the left const flipAndNudgeLeft = flipSidesAndNudgeContent(flipSides, nudgeContent, true); this.contentOffsets = align(flipAndNudgeLeft(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } case 1: { // BOTTOM(0)+LEFT(1) is case 1. We need to flip sides and nudge to the right const flipAndNudgeRight = flipSidesAndNudgeContent(flipSides, nudgeContent, false); this.contentOffsets = align(flipAndNudgeRight(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } default: { break; } } } handleHorizontalAxisOneViolation(errorSum) { switch (errorSum) { case 1: case 2: { // LEFT(1) and RIGHT(2) are primary violations so we can flip sides this.contentOffsets = align(flipSides(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } case 0: { // BOTTOM(0) is a secondary violation and we need to nudge content up this.contentOffsets = align(nudgeContent(this.position, true), this.currentAnchorCoords, this.currentContentCoords); break; } case 3: { // TOP(3) is a secondary violation and we need to nudge content down this.contentOffsets = align(nudgeContent(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } default: { break; } } } handleHorizontalAxisTwoViolations(errorSum) { switch (errorSum) { case 5: case 4: { // TOP(3)+LEFT(1) is case 4. // TOP(3)+RIGHT(2) is case 5. // In both of these cases we need to flip sides and nudge content down const flipAndNudgeDown = flipSidesAndNudgeContent(flipSides, nudgeContent, false); this.contentOffsets = align(flipAndNudgeDown(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } case 3: { // TOP(3)+BOTTOM(0) || left(1)+RIGHT(2) is case 3. There is nothing we can do position wise to improve the // placement for this content. break; } case 2: case 1: { // BOTTOM(0)+RIGHT(2) is case 2. // BOTTOM(0)+LEFT(1) is case 1. // In both cases we need to flip sides and nudge content up const flipAndNudgeUp = flipSidesAndNudgeContent(flipSides, nudgeContent, true); this.contentOffsets = align(flipAndNudgeUp(this.position), this.currentAnchorCoords, this.currentContentCoords); break; } default: { break; } } } } ClrPopoverPositionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverPositionService, deps: [{ token: ClrPopoverEventsService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); ClrPopoverPositionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverPositionService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverPositionService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: ClrPopoverEventsService }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // https://github.com/angular/angular/issues/20351#issuecomment-344009887 /** @dynamic */ class ClrPopoverContent { constructor(document, container, template, renderer, smartPositionService, smartEventsService, smartOpenService) { this.document = document; this.container = container; this.template = template; this.renderer = renderer; this.smartPositionService = smartPositionService; this.smartEventsService = smartEventsService; this.smartOpenService = smartOpenService; this.subscriptions = []; this.removeClickListenerFn = null; this.shouldRealign = false; // Check-collector pattern: // In order to get accurate content height/width values, we cannot calculate alignment offsets until // after the projected content has stabilized. // As multiple check events may happen in the same rendering cycle, we need to collect all events // and only act after the content is really stable. Or we may get wrong intermediate positioning values. // We will channel subsequent content check events through this observable. this.checkCollector = new EventEmitter(); } set open(value) { this.smartOpenService.open = !!value; } set contentAt(position) { this.smartPositionService.position = position; } set outsideClickClose(clickToClose) { this.smartEventsService.outsideClickClose = !!clickToClose; } set scrollToClose(scrollToClose) { this.smartEventsService.scrollToClose = !!scrollToClose; } ngAfterContentChecked() { if (this.smartOpenService.open && this.view && this.shouldRealign) { // Channel content-check event through the check-collector this.checkCollector.emit(); } } ngAfterViewInit() { this.subscriptions.push(this.smartOpenService.openChange.subscribe(change => { if (change) { this.addContent(); } else { this.removeContent(); } }), this.smartPositionService.shouldRealign.subscribe(() => { this.shouldRealign = true; }), // Here we collect subsequent synchronously received content-check events and only take action // at the end of the cycle. See below for details on the check-collector pattern. this.checkCollector.pipe(debounceTime(0)).subscribe(() => { this.alignContent(); this.shouldRealign = false; if (this.view) { this.renderer.setStyle(this.view.rootNodes[0], 'opacity', '1'); this.smartOpenService.popoverVisibleEmit(true); } })); } ngOnDestroy() { this.removeContent(); this.subscriptions.forEach(sub => sub.unsubscribe()); } /** * TODO(matt): investigate why DebugElement retains a reference to the nodes and causes a memory leak. * A note about the use of appendChild/removeChild * The DebugElement is keeping a reference to the detached node and its unclear why. * This does warrant further investigation. But, since it doesn't happen in production mode * it is a low priority issue for now. */ addContent() { // Create the view container this.view = this.container.createEmbeddedView(this.template); const [rootNode] = this.view.rootNodes; this.smartEventsService.contentRef = rootNode; // So we know where/what to set close focus on this.renderer.addClass(rootNode, 'clr-popover-content'); // Reset to the begining of the document to be available for sizing/positioning calculations. // If we add new content to the bottom it triggers changes in the layout that may lead to false anchor // coordinates values. this.renderer.setStyle(rootNode, 'top', '0px'); this.renderer.setStyle(rootNode, 'left', '0px'); // We need to hide it during the calculation phase, while it's not yet finally positioned. this.renderer.setStyle(rootNode, 'opacity', '0'); this.removeClickListenerFn = this.renderer.listen(rootNode, 'click', event => { this.smartOpenService.openEvent = event; }); this.view.rootNodes.forEach(node => { this.renderer.appendChild(this.document.body, node); }); // Mark for realingment on the next content-check cycle. this.shouldRealign = true; } removeContent() { if (!this.view) { return; } if (this.removeClickListenerFn) { this.removeClickListenerFn(); this.removeClickListenerFn = null; } this.view.rootNodes.forEach(node => this.renderer.removeChild(this.document.body, node)); this.container.clear(); delete this.view; this.smartOpenService.popoverVisibleEmit(false); } alignContent() { if (!this.view) { return; } const positionCoords = this.smartPositionService.alignContent(this.view.rootNodes[0]); this.renderer.setStyle(this.view.rootNodes[0], 'top', `${positionCoords.yOffset}px`); this.renderer.setStyle(this.view.rootNodes[0], 'left', `${positionCoords.xOffset}px`); this.smartOpenService.popoverAlignedEmit(this.view.rootNodes[0]); } } ClrPopoverContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverContent, deps: [{ token: DOCUMENT }, { token: i0.ViewContainerRef }, { token: i0.TemplateRef }, { token: i0.Renderer2 }, { token: ClrPopoverPositionService }, { token: ClrPopoverEventsService }, { token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Directive }); ClrPopoverContent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: { open: ["clrPopoverContent", "open"], contentAt: ["clrPopoverContentAt", "contentAt"], outsideClickClose: ["clrPopoverContentOutsideClickToClose", "outsideClickClose"], scrollToClose: ["clrPopoverContentScrollToClose", "scrollToClose"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverContent, decorators: [{ type: Directive, args: [{ selector: '[clrPopoverContent]', }] }], ctorParameters: function () { return [{ type: Document, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: i0.ViewContainerRef }, { type: i0.TemplateRef }, { type: i0.Renderer2 }, { type: ClrPopoverPositionService }, { type: ClrPopoverEventsService }, { type: ClrPopoverToggleService }]; }, propDecorators: { open: [{ type: Input, args: ['clrPopoverContent'] }], contentAt: [{ type: Input, args: ['clrPopoverContentAt'] }], outsideClickClose: [{ type: Input, args: ['clrPopoverContentOutsideClickToClose'] }], scrollToClose: [{ type: Input, args: ['clrPopoverContentScrollToClose'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverOpenCloseButton { constructor(smartOpenService) { this.smartOpenService = smartOpenService; this.openCloseChange = new EventEmitter(); this.subscriptions = []; this.subscriptions.push(this.smartOpenService.openChange.subscribe(change => { this.openCloseChange.next(change); })); } handleClick(event) { this.smartOpenService.toggleWithEvent(event); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrPopoverOpenCloseButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverOpenCloseButton, deps: [{ token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Directive }); ClrPopoverOpenCloseButton.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: { openCloseChange: "clrPopoverOpenCloseChange" }, host: { listeners: { "click": "handleClick($event)" }, properties: { "class.clr-smart-open-close": "true" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverOpenCloseButton, decorators: [{ type: Directive, args: [{ selector: '[clrPopoverOpenCloseButton]', host: { '[class.clr-smart-open-close]': 'true', }, }] }], ctorParameters: function () { return [{ type: ClrPopoverToggleService }]; }, propDecorators: { openCloseChange: [{ type: Output, args: ['clrPopoverOpenCloseChange'] }], handleClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverModuleNext { } ClrPopoverModuleNext.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModuleNext, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrPopoverModuleNext.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModuleNext, declarations: [ClrPopoverAnchor, ClrPopoverCloseButton, ClrPopoverOpenCloseButton, ClrPopoverContent], exports: [ClrPopoverAnchor, ClrPopoverCloseButton, ClrPopoverOpenCloseButton, ClrPopoverContent] }); ClrPopoverModuleNext.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModuleNext }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModuleNext, decorators: [{ type: NgModule, args: [{ imports: [], declarations: [ClrPopoverAnchor, ClrPopoverCloseButton, ClrPopoverOpenCloseButton, ClrPopoverContent], exports: [ClrPopoverAnchor, ClrPopoverCloseButton, ClrPopoverOpenCloseButton, ClrPopoverContent], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ButtonInGroupService { constructor() { this._changes = new Subject(); } get changes() { return this._changes.asObservable(); } updateButtonGroup(button) { this._changes.next(button); } } ButtonInGroupService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonInGroupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ButtonInGroupService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonInGroupService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonInGroupService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrButton { constructor(buttonInGroupService) { this.buttonInGroupService = buttonInGroupService; this._click = new EventEmitter(false); this._inMenu = false; this._enableService = false; this._classNames = 'btn'; this._name = null; this._type = null; this._disabled = null; this._id = uniqueIdFactory(); } get inMenu() { return this._inMenu; } set inMenu(value) { value = !!value; if (this._inMenu !== value) { this._inMenu = value; // We check if the service flag is enabled // and if the service exists because the service is optional if (this._enableService && this.buttonInGroupService) { this.buttonInGroupService.updateButtonGroup(this); } } } get classNames() { return this._classNames; } set classNames(value) { if (typeof value === 'string') { const classNames = value.split(' '); if (classNames.indexOf('btn') === -1) { classNames.push('btn'); } this._classNames = classNames.join(' '); } } get name() { return this._name; } set name(value) { if (typeof value === 'string') { this._name = value; } } get type() { return this._type; } set type(value) { if (typeof value === 'string') { this._type = value; } } get id() { return this._id; } set id(value) { if (typeof value === 'string') { this._id = value; } } get disabled() { return this._disabled; } set disabled(value) { if (value !== null && value !== false) { this._disabled = ''; } else { this._disabled = null; } } get role() { return this.inMenu ? 'menuitem' : null; } ngAfterViewInit() { this._enableService = true; } loadingStateChange(state) { this.loading = state === ClrLoadingState.LOADING; } emitClick() { this._click.emit(true); } } ClrButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButton, deps: [{ token: ButtonInGroupService, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Component }); ClrButton.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrButton, selector: "clr-button", inputs: { inMenu: ["clrInMenu", "inMenu"], classNames: ["class", "classNames"], name: "name", type: "type", id: "id", disabled: "disabled" }, outputs: { _click: "click" }, providers: [{ provide: LoadingListener, useExisting: ClrButton }], viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["buttonProjectedRef"], descendants: true, static: true }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButton, decorators: [{ type: Component, args: [{ selector: 'clr-button', template: ` `, providers: [{ provide: LoadingListener, useExisting: ClrButton }], }] }], ctorParameters: function () { return [{ type: ButtonInGroupService, decorators: [{ type: SkipSelf }, { type: Optional }] }]; }, propDecorators: { _click: [{ type: Output, args: ['click'] }], templateRef: [{ type: ViewChild, args: ['buttonProjectedRef', { static: true }] }], inMenu: [{ type: Input, args: ['clrInMenu'] }], classNames: [{ type: Input, args: ['class'] }], name: [{ type: Input, args: ['name'] }], type: [{ type: Input, args: ['type'] }], id: [{ type: Input, args: ['id'] }], disabled: [{ type: Input, args: ['disabled'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * @description * * Developers should explicitly add this service to providers; it then can be injected * into a constructor and used as a notifier for the `takeUntil` operator. This eliminates * the need for boilerplates with subscriptions, and we don't need to implement the `OnDestroy` * interface and teardown subscriptions there. * * This can be used as follows: * ```ts * @Component({ * selector: 'clr-button-group', * templateUrl: 'button-group.html', * providers: [ClrDestroyService], * }) * export class ClrButtonGroup { * constructor(public buttonGroupNewService: ButtonInGroupService, private destroy$: ClrDestroyService) {} * * ngAfterContentInit() { * this.buttonGroupNewService.changes.pipe(takeUntil(this.destroy$)).subscribe(button => this.rearrangeButton(button)); * } * } * ``` */ class ClrDestroyService extends Subject { ngOnDestroy() { this.next(); this.complete(); } } ClrDestroyService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDestroyService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); ClrDestroyService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDestroyService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDestroyService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ArrowKeyDirection; (function (ArrowKeyDirection) { ArrowKeyDirection["UP"] = "up"; ArrowKeyDirection["DOWN"] = "down"; ArrowKeyDirection["LEFT"] = "left"; ArrowKeyDirection["RIGHT"] = "right"; })(ArrowKeyDirection || (ArrowKeyDirection = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let FocusService$1 = class FocusService { constructor(renderer) { this.renderer = renderer; this._unlistenFuncs = []; } get current() { return this._current; } reset(first) { this._current = first; } listenToArrowKeys(el) { // The following listeners return false when there was an action to take for the key pressed, // in order to prevent the default behavior of that key. this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowup', () => !this.move(ArrowKeyDirection.UP))); this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowdown', () => !this.move(ArrowKeyDirection.DOWN))); this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowleft', () => !this.move(ArrowKeyDirection.LEFT))); this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowright', () => !this.move(ArrowKeyDirection.RIGHT))); } registerContainer(el, tabIndex = '0') { this.renderer.setAttribute(el, 'tabindex', tabIndex); this.listenToArrowKeys(el); // The following listeners return false when there was an action to take for the key pressed, // in order to prevent the default behavior of that key. this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.space', () => !this.activateCurrent())); this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.enter', () => !this.activateCurrent())); } moveTo(item) { /** * Make sure that item is not undefined, * This is safety net in the case that someone sometime decide to * call this method without having FocusableItem. */ if (item === undefined) { return; } if (this.current) { this.current.blur(); } item.focus(); this._current = item; } move(direction) { let moved = false; if (this.current) { const next = this.current[direction]; if (next) { // Turning the value into an Observable isn't great, but it's the fastest way to avoid code duplication. // If performance ever matters for this, we can refactor using additional private methods. const nextObs = isObservable(next) ? next : of(next); nextObs.subscribe(item => { if (item) { this.moveTo(item); moved = true; } }); } } return moved; } activateCurrent() { if (this.current && this.current.activate) { this.current.activate(); return true; } return false; } detachListeners() { this._unlistenFuncs.forEach(unlisten => unlisten()); } }; FocusService$1.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FocusService$1, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Injectable }); FocusService$1.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FocusService$1 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FocusService$1, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.Renderer2 }]; } }); function clrFocusServiceFactory(existing, renderer) { return existing || new FocusService$1(renderer); } const FOCUS_SERVICE_PROVIDER = { provide: FocusService$1, useFactory: clrFocusServiceFactory, deps: [[new Optional(), new SkipSelf(), FocusService$1], Renderer2], }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrSide; (function (ClrSide) { ClrSide[ClrSide["BEFORE"] = -1] = "BEFORE"; ClrSide[ClrSide["AFTER"] = 1] = "AFTER"; })(ClrSide || (ClrSide = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverPositions { } ClrPopoverPositions['top-right'] = { axis: ClrAxis.VERTICAL, side: ClrSide.BEFORE, anchor: ClrAlignment.END, content: ClrAlignment.END, }; ClrPopoverPositions['top-left'] = { axis: ClrAxis.VERTICAL, side: ClrSide.BEFORE, anchor: ClrAlignment.START, content: ClrAlignment.START, }; ClrPopoverPositions['bottom-right'] = { axis: ClrAxis.VERTICAL, side: ClrSide.AFTER, anchor: ClrAlignment.END, content: ClrAlignment.END, }; ClrPopoverPositions['bottom-left'] = { axis: ClrAxis.VERTICAL, side: ClrSide.AFTER, anchor: ClrAlignment.START, content: ClrAlignment.START, }; ClrPopoverPositions['right-top'] = { axis: ClrAxis.HORIZONTAL, side: ClrSide.AFTER, anchor: ClrAlignment.CENTER, content: ClrAlignment.END, }; ClrPopoverPositions['right-bottom'] = { axis: ClrAxis.HORIZONTAL, side: ClrSide.AFTER, anchor: ClrAlignment.START, content: ClrAlignment.START, }; ClrPopoverPositions['left-top'] = { axis: ClrAxis.HORIZONTAL, side: ClrSide.BEFORE, anchor: ClrAlignment.CENTER, content: ClrAlignment.END, }; ClrPopoverPositions['left-bottom'] = { axis: ClrAxis.HORIZONTAL, side: ClrSide.BEFORE, anchor: ClrAlignment.START, content: ClrAlignment.START, }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const POPOVER_HOST_ANCHOR = new InjectionToken('POPOVER_HOST_ANCHOR'); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStopEscapePropagationDirective { constructor(toggleService) { this.toggleService = toggleService; this.lastOpenChange = null; } ngOnInit() { this.subscription = this.toggleService.openChange.subscribe(open => { this.lastOpenChange = open; }); } ngOnDestroy() { this.subscription?.unsubscribe(); } onEscapeKey(event) { if (this.lastOpenChange !== null) { if (this.lastOpenChange === false) { event.stopPropagation(); } this.lastOpenChange = null; } } } ClrStopEscapePropagationDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStopEscapePropagationDirective, deps: [{ token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Directive }); ClrStopEscapePropagationDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrStopEscapePropagationDirective, isStandalone: true, host: { listeners: { "keyup.escape": "onEscapeKey($event)" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStopEscapePropagationDirective, decorators: [{ type: Directive, args: [{ standalone: true, }] }], ctorParameters: function () { return [{ type: ClrPopoverToggleService }]; }, propDecorators: { onEscapeKey: [{ type: HostListener, args: ['keyup.escape', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverHostDirective { } ClrPopoverHostDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverHostDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); ClrPopoverHostDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrPopoverHostDirective, isStandalone: true, providers: [ ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService, { provide: POPOVER_HOST_ANCHOR, useExisting: ElementRef }, ], hostDirectives: [{ directive: ClrStopEscapePropagationDirective }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverHostDirective, decorators: [{ type: Directive, args: [{ standalone: true, providers: [ ClrPopoverToggleService, ClrPopoverEventsService, ClrPopoverPositionService, { provide: POPOVER_HOST_ANCHOR, useExisting: ElementRef }, ], hostDirectives: [ClrStopEscapePropagationDirective], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class Linkers { /** * Links a set of focusable items to a parent along one direction */ static linkParent(items, parent, direction) { items.forEach(item => (item[direction] = parent)); } /** * Double-links a set of focusable items vertically, possibly looping */ static linkVertical(items, loop = true) { items.forEach((item, index) => { if (index > 0) { item.up = items[index - 1]; } if (index < items.length - 1) { item.down = items[index + 1]; } }); if (loop && items.length > 1) { items[0].up = items[items.length - 1]; items[items.length - 1].down = items[0]; } } } // Right now I only need the two linkers above, but we can easily add more linkers. A couple examples: // export function linkHorizontal(items: FocusableItem[], loop = true); // export function linkTable(items: FocusableItem[][]); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var InitialFocus; (function (InitialFocus) { InitialFocus["FIRST_ITEM"] = "first"; InitialFocus["LAST_ITEM"] = "last"; })(InitialFocus || (InitialFocus = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function collapse() { 'use strict'; return [ state('true', style({ height: 0, 'overflow-y': 'hidden' })), transition('true => false', [animate(defaultAnimationTiming, style({ height: '*', 'overflow-y': 'hidden' }))]), transition('false => true', [style({ height: '*', 'overflow-y': 'hidden' }), animate(defaultAnimationTiming)]), ]; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DomAdapter { userDefinedWidth(element) { element.classList.add('datagrid-cell-width-zero'); const userDefinedWidth = this.clientRect(element).width; element.classList.remove('datagrid-cell-width-zero'); return userDefinedWidth; } scrollBarWidth(element) { return element.offsetWidth - element.clientWidth; } scrollWidth(element) { return element.scrollWidth || 0; } computedHeight(element) { return parseInt(getComputedStyle(element).getPropertyValue('height'), 10); } clientRect(element) { const elementClientRect = element.getBoundingClientRect(); return { top: parseInt(elementClientRect.top, 10), bottom: parseInt(elementClientRect.bottom, 10), left: parseInt(elementClientRect.left, 10), right: parseInt(elementClientRect.right, 10), width: parseInt(elementClientRect.width, 10), height: parseInt(elementClientRect.height, 10), }; } minWidth(element) { return parseInt(getComputedStyle(element).getPropertyValue('min-width'), 10); } focus(element) { element.focus(); } } DomAdapter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DomAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DomAdapter.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DomAdapter }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DomAdapter, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrExpandableAnimation { constructor(element, domAdapter) { this.element = element; this.domAdapter = domAdapter; this.startHeight = 0; } get expandAnimation() { return { value: this.clrExpandTrigger, params: { startHeight: this.startHeight } }; } animationDone() { // A "safe" auto-update of the height ensuring basic OOTB user experience . // Prone to small jumps in initial animation height if data was changed in the meantime, window was resized, etc. // For optimal behavior call manually updateStartHeight() from the parent component before initiating the update. this.updateStartHeight(); } updateStartHeight() { this.startHeight = this.domAdapter.computedHeight(this.element.nativeElement) || 0; } } ClrExpandableAnimation.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrExpandableAnimation, deps: [{ token: i0.ElementRef }, { token: DomAdapter }], target: i0.ɵɵFactoryTarget.Component }); ClrExpandableAnimation.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrExpandableAnimation, selector: "clr-expandable-animation", inputs: { clrExpandTrigger: "clrExpandTrigger" }, host: { listeners: { "@expandAnimation.done": "animationDone()" }, properties: { "@expandAnimation": "this.expandAnimation" } }, providers: [DomAdapter], ngImport: i0, template: ``, isInline: true, styles: [":host{display:block;overflow:hidden}\n"], animations: [ trigger('expandAnimation', [ transition('true <=> false', [ style({ height: '{{startHeight}}px' }), animate('0.2s ease-in-out', style({ height: '*' })), ]), ]), ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrExpandableAnimation, decorators: [{ type: Component, args: [{ selector: 'clr-expandable-animation', template: ``, animations: [ trigger('expandAnimation', [ transition('true <=> false', [ style({ height: '{{startHeight}}px' }), animate('0.2s ease-in-out', style({ height: '*' })), ]), ]), ], providers: [DomAdapter], styles: [":host{display:block;overflow:hidden}\n"] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: DomAdapter }]; }, propDecorators: { clrExpandTrigger: [{ type: Input }], expandAnimation: [{ type: HostBinding, args: ['@expandAnimation'] }], animationDone: [{ type: HostListener, args: ['@expandAnimation.done'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const EXPANDABLE_ANIMATION_DIRECTIVES = [ClrExpandableAnimation]; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function fade(opacity = 1) { return [ transition('void => *', [style({ opacity: 0 }), animate(defaultAnimationTiming, style({ opacity: opacity }))]), transition('* => void', [animate(defaultAnimationTiming, style({ opacity: 0 }))]), ]; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function fadeSlide(direction) { let transform = null; if (direction === 'up') { transform = 'translate(0, 25%)'; } else if (direction === 'down') { transform = 'translate(0, -25%)'; } else if (direction === 'left') { transform = 'translate(25%, 0)'; } else if (direction === 'right') { transform = 'translate(-25%, 0)'; } else { throw new Error('Unknown direction ' + direction + ' for slide animation.'); } return [ transition('void => *', [style({ opacity: 0, transform: transform }), animate(defaultAnimationTiming)]), transition('* => void', [animate(defaultAnimationTiming, style({ opacity: 0, transform: transform }))]), ]; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function slide(direction) { let transform = null; if (direction === 'up') { transform = 'translate(0, 25%)'; } else if (direction === 'down') { transform = 'translate(0, -25%)'; } else if (direction === 'left') { transform = 'translate(25%, 0)'; } else if (direction === 'right') { transform = 'translate(-25%, 0)'; } else { throw new Error('Unknown direction ' + direction + ' for slide animation.'); } return [ transition('void => *', [style({ transform: transform }), animate(defaultAnimationTiming)]), transition('* => void', [animate(defaultAnimationTiming, style({ transform: transform }))]), ]; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_LOADING_DIRECTIVES = [ClrLoading]; class ClrLoadingModule { } ClrLoadingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrLoadingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingModule, declarations: [ClrLoading], imports: [CommonModule], exports: [ClrLoading] }); ClrLoadingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_LOADING_DIRECTIVES], exports: [CLR_LOADING_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let activeCounter = 0; const IF_ACTIVE_ID = new InjectionToken('IF_ACTIVE_ID'); function tokenFactory$1() { return ++activeCounter; } const IF_ACTIVE_ID_PROVIDER = { provide: IF_ACTIVE_ID, useFactory: tokenFactory$1, }; /********* * @class IfActiveService * * @description * An injectable service used by IfActive structural directives and the components that implement IfActive in their * templates. It holds the value of the current state and provides an Observable that both the directive and the * implementing component can subscribe to in order to take action on current value changes. * */ class IfActiveService { constructor() { /******** * @property _currentChange * * @description * A RXJS Subject that updates and provides subscriptions to for the current current state of a component template * implemting the IfActive structural directive. * */ this._currentChange = new Subject(); } /********* * * @description * A getter function that provides an observable for the _current Subject. * */ get currentChange() { return this._currentChange.asObservable(); } /********* * * @description * A property that gets/sets the current state of _current for this instance of IfActive structural directive. * And, broadcasts the new value to all subscribers. * */ get current() { return this._current; } set current(value) { if (this._current !== value) { this._current = value; this._currentChange.next(value); } } } IfActiveService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfActiveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); IfActiveService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfActiveService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfActiveService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /********** * * @class ClrIfActive * * @description * A structural directive that controls whether or not the associated TemplateRef is instantiated or not. * It makes use of a Component instance level service: IfActiveService to maintain state between itself and * the component using it in the component template. * */ class ClrIfActive { constructor(ifActiveService, id, template, container) { this.ifActiveService = ifActiveService; this.id = id; this.template = template; this.container = container; /********** * @property activeChange * * @description * An event emitter that emits when the active property is set to allow for 2way binding when the directive is * used with de-structured / de-sugared syntax. * */ this.activeChange = new EventEmitter(false); this.wasActive = false; this.checkAndUpdateView(ifActiveService.current); this.subscription = this.ifActiveService.currentChange.subscribe(newCurrentId => { this.checkAndUpdateView(newCurrentId); }); } /** * @description * A property that gets/sets IfActiveService.active with value. * */ get active() { return this.ifActiveService.current === this.id; } set active(value) { if (value) { this.ifActiveService.current = this.id; } } ngOnDestroy() { this.subscription.unsubscribe(); } /** * @description * Function that takes a any value and either created an embedded view for the associated ViewContainerRef or, * Clears all views from the ViewContainerRef */ updateView(value) { if (value) { this.container.createEmbeddedView(this.template); } else { this.container.clear(); } } checkAndUpdateView(currentId) { const isNowActive = currentId === this.id; // only emit if the new active state is changed since last time. if (isNowActive !== this.wasActive) { this.updateView(isNowActive); this.activeChange.emit(isNowActive); this.wasActive = isNowActive; } } } ClrIfActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfActive, deps: [{ token: IfActiveService }, { token: IF_ACTIVE_ID }, { token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrIfActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIfActive, selector: "[clrIfActive]", inputs: { active: ["clrIfActive", "active"] }, outputs: { activeChange: "clrIfActiveChange" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfActive, decorators: [{ type: Directive, args: [{ selector: '[clrIfActive]', }] }], ctorParameters: function () { return [{ type: IfActiveService }, { type: undefined, decorators: [{ type: Inject, args: [IF_ACTIVE_ID] }] }, { type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { activeChange: [{ type: Output, args: ['clrIfActiveChange'] }], active: [{ type: Input, args: ['clrIfActive'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /********** * * @class ClrIfOpen * * @description * A structural directive that controls whether or not the associated TemplateRef is instantiated or not. * It makes use of a Component instance level service: ClrPopoverToggleService to maintain state between itself and the component * using it in the component template. * */ class ClrIfOpen { constructor(toggleService, template, container) { this.toggleService = toggleService; this.template = template; this.container = container; /********** * @property openChange * * @description * An event emitter that emits when the open property is set to allow for 2way binding when the directive is * used with de-structured / de-sugared syntax. */ this.openChange = new EventEmitter(false); this.subscription = this.toggleService.openChange.subscribe(change => { this.updateView(change); this.openChange.emit(change); }); } /** * @description * A property that gets/sets ClrPopoverToggleService.open with value. */ get open() { return this.toggleService.open; } set open(value) { this.toggleService.open = value; } ngOnDestroy() { this.subscription.unsubscribe(); } /** * @description * Function that takes a boolean value and either created an embedded view for the associated ViewContainerRef or, * Clears all views from the ViewContainerRef * * @param value */ updateView(value) { if (value) { this.container.createEmbeddedView(this.template); } else { this.container.clear(); } } } ClrIfOpen.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfOpen, deps: [{ token: ClrPopoverToggleService }, { token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrIfOpen.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIfOpen, selector: "[clrIfOpen]", inputs: { open: ["clrIfOpen", "open"] }, outputs: { openChange: "clrIfOpenChange" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfOpen, decorators: [{ type: Directive, args: [{ selector: '[clrIfOpen]', }] }], ctorParameters: function () { return [{ type: ClrPopoverToggleService }, { type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { openChange: [{ type: Output, args: ['clrIfOpenChange'] }], open: [{ type: Input, args: ['clrIfOpen'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrIfExpanded { constructor(template, container, el, renderer, expand) { this.template = template; this.container = container; this.el = el; this.renderer = renderer; this.expand = expand; this.expandedChange = new EventEmitter(true); this._expanded = false; /** * Subscriptions to all the services and queries changes */ this._subscriptions = []; this._subscriptions.push(expand.expandChange.subscribe(() => { this.updateView(); this.expandedChange.emit(this.expand.expanded); })); } get expanded() { return this._expanded; } set expanded(value) { if (typeof value === 'boolean') { this.expand.expanded = value; this._expanded = value; } } ngOnInit() { this.expand.expandable++; this.updateView(); } ngOnDestroy() { this.expand.expandable--; this._subscriptions.forEach((sub) => sub.unsubscribe()); } updateView() { if (this.expand.expanded && this.container.length !== 0) { return; } if (this.template) { if (this.expand.expanded) { // Should we pass a context? I don't see anything useful to pass right now, // but we can come back to it in the future as a solution for additional features. this.container.createEmbeddedView(this.template); } else { // TODO: Move when we move the animation logic to Datagrid Row Expand // We clear before the animation is over. Not ideal, but doing better would involve a much heavier // process for very little gain. Once Angular animations are dynamic enough, we should be able to // get the optimal behavior. this.container.clear(); } } else { try { // If we don't have a template ref, we fallback to a crude display: none for now. if (this.expand.expanded) { this.renderer.setStyle(this.el.nativeElement, 'display', null); } else { this.renderer.setStyle(this.el.nativeElement, 'display', 'none'); } } catch (e) { // We catch the case where clrIfExpanded was put on a non-DOM element, and we just do nothing } } } } ClrIfExpanded.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfExpanded, deps: [{ token: i0.TemplateRef, optional: true }, { token: i0.ViewContainerRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: IfExpandService }], target: i0.ɵɵFactoryTarget.Directive }); ClrIfExpanded.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIfExpanded, selector: "[clrIfExpanded]", inputs: { expanded: ["clrIfExpanded", "expanded"] }, outputs: { expandedChange: "clrIfExpandedChange" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfExpanded, decorators: [{ type: Directive, args: [{ selector: '[clrIfExpanded]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }, { type: i0.ViewContainerRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: IfExpandService }]; }, propDecorators: { expandedChange: [{ type: Output, args: ['clrIfExpandedChange'] }], expanded: [{ type: Input, args: ['clrIfExpanded'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CONDITIONAL_DIRECTIVES = [ClrIfActive, ClrIfOpen, ClrIfExpanded]; class ClrConditionalModule { } ClrConditionalModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrConditionalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrConditionalModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrConditionalModule, declarations: [ClrIfActive, ClrIfOpen, ClrIfExpanded], imports: [CommonModule], exports: [ClrIfActive, ClrIfOpen, ClrIfExpanded] }); ClrConditionalModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrConditionalModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrConditionalModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CONDITIONAL_DIRECTIVES], exports: [CONDITIONAL_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const FOCUS_ON_VIEW_INIT = new InjectionToken('FOCUS_ON_VIEW_INIT'); // This provider holds the default value for clrFocusOnViewInit directive's isEnabled property. // So users can interject this provider and set their own value for this provider. const FOCUS_ON_VIEW_INIT_PROVIDER = { provide: FOCUS_ON_VIEW_INIT, useValue: true, }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* This directive is for guiding the document focus to the newly added content when its view is initialized so that assistive technologies can read its content. */ class ClrFocusOnViewInit { constructor(el, platformId, focusOnViewInit, document, renderer, ngZone) { this.el = el; this.platformId = platformId; this.focusOnViewInit = focusOnViewInit; this.renderer = renderer; this.directFocus = true; // true if the element gets focused without need to set tabindex; this.destroy$ = new Subject(); this._isEnabled = this.focusOnViewInit; // Angular compiler doesn't understand the type Document // when working out the metadata for injectable parameters, // even though it understands the injection token DOCUMENT // https://github.com/angular/angular/issues/20351 this.document = document; ngZone.runOutsideAngular(() => fromEvent(el.nativeElement, 'focusout') .pipe(takeUntil(this.destroy$)) .subscribe(() => { if (!this.directFocus) { // manually set attributes and styles should be removed this.renderer.removeAttribute(this.el.nativeElement, 'tabindex'); this.renderer.setStyle(this.el.nativeElement, 'outline', null); } })); } set isEnabled(value) { if (this.focusOnViewInit && typeof value === 'boolean') { this._isEnabled = value; } } ngAfterViewInit() { this.focus(); } ngOnDestroy() { this.destroy$.next(); } focus() { if (!isPlatformBrowser(this.platformId)) { return; } if (!this._isEnabled) { return; } if (this.document && this.document.activeElement !== this.el.nativeElement) { this.el.nativeElement.focus(); if (this.document.activeElement !== this.el.nativeElement) { // if it's not directly focused now, it means it was a non-interactive element // so we need to give it a tabindex. this.directFocus = false; this.renderer.setAttribute(this.el.nativeElement, 'tabindex', '-1'); this.renderer.setStyle(this.el.nativeElement, 'outline', 'none'); this.el.nativeElement.focus(); } } } } ClrFocusOnViewInit.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFocusOnViewInit, deps: [{ token: i0.ElementRef }, { token: PLATFORM_ID }, { token: FOCUS_ON_VIEW_INIT }, { token: DOCUMENT }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); ClrFocusOnViewInit.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrFocusOnViewInit, selector: "[clrFocusOnViewInit]", inputs: { isEnabled: ["clrFocusOnViewInit", "isEnabled"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFocusOnViewInit, decorators: [{ type: Directive, args: [{ selector: '[clrFocusOnViewInit]', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: undefined, decorators: [{ type: Inject, args: [FOCUS_ON_VIEW_INIT] }] }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { isEnabled: [{ type: Input, args: ['clrFocusOnViewInit'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const FOCUS_ON_VIEW_INIT_DIRECTIVES = [ClrFocusOnViewInit]; class ClrFocusOnViewInitModule { } ClrFocusOnViewInitModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFocusOnViewInitModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrFocusOnViewInitModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrFocusOnViewInitModule, declarations: [ClrFocusOnViewInit], imports: [CommonModule], exports: [ClrFocusOnViewInit] }); ClrFocusOnViewInitModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFocusOnViewInitModule, providers: [FOCUS_ON_VIEW_INIT_PROVIDER], imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFocusOnViewInitModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [FOCUS_ON_VIEW_INIT_DIRECTIVES], providers: [FOCUS_ON_VIEW_INIT_PROVIDER], exports: [FOCUS_ON_VIEW_INIT_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStandaloneCdkTrapFocus extends CdkTrapFocus { } ClrStandaloneCdkTrapFocus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStandaloneCdkTrapFocus, deps: null, target: i0.ɵɵFactoryTarget.Directive }); ClrStandaloneCdkTrapFocus.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrStandaloneCdkTrapFocus, isStandalone: true, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStandaloneCdkTrapFocus, decorators: [{ type: Directive, args: [{ standalone: true, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ButtonGroupFocusHandler { constructor(focusService, toggleService, renderer) { this.focusService = focusService; this.toggleService = toggleService; this.renderer = renderer; this.initialFocus = InitialFocus.FIRST_ITEM; this._unlistenFuncs = []; } ngOnDestroy() { this._unlistenFuncs.forEach((unlisten) => unlisten()); this.focusService.detachListeners(); } initialize({ menu, menuToggle }) { this.menu = menu; this.menuToggle = menuToggle; this.focusService.registerContainer(this.menu, '-1'); this.listenToKeys(); this.linkButtons(); switch (this.initialFocus) { case InitialFocus.LAST_ITEM: this.focusLastItem(); break; default: this.focusFirstItem(); break; } } resetButtonsFocus() { this.buttons.forEach(button => { button.blur(); }); } listenToKeys() { this._unlistenFuncs.push(this.renderer.listen(this.menu, 'keydown.shift.tab', event => this.closeMenu(event, false))); this._unlistenFuncs.push(this.renderer.listen(this.menu, 'keydown.tab', event => this.closeMenu(event, true))); } closeMenu(event, focusBackOnToggle) { this.toggleService.toggleWithEvent(event); if (focusBackOnToggle) { this.menuToggle.focus(); } this.resetButtonsFocus(); } linkButtons() { const buttonElements = Array.from(this.menu.children); this.buttons = buttonElements.map(buttonElement => { this._unlistenFuncs.push(this.renderer.listen(buttonElement, 'click', event => this.closeMenu(event, true))); return { id: buttonElement.id, value: buttonElement, focus: () => { buttonElement.setAttribute('tabindex', '0'); buttonElement.focus(); }, blur: () => { buttonElement.setAttribute('tabindex', '-1'); buttonElement.blur(); }, }; }); this.resetButtonsFocus(); Linkers.linkVertical(this.buttons); } focusFirstItem() { if (this.buttons.length) { this.focusService.moveTo(this.buttons[0]); } this.initialFocus = InitialFocus.FIRST_ITEM; } focusLastItem() { if (this.buttons.length) { this.focusService.moveTo(this.buttons[this.buttons.length - 1]); } this.initialFocus = InitialFocus.FIRST_ITEM; } } ButtonGroupFocusHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonGroupFocusHandler, deps: [{ token: FocusService$1 }, { token: ClrPopoverToggleService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Injectable }); ButtonGroupFocusHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonGroupFocusHandler }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonGroupFocusHandler, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: FocusService$1 }, { type: ClrPopoverToggleService }, { type: i0.Renderer2 }]; } }); const BUTTON_GROUP_FOCUS_HANDLER_PROVIDER = { provide: ButtonGroupFocusHandler, }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrButtonGroup { constructor(buttonGroupNewService, toggleService, commonStrings, destroy$, focusHandler) { this.buttonGroupNewService = buttonGroupNewService; this.toggleService = toggleService; this.commonStrings = commonStrings; this.destroy$ = destroy$; this.focusHandler = focusHandler; this.clrToggleButtonAriaLabel = this.commonStrings.keys.rowActions; this.popoverId = uniqueIdFactory(); this.InitialFocus = InitialFocus; this.popoverPosition = ClrPopoverPositions['bottom-left']; this.inlineButtons = []; this.menuButtons = []; } get menuPosition() { return this._menuPosition; } set menuPosition(pos) { if (pos && ClrPopoverPositions[pos]) { this._menuPosition = pos; } else { this._menuPosition = 'bottom-left'; } this.popoverPosition = ClrPopoverPositions[this._menuPosition]; } get open() { return this.toggleService.open; } /** * 1. Initializes the initial Button Group View * 2. Subscribes to changes on the ContentChildren * in case the user content projection changes */ ngAfterContentInit() { this.initializeButtons(); this.buttonGroupNewService.changes.pipe(takeUntil(this.destroy$)).subscribe(button => this.rearrangeButton(button)); this.buttons.changes.subscribe(() => { this.initializeButtons(); }); } ngAfterViewInit() { this.handleFocusOnMenuOpen(); } /** * Moves the button into the other ViewContainer * when an update is received. * * @param button */ rearrangeButton(button) { let fromView; let toView; if (button.inMenu) { fromView = this.inlineButtons; toView = this.menuButtons; } else { fromView = this.menuButtons; toView = this.inlineButtons; } const index = fromView.indexOf(button); if (index > -1) { fromView.splice(index, 1); const moveIndex = this.getMoveIndex(button); if (moveIndex <= toView.length) { toView.splice(moveIndex, 0, button); } } } openMenu(event, initialFocus) { this.focusHandler.initialFocus = initialFocus; if (!this.toggleService.open) { this.toggleService.toggleWithEvent(event); } } /** * Author: Eudes * * Finds the order of a button w.r.t other buttons * * @param buttonToMove * @returns */ getMoveIndex(buttonToMove) { const tempArr = this.buttons.filter(button => button.inMenu === buttonToMove.inMenu); return tempArr.indexOf(buttonToMove); } initializeButtons() { const tempInlineButtons = []; const tempInMenuButtons = []; this.buttons.forEach(button => { if (button.inMenu) { tempInMenuButtons.push(button); } else { tempInlineButtons.push(button); } }); this.inlineButtons = tempInlineButtons; this.menuButtons = tempInMenuButtons; } handleFocusOnMenuOpen() { this.toggleService.popoverVisible.pipe(takeUntil(this.destroy$)).subscribe(visible => { if (visible) { this.focusHandler.initialize({ menu: this.menu.nativeElement, menuToggle: this.menuToggle.nativeElement, }); } }); } } ClrButtonGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonGroup, deps: [{ token: ButtonInGroupService }, { token: ClrPopoverToggleService }, { token: ClrCommonStringsService }, { token: ClrDestroyService }, { token: ButtonGroupFocusHandler }], target: i0.ɵɵFactoryTarget.Component }); ClrButtonGroup.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrButtonGroup, selector: "clr-button-group", inputs: { clrToggleButtonAriaLabel: "clrToggleButtonAriaLabel", menuPosition: ["clrMenuPosition", "menuPosition"] }, host: { properties: { "class.btn-group": "true" } }, providers: [ButtonInGroupService, ClrDestroyService, BUTTON_GROUP_FOCUS_HANDLER_PROVIDER, FOCUS_SERVICE_PROVIDER], queries: [{ propertyName: "buttons", predicate: ClrButton }], viewQueries: [{ propertyName: "menuToggle", first: true, predicate: ["menuToggle"], descendants: true }, { propertyName: "menu", first: true, predicate: ["menu"], descendants: true }], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: "\n\n\n\n
0\" class=\"btn-group-overflow open\" [ngClass]=\"menuPosition\">\n \n \n \n \n \n
\n\n", dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonGroup, decorators: [{ type: Component, args: [{ selector: 'clr-button-group', providers: [ButtonInGroupService, ClrDestroyService, BUTTON_GROUP_FOCUS_HANDLER_PROVIDER, FOCUS_SERVICE_PROVIDER], hostDirectives: [ClrPopoverHostDirective], host: { '[class.btn-group]': 'true' }, template: "\n\n\n\n
0\" class=\"btn-group-overflow open\" [ngClass]=\"menuPosition\">\n \n \n \n \n \n
\n\n" }] }], ctorParameters: function () { return [{ type: ButtonInGroupService }, { type: ClrPopoverToggleService }, { type: ClrCommonStringsService }, { type: ClrDestroyService }, { type: ButtonGroupFocusHandler }]; }, propDecorators: { clrToggleButtonAriaLabel: [{ type: Input, args: ['clrToggleButtonAriaLabel'] }], menuToggle: [{ type: ViewChild, args: ['menuToggle'] }], menu: [{ type: ViewChild, args: ['menu'] }], buttons: [{ type: ContentChildren, args: [ClrButton] }], menuPosition: [{ type: Input, args: ['clrMenuPosition'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_BUTTON_GROUP_DIRECTIVES = [ClrButton, ClrButtonGroup]; class ClrButtonGroupModule { } ClrButtonGroupModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonGroupModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrButtonGroupModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonGroupModule, declarations: [ClrButton, ClrButtonGroup], imports: [CommonModule, ClrIconModule, ClrPopoverModuleNext], exports: [ClrButton, ClrButtonGroup] }); ClrButtonGroupModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonGroupModule, imports: [CommonModule, ClrIconModule, ClrPopoverModuleNext] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonGroupModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrPopoverModuleNext], declarations: [CLR_BUTTON_GROUP_DIRECTIVES], exports: [CLR_BUTTON_GROUP_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // minimum width to fit loading spinner const MIN_BUTTON_WIDTH = 42; class ClrLoadingButton { constructor(el, renderer) { this.el = el; this.renderer = renderer; this.clrLoadingChange = new EventEmitter(false); this.buttonState = ClrLoadingState; this.state = ClrLoadingState.DEFAULT; } loadingStateChange(state) { if (state === this.state) { return; } this.state = state; switch (state) { case ClrLoadingState.DEFAULT: this.renderer.removeStyle(this.el.nativeElement, 'width'); this.renderer.removeStyle(this.el.nativeElement, 'transform'); // for chromium render bug see issue https://github.com/vmware/clarity/issues/2700 if (!this.disabled) { this.renderer.removeAttribute(this.el.nativeElement, 'disabled'); } break; case ClrLoadingState.LOADING: this.setExplicitButtonWidth(); this.renderer.setStyle(this.el.nativeElement, 'transform', 'translatez(0)'); // for chromium render bug see issue https://github.com/vmware/clarity/issues/2700 this.renderer.setAttribute(this.el.nativeElement, 'disabled', ''); break; case ClrLoadingState.SUCCESS: this.setExplicitButtonWidth(); break; case ClrLoadingState.ERROR: this.loadingStateChange(ClrLoadingState.DEFAULT); break; default: break; } this.clrLoadingChange.emit(state); } setExplicitButtonWidth() { if (this.el.nativeElement && this.el.nativeElement.getBoundingClientRect) { const boundingClientRect = this.el.nativeElement.getBoundingClientRect(); const width = Math.max(MIN_BUTTON_WIDTH, boundingClientRect.width); this.renderer.setStyle(this.el.nativeElement, 'width', `${width}px`); } } } ClrLoadingButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingButton, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); ClrLoadingButton.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrLoadingButton, selector: "button[clrLoading]", inputs: { disabled: "disabled" }, outputs: { clrLoadingChange: "clrLoadingChange" }, host: { properties: { "attr.disabled": "disabled? '' : null" } }, providers: [{ provide: LoadingListener, useExisting: ClrLoadingButton }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }], animations: [ trigger('parent', [ // Skip :enter animation on first render. // The button text/content should only be faded when transitioning to or from a non-default state. transition(':enter', []), ]), trigger('defaultButton', [ transition(':enter', [style({ opacity: 0 }), animate('200ms 100ms ease-in', style({ opacity: 1 }))]), // TODO: see if we can get leave animation to work before spinner's enter animation transition(':leave', [style({ opacity: 0 })]), ]), trigger('spinner', [ transition(':enter', [style({ opacity: 0 }), animate('200ms 100ms ease-in', style({ opacity: 1 }))]), transition(':leave', [style({ opacity: 1 }), animate('100ms ease-out', style({ opacity: 0 }))]), ]), trigger('validated', [ transition(':enter', [ animate('600ms', keyframes([ style({ transform: 'scale(0,0)', offset: 0 }), style({ opacity: 1, offset: 0.2 }), style({ transform: 'scale(1.2,1.2)', offset: 0.4 }), style({ transform: 'scale(.9,.9)', offset: 0.6 }), style({ transform: 'scale(1,1)', offset: 1 }), ])), ]), transition(':leave', [style({ opacity: 1 }), animate('100ms ease-out', style({ opacity: 0 }))]), ]), ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingButton, decorators: [{ type: Component, args: [{ selector: 'button[clrLoading]', template: ` `, providers: [{ provide: LoadingListener, useExisting: ClrLoadingButton }], animations: [ trigger('parent', [ // Skip :enter animation on first render. // The button text/content should only be faded when transitioning to or from a non-default state. transition(':enter', []), ]), trigger('defaultButton', [ transition(':enter', [style({ opacity: 0 }), animate('200ms 100ms ease-in', style({ opacity: 1 }))]), // TODO: see if we can get leave animation to work before spinner's enter animation transition(':leave', [style({ opacity: 0 })]), ]), trigger('spinner', [ transition(':enter', [style({ opacity: 0 }), animate('200ms 100ms ease-in', style({ opacity: 1 }))]), transition(':leave', [style({ opacity: 1 }), animate('100ms ease-out', style({ opacity: 0 }))]), ]), trigger('validated', [ transition(':enter', [ animate('600ms', keyframes([ style({ transform: 'scale(0,0)', offset: 0 }), style({ opacity: 1, offset: 0.2 }), style({ transform: 'scale(1.2,1.2)', offset: 0.4 }), style({ transform: 'scale(.9,.9)', offset: 0.6 }), style({ transform: 'scale(1,1)', offset: 1 }), ])), ]), transition(':leave', [style({ opacity: 1 }), animate('100ms ease-out', style({ opacity: 0 }))]), ]), ], host: { '[attr.disabled]': "disabled? '' : null" }, }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { disabled: [{ type: Input, args: ['disabled'] }], clrLoadingChange: [{ type: Output, args: ['clrLoadingChange'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_LOADING_BUTTON_DIRECTIVES = [ClrLoadingButton]; class ClrLoadingButtonModule { } ClrLoadingButtonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrLoadingButtonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingButtonModule, declarations: [ClrLoadingButton], imports: [CommonModule], exports: [ClrLoadingButton] }); ClrLoadingButtonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingButtonModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLoadingButtonModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_LOADING_BUTTON_DIRECTIVES], exports: [CLR_LOADING_BUTTON_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrButtonModule { constructor() { ClarityIcons.addIcons(ellipsisHorizontalIcon); } } ClrButtonModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrButtonModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonModule, exports: [ClrLoadingButtonModule, ClrButtonGroupModule] }); ClrButtonModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonModule, imports: [ClrLoadingButtonModule, ClrButtonGroupModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrButtonModule, decorators: [{ type: NgModule, args: [{ exports: [ClrLoadingButtonModule, ClrButtonGroupModule], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class EmptyAnchor { } EmptyAnchor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: EmptyAnchor, deps: [], target: i0.ɵɵFactoryTarget.Component }); EmptyAnchor.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: EmptyAnchor, selector: "ng-component", ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: EmptyAnchor, decorators: [{ type: Component, args: [{ template: '', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Internal module, please do not export! */ class ClrHostWrappingModule { } ClrHostWrappingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrHostWrappingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrHostWrappingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrHostWrappingModule, declarations: [EmptyAnchor], exports: [EmptyAnchor] }); ClrHostWrappingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrHostWrappingModule }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrHostWrappingModule, decorators: [{ type: NgModule, args: [{ declarations: [EmptyAnchor], exports: [EmptyAnchor], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let counter$2 = 0; class ControlIdService { constructor() { this._id = 'clr-form-control-' + ++counter$2; this._idChange = new BehaviorSubject(this._id); } get id() { return this._id; } set id(value) { this._id = value; this._idChange.next(value); } get idChange() { return this._idChange.asObservable(); } } ControlIdService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ControlIdService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ControlIdService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ControlIdService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ControlIdService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let counter$1 = 0; /** * @TODO No idea why I need to use provideIn .. without I'm getting error that * ContainerIdService is not defined - But this must be optional service!? * * There is something wrong - will come back to investigate it when I have more time * */ class ContainerIdService { constructor() { this._id = `clr-form-container-${++counter$1}`; this._idChange = new BehaviorSubject(this._id); } get id() { return this._id; } set id(value) { this._id = value; this._idChange.next(value); } get idChange() { return this._idChange.asObservable(); } } ContainerIdService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ContainerIdService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ContainerIdService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ContainerIdService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ContainerIdService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CONTROL_SUFFIX = { HELPER: 'helper', ERROR: 'error', SUCCESS: 'success', NONE: null, }; class ClrAbstractControl { constructor(controlIdService, containerIdService) { this.controlIdService = controlIdService; this.containerIdService = containerIdService; /** * Hold the suffix for the ID */ this.controlIdSuffix = 'abstract'; } get id() { /** * The order of witch the id will be pick is: * - Container ID (Wrapper arround multiple Controls like, Checkbox, Radio, ...) * - Control ID (Single Control wrapper like Input, Textarea, Password, ...) * - None */ if (this.containerIdService) { return `${this.containerIdService.id}-${this.controlIdSuffix}`; } if (this.controlIdService) { return `${this.controlIdService.id}-${this.controlIdSuffix}`; } return null; } } ClrAbstractControl.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAbstractControl, deps: [{ token: ControlIdService, optional: true }, { token: ContainerIdService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrAbstractControl.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrAbstractControl, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAbstractControl, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: ControlIdService, decorators: [{ type: Optional }] }, { type: ContainerIdService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrControlError extends ClrAbstractControl { constructor(controlIdService, containerIdService) { super(controlIdService, containerIdService); this.controlIdService = controlIdService; this.containerIdService = containerIdService; this.controlIdSuffix = CONTROL_SUFFIX.ERROR; } } ClrControlError.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlError, deps: [{ token: ControlIdService, optional: true }, { token: ContainerIdService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); ClrControlError.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrControlError, selector: "clr-control-error", host: { properties: { "class.clr-subtext": "true", "attr.id": "id" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlError, decorators: [{ type: Component, args: [{ selector: 'clr-control-error', template: ``, host: { '[class.clr-subtext]': 'true', '[attr.id]': 'id', }, }] }], ctorParameters: function () { return [{ type: ControlIdService, decorators: [{ type: Optional }] }, { type: ContainerIdService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrControlHelper extends ClrAbstractControl { constructor(controlIdService, containerIdService) { super(controlIdService, containerIdService); this.controlIdService = controlIdService; this.containerIdService = containerIdService; this.controlIdSuffix = CONTROL_SUFFIX.HELPER; } } ClrControlHelper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlHelper, deps: [{ token: ControlIdService, optional: true }, { token: ContainerIdService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); ClrControlHelper.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrControlHelper, selector: "clr-control-helper", host: { properties: { "class.clr-subtext": "true", "attr.id": "id" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlHelper, decorators: [{ type: Component, args: [{ selector: 'clr-control-helper', template: ``, host: { '[class.clr-subtext]': 'true', '[attr.id]': 'id', }, }] }], ctorParameters: function () { return [{ type: ControlIdService, decorators: [{ type: Optional }] }, { type: ContainerIdService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class NgControlService { constructor() { // Observable to subscribe to the control, since its not available immediately for projected content this._controlChanges = new Subject(); this._helpers = new Subject(); } get controlChanges() { return this._controlChanges.asObservable(); } get helpersChange() { return this._helpers.asObservable(); } setControl(control) { this._controlChanges.next(control); } setHelpers(state) { this._helpers.next(state); } } NgControlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NgControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); NgControlService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NgControlService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NgControlService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var CONTROL_STATE; (function (CONTROL_STATE) { CONTROL_STATE["NONE"] = "NONE"; CONTROL_STATE["VALID"] = "VALID"; CONTROL_STATE["INVALID"] = "INVALID"; })(CONTROL_STATE || (CONTROL_STATE = {})); class IfControlStateService { constructor(ngControlService) { this.ngControlService = ngControlService; this.subscriptions = []; // Implement our own status changes observable, since Angular controls don't this._statusChanges = new BehaviorSubject(CONTROL_STATE.NONE); // Wait for the control to be available this.subscriptions.push(this.ngControlService.controlChanges.subscribe(control => { if (control) { this.control = control; // Subscribe to the status change events, only after touched // and emit the control this.subscriptions.push(this.control.statusChanges.subscribe(() => { this.triggerStatusChange(); })); } })); } get statusChanges() { return this._statusChanges.asObservable(); } ngOnDestroy() { this.subscriptions.forEach(subscription => subscription.unsubscribe()); } triggerStatusChange() { /* Check if control is defined and run the code only then */ if (this.control) { // These status values are mutually exclusive, so a control // cannot be both valid AND invalid or invalid AND disabled. const status = CONTROL_STATE[this.control.status]; this._statusChanges.next(['VALID', 'INVALID'].includes(status) ? status : CONTROL_STATE.NONE); } } } IfControlStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfControlStateService, deps: [{ token: NgControlService }], target: i0.ɵɵFactoryTarget.Injectable }); IfControlStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfControlStateService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: IfControlStateService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: NgControlService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrFormLayout; (function (ClrFormLayout) { ClrFormLayout["VERTICAL"] = "vertical"; ClrFormLayout["HORIZONTAL"] = "horizontal"; ClrFormLayout["COMPACT"] = "compact"; })(ClrFormLayout || (ClrFormLayout = {})); class LayoutService { constructor() { this.minLabelSize = 1; this.maxLabelSize = 12; this.layout = ClrFormLayout.HORIZONTAL; // This is basically a replacement for Object.values(), which IE11 and Node <9 don't support :( // String enums cannot be reverse-mapped, meaning ClrFormLayout['COMPACT'] does not return 'compact' so // this exists to deal with this little caveat to get the list of the values as an array. this.layoutValues = Object.keys(ClrFormLayout).map(key => ClrFormLayout[key]); this._labelSize = 2; } get labelSize() { return this._labelSize; } set labelSize(size) { if (this.labelSizeIsValid(size)) { this._labelSize = size; } } get layoutClass() { return `clr-form-${this.layout}`; } isVertical() { return this.layout === ClrFormLayout.VERTICAL; } isHorizontal() { return this.layout === ClrFormLayout.HORIZONTAL; } isCompact() { return this.layout === ClrFormLayout.COMPACT; } isValid(layout) { return this.layoutValues.indexOf(layout) > -1; } labelSizeIsValid(labelSize) { return Number.isInteger(labelSize) && labelSize >= this.minLabelSize && labelSize <= this.maxLabelSize; } } LayoutService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); LayoutService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: LayoutService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: LayoutService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrLabel { constructor(controlIdService, layoutService, ngControlService, renderer, el) { this.controlIdService = controlIdService; this.layoutService = layoutService; this.ngControlService = ngControlService; this.renderer = renderer; this.el = el; this.enableGrid = true; this.subscriptions = []; } get labelText() { return this.el.nativeElement && this.el.nativeElement.textContent; } ngOnInit() { // Only add the clr-control-label if it is inside a control container if (this.controlIdService || this.ngControlService) { this.renderer.addClass(this.el.nativeElement, 'clr-control-label'); } // Only set the grid column classes if we are in the right context and if they aren't already set if (this.enableGrid && this.layoutService && !this.layoutService.isVertical() && this.el.nativeElement && this.el.nativeElement.className.indexOf('clr-col') < 0) { this.renderer.addClass(this.el.nativeElement, 'clr-col-12'); this.renderer.addClass(this.el.nativeElement, `clr-col-md-${this.layoutService.labelSize}`); } if (this.controlIdService && !this.forAttr) { this.subscriptions.push(this.controlIdService.idChange.subscribe(id => (this.forAttr = id))); } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } disableGrid() { this.enableGrid = false; } } ClrLabel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLabel, deps: [{ token: ControlIdService, optional: true }, { token: LayoutService, optional: true }, { token: NgControlService, optional: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrLabel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrLabel, selector: "label", inputs: { forAttr: ["for", "forAttr"] }, host: { properties: { "attr.for": "this.forAttr" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLabel, decorators: [{ type: Directive, args: [{ selector: 'label', }] }], ctorParameters: function () { return [{ type: ControlIdService, decorators: [{ type: Optional }] }, { type: LayoutService, decorators: [{ type: Optional }] }, { type: NgControlService, decorators: [{ type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { forAttr: [{ type: Input, args: ['for'] }, { type: HostBinding, args: ['attr.for'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrControlSuccess extends ClrAbstractControl { constructor(controlIdService, containerIdService) { super(controlIdService, containerIdService); this.controlIdService = controlIdService; this.containerIdService = containerIdService; this.controlIdSuffix = CONTROL_SUFFIX.SUCCESS; } } ClrControlSuccess.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlSuccess, deps: [{ token: ControlIdService, optional: true }, { token: ContainerIdService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); ClrControlSuccess.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrControlSuccess, selector: "clr-control-success", host: { properties: { "class.clr-subtext": "true", "attr.id": "id" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlSuccess, decorators: [{ type: Component, args: [{ selector: 'clr-control-success', template: ``, host: { '[class.clr-subtext]': 'true', '[attr.id]': 'id', }, }] }], ctorParameters: function () { return [{ type: ControlIdService, decorators: [{ type: Optional }] }, { type: ContainerIdService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLASS_ERROR = 'clr-error'; const CLASS_SUCCESS = 'clr-success'; class ControlClassService { constructor(layoutService) { this.layoutService = layoutService; this.className = ''; } controlClass(state = CONTROL_STATE.NONE, grid = false, additional = '') { const controlClasses = [this.className, additional]; switch (state) { case CONTROL_STATE.VALID: controlClasses.push(CLASS_SUCCESS); break; case CONTROL_STATE.INVALID: controlClasses.push(CLASS_ERROR); break; } if (grid && this.layoutService && this.className.indexOf('clr-col') === -1) { controlClasses.push(`clr-col-md-${this.layoutService.maxLabelSize - this.layoutService.labelSize} clr-col-12`); } return controlClasses.join(' ').trim(); } // We want to remove the column classes from the input up to the container initControlClass(renderer, element) { if (element && element.className) { this.className = element.className; const klasses = element.className.split(' '); klasses.forEach(klass => { if (klass.startsWith('clr-col')) { renderer.removeClass(element, klass); } }); } } } ControlClassService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ControlClassService, deps: [{ token: LayoutService, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); ControlClassService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ControlClassService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ControlClassService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: LayoutService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAbstractContainer { constructor(ifControlStateService, layoutService, controlClassService, ngControlService) { this.ifControlStateService = ifControlStateService; this.layoutService = layoutService; this.controlClassService = controlClassService; this.ngControlService = ngControlService; this._dynamic = false; this.subscriptions = []; this.subscriptions.push(this.ifControlStateService.statusChanges.subscribe((state) => { this.state = state; this.updateHelpers(); })); this.subscriptions.push(this.ngControlService.controlChanges.subscribe(control => { this.control = control; })); } /** * @NOTE * Helper control is a bit different than the others, it must be visible most of the time: * - Helper must NOT be visible when CONTROL_STATE is not NONE and Success or Error components are \ * defined. * * For example user implement only Error control then if CONTROL_STATE is VALID then helper * control must be visible. */ get showHelper() { // without existence of helper component there is no need of additional checks. if (!!this.controlHelperComponent === false) { return false; } return ( /* Helper Component exist and the state of the form is NONE (not touched) */ (!!this.controlHelperComponent && (!this.touched || this.state === CONTROL_STATE.NONE)) || /* or there is no success component but the state of the form is VALID - show helper information */ (!!this.controlSuccessComponent === false && this.state === CONTROL_STATE.VALID) || /* or there is no error component but the state of the form is INVALID - show helper information */ (!!this.controlErrorComponent === false && this.state === CONTROL_STATE.INVALID)); } get showValid() { return this.touched && this.state === CONTROL_STATE.VALID && !!this.controlSuccessComponent; } get showInvalid() { return this.touched && this.state === CONTROL_STATE.INVALID && !!this.controlErrorComponent; } get touched() { return this.control?.touched; } ngAfterContentInit() { /** * We gonna set the helper control state, after all or most of the components * are ready - also this will trigger some initial flows into wrappers and controls, * like locating IDs and setting attributes. */ this.updateHelpers(); } ngOnDestroy() { this.subscriptions.forEach(subscription => subscription.unsubscribe()); } controlClass() { /** * Decide what subtext to display: * - container is valid but no success component is implemented - use helper class * - container is valid and success component is implemented - use success class */ if ((!this.controlSuccessComponent && this.state === CONTROL_STATE.VALID) || !this.touched) { return this.controlClassService.controlClass(CONTROL_STATE.NONE, this.addGrid()); } /** * Pass form control state and return string of classes to be applied to the container. */ return this.controlClassService.controlClass(this.state, this.addGrid()); } addGrid() { return this.layoutService && !this.layoutService.isVertical(); } updateHelpers() { if (this.ngControlService) { this.ngControlService.setHelpers({ show: this.showInvalid || this.showHelper || this.showValid, showInvalid: this.showInvalid, showHelper: this.showHelper, showValid: this.showValid, }); } } } ClrAbstractContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAbstractContainer, deps: [{ token: IfControlStateService }, { token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }], target: i0.ɵɵFactoryTarget.Directive }); ClrAbstractContainer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrAbstractContainer, queries: [{ propertyName: "label", first: true, predicate: ClrLabel, descendants: true }, { propertyName: "controlSuccessComponent", first: true, predicate: ClrControlSuccess, descendants: true }, { propertyName: "controlErrorComponent", first: true, predicate: ClrControlError, descendants: true }, { propertyName: "controlHelperComponent", first: true, predicate: ClrControlHelper, descendants: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAbstractContainer, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: IfControlStateService }, { type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }]; }, propDecorators: { label: [{ type: ContentChild, args: [ClrLabel, { static: false }] }], controlSuccessComponent: [{ type: ContentChild, args: [ClrControlSuccess] }], controlErrorComponent: [{ type: ContentChild, args: [ClrControlError] }], controlHelperComponent: [{ type: ContentChild, args: [ClrControlHelper] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrControlContainer extends ClrAbstractContainer { } ClrControlContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlContainer, deps: null, target: i0.ɵɵFactoryTarget.Component }); ClrControlContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrControlContainer, selector: "clr-control-container", host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControlContainer, decorators: [{ type: Component, args: [{ selector: 'clr-control-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * HostWrapper must be called in OnInit to ensure that the Views are ready. If its called in a constructor the view is * still undefined. * TODO - make sure these comment annotations do not break ng-packgr. */ class HostWrapper { constructor(containerType, vcr, index = 0) { this.injector = vcr.injector; // If the host is already wrapped, we don't do anything if (!this.injector.get(containerType, null)) { const cfr = this.injector.get(ComponentFactoryResolver); const el = this.injector.get(ElementRef); // We need a new anchor, since we're projecting the current one. vcr.createComponent(cfr.resolveComponentFactory(EmptyAnchor)); const factory = cfr.resolveComponentFactory(containerType); // Craft the element array based on what slot to use. Angular only uses the index to determine // which ng-content to project into, so if you have more than one ng-content you'll need to set // the index in the constructor appropriately const element = []; element[index] = [el.nativeElement]; // We're assuming only one projection slot, but in more complex cases we might want to provide // a different array of projected elements. const containerRef = vcr.createComponent(factory, undefined, undefined, element); // We can now remove the useless anchor vcr.remove(0); // We note that the container was dynamically created containerRef.instance._dynamic = true; // We keep the wrapper's injector to access the dependencies that weren't available before. this.injector = containerRef.injector; } } get(token, notFoundValue) { return this.injector.get(token, notFoundValue); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class MarkControlService { constructor() { this._touched = new Subject(); } get touchedChange() { return this._touched.asObservable(); } markAsTouched() { this._touched.next(); } } MarkControlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MarkControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); MarkControlService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MarkControlService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MarkControlService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var CHANGE_KEYS; (function (CHANGE_KEYS) { CHANGE_KEYS["FORM"] = "form"; CHANGE_KEYS["MODEL"] = "model"; })(CHANGE_KEYS || (CHANGE_KEYS = {})); class WrappedFormControl { // I lost way too much time trying to make this work without injecting the ViewContainerRef and the Injector, // I'm giving up. So we have to inject these two manually for now. constructor(vcr, wrapperType, injector, ngControl, renderer, el) { this.vcr = vcr; this.wrapperType = wrapperType; this.ngControl = ngControl; this.index = 0; this.subscriptions = []; this.renderer = renderer; this.el = el; if (injector) { this.ngControlService = injector.get(NgControlService, null); this.ifControlStateService = injector.get(IfControlStateService, null); this.controlClassService = injector.get(ControlClassService, null); this.markControlService = injector.get(MarkControlService, null); this.differs = injector.get(KeyValueDiffers, null); } if (this.controlClassService) { this.controlClassService.initControlClass(renderer, el.nativeElement); } if (this.markControlService) { this.subscriptions.push(this.markControlService.touchedChange.subscribe(() => { this.markAsTouched(); })); } if (this.ngControlService) { this.subscriptions.push(this.ngControlService.helpersChange.subscribe((state) => { this.setAriaDescribedBy(state); })); } if (ngControl) { this.differ = this.differs.find(ngControl).create(); } } get id() { return this._id; } set id(value) { this._id = value; if (this.controlIdService) { this.controlIdService.id = value; } } ngOnInit() { this._containerInjector = new HostWrapper(this.wrapperType, this.vcr, this.index); this.controlIdService = this._containerInjector.get(ControlIdService); /** * not all containers will provide `ContainerIdService` */ this.containerIdService = this._containerInjector.get(ContainerIdService, null); if (this._id) { this.controlIdService.id = this._id; } else { this._id = this.controlIdService.id; } if (this.ngControlService) { this.ngControlService.setControl(this.ngControl); } } ngDoCheck() { if (this.differ) { const changes = this.differ.diff(this.ngControl); if (changes) { changes.forEachChangedItem(change => { if ((change.key === CHANGE_KEYS.FORM || change.key === CHANGE_KEYS.MODEL) && change.currentValue !== change.previousValue) { this.triggerValidation(); } }); } } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } triggerValidation() { if (this.ifControlStateService) { this.ifControlStateService.triggerStatusChange(); } } // @TODO This method has a try/catch due to an unknown issue that came when building the clrToggle feature // We need to figure out why this fails for the ClrToggle scenario but works for Date picker... // To see the error, remove the try/catch here and run the ClrToggle suite to see issues getting the container // injector in time, and this ONLY HAPPENS in tests and not in dev/prod mode. getProviderFromContainer(token, notFoundValue) { try { return this._containerInjector.get(token, notFoundValue); } catch (e) { return notFoundValue; } } markAsTouched() { this.ngControl.control.markAsTouched(); this.ngControl.control.updateValueAndValidity(); } setAriaDescribedBy(helpers) { if (helpers.show) { const ariaDescribedBy = this.getAriaDescribedById(helpers); if (ariaDescribedBy !== null) { this.renderer.setAttribute(this.el.nativeElement, 'aria-describedby', ariaDescribedBy); return; } } this.renderer.removeAttribute(this.el.nativeElement, 'aria-describedby'); } getAriaDescribedById(helpers) { let suffix = CONTROL_SUFFIX.HELPER; if (helpers.showInvalid) { suffix = CONTROL_SUFFIX.ERROR; } else if (helpers.showValid) { suffix = CONTROL_SUFFIX.SUCCESS; } if (this.containerIdService) { return this.containerIdService.id.concat('-', suffix); } if (this.controlIdService) { return this.controlIdService.id.concat('-', suffix); } /** * If ContainerIdService or ControlIdService are missing don't try to guess * Don't set anything. */ return null; } } WrappedFormControl.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedFormControl, deps: [{ token: i0.ViewContainerRef }, { token: i0.Type }, { token: i0.Injector }, { token: i1.NgControl }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); WrappedFormControl.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: WrappedFormControl, inputs: { id: "id" }, host: { listeners: { "blur": "triggerValidation()" }, properties: { "id": "this.id" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedFormControl, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Type }, { type: i0.Injector }, { type: i1.NgControl }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { id: [{ type: Input }, { type: HostBinding }], triggerValidation: [{ type: HostListener, args: ['blur'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrControl extends WrappedFormControl { constructor(vcr, injector, control, renderer, el) { super(vcr, ClrControlContainer, injector, control, renderer, el); this.index = 1; } } ClrControl.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControl, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrControl.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrControl, selector: "[clrControl]", host: { properties: { "class.clr-input": "true" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrControl, decorators: [{ type: Directive, args: [{ selector: '[clrControl]', host: { '[class.clr-input]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrForm { constructor(layoutService, markControlService) { this.layoutService = layoutService; this.markControlService = markControlService; } set labelSize(size) { const sizeNumber = parseInt(size, 10) || 2; this.layoutService.labelSize = sizeNumber; } onFormSubmit() { this.markAsTouched(); } // Trying to avoid adding an input and keep this backwards compatible at the same time markAsTouched() { this.markControlService.markAsTouched(); } } ClrForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrForm, deps: [{ token: LayoutService }, { token: MarkControlService }], target: i0.ɵɵFactoryTarget.Directive }); ClrForm.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrForm, selector: "[clrForm]", inputs: { labelSize: ["clrLabelSize", "labelSize"] }, host: { listeners: { "submit": "onFormSubmit()" }, properties: { "class.clr-form": "true", "class.clr-form-horizontal": "layoutService.isHorizontal()", "class.clr-form-compact": "layoutService.isCompact()" } }, providers: [LayoutService, MarkControlService], queries: [{ propertyName: "labels", predicate: ClrLabel, descendants: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrForm, decorators: [{ type: Directive, args: [{ selector: '[clrForm]', providers: [LayoutService, MarkControlService], host: { '[class.clr-form]': 'true', '[class.clr-form-horizontal]': 'layoutService.isHorizontal()', '[class.clr-form-compact]': 'layoutService.isCompact()', }, }] }], ctorParameters: function () { return [{ type: LayoutService }, { type: MarkControlService }]; }, propDecorators: { labels: [{ type: ContentChildren, args: [ClrLabel, { descendants: true }] }], labelSize: [{ type: Input, args: ['clrLabelSize'] }], onFormSubmit: [{ type: HostListener, args: ['submit'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class AbstractIfState { constructor(ifControlStateService, ngControlService) { this.ifControlStateService = ifControlStateService; this.ngControlService = ngControlService; this.subscriptions = []; this.displayedContent = false; if (ngControlService) { this.subscriptions.push(this.ngControlService.controlChanges.subscribe(control => { this.control = control; })); } if (ifControlStateService) { this.subscriptions.push(this.ifControlStateService.statusChanges.subscribe((state) => { this.handleState(state); })); } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } handleState(_state) { /* overwrite in implementation to handle status change */ } } AbstractIfState.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AbstractIfState, deps: [{ token: IfControlStateService, optional: true }, { token: NgControlService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); AbstractIfState.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: AbstractIfState, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AbstractIfState, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: IfControlStateService, decorators: [{ type: Optional }] }, { type: NgControlService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrIfError extends AbstractIfState { constructor(ifControlStateService, ngControlService, template, container) { super(ifControlStateService, ngControlService); this.template = template; this.container = container; if (!this.ifControlStateService) { throw new Error('clrIfError can only be used within a form control container element like clr-input-container'); } } /** * @param state CONTROL_STATE */ handleState(state) { if (this.error && this.control) { this.displayError(this.control.hasError(this.error)); } else { this.displayError(CONTROL_STATE.INVALID === state); } } displayError(invalid) { /* if no container do nothing */ if (!this.container) { return; } if (invalid) { if (this.displayedContent === false) { this.embeddedViewRef = this.container.createEmbeddedView(this.template, { error: this.control.getError(this.error), }); this.displayedContent = true; } else if (this.embeddedViewRef && this.embeddedViewRef.context) { // if view is already rendered, update the error object to keep it in sync this.embeddedViewRef.context.error = this.control.getError(this.error); } } else { this.container.clear(); this.displayedContent = false; } } } ClrIfError.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfError, deps: [{ token: IfControlStateService, optional: true }, { token: NgControlService, optional: true }, { token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrIfError.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIfError, selector: "[clrIfError]", inputs: { error: ["clrIfError", "error"] }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfError, decorators: [{ type: Directive, args: [{ selector: '[clrIfError]', }] }], ctorParameters: function () { return [{ type: IfControlStateService, decorators: [{ type: Optional }] }, { type: NgControlService, decorators: [{ type: Optional }] }, { type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; }, propDecorators: { error: [{ type: Input, args: ['clrIfError'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrIfSuccess extends AbstractIfState { constructor(ifControlStateService, ngControlService, template, container) { super(ifControlStateService, ngControlService); this.template = template; this.container = container; if (!ifControlStateService) { throw new Error('ClrIfSuccess can only be used within a form control container element like clr-input-container'); } } /** * @param state CONTROL_STATE */ handleState(state) { const isValid = CONTROL_STATE.VALID === state; if (isValid && !this.displayedContent) { this.container.createEmbeddedView(this.template); } else if (!isValid && this.container) { this.container.clear(); } this.displayedContent = isValid; } } ClrIfSuccess.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfSuccess, deps: [{ token: IfControlStateService, optional: true }, { token: NgControlService, optional: true }, { token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrIfSuccess.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIfSuccess, selector: "[clrIfSuccess]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfSuccess, decorators: [{ type: Directive, args: [{ selector: '[clrIfSuccess]', }] }], ctorParameters: function () { return [{ type: IfControlStateService, decorators: [{ type: Optional }] }, { type: NgControlService, decorators: [{ type: Optional }] }, { type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrLayout { constructor(layoutService) { this.layoutService = layoutService; } ngOnInit() { // Only set the layout if it is a valid option if (this.layout && this.layoutService.isValid(this.layout)) { this.layoutService.layout = this.layout; } } } ClrLayout.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLayout, deps: [{ token: LayoutService }], target: i0.ɵɵFactoryTarget.Directive }); ClrLayout.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrLayout, selector: "[clrForm][clrLayout]", inputs: { layout: ["clrLayout", "layout"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLayout, decorators: [{ type: Directive, args: [{ selector: '[clrForm][clrLayout]', }] }], ctorParameters: function () { return [{ type: LayoutService }]; }, propDecorators: { layout: [{ type: Input, args: ['clrLayout'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrCommonFormsModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrCommonFormsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrCommonFormsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonFormsModule, declarations: [ClrLabel, ClrControlError, ClrControlSuccess, ClrControlHelper, ClrIfError, ClrIfSuccess, ClrForm, ClrLayout, ClrControlContainer, ClrControl], imports: [CommonModule, ClrIconModule], exports: [ClrLabel, ClrControlError, ClrControlSuccess, ClrControlHelper, ClrIfError, ClrIfSuccess, ClrForm, ClrLayout, ClrControlContainer, ClrControl] }); ClrCommonFormsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonFormsModule, imports: [CommonModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCommonFormsModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule], declarations: [ ClrLabel, ClrControlError, ClrControlSuccess, ClrControlHelper, ClrIfError, ClrIfSuccess, ClrForm, ClrLayout, ClrControlContainer, ClrControl, ], exports: [ ClrLabel, ClrControlError, ClrControlSuccess, ClrControlHelper, ClrIfError, ClrIfSuccess, ClrForm, ClrLayout, ClrControlContainer, ClrControl, ], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const IS_TOGGLE = new InjectionToken('IS_TOGGLE'); function isToggleFactory() { return new BehaviorSubject(false); } const IS_TOGGLE_PROVIDER = { provide: IS_TOGGLE, useFactory: isToggleFactory }; class ClrCheckboxWrapper { constructor(toggleService) { // We need both _dynamic for HostWrapper and ContentChild(ClrLabel) in cases where // the user puts a radio inside a wrapper without a label, host wrapping doesn't apply // but we'd still need to insert a label this._dynamic = false; this.toggle = false; this.subscriptions = []; this.subscriptions.push(toggleService.subscribe(state => { this.toggle = state; })); } ngOnInit() { if (this.label) { this.label.disableGrid(); } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrCheckboxWrapper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxWrapper, deps: [{ token: IS_TOGGLE }], target: i0.ɵɵFactoryTarget.Component }); ClrCheckboxWrapper.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrCheckboxWrapper, selector: "clr-checkbox-wrapper,clr-toggle-wrapper", host: { properties: { "class.clr-checkbox-wrapper": "!toggle", "class.clr-toggle-wrapper": "toggle" } }, providers: [ControlIdService, IS_TOGGLE_PROVIDER], queries: [{ propertyName: "label", first: true, predicate: ClrLabel, descendants: true, static: true }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxWrapper, decorators: [{ type: Component, args: [{ selector: 'clr-checkbox-wrapper,clr-toggle-wrapper', template: ` `, host: { '[class.clr-checkbox-wrapper]': '!toggle', '[class.clr-toggle-wrapper]': 'toggle', }, providers: [ControlIdService, IS_TOGGLE_PROVIDER], }] }], ctorParameters: function () { return [{ type: i3.BehaviorSubject, decorators: [{ type: Inject, args: [IS_TOGGLE] }] }]; }, propDecorators: { label: [{ type: ContentChild, args: [ClrLabel, { static: true }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This implements both the clrCheckbox and clrToggle functionality, since they are both just checkboxes with different * visual styling. The challenge is that the container needs to know which selector was used, which the @Attribute * decorator gets for us to determine if the toggle is used, and emits a value to the wrapper container to tell it * there is a toggle switch instead. */ class ClrCheckbox extends WrappedFormControl { constructor(vcr, injector, control, renderer, el, toggle) { super(vcr, ClrCheckboxWrapper, injector, control, renderer, el); this.toggle = toggle; } ngOnInit() { super.ngOnInit(); const toggleService = this.getProviderFromContainer(IS_TOGGLE, null); if (toggleService && this.toggle !== null) { toggleService.next(true); } } } ClrCheckbox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckbox, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: 'clrToggle', attribute: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrCheckbox.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrCheckbox, selector: "[clrCheckbox],[clrToggle]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckbox, decorators: [{ type: Directive, args: [{ selector: '[clrCheckbox],[clrToggle]', }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: undefined, decorators: [{ type: Attribute, args: ['clrToggle'] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrCheckboxContainer extends ClrAbstractContainer { constructor(layoutService, controlClassService, ngControlService, ifControlStateService) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.layoutService = layoutService; this.controlClassService = controlClassService; this.ngControlService = ngControlService; this.ifControlStateService = ifControlStateService; this.inline = false; } /* * Here we want to support the following cases * clrInline - true by presence * clrInline="true|false" - unless it is explicitly false, strings are considered true * [clrInline]="true|false" - expect a boolean */ get clrInline() { return this.inline; } set clrInline(value) { if (typeof value === 'string') { this.inline = value === 'false' ? false : true; } else { this.inline = !!value; } } ngAfterContentInit() { this.setAriaRoles(); } setAriaRoles() { this.role = this.checkboxes.length ? 'group' : null; } } ClrCheckboxContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxContainer, deps: [{ token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }, { token: IfControlStateService }], target: i0.ɵɵFactoryTarget.Component }); ClrCheckboxContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrCheckboxContainer, selector: "clr-checkbox-container,clr-toggle-container", inputs: { clrInline: "clrInline" }, host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()", "attr.role": "role" } }, providers: [IfControlStateService, NgControlService, ControlClassService, ContainerIdService], queries: [{ propertyName: "checkboxes", predicate: ClrCheckbox, descendants: true }], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxContainer, decorators: [{ type: Component, args: [{ selector: 'clr-checkbox-container,clr-toggle-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', '[attr.role]': 'role', }, providers: [IfControlStateService, NgControlService, ControlClassService, ContainerIdService], }] }], ctorParameters: function () { return [{ type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }, { type: IfControlStateService }]; }, propDecorators: { checkboxes: [{ type: ContentChildren, args: [ClrCheckbox, { descendants: true }] }], clrInline: [{ type: Input }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrCheckboxModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrCheckboxModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrCheckboxModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxModule, declarations: [ClrCheckbox, ClrCheckboxContainer, ClrCheckboxWrapper], imports: [CommonModule, ClrIconModule, ClrCommonFormsModule, ClrHostWrappingModule], exports: [ClrCommonFormsModule, ClrCheckbox, ClrCheckboxContainer, ClrCheckboxWrapper] }); ClrCheckboxModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxModule, imports: [CommonModule, ClrIconModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCheckboxModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrCommonFormsModule, ClrHostWrappingModule], declarations: [ClrCheckbox, ClrCheckboxContainer, ClrCheckboxWrapper], exports: [ClrCommonFormsModule, ClrCheckbox, ClrCheckboxContainer, ClrCheckboxWrapper], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function isBooleanAttributeSet(value) { // for null just return false no need to check anything if (value === null) { return false; } if (typeof value === 'string') { // Empty string is valid, 'true' as string is also valid return value.length >= 0; } // Boolean value will be read as it is, everything else is false return typeof value === 'boolean' ? value : false; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrSpinner { /** * Default class for all spinners. This class is always true */ get spinnerClass() { return true; } get inlineClass() { return this._inline; } set clrInline(value) { this._inline = isBooleanAttributeSet(value); } get inverseClass() { return this._inverse; } set clrInverse(value) { this._inverse = isBooleanAttributeSet(value); } get smallClass() { return this._small; } set clrSmall(value) { this._small = isBooleanAttributeSet(value); } /** * When clrSmall & clrMedium are set both to true. * The CSS with high priority will be small - so medium size will be ignored. * * For this reason if clrSmall is set we won't add clrMedium class. * * NOTE: This is dictated by the CSS rules. * DON'T USE clrSmall & clrMedium to toggle classes. This could change without notice. * * Also there is no logical need to have both of them set to TRUE or FALSE. */ get mediumClass() { if (this._small) { return false; } return this._medium; } set clrMedium(value) { this._medium = isBooleanAttributeSet(value); } } ClrSpinner.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSpinner, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrSpinner.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrSpinner, selector: "clr-spinner", inputs: { clrInline: "clrInline", clrInverse: "clrInverse", clrSmall: "clrSmall", clrMedium: "clrMedium" }, host: { properties: { "attr.aria-busy": "true", "class.spinner": "this.spinnerClass", "class.spinner-inline": "this.inlineClass", "class.spinner-inverse": "this.inverseClass", "class.spinner-sm": "this.smallClass", "class.spinner-md": "this.mediumClass" } }, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSpinner, decorators: [{ type: Component, args: [{ selector: 'clr-spinner', template: ``, host: { '[attr.aria-busy]': 'true', }, }] }], propDecorators: { spinnerClass: [{ type: HostBinding, args: ['class.spinner'] }], inlineClass: [{ type: HostBinding, args: ['class.spinner-inline'] }], clrInline: [{ type: Input, args: ['clrInline'] }], inverseClass: [{ type: HostBinding, args: ['class.spinner-inverse'] }], clrInverse: [{ type: Input, args: ['clrInverse'] }], smallClass: [{ type: HostBinding, args: ['class.spinner-sm'] }], clrSmall: [{ type: Input, args: ['clrSmall'] }], mediumClass: [{ type: HostBinding, args: ['class.spinner-md'] }], clrMedium: [{ type: Input, args: ['clrMedium'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_SPINNER_DIRECTIVES = [ClrSpinner]; class ClrSpinnerModule { } ClrSpinnerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSpinnerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrSpinnerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrSpinnerModule, declarations: [ClrSpinner], imports: [CommonModule], exports: [ClrSpinner] }); ClrSpinnerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSpinnerModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSpinnerModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_SPINNER_DIRECTIVES], exports: [CLR_SPINNER_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrFocusDirection; (function (ClrFocusDirection) { ClrFocusDirection["VERTICAL"] = "vertical"; ClrFocusDirection["HORIZONTAL"] = "horizontal"; ClrFocusDirection["BOTH"] = "both"; })(ClrFocusDirection || (ClrFocusDirection = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrKeyFocusItem { constructor(elementRef, platformId) { this.elementRef = elementRef; this.platformId = platformId; } get nativeElement() { return this.elementRef.nativeElement; } focus() { if (isPlatformBrowser(this.platformId)) { this.elementRef.nativeElement.focus(); } } } ClrKeyFocusItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocusItem, deps: [{ token: i0.ElementRef }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Directive }); ClrKeyFocusItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrKeyFocusItem, selector: "[clrKeyFocusItem]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocusItem, decorators: [{ type: Directive, args: [{ selector: '[clrKeyFocusItem]', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrKeyFocus { constructor(elementRef) { this.elementRef = elementRef; this.direction = ClrFocusDirection.VERTICAL; this.focusOnLoad = false; this.subscriptions = []; this.focusChange = new EventEmitter(); this._current = 0; } /** * Here we use `any` cause any other type require reworking all methods below and a lot of more ifs. * this method will only work with array with FocusableItems anyway so any other value will be ignored. */ get focusableItems() { if (this._focusableItems) { return this._focusableItems; } else if (this.clrKeyFocusItems) { return this.clrKeyFocusItems.toArray(); } return []; } set focusableItems(elements) { // We accept a list of focusable elements (HTMLElements or existing Directives) or auto query for clrKeyFocusItem // We accept a list reference in the cases where we cannot use ContentChildren to query // ContentChildren can be unavailable if content is projected outside the scope of the component (see tabs). if (Array.isArray(elements) && elements.length) { this._focusableItems = elements; this.initializeFocus(); } } get nativeElement() { return this.elementRef.nativeElement; } get current() { return this._current; } set current(value) { if (this._current !== value) { this._current = value; } } get currentItem() { return this.focusableItems[this._current]; } get currentItemElement() { return this.currentItem.nativeElement ? this.currentItem.nativeElement : this.currentItem; } ngAfterContentInit() { this.subscriptions.push(this.listenForItemUpdates()); this.initializeFocus(); } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } handleKeyboardEvent(event) { // Make sure event was originated on the current item's element if (this.currentItemElement !== event.target) { const position = this.getItemPosition(event.target); if (this.positionInRange(position)) { this.current = position; } } if (this.prevKeyPressed(event) && this.currentFocusIsNotFirstItem()) { this.moveTo(this.current - 1); } else if (this.nextKeyPressed(event) && this.currentFocusIsNotLastItem()) { this.moveTo(this.current + 1); } else if (event.code === Keys.Home) { this.moveTo(0); } else if (event.code === Keys.End) { this.moveTo(this.focusableItems.length - 1); } preventArrowKeyScroll(event); } setClickedItemCurrent(event) { const position = this.getItemPosition(event.target); if (position > -1) { this.moveTo(position); } } focusCurrent() { this.currentItem.focus(); this.focusChange.next(this._current); } moveTo(position) { if (this.positionInRange(position)) { this.current = position; this.focusCurrent(); } } positionInRange(position) { return position >= 0 && position < this.focusableItems.length; } currentFocusIsNotFirstItem() { return this._current - 1 >= 0; } currentFocusIsNotLastItem() { return this._current + 1 < this.focusableItems.length; } initializeFocus() { if (this.focusableItems && this.focusableItems.length) { // It is possible that the focus was on an element, whose index is no longer available. // This can happen when some of the focusable elements are being removed. // In such cases, the new focus is initialized on the last focusable element. if (this._current >= this.focusableItems.length) { this._current = this.focusableItems.length - 1; } if (this.focusOnLoad) { this.currentItem.focus(); this.focusChange.next(); } } } nextKeyPressed(event) { const key = normalizeKey(event.key); switch (this.direction) { case ClrFocusDirection.VERTICAL: return key === Keys.ArrowDown; case ClrFocusDirection.HORIZONTAL: return key === Keys.ArrowRight; case ClrFocusDirection.BOTH: return key === Keys.ArrowDown || key === Keys.ArrowRight; default: return false; } } prevKeyPressed(event) { const key = normalizeKey(event.key); switch (this.direction) { case ClrFocusDirection.VERTICAL: return key === Keys.ArrowUp; case ClrFocusDirection.HORIZONTAL: return key === Keys.ArrowLeft; case ClrFocusDirection.BOTH: return key === Keys.ArrowUp || key === Keys.ArrowLeft; default: return false; } } getItemPosition(item) { if (this._focusableItems) { return this.focusableItems.indexOf(item); } else { return this.focusableItems.map(_item => _item.nativeElement).indexOf(item); } } listenForItemUpdates() { return this.clrKeyFocusItems.changes.subscribe(() => { this.initializeFocus(); }); } } ClrKeyFocus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocus, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ClrKeyFocus.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrKeyFocus, selector: "[clrKeyFocus]", inputs: { direction: ["clrDirection", "direction"], focusOnLoad: ["clrFocusOnLoad", "focusOnLoad"], focusableItems: ["clrKeyFocus", "focusableItems"] }, outputs: { focusChange: "clrFocusChange" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)", "click": "setClickedItemCurrent($event)" } }, queries: [{ propertyName: "clrKeyFocusItems", predicate: ClrKeyFocusItem, descendants: true }], ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocus, decorators: [{ type: Component, args: [{ selector: '[clrKeyFocus]', template: '', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { direction: [{ type: Input, args: ['clrDirection'] }], focusOnLoad: [{ type: Input, args: ['clrFocusOnLoad'] }], clrKeyFocusItems: [{ type: ContentChildren, args: [ClrKeyFocusItem, { descendants: true }] }], focusChange: [{ type: Output, args: ['clrFocusChange'] }], focusableItems: [{ type: Input, args: ['clrKeyFocus'] }], handleKeyboardEvent: [{ type: HostListener, args: ['keydown', ['$event']] }], setClickedItemCurrent: [{ type: HostListener, args: ['click', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRovingTabindex extends ClrKeyFocus { constructor(elementRef, renderer) { super(elementRef); this.renderer = renderer; this.disabled = false; } // Proxy the input, as the selector name from parent class will still be "clrKeyFocus". get rovingIndexItems() { return this.focusableItems; } set rovingIndexItems(elements) { this.focusableItems = elements; } set rovingTabindexDisabled(disabled) { this.disabled = disabled; if (this.currentItem) { this.setTabindex(this.currentItem, disabled ? -1 : 0); } } handleKeyboardEvent(event) { if (this.prevKeyPressed(event) && this.currentFocusIsNotFirstItem()) { this.updateTabindex(this.current - 1); } else if (this.nextKeyPressed(event) && this.currentFocusIsNotLastItem()) { this.updateTabindex(this.current + 1); } else if (event.code === Keys.Home) { this.updateTabindex(0); } else if (event.code === Keys.End) { this.updateTabindex(this.focusableItems.length - 1); } super.handleKeyboardEvent(event); } setClickedItemCurrent(event) { let position; if (this.focusableItems[0].nativeElement) { position = this.focusableItems.map(item => item.nativeElement).indexOf(event.target); } else { position = this.focusableItems.indexOf(event.target); } if (position > -1) { this.updateTabindex(position); } super.setClickedItemCurrent(event); } initializeFocus() { if (this.focusableItems && this.focusableItems.length) { this.focusableItems.forEach(item => { this.setTabindex(item, -1); }); // It is possible that the focus was on an element, whose index is no longer available. // This can happen when some of the focusable elements are being removed. // In such cases, the new focus is initialized on the last focusable element. if (this.current >= this.focusableItems.length) { this.current = this.focusableItems.length - 1; } if (!this.disabled && this.currentItem) { this.setTabindex(this.currentItem, 0); } } super.initializeFocus(); } updateTabindex(newIndex) { this.setTabindex(this.currentItem, -1); this.setTabindex(this.focusableItems[newIndex], 0); } setTabindex(item, value) { if (item instanceof HTMLElement) { this.renderer.setAttribute(item, 'tabindex', value.toString()); } else { this.renderer.setAttribute(item.nativeElement, 'tabindex', value.toString()); } } } ClrRovingTabindex.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRovingTabindex, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); ClrRovingTabindex.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrRovingTabindex, selector: "[clrRovingTabindex]", inputs: { rovingIndexItems: ["clrRovingTabindex", "rovingIndexItems"], rovingTabindexDisabled: ["clrRovingTabindexDisabled", "rovingTabindexDisabled"] }, usesInheritance: true, ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRovingTabindex, decorators: [{ type: Component, args: [{ selector: '[clrRovingTabindex]', template: '', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { rovingIndexItems: [{ type: Input, args: ['clrRovingTabindex'] }], rovingTabindexDisabled: [{ type: Input, args: ['clrRovingTabindexDisabled'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const KEY_FOCUS_DIRECTIVES = [ClrKeyFocus, ClrRovingTabindex, ClrKeyFocusItem]; class ClrKeyFocusModule { } ClrKeyFocusModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocusModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrKeyFocusModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocusModule, declarations: [ClrKeyFocus, ClrRovingTabindex, ClrKeyFocusItem], imports: [CommonModule], exports: [ClrKeyFocus, ClrRovingTabindex, ClrKeyFocusItem] }); ClrKeyFocusModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocusModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrKeyFocusModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [KEY_FOCUS_DIRECTIVES], exports: [KEY_FOCUS_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ComboboxContainerService { constructor() { this.labelOffset = 0; } } ComboboxContainerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ComboboxContainerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ComboboxContainerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ComboboxContainerService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ComboboxContainerService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrComboboxContainer extends ClrAbstractContainer { constructor(ifControlStateService, layoutService, controlClassService, ngControlService, containerService, el) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.containerService = containerService; this.el = el; } ngAfterContentInit() { if (this.label) { this.containerService.labelText = this.label.labelText; } } ngAfterViewInit() { this.containerService.labelOffset = this.controlContainer.nativeElement.offsetHeight - this.el.nativeElement.offsetHeight; } } ClrComboboxContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrComboboxContainer, deps: [{ token: IfControlStateService }, { token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }, { token: ComboboxContainerService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ClrComboboxContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrComboboxContainer, selector: "clr-combobox-container", host: { properties: { "class.clr-form-control": "true", "class.clr-combobox-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService, ComboboxContainerService], viewQueries: [{ propertyName: "controlContainer", first: true, predicate: ["controlContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrComboboxContainer, decorators: [{ type: Component, args: [{ selector: 'clr-combobox-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-combobox-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService, ComboboxContainerService], }] }], ctorParameters: function () { return [{ type: IfControlStateService }, { type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }, { type: ComboboxContainerService }, { type: i0.ElementRef }]; }, propDecorators: { controlContainer: [{ type: ViewChild, args: ['controlContainer'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class MultiSelectComboboxModel { containsItem(item) { return this.model ? this.model.includes(item) : false; } select(item) { this.addItem(item); } unselect(item) { this.removeItem(item); } isEmpty() { return !(this.model && this.model.length > 0); } pop() { let item; if (this.model && this.model.length > 0) { item = this.model[this.model.length - 1]; this.removeItem(item); } return item; } toString(displayField, index = -1) { let displayString = ''; if (this.model) { // If the model is array, we can use a specific item from it, to retrieve the display value. if (index > -1) { if (this.model[index]) { // If we have a defined display field, we'll use it's value as display value if (displayField && this.model[index][displayField]) { displayString += this.model[index][displayField]; } else { // If we don't have a defined display field, we'll use the toString representation of the // item as display value. displayString += this.model[index].toString(); } } } else { this.model.forEach((model) => { // If we have a defined display field, we'll use it's value as display value if (displayField && model[displayField]) { displayString += model[displayField]; } else { // If we don't have a defined display field, we'll use the toString representation of the // model as display value. displayString += model.toString(); } displayString += ' '; }); } } return displayString.trim(); } addItem(item) { if (!this.containsItem(item)) { this.model = this.model || []; this.model.push(item); } } removeItem(item) { if (this.model === null || this.model === undefined) { return; } const index = this.model.indexOf(item); if (index > -1) { this.model.splice(index, 1); } // we intentionally set the model to null for form validation if (this.model.length === 0) { this.model = null; } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class SingleSelectComboboxModel { containsItem(item) { return this.model === item; } select(item) { this.model = item; } unselect(item) { if (this.containsItem(item)) { this.model = null; } } isEmpty() { return !this.model; } pop() { const item = this.model; this.model = null; return item; } toString(displayField) { if (!this.model) { return ''; } if (displayField && this.model[displayField]) { return this.model[displayField]; } else { return this.model.toString(); } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrOptionSelected { constructor(template) { this.template = template; } } ClrOptionSelected.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOptionSelected, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrOptionSelected.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrOptionSelected, selector: "[clrOptionSelected]", inputs: { selected: ["clrOptionSelected", "selected"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOptionSelected, decorators: [{ type: Directive, args: [{ selector: '[clrOptionSelected]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; }, propDecorators: { selected: [{ type: Input, args: ['clrOptionSelected'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class FocusableItem { } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function customFocusableItemProvider(implementation) { return [ implementation, { provide: FocusableItem, useExisting: implementation, }, ]; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class PseudoFocusModel extends SingleSelectComboboxModel { constructor() { super(...arguments); this._focusChanged = new BehaviorSubject(null); } get focusChanged() { return this._focusChanged.asObservable(); } select(item) { if (this.model !== item) { this.model = item; this._focusChanged.next(item); } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class OptionSelectionService { constructor() { this.loading = false; // Display all options on first open, even if filter text exists. // https://github.com/vmware-clarity/ng-clarity/issues/386 this.showAllOptions = true; this._currentInput = ''; this._inputChanged = new BehaviorSubject(''); this._selectionChanged = new ReplaySubject(1); this.inputChanged = this._inputChanged.asObservable(); } get currentInput() { return this._currentInput; } set currentInput(input) { // clear value in single selection model when input is empty if (input === '' && !this.multiselectable) { this.setSelectionValue(null); } this._currentInput = input; this._inputChanged.next(input); } // This observable is for notifying the ClrOption to update its // selection by comparing the value get selectionChanged() { return this._selectionChanged.asObservable(); } get multiselectable() { return this.selectionModel instanceof MultiSelectComboboxModel; } select(item) { if (item === null || item === undefined || this.selectionModel.containsItem(item)) { return; } this.selectionModel.select(item); this._selectionChanged.next(this.selectionModel); } toggle(item) { if (item === null || item === undefined) { return; } if (this.selectionModel.containsItem(item)) { this.selectionModel.unselect(item); } else { this.selectionModel.select(item); } this._selectionChanged.next(this.selectionModel); } unselect(item) { if (item === null || item === undefined || !this.selectionModel.containsItem(item)) { return; } this.selectionModel.unselect(item); this._selectionChanged.next(this.selectionModel); } // TODO: Add support for trackBy and compareFn setSelectionValue(value) { // NOTE: Currently we assume that no 2 options will have the same value // but Eudes and I discussed that this is a possibility but we will handle // this later // if selection is undefined, or its value hasn't changed, or changing from null <-> undefined, that's not really changing so we return if (!this.selectionModel || this.selectionModel.model === value || (!this.selectionModel.model && !value)) { return; } this.selectionModel.model = value; this._selectionChanged.next(this.selectionModel); } } OptionSelectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OptionSelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); OptionSelectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OptionSelectionService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OptionSelectionService, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ComboboxFocusHandler { constructor(rendererFactory, toggleService, selectionService, platformId) { this.toggleService = toggleService; this.selectionService = selectionService; this.platformId = platformId; this.pseudoFocus = new PseudoFocusModel(); this.optionData = []; this.handleFocusSubscription(); // Direct renderer injection can be problematic and leads to failing tests at least this.renderer = rendererFactory.createRenderer(null, null); } get trigger() { return this._trigger; } set trigger(el) { this._trigger = el; this.addFocusOnBlurListener(el); } get listbox() { return this._listbox; } set listbox(el) { this._listbox = el; this.addFocusOnBlurListener(el); } get textInput() { return this._textInput; } set textInput(el) { this._textInput = el; this.renderer.listen(el, 'keydown', event => !this.handleTextInput(event)); this.addFocusOnBlurListener(el); } focusInput() { if (this.textInput && isPlatformBrowser(this.platformId)) { this.textInput.focus(); } } focusFirstActive() { if (this.optionData.length > 0) { if (this.selectionService.selectionModel.isEmpty()) { this.pseudoFocus.select(this.optionData[0]); } else { let firstActive; if (this.selectionService.multiselectable) { firstActive = this.selectionService.selectionModel.model[0]; } else { firstActive = this.selectionService.selectionModel.model; } const activeProxy = this.optionData.find(option => option.value === firstActive); if (activeProxy) { // active element is visible this.pseudoFocus.select(activeProxy); } else { // we have active element, but it's filtered out this.pseudoFocus.select(this.optionData[0]); } this.scrollIntoSelectedModel('auto'); } } } addOptionValues(options) { this.optionData = options; } handleFocusSubscription() { this.toggleService.openChange.subscribe(open => { if (!open) { this.pseudoFocus.model = null; } }); } moveFocusTo(direction) { let index = this.optionData.findIndex(option => option.equals(this.pseudoFocus.model)); if (direction === ArrowKeyDirection.UP) { if (index === -1 || index === 0) { index = this.optionData.length - 1; } else { index--; } } else if (direction === ArrowKeyDirection.DOWN) { if (index === -1 || index === this.optionData.length - 1) { index = 0; } else { index++; } } this.pseudoFocus.select(this.optionData[index]); this.scrollIntoSelectedModel(); } openAndMoveTo(direction) { if (!this.toggleService.open) { this.toggleService.openChange.pipe(take(1)).subscribe(open => { if (open) { this.moveFocusTo(direction); } }); this.toggleService.open = true; } else { this.moveFocusTo(direction); } } // this service is only interested in keys that may move the focus handleTextInput(event) { let preventDefault = false; const key = normalizeKey(event.key); if (event) { switch (key) { case Keys.Enter: if (this.toggleService.open && this.pseudoFocus.model) { if (this.selectionService.multiselectable) { this.selectionService.toggle(this.pseudoFocus.model.value); } else { this.selectionService.select(this.pseudoFocus.model.value); } preventDefault = true; } break; case Keys.Space: if (!this.toggleService.open) { this.toggleService.open = true; preventDefault = true; } break; case Keys.ArrowUp: this.preventViewportScrolling(event); this.openAndMoveTo(ArrowKeyDirection.UP); preventDefault = true; break; case Keys.ArrowDown: this.preventViewportScrolling(event); this.openAndMoveTo(ArrowKeyDirection.DOWN); preventDefault = true; break; default: // Any other keypress if (event.key !== Keys.Tab && !(this.selectionService.multiselectable && event.key === Keys.Backspace) && !(event.key === Keys.Escape) && !this.toggleService.open) { this.toggleService.open = true; } break; } } return preventDefault; } scrollIntoSelectedModel(behavior = 'smooth') { if (this.pseudoFocus.model && this.pseudoFocus.model.el) { this.pseudoFocus.model.el.scrollIntoView({ behavior, block: 'center', inline: 'nearest' }); } } preventViewportScrolling(event) { event.preventDefault(); event.stopImmediatePropagation(); } addFocusOnBlurListener(el) { if (isPlatformBrowser(this.platformId)) { this.renderer.listen(el, 'blur', event => { if (this.focusOutOfComponent(event)) { this.toggleService.open = false; // Workaround for popover close-on-outside-click timing issues in Edge browser if (this.componentCdRef) { this.componentCdRef.detectChanges(); } } }); } } focusOutOfComponent(event) { // event.relatedTarget is null in IE11. In that case we use document.activeElement // which points to the element that becomes active as the blur event occurs on the input. const target = (event.relatedTarget || document.activeElement); return !(this.textInput.contains(target) || this.trigger.contains(target) || this.listbox.contains(target)); } } ComboboxFocusHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ComboboxFocusHandler, deps: [{ token: i0.RendererFactory2 }, { token: ClrPopoverToggleService }, { token: OptionSelectionService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); ComboboxFocusHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ComboboxFocusHandler }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ComboboxFocusHandler, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.RendererFactory2 }, { type: ClrPopoverToggleService }, { type: OptionSelectionService }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); const COMBOBOX_FOCUS_HANDLER_PROVIDER = customFocusableItemProvider(ComboboxFocusHandler); class OptionData { constructor(id, value) { this.id = id; this.value = value; } equals(other) { if (!other) { return false; } return this.id === other.id && this.value === other.value; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrOption { constructor(elRef, commonStrings, focusHandler, optionSelectionService) { this.elRef = elRef; this.commonStrings = commonStrings; this.focusHandler = focusHandler; this.optionSelectionService = optionSelectionService; // A proxy with only the necessary data to be used for a11y and the focus handler service. this.optionProxy = new OptionData(null, null); this.optionProxy.el = this.elRef.nativeElement; } get optionId() { return this._id; } set optionId(id) { this._id = id; this.optionProxy.id = this._id; } get value() { return this._value; } set value(value) { this._value = value; this.optionProxy.value = value; } get selected() { return (this.optionSelectionService.selectionModel && this.optionSelectionService.selectionModel.containsItem(this.value)); } get focusClass() { return this.focusHandler.pseudoFocus.containsItem(this.optionProxy); } ngOnInit() { if (!this._id) { this._id = 'clr-option-' + uniqueIdFactory(); this.optionProxy.id = this._id; } } onClick() { if (this.optionSelectionService.multiselectable) { this.optionSelectionService.toggle(this.value); } else { this.optionSelectionService.select(this.value); } // As the popover stays open in multi-select mode now, we have to take focus back to the input // This way we achieve two things: // - do not lose focus // - we're still able to use onBlur for "outside-click" handling this.focusHandler.focusInput(); } } ClrOption.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOption, deps: [{ token: i0.ElementRef }, { token: ClrCommonStringsService }, { token: ComboboxFocusHandler }, { token: OptionSelectionService }], target: i0.ɵɵFactoryTarget.Component }); ClrOption.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrOption, selector: "clr-option", inputs: { optionId: ["id", "optionId"], value: ["clrValue", "value"] }, host: { listeners: { "click": "onClick()" }, properties: { "class.clr-combobox-option": "true", "attr.role": "\"option\"", "attr.tabindex": "-1", "attr.id": "optionId", "class.active": "this.selected", "class.clr-focus": "this.focusClass" } }, ngImport: i0, template: ` {{ commonStrings.keys.comboboxSelected }} `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOption, decorators: [{ type: Component, args: [{ selector: 'clr-option', template: ` {{ commonStrings.keys.comboboxSelected }} `, host: { '[class.clr-combobox-option]': 'true', '[attr.role]': '"option"', // Do not remove. Or click-selection will not work. '[attr.tabindex]': '-1', '[attr.id]': 'optionId', }, }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ClrCommonStringsService }, { type: ComboboxFocusHandler }, { type: OptionSelectionService }]; }, propDecorators: { optionId: [{ type: Input, args: ['id'] }], value: [{ type: Input, args: ['clrValue'] }], selected: [{ type: HostBinding, args: ['class.active'] }], focusClass: [{ type: HostBinding, args: ['class.clr-focus'] }], onClick: [{ type: HostListener, args: ['click'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbOptionsComponents = 0; class ClrOptions { constructor(optionSelectionService, id, el, commonStrings, focusHandler, toggleService, parentHost, document) { this.optionSelectionService = optionSelectionService; this.id = id; this.el = el; this.commonStrings = commonStrings; this.focusHandler = focusHandler; this.toggleService = toggleService; this.document = document; this.loading = false; this.subscriptions = []; if (!parentHost) { throw new Error('clr-options should only be used inside of a clr-combobox'); } if (!this.optionsId) { this.optionsId = 'clr-options-' + nbOptionsComponents++; } } get items() { return this._items; } set items(items) { this._items = items; this.focusHandler.addOptionValues(this._items.map(option => option.optionProxy)); } /** * Tests if the list of options is empty, meaning it doesn't contain any items */ get emptyOptions() { return !this.optionSelectionService.loading && this.items.length === 0; } ngAfterViewInit() { this.focusHandler.listbox = this.el.nativeElement; this.subscriptions.push(fromEvent(this.document, 'scroll', { capture: true }).subscribe(event => { if (this.toggleService.open && event.target !== this.el.nativeElement && event.target !== this.focusHandler.textInput) { this.toggleService.open = false; } }), this.items.changes.subscribe(items => { if (items.length) { setTimeout(() => { this.focusHandler.focusFirstActive(); }); } else { this.focusHandler.pseudoFocus.pop(); } })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } searchText(input) { return this.commonStrings.parse(this.commonStrings.keys.comboboxSearching, { INPUT: input }); } loadingStateChange(state) { this.loading = state === ClrLoadingState.LOADING; } } ClrOptions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOptions, deps: [{ token: OptionSelectionService }, { token: IF_ACTIVE_ID }, { token: i0.ElementRef }, { token: ClrCommonStringsService }, { token: ComboboxFocusHandler }, { token: ClrPopoverToggleService }, { token: POPOVER_HOST_ANCHOR, optional: true }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); ClrOptions.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrOptions, selector: "clr-options", inputs: { optionsId: ["id", "optionsId"] }, host: { properties: { "class.clr-combobox-options": "true", "attr.role": "\"listbox\"", "id": "optionsId" } }, providers: [{ provide: LoadingListener, useExisting: ClrOptions }], queries: [{ propertyName: "items", predicate: ClrOption }], ngImport: i0, template: `
{{ commonStrings.keys.loading }} {{ searchText(optionSelectionService.currentInput) }}
{{ commonStrings.keys.comboboxNoResults }}
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOptions, decorators: [{ type: Component, args: [{ selector: 'clr-options', template: `
{{ commonStrings.keys.loading }} {{ searchText(optionSelectionService.currentInput) }}
{{ commonStrings.keys.comboboxNoResults }}
`, providers: [{ provide: LoadingListener, useExisting: ClrOptions }], host: { '[class.clr-combobox-options]': 'true', '[attr.role]': '"listbox"', '[id]': 'optionsId', }, }] }], ctorParameters: function () { return [{ type: OptionSelectionService }, { type: undefined, decorators: [{ type: Inject, args: [IF_ACTIVE_ID] }] }, { type: i0.ElementRef }, { type: ClrCommonStringsService }, { type: ComboboxFocusHandler }, { type: ClrPopoverToggleService }, { type: i0.ElementRef, decorators: [{ type: Optional }, { type: Inject, args: [POPOVER_HOST_ANCHOR] }] }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { optionsId: [{ type: Input, args: ['id'] }], items: [{ type: ContentChildren, args: [ClrOption] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrCombobox extends WrappedFormControl { constructor(vcr, injector, control, renderer, el, optionSelectionService, commonStrings, toggleService, positionService, controlStateService, containerService, platformId, focusHandler, cdr) { super(vcr, ClrComboboxContainer, injector, control, renderer, el); this.control = control; this.renderer = renderer; this.el = el; this.optionSelectionService = optionSelectionService; this.commonStrings = commonStrings; this.toggleService = toggleService; this.positionService = positionService; this.controlStateService = controlStateService; this.containerService = containerService; this.platformId = platformId; this.focusHandler = focusHandler; this.cdr = cdr; this.placeholder = ''; this.clrInputChange = new EventEmitter(false); this.clrOpenChange = this.toggleService.openChange; /** * This output should be used to set up a live region using aria-live and populate it with updates that reflect each combobox change. */ this.clrSelectionChange = this.optionSelectionService.selectionChanged; this.invalid = false; this.focused = false; this.smartPosition = { axis: ClrAxis.VERTICAL, side: ClrSide.AFTER, anchor: ClrAlignment.START, content: ClrAlignment.START, }; this.index = 1; this._searchText = ''; if (control) { control.valueAccessor = this; } // default to SingleSelectComboboxModel, in case the optional input [ClrMulti] isn't used this.optionSelectionService.selectionModel = new SingleSelectComboboxModel(); this.updateControlValue(); } get multiSelect() { return this.optionSelectionService.multiselectable; } set multiSelect(value) { if (value) { this.optionSelectionService.selectionModel = new MultiSelectComboboxModel(); } else { // in theory, setting this again should not cause errors even though we already set it in constructor, // since the initial call to writeValue (caused by [ngModel] input) should happen after this this.optionSelectionService.selectionModel = new SingleSelectComboboxModel(); } this.updateControlValue(); } // Override the id of WrappedFormControl, as we want to move it to the embedded input. // Otherwise the label/component connection does not work and screen readers do not read the label. get id() { return this.controlIdService.id + '-combobox'; } set id(id) { super.id = id; } get searchText() { return this._searchText; } set searchText(text) { // if input text has changed since last time, fire a change event so application can react to it if (text !== this._searchText) { if (this.toggleService.open) { this.optionSelectionService.showAllOptions = false; } this._searchText = text; this.clrInputChange.emit(this.searchText); } // We need to trigger this even if unchanged, so the option-items directive will update its list // based on the "showAllOptions" variable which may have changed in the openChange subscription below. // The option-items directive does not listen to openChange, but it listens to currentInput changes. this.optionSelectionService.currentInput = this.searchText; } get openState() { return this.toggleService.open; } get multiSelectModel() { if (!this.multiSelect) { throw Error('multiSelectModel is not available in single selection context'); } return this.optionSelectionService.selectionModel.model; } get ariaControls() { return this.options?.optionsId; } get ariaOwns() { return this.options?.optionsId; } get ariaDescribedBySelection() { return 'selection-' + this.id; } get displayField() { return this.optionSelectionService.displayField; } get disabled() { return this.control && this.control.disabled; } ngAfterContentInit() { this.initializeSubscriptions(); // Initialize with preselected value if (!this.optionSelectionService.selectionModel.isEmpty()) { this.updateInputValue(this.optionSelectionService.selectionModel); } } ngAfterViewInit() { this.focusHandler.componentCdRef = this.cdr; this.focusHandler.textInput = this.textbox.nativeElement; this.focusHandler.trigger = this.trigger.nativeElement; // The text input is the actual element we are wrapping // This assignment is needed by the wrapper, so it can set // the aria properties on the input element, not on the component. this.el = this.textbox; } onKeyUp(event) { // if BACKSPACE in multiselect mode, delete the last pill if text is empty if (event.key === Keys.Backspace && this.multiSelect && this._searchText.length === 0) { const multiModel = this.optionSelectionService.selectionModel.model; if (multiModel && multiModel.length > 0) { const lastItem = multiModel[multiModel.length - 1]; this.control.control.markAsTouched(); this.optionSelectionService.unselect(lastItem); } } } inputId() { return this.controlIdService.id; } loadingStateChange(state) { this.optionSelectionService.loading = state === ClrLoadingState.LOADING; this.positionService.realign(); if (state !== ClrLoadingState.LOADING && isPlatformBrowser(this.platformId)) { this.focusFirstActive(); } } unselect(item) { if (!this.disabled) { this.optionSelectionService.unselect(item); } } onBlur() { this.onTouchedCallback(); if (this.control.control.updateOn === 'blur') { this.control.control.updateValueAndValidity(); } this.focused = false; } onFocus() { this.focused = true; // fix for "expression changed" error when focus is returned to a combobox after a modal is closed // https://github.com/vmware-clarity/ng-clarity/issues/663 this.cdr.detectChanges(); } getSelectionAriaLabel() { if (this.containerService && this.containerService.labelText) { return `${this.containerService.labelText} ${this.commonStrings.keys.comboboxSelection}`; } return this.commonStrings.keys.comboboxSelection; } focusFirstActive() { setTimeout(() => { this.focusHandler.focusFirstActive(); }); } writeValue(value) { this.optionSelectionService.selectionModel.model = value; this.updateInputValue(this.optionSelectionService.selectionModel); } registerOnTouched(onTouched) { this.onTouchedCallback = onTouched; } registerOnChange(onChange) { this.onChangeCallback = onChange; } getActiveDescendant() { const model = this.focusHandler.pseudoFocus.model; return model ? model.id : null; } setDisabledState() { // do nothing } focusInput() { this.focusHandler.focusInput(); } initializeSubscriptions() { this.subscriptions.push(this.optionSelectionService.selectionChanged.subscribe((newSelection) => { this.updateInputValue(newSelection); if (this.multiSelect) { this.positionService.realign(); } if (!this.multiSelect && newSelection && !newSelection.isEmpty()) { this.toggleService.open = false; } this.updateControlValue(); })); this.subscriptions.push(this.toggleService.openChange.subscribe(open => { if (open) { this.focusFirstActive(); } else { this.optionSelectionService.showAllOptions = true; } if (this.multiSelect) { this.searchText = ''; } else { this.searchText = this.getDisplayNames(this.optionSelectionService.selectionModel.model)[0] || ''; } })); this.subscriptions.push(this.toggleService.popoverAligned.subscribe(popoverNode => { // When used outside a combobox container if (!this.containerService) { return; } const popover = popoverNode; // Update position if popover hides the label if (popover.getBoundingClientRect().top < this.el.nativeElement.getBoundingClientRect().top) { this.renderer.setStyle(popoverNode, 'top', `${popover.offsetTop + this.containerService.labelOffset}px`); } })); if (this.controlStateService) { this.subscriptions.push(this.controlStateService.statusChanges.subscribe(invalid => { this.invalid = invalid === CONTROL_STATE.INVALID; })); } } updateInputValue(model) { if (!this.multiSelect) { this.searchText = model.model ? this.getDisplayNames(model.model)[0] : ''; if (this.searchText) { this.optionSelectionService.currentInput = this.searchText; } } } updateControlValue() { if (this.onChangeCallback) { this.onChangeCallback(this.optionSelectionService.selectionModel.model); } } getDisplayNames(model) { if (this.displayField) { if (!Array.isArray(model)) { model = [model]; } return model.map(item => (item ? item[this.displayField] : null)); } return [this.optionSelectionService.selectionModel.model]; } } ClrCombobox.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCombobox, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: OptionSelectionService }, { token: ClrCommonStringsService }, { token: ClrPopoverToggleService }, { token: ClrPopoverPositionService }, { token: IfControlStateService, optional: true }, { token: ComboboxContainerService, optional: true }, { token: PLATFORM_ID }, { token: ComboboxFocusHandler }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); ClrCombobox.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrCombobox, selector: "clr-combobox", inputs: { placeholder: "placeholder", multiSelect: ["clrMulti", "multiSelect"] }, outputs: { clrInputChange: "clrInputChange", clrOpenChange: "clrOpenChange", clrSelectionChange: "clrSelectionChange" }, host: { listeners: { "keydown": "onKeyUp($event)" }, properties: { "class.aria-required": "true", "class.clr-combobox": "true", "class.clr-combobox-disabled": "control?.disabled" } }, providers: [ OptionSelectionService, { provide: LoadingListener, useExisting: ClrCombobox }, IF_ACTIVE_ID_PROVIDER, FOCUS_SERVICE_PROVIDER, COMBOBOX_FOCUS_HANDLER_PROVIDER, ], queries: [{ propertyName: "optionSelected", first: true, predicate: ClrOptionSelected, descendants: true }, { propertyName: "options", first: true, predicate: ClrOptions, descendants: true }], viewQueries: [{ propertyName: "textbox", first: true, predicate: ["textboxInput"], descendants: true }, { propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true }], usesInheritance: true, hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: "\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n \n \n \n\n
\n\n\n\n
\n \n
\n", dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrRovingTabindex, selector: "[clrRovingTabindex]", inputs: ["clrRovingTabindex", "clrRovingTabindexDisabled"] }, { kind: "directive", type: ClrKeyFocusItem, selector: "[clrKeyFocusItem]" }, { kind: "directive", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCombobox, decorators: [{ type: Component, args: [{ selector: 'clr-combobox', providers: [ OptionSelectionService, { provide: LoadingListener, useExisting: ClrCombobox }, IF_ACTIVE_ID_PROVIDER, FOCUS_SERVICE_PROVIDER, COMBOBOX_FOCUS_HANDLER_PROVIDER, ], hostDirectives: [ClrPopoverHostDirective], host: { '[class.aria-required]': 'true', '[class.clr-combobox]': 'true', '[class.clr-combobox-disabled]': 'control?.disabled', }, template: "\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n\n \n \n \n \n\n
\n\n\n\n
\n \n
\n" }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: OptionSelectionService }, { type: ClrCommonStringsService }, { type: ClrPopoverToggleService }, { type: ClrPopoverPositionService }, { type: IfControlStateService, decorators: [{ type: Optional }] }, { type: ComboboxContainerService, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: ComboboxFocusHandler }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { placeholder: [{ type: Input, args: ['placeholder'] }], clrInputChange: [{ type: Output, args: ['clrInputChange'] }], clrOpenChange: [{ type: Output, args: ['clrOpenChange'] }], clrSelectionChange: [{ type: Output, args: ['clrSelectionChange'] }], textbox: [{ type: ViewChild, args: ['textboxInput'] }], trigger: [{ type: ViewChild, args: ['trigger'] }], optionSelected: [{ type: ContentChild, args: [ClrOptionSelected] }], options: [{ type: ContentChild, args: [ClrOptions] }], multiSelect: [{ type: Input, args: ['clrMulti'] }], onKeyUp: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrOptionItems { constructor(template, differs, optionService, positionService, vcr) { this.template = template; this.differs = differs; this.optionService = optionService; this.positionService = positionService; this.vcr = vcr; this.subscriptions = []; this.filter = ''; this.differ = null; this.iterableProxy = new NgForOf(this.vcr, this.template, this.differs); this.subscriptions.push(optionService.inputChanged.subscribe(filter => { this.filter = filter; this.updateItems(); })); } set rawItems(items) { this._rawItems = items ? items : []; this.updateItems(); } set trackBy(value) { this.iterableProxy.ngForTrackBy = value; } set field(field) { this._filterField = field; this.optionService.displayField = field; } ngDoCheck() { if (!this.differ) { this.differ = this.differs.find(this.filteredItems).create(this.iterableProxy.ngForTrackBy); } if (this.differ) { const changes = this.differ.diff(this.filteredItems); if (changes) { this.iterableProxy.ngDoCheck(); this.positionService.realign(); } } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } updateItems() { if (!this._rawItems || this.filter === undefined || this.filter === null) { return; } const normalizedFilterValue = normalizeValue(this.filter); if (this.optionService.showAllOptions) { this.filteredItems = this._rawItems; } else if (this._filterField) { this.filteredItems = this._rawItems.filter(item => { const objValue = item[this._filterField]; return objValue ? normalizeValue(objValue).includes(normalizedFilterValue) : false; }); } else { // Filter by all item object values this.filteredItems = this._rawItems.filter(item => { if (typeof item !== 'object') { return normalizeValue(item).includes(normalizedFilterValue); } const objValues = Object.values(item).filter(value => { return value !== null && value !== undefined ? normalizeValue(value).includes(normalizedFilterValue) : false; }); return objValues.length > 0; }); } this.iterableProxy.ngForOf = this.filteredItems; } } ClrOptionItems.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOptionItems, deps: [{ token: i0.TemplateRef }, { token: i0.IterableDiffers }, { token: OptionSelectionService }, { token: ClrPopoverPositionService }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrOptionItems.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrOptionItems, selector: "[clrOptionItems][clrOptionItemsOf]", inputs: { rawItems: ["clrOptionItemsOf", "rawItems"], trackBy: ["clrOptionItemsTrackBy", "trackBy"], field: ["clrOptionItemsField", "field"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOptionItems, decorators: [{ type: Directive, args: [{ selector: '[clrOptionItems][clrOptionItemsOf]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.IterableDiffers }, { type: OptionSelectionService }, { type: ClrPopoverPositionService }, { type: i0.ViewContainerRef }]; }, propDecorators: { rawItems: [{ type: Input, args: ['clrOptionItemsOf'] }], trackBy: [{ type: Input, args: ['clrOptionItemsTrackBy'] }], field: [{ type: Input, args: ['clrOptionItemsField'] }] } }); function normalizeValue(value) { return value .toString() .normalize('NFD') .replace(/\p{Diacritic}/gu, '') .toLowerCase(); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrComboboxModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon, angleIcon, windowCloseIcon); } } ClrComboboxModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrComboboxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrComboboxModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrComboboxModule, declarations: [ClrCombobox, ClrComboboxContainer, ClrOptions, ClrOption, ClrOptionSelected, ClrOptionItems], imports: [CommonModule, FormsModule, ClrIconModule, ClrKeyFocusModule, ClrCommonFormsModule, ClrConditionalModule, ClrPopoverModuleNext, ClrSpinnerModule], exports: [ClrCommonFormsModule, ClrCombobox, ClrComboboxContainer, ClrOptions, ClrOption, ClrOptionSelected, ClrConditionalModule, ClrOptionItems] }); ClrComboboxModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrComboboxModule, imports: [CommonModule, FormsModule, ClrIconModule, ClrKeyFocusModule, ClrCommonFormsModule, ClrConditionalModule, ClrPopoverModuleNext, ClrSpinnerModule, ClrCommonFormsModule, ClrConditionalModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrComboboxModule, decorators: [{ type: NgModule, args: [{ imports: [ CommonModule, FormsModule, ClrIconModule, ClrKeyFocusModule, ClrCommonFormsModule, ClrConditionalModule, ClrPopoverModuleNext, ClrSpinnerModule, ], declarations: [ClrCombobox, ClrComboboxContainer, ClrOptions, ClrOption, ClrOptionSelected, ClrOptionItems], exports: [ ClrCommonFormsModule, ClrCombobox, ClrComboboxContainer, ClrOptions, ClrOption, ClrOptionSelected, ClrConditionalModule, ClrOptionItems, ], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrInputContainer extends ClrAbstractContainer { } ClrInputContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInputContainer, deps: null, target: i0.ɵɵFactoryTarget.Component }); ClrInputContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrInputContainer, selector: "clr-input-container", host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInputContainer, decorators: [{ type: Component, args: [{ selector: 'clr-input-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrInput extends WrappedFormControl { constructor(vcr, injector, control, renderer, el) { super(vcr, ClrInputContainer, injector, control, renderer, el); this.index = 1; } } ClrInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInput, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrInput.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrInput, selector: "[clrInput]", host: { properties: { "class.clr-input": "true" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInput, decorators: [{ type: Directive, args: [{ selector: '[clrInput]', host: { '[class.clr-input]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrInputModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon // caret ); } } ClrInputModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrInputModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrInputModule, declarations: [ClrInput, ClrInputContainer], imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], exports: [ClrCommonFormsModule, ClrInput, ClrInputContainer] }); ClrInputModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInputModule, imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrInputModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], declarations: [ClrInput, ClrInputContainer], exports: [ClrCommonFormsModule, ClrInput, ClrInputContainer], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let counter = 0; class DatalistIdService { constructor() { this._id = 'clr-datalist-' + ++counter; this._idChange = new BehaviorSubject(this._id); } get id() { return this._id; } set id(value) { this._id = value; this._idChange.next(value); } get idChange() { return this._idChange.asObservable(); } } DatalistIdService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatalistIdService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DatalistIdService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatalistIdService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatalistIdService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatalist { constructor(datalistIdService) { this.datalistIdService = datalistIdService; this.subscriptions = []; } set id(idValue) { if (!!idValue && this.datalistIdService) { this.datalistId = idValue; this.datalistIdService.id = idValue; } else if (idValue) { this.datalistId = idValue; } } ngAfterContentInit() { if (!this.datalistIdService) { return; } this.subscriptions.push(this.datalistIdService.idChange.subscribe(id => (this.datalistId = id))); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrDatalist.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalist, deps: [{ token: DatalistIdService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrDatalist.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatalist, selector: "datalist", inputs: { id: "id" }, host: { properties: { "id": "datalistId" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalist, decorators: [{ type: Directive, args: [{ selector: 'datalist', host: { '[id]': 'datalistId', }, }] }], ctorParameters: function () { return [{ type: DatalistIdService, decorators: [{ type: Optional }] }]; }, propDecorators: { id: [{ type: Input }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class FocusService { constructor() { this._focused = new BehaviorSubject(false); } get focusChange() { return this._focused.asObservable(); } set focused(state) { this._focused.next(state); } } FocusService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FocusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); FocusService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FocusService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FocusService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatalistContainer extends ClrAbstractContainer { constructor(controlClassService, layoutService, ngControlService, focusService, ifControlStateService) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.focusService = focusService; this.ifControlStateService = ifControlStateService; this.focus = false; this.subscriptions.push(this.focusService.focusChange.subscribe(state => (this.focus = state))); } } ClrDatalistContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistContainer, deps: [{ token: ControlClassService }, { token: LayoutService, optional: true }, { token: NgControlService }, { token: FocusService }, { token: IfControlStateService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatalistContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatalistContainer, selector: "clr-datalist-container", host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [ ControlClassService, LayoutService, ControlIdService, FocusService, NgControlService, DatalistIdService, IfControlStateService, ], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistContainer, decorators: [{ type: Component, args: [{ selector: 'clr-datalist-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [ ControlClassService, LayoutService, ControlIdService, FocusService, NgControlService, DatalistIdService, IfControlStateService, ], }] }], ctorParameters: function () { return [{ type: ControlClassService }, { type: LayoutService, decorators: [{ type: Optional }] }, { type: NgControlService }, { type: FocusService }, { type: IfControlStateService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatalistInput extends WrappedFormControl { constructor(focusService, vcr, injector, control, renderer, el, datalistIdService) { super(vcr, ClrDatalistContainer, injector, control, renderer, el); this.focusService = focusService; this.datalistIdService = datalistIdService; if (!this.focusService) { throw new Error('clrDatalist requires being wrapped in '); } } ngAfterContentInit() { // Subscriptions is inherited from WrappedFormControl, unsubscribe is handled there this.subscriptions.push(this.datalistIdService.idChange.subscribe(id => (this.listValue = id))); } triggerFocus() { if (this.focusService) { this.focusService.focused = true; } } triggerValidation() { super.triggerValidation(); if (this.focusService) { this.focusService.focused = false; } } } ClrDatalistInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistInput, deps: [{ token: FocusService, optional: true }, { token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: DatalistIdService }], target: i0.ɵɵFactoryTarget.Directive }); ClrDatalistInput.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatalistInput, selector: "[clrDatalistInput]", host: { listeners: { "focus": "triggerFocus()", "blur": "triggerValidation()" }, properties: { "class.clr-input": "true", "attr.list": "listValue" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistInput, decorators: [{ type: Directive, args: [{ selector: '[clrDatalistInput]', host: { '[class.clr-input]': 'true', '[attr.list]': 'listValue', }, }] }], ctorParameters: function () { return [{ type: FocusService, decorators: [{ type: Optional }] }, { type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: DatalistIdService }]; }, propDecorators: { triggerFocus: [{ type: HostListener, args: ['focus'] }], triggerValidation: [{ type: HostListener, args: ['blur'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatalistModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrDatalistModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrDatalistModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistModule, declarations: [ClrDatalist, ClrDatalistInput, ClrDatalistContainer], imports: [CommonModule, ClrInputModule, ClrIconModule], exports: [ClrDatalist, ClrDatalistInput, ClrDatalistContainer] }); ClrDatalistModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistModule, imports: [CommonModule, ClrInputModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatalistModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrInputModule, ClrIconModule], declarations: [ClrDatalist, ClrDatalistInput, ClrDatalistContainer], exports: [ClrDatalist, ClrDatalistInput, ClrDatalistContainer], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This is just a copy of CdkTrapFocus so it can be used independent of the rest of the A11yModule. */ class CdkTrapFocusModule_CdkTrapFocus extends CdkTrapFocus { } CdkTrapFocusModule_CdkTrapFocus.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkTrapFocusModule_CdkTrapFocus, deps: null, target: i0.ɵɵFactoryTarget.Directive }); CdkTrapFocusModule_CdkTrapFocus.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkTrapFocusModule_CdkTrapFocus, decorators: [{ type: Directive, args: [{ selector: '[cdkTrapFocus]', }] }] }); /** * This module allows us to avoid importing all of A11yModule which results in a smaller application bundle. */ class CdkTrapFocusModule { } CdkTrapFocusModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkTrapFocusModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); CdkTrapFocusModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: CdkTrapFocusModule, declarations: [CdkTrapFocusModule_CdkTrapFocus], exports: [CdkTrapFocusModule_CdkTrapFocus] }); CdkTrapFocusModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkTrapFocusModule }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkTrapFocusModule, decorators: [{ type: NgModule, args: [{ declarations: [CdkTrapFocusModule_CdkTrapFocus], exports: [CdkTrapFocusModule_CdkTrapFocus], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This is the en-001 short locale date format. Setting as default. */ const DEFAULT_LOCALE_FORMAT = 'dd/MM/y'; // https://en.wikipedia.org/wiki/Date_format_by_country const LITTLE_ENDIAN_REGEX = /d+.+m+.+y+/i; const MIDDLE_ENDIAN_REGEX = /m+.+d+.+y+/i; // No need for BIG_ENDIAN_REGEX because anything that doesn't satisfy the above 2 // is automatically BIG_ENDIAN const DELIMITER_REGEX = /d+|m+|y+/i; const USER_INPUT_REGEX = /\d+/g; const MOBILE_USERAGENT_REGEX = /Mobi/i; const RTL_REGEX = /\u200f/g; const YEAR = 'YYYY'; const MONTH = 'MM'; const DATE = 'DD'; const LITTLE_ENDIAN = { name: 'LITTLE_ENDIAN', format: [DATE, MONTH, YEAR], }; const MIDDLE_ENDIAN = { name: 'MIDDLE_ENDIAN', format: [MONTH, DATE, YEAR], }; const BIG_ENDIAN = { name: 'BIG_ENDIAN', format: [YEAR, MONTH, DATE], }; const NO_OF_DAYS_IN_A_WEEK = 7; const NO_OF_ROWS_IN_CALENDAR_VIEW = 6; const TOTAL_DAYS_IN_DAYS_VIEW = NO_OF_DAYS_IN_A_WEEK * NO_OF_ROWS_IN_CALENDAR_VIEW; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Returns the number of days in a month. */ function getNumberOfDaysInTheMonth(year, month) { // If we go to the next month, but use a day of 0, it returns the last day from the previous month return new Date(year, month + 1, 0).getDate(); } /** * Returns the day for the corresponding date where 0 represents Sunday. */ function getDay(year, month, date) { return new Date(year, month, date).getDay(); } /** * Takes in a year and if it is a 2 digit year, returns the corresponding 4 digit year. * Window of 80 years before and 20 years after the present year. * Credit: https://github.com/globalizejs/globalize/blob/e1b31cd6a4f1cff75b185b68b7a32220aac5196f/src/date/parse.js */ function parseToFourDigitYear(year) { if (year > 9999 || (year > 100 && year < 999) || year < 10) { return -1; } if (year > 999) { return year; } const currYear = new Date().getFullYear(); const century = Math.floor(currYear / 100) * 100; let result = year + century; if (result > currYear + 20) { result = result - 100; } return result; } function datesAreEqual(date1, date2) { if (date1 instanceof Date && date2 instanceof Date) { return (date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate()); } else { return false; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DayViewModel { constructor(dayModel, isTodaysDate = false, isExcluded = false, isDisabled = false, isSelected = false, isFocusable = false) { this.dayModel = dayModel; this.isTodaysDate = isTodaysDate; this.isExcluded = isExcluded; this.isDisabled = isDisabled; this.isSelected = isSelected; this.isFocusable = isFocusable; } /** * Gets the tab index based on the isFocusable flag. */ get tabIndex() { return this.isFocusable ? 0 : -1; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DayModel { constructor(year, month, date) { this.year = year; this.month = month; this.date = date; } /** * Checks if the passed CalendarDate is equal to itself. */ isEqual(day) { if (day) { return this.year === day.year && this.month === day.month && this.date === day.date; } return false; } toDate() { return new Date(this.year, this.month, this.date); } /** * Returns a new DayModel which is incremented based on the value passed. */ incrementBy(value) { // Creating new Javascript Date object to increment because // it will automatically take care of switching to next or previous // months & years without we having to worry about it. const date = new Date(this.year, this.month, this.date + value); return new DayModel(date.getFullYear(), date.getMonth(), date.getDate()); } /** * Clones the current day model. */ clone() { return new DayModel(this.year, this.month, this.date); } toComparisonString() { return `${this.year}${this.pad(this.month)}${this.pad(this.date)}`; } toDateString() { return this.toDate().toLocaleDateString(); } pad(num) { return num < 10 ? `0${num}` : `${num}`; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class CalendarViewModel { constructor(calendar, selectedDay, focusableDay, today, firstDayOfWeek, excludedDates) { this.calendar = calendar; this.selectedDay = selectedDay; this.focusableDay = focusableDay; this.today = today; this.firstDayOfWeek = firstDayOfWeek; this.excludedDates = excludedDates; this.currMonthDayViews = []; this.initializeCalendarView(); } /** * DayViewModel matrix. Size 6x7 */ get calendarView() { return this._calendarView; } /** * Updates the focusable day in the calendar. */ updateFocusableDay(day) { this.setFocusableFlag(this.focusableDay, false); this.setFocusableFlag(day, true); this.focusableDay = day; } /** * Generates a 6x7 matrix of DayViewModel based on the Calendar. * The 6x7 matrix is structured according to the first day of the week. * 6 rows to accommodate months which might have dates spanning over 6 weeks. * 7 columns because there are 7 days in a week :P :D */ initializeCalendarView() { // Generate prev and next month calendar models. const prevMonthCalendar = this.calendar.previousMonth(); const nextMonthCalendar = this.calendar.nextMonth(); // Get no of days from prev and next months. const daysFromPrevMonthInCalView = this.numDaysFromPrevMonthInCalView(this.calendar.year, this.calendar.month); const daysFromNextMonthInCalView = TOTAL_DAYS_IN_DAYS_VIEW - (this.calendar.days.length + daysFromPrevMonthInCalView); // Generate prev, curr and next day view models let prevMonthDayViews = []; let nextMonthDayViews = []; if (daysFromPrevMonthInCalView > 0) { prevMonthDayViews = this.generateDayViewModels(prevMonthCalendar.days.slice(-1 * daysFromPrevMonthInCalView), true, false); } this.currMonthDayViews = this.generateDayViewModels(this.calendar.days, false, true); if (daysFromNextMonthInCalView > 0) { nextMonthDayViews = this.generateDayViewModels(nextMonthCalendar.days.slice(0, daysFromNextMonthInCalView), true, false); } // Generate calendar view and initialize flags this._calendarView = this.generateCalendarView(prevMonthDayViews, this.currMonthDayViews, nextMonthDayViews); this.initializeSelectedDay(); this.initializeFocusableDay(); } isDateExcluded(date) { const { minDate, maxDate } = this.excludedDates; const from = minDate.toComparisonString(); const to = maxDate.toComparisonString(); const today = date.toComparisonString(); return !(today >= from && today <= to); } /** * Generates a DayViewModel array based on the DayModel passed */ generateDayViewModels(days, isExcluded, isCurrentCalendar) { const dayViews = days.map(day => { return new DayViewModel(day, false, isExcluded, this.isDateExcluded(day), false, false); }); if (isCurrentCalendar && this.calendar.isDayInCalendar(this.today)) { dayViews[this.today.date - 1].isTodaysDate = true; } return dayViews; } /** * Gets the first day of the current month to figure out how many dates of previous month * are needed to complete the Calendar View based on the first day of the week. * eg: Assuming locale en-US, the first day of the week is Sunday, * if first day of the current month lands on Wednesday, then * (this.getDay function would return 3 since * first day of the week is 0), we need the 3 days from the previous month. */ numDaysFromPrevMonthInCalView(currentYear, currentMonth) { const firstDayOfCurrMonth = getDay(currentYear, currentMonth, 1); if (firstDayOfCurrMonth >= this.firstDayOfWeek) { return firstDayOfCurrMonth - this.firstDayOfWeek; } else { return NO_OF_DAYS_IN_A_WEEK + firstDayOfCurrMonth - this.firstDayOfWeek; } } /** * Checks if the Day passed is in the CalendarView. */ isDayInCalendarView(day) { if (!this.calendar.isDayInCalendar(day)) { return false; } return true; } /** * Using the DayViewModels from the previous, current and next month, this function * generates the CalendarView. */ generateCalendarView(prev, curr, next) { const combinationArr = [...prev, ...curr, ...next]; const calendarView = []; for (let i = 0; i < NO_OF_ROWS_IN_CALENDAR_VIEW; i++) { calendarView[i] = combinationArr.slice(i * NO_OF_DAYS_IN_A_WEEK, (i + 1) * NO_OF_DAYS_IN_A_WEEK); } return calendarView; } /** * Initialize the selected day if the day is in the calendar. */ initializeSelectedDay() { if (this.selectedDay && this.isDayInCalendarView(this.selectedDay)) { this.currMonthDayViews[this.selectedDay.date - 1].isSelected = true; } } /** * Initializes the focusable day if the day is in the calendar. If focusable day is not set, then * we check for the selected day. If selected day is not set then check if today is in the current * calendar. If not then just set the 15th of the current calendar month. */ initializeFocusableDay() { if (this.focusableDay && this.isDayInCalendarView(this.focusableDay)) { this.setFocusableFlag(this.focusableDay, true); } else if (this.selectedDay && this.isDayInCalendarView(this.selectedDay)) { this.setFocusableFlag(this.selectedDay, true); this.focusableDay = this.selectedDay.clone(); } else if (this.isDayInCalendarView(this.today)) { this.setFocusableFlag(this.today, true); this.focusableDay = this.today.clone(); } else { this.focusableDay = new DayModel(this.calendar.year, this.calendar.month, 15); this.setFocusableFlag(this.focusableDay, true); } } setFocusableFlag(day, flag) { if (day) { this.currMonthDayViews[day.date - 1].isFocusable = flag; } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This service extracts the Angular CLDR data needed by the datepicker. */ class LocaleHelperService { constructor(locale) { this.locale = locale; this._firstDayOfWeek = 0; this.initializeLocaleData(); } get firstDayOfWeek() { return this._firstDayOfWeek; } get localeDays() { return this._localeDays; } // leave for backward compatibility get localeDaysNarrow() { return this._localeDays.map(day => day.narrow); } get localeMonthsAbbreviated() { return this._localeMonthsAbbreviated; } get localeMonthsWide() { return this._localeMonthsWide; } get localeDateFormat() { return this._localeDateFormat; } /** * Initializes the locale data. */ initializeLocaleData() { // Order in which these functions is called is very important. this.initializeFirstDayOfWeek(); this.initializeLocaleDateFormat(); this.initializeLocaleMonthsAbbreviated(); this.initializeLocaleMonthsWide(); this.initializeLocaleDays(); } /** * Initialize day names based on the locale. * eg: [{day: Sunday, narrow: S}, {day: Monday, narrow: M}...] for en-US. */ initializeLocaleDays() { // Get locale day names starting with Sunday const tempArr = []; const tempWideArr = getLocaleDayNames(this.locale, FormStyle.Standalone, TranslationWidth.Wide).slice(); const tempNarrowArr = getLocaleDayNames(this.locale, FormStyle.Standalone, TranslationWidth.Narrow).slice(); // Get first day of the week based on the locale const firstDayOfWeek = this.firstDayOfWeek; for (let i = 0; i < 7; i++) { tempArr.push({ day: tempWideArr[i], narrow: tempNarrowArr[i] }); } // Rearrange the tempArr to start with the first day of the week based on the locale. if (firstDayOfWeek > 0) { const prevDays = tempArr.splice(0, firstDayOfWeek); tempArr.push(...prevDays); } this._localeDays = tempArr; } /** * Initializes the array of month names in the TranslationWidth.Abbreviated format. * e.g. `[Jan, Feb, ...]` for en-US */ initializeLocaleMonthsAbbreviated() { this._localeMonthsAbbreviated = getLocaleMonthNames(this.locale, FormStyle.Standalone, TranslationWidth.Abbreviated).slice(); } /** * Initializes the array of month names in the TranslationWidth.Wide format. * e.g. `[January, February, ...]` for en-US */ initializeLocaleMonthsWide() { this._localeMonthsWide = getLocaleMonthNames(this.locale, FormStyle.Standalone, TranslationWidth.Wide).slice(); } /** * Initializes the first day of the week based on the locale. */ initializeFirstDayOfWeek() { this._firstDayOfWeek = getLocaleFirstDayOfWeek(this.locale); } initializeLocaleDateFormat() { this._localeDateFormat = getLocaleDateFormat(this.locale, FormatWidth.Short); } } LocaleHelperService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: LocaleHelperService, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Injectable }); LocaleHelperService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: LocaleHelperService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: LocaleHelperService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [LOCALE_ID] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class CalendarModel { constructor(year, month) { this.year = year; this.month = month; this.initializeDaysInCalendar(); } /** * Checks if the calendar passed is equal to the current calendar. */ isEqual(calendar) { if (calendar) { return this.year === calendar.year && this.month === calendar.month; } return false; } /** * Checks if a DayModel is in the Calendar */ isDayInCalendar(day) { if (day) { return this.year === day.year && this.month === day.month; } return false; } /** * Returns CalendarModel of the previous month. */ previousMonth() { if (this.month === 0) { return new CalendarModel(this.year - 1, 11); } else { return new CalendarModel(this.year, this.month - 1); } } /** * Returns CalendarModel of the next month. */ nextMonth() { if (this.month === 11) { return new CalendarModel(this.year + 1, 0); } else { return new CalendarModel(this.year, this.month + 1); } } /** * Populates the days array with the DayModels in the current Calendar. */ initializeDaysInCalendar() { const noOfDaysInCalendar = getNumberOfDaysInTheMonth(this.year, this.month); this.days = Array(noOfDaysInCalendar) .fill(null) .map((_date, index) => { return new DayModel(this.year, this.month, index + 1); }); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This service is responsible for: * 1. Initializing the displayed calendar. * 2. Moving the calendar to the next, previous or current months * 3. Managing the focused and selected day models. */ class DateNavigationService { constructor() { this._todaysFullDate = new Date(); this._selectedDayChange = new Subject(); this._displayedCalendarChange = new Subject(); this._focusOnCalendarChange = new Subject(); this._focusedDayChange = new Subject(); } get today() { return this._today; } get displayedCalendar() { return this._displayedCalendar; } get selectedDayChange() { return this._selectedDayChange.asObservable(); } /** * This observable lets the subscriber know that the displayed calendar has changed. */ get displayedCalendarChange() { return this._displayedCalendarChange.asObservable(); } /** * This observable lets the subscriber know that the focus should be applied on the calendar. */ get focusOnCalendarChange() { return this._focusOnCalendarChange.asObservable(); } /** * This observable lets the subscriber know that the focused day in the displayed calendar has changed. */ get focusedDayChange() { return this._focusedDayChange.asObservable(); } /** * Notifies that the selected day has changed so that the date can be emitted to the user. * Note: Only to be called from day.ts */ notifySelectedDayChanged(dayModel) { this.selectedDay = dayModel; this._selectedDayChange.next(dayModel); } /** * Initializes the calendar based on the selected day. */ initializeCalendar() { this.focusedDay = null; // Can be removed later on the store focus this.initializeTodaysDate(); if (this.selectedDay) { this._displayedCalendar = new CalendarModel(this.selectedDay.year, this.selectedDay.month); } else { this._displayedCalendar = new CalendarModel(this.today.year, this.today.month); } } changeMonth(month) { this.setDisplayedCalendar(new CalendarModel(this._displayedCalendar.year, month)); } changeYear(year) { this.setDisplayedCalendar(new CalendarModel(year, this._displayedCalendar.month)); } /** * Moves the displayed calendar to the next month. */ moveToNextMonth() { this.setDisplayedCalendar(this._displayedCalendar.nextMonth()); } /** * Moves the displayed calendar to the previous month. */ moveToPreviousMonth() { this.setDisplayedCalendar(this._displayedCalendar.previousMonth()); } /** * Moves the displayed calendar to the current month and year. */ moveToCurrentMonth() { if (!this.displayedCalendar.isDayInCalendar(this.today)) { this.setDisplayedCalendar(new CalendarModel(this.today.year, this.today.month)); } this._focusOnCalendarChange.next(); } incrementFocusDay(value) { this.focusedDay = this.focusedDay.incrementBy(value); if (this._displayedCalendar.isDayInCalendar(this.focusedDay)) { this._focusedDayChange.next(this.focusedDay); } else { this.setDisplayedCalendar(new CalendarModel(this.focusedDay.year, this.focusedDay.month)); } this._focusOnCalendarChange.next(); } // not a setter because i want this to remain private setDisplayedCalendar(value) { if (!this._displayedCalendar.isEqual(value)) { this._displayedCalendar = value; this._displayedCalendarChange.next(); } } initializeTodaysDate() { this._todaysFullDate = new Date(); this._today = new DayModel(this._todaysFullDate.getFullYear(), this._todaysFullDate.getMonth(), this._todaysFullDate.getDate()); } } DateNavigationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateNavigationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DateNavigationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateNavigationService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateNavigationService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This service focuses the day that is focusable in the calendar. */ class DatepickerFocusService { constructor(_ngZone, platformId) { this._ngZone = _ngZone; this.platformId = platformId; } focusCell(elRef) { this._ngZone.runOutsideAngular(() => { this.ngZoneIsStableInBrowser().subscribe(() => { const focusEl = elRef.nativeElement.querySelector('[tabindex="0"]'); if (focusEl) { focusEl.focus(); } }); }); } focusInput(element) { this._ngZone.runOutsideAngular(() => this.ngZoneIsStableInBrowser().subscribe(() => element.focus())); } elementIsFocused(element) { return isPlatformBrowser(this.platformId) && document.activeElement === element; } ngZoneIsStableInBrowser() { // Credit: Material: https://github.com/angular/material2/blob/master/src/lib/datepicker/calendar.ts return this._ngZone.onStable.asObservable().pipe(first(), filter(() => isPlatformBrowser(this.platformId))); } } DatepickerFocusService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatepickerFocusService, deps: [{ token: i0.NgZone }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); DatepickerFocusService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatepickerFocusService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatepickerFocusService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DateIOService { constructor(_localeHelperService) { this._localeHelperService = _localeHelperService; this.disabledDates = { // This is the default range. It approximates the beginning of time to the end of time. // Unless a minDate or maxDate is set with the native HTML5 api the range is all dates // TODO: turn this into an Array of min/max ranges that allow configuration of multiple ranges. minDate: new DayModel(0, 0, 1), maxDate: new DayModel(9999, 11, 31), }; this.cldrLocaleDateFormat = DEFAULT_LOCALE_FORMAT; this.localeDisplayFormat = LITTLE_ENDIAN; this.delimiters = ['/', '/']; this.cldrLocaleDateFormat = this._localeHelperService.localeDateFormat; this.initializeLocaleDisplayFormat(); } get placeholderText() { const format = this.localeDisplayFormat.format; return format[0] + this.delimiters[0] + format[1] + this.delimiters[1] + format[2]; } setMinDate(date) { // NOTE: I'm expecting consumers to pass one of four things here: // A proper date string(2019-11-11), null, undefined or empty string ('') if (!date) { // attribute binding was removed, reset back to the beginning of time this.disabledDates.minDate = new DayModel(0, 0, 1); } else { const [year, month, day] = date.split('-').map(n => parseInt(n, 10)); this.disabledDates.minDate = new DayModel(year, month - 1, day); } } setMaxDate(date) { // NOTE: I'm expecting consumers to pass one of four things here: // A proper date string(2019-11-11), null, undefined or empty string ('') if (!date) { // attribute binding was removed, reset forward to the end of time this.disabledDates.maxDate = new DayModel(9999, 11, 31); } else { const [year, month, day] = date.split('-').map(n => parseInt(n, 10)); this.disabledDates.maxDate = new DayModel(year, month - 1, day); } } toLocaleDisplayFormatString(date) { if (date) { if (isNaN(date.getTime())) { return ''; } const dateNo = date.getDate(); const monthNo = date.getMonth() + 1; const dateStr = dateNo > 9 ? dateNo.toString() : '0' + dateNo; const monthStr = monthNo > 9 ? monthNo.toString() : '0' + monthNo; if (this.localeDisplayFormat === LITTLE_ENDIAN) { return dateStr + this.delimiters[0] + monthStr + this.delimiters[1] + date.getFullYear(); } else if (this.localeDisplayFormat === MIDDLE_ENDIAN) { return monthStr + this.delimiters[0] + dateStr + this.delimiters[1] + date.getFullYear(); } else { return date.getFullYear() + this.delimiters[0] + monthStr + this.delimiters[1] + dateStr; } } return ''; } getDateValueFromDateString(date) { if (!date || typeof date !== 'string') { return null; } const dateParts = date.match(USER_INPUT_REGEX); if (!dateParts || dateParts.length !== 3) { return null; } const [firstPart, secondPart, thirdPart] = dateParts; if (this.localeDisplayFormat === LITTLE_ENDIAN) { // secondPart is month && firstPart is date return this.validateAndGetDate(thirdPart, secondPart, firstPart); } else if (this.localeDisplayFormat === MIDDLE_ENDIAN) { // firstPart is month && secondPart is date return this.validateAndGetDate(thirdPart, firstPart, secondPart); } else { // secondPart is month && thirdPart is date return this.validateAndGetDate(firstPart, secondPart, thirdPart); } } initializeLocaleDisplayFormat() { const format = this.cldrLocaleDateFormat.toLocaleLowerCase(); if (LITTLE_ENDIAN_REGEX.test(format)) { this.localeDisplayFormat = LITTLE_ENDIAN; } else if (MIDDLE_ENDIAN_REGEX.test(format)) { this.localeDisplayFormat = MIDDLE_ENDIAN; } else { // everything else is set to BIG-ENDIAN FORMAT this.localeDisplayFormat = BIG_ENDIAN; } this.extractDelimiters(); } extractDelimiters() { if (this.cldrLocaleDateFormat) { // Sanitize Date Format. Remove RTL characters. // FIXME: When we support RTL, remove this and handle it correctly. const localeFormat = this.cldrLocaleDateFormat.replace(RTL_REGEX, ''); const delimiters = localeFormat.split(DELIMITER_REGEX); // NOTE: The split from the CLDR date format should always result // in an arary with 4 elements. The 1st and the 2nd values are the delimiters // we will use in order. // Eg: "dd/MM/y".split(/d+|m+|y+/i) results in ["", "/", "/", ""] if (delimiters && delimiters.length === 4) { this.delimiters = [delimiters[1], delimiters[2]]; } else { console.error('Unexpected date format received. Delimiters extracted: ', delimiters); } } } /** * Checks if the month entered by the user is valid or not. * Note: Month is 0 based. */ isValidMonth(month) { return month > -1 && month < 12; } /** * Checks if the date is valid depending on the year and month provided. */ isValidDate(year, month, date) { return date > 0 && date <= getNumberOfDaysInTheMonth(year, month); } /** * Validates the parameters provided and returns the date. * If the parameters are not * valid then return null. * NOTE: (Month here is 1 based since the user has provided that as an input) */ validateAndGetDate(year, month, date) { // I don't know whats wrong with the TS compiler. It throws an error if I write // the below if statement. The error is: // Operator '!==' cannot be applied to types '2' and '4' // More info here: https://github.com/Microsoft/TypeScript/issues/12794#issuecomment-270342936 /* if (year.length !== 2 || year.length !== 4) { return null; } */ // Instead I have to write the logic like this x-( const y = +year; const m = +month - 1; // month is 0 based const d = +date; if (!this.isValidMonth(m) || !this.isValidDate(y, m, d)) { return null; } const result = parseToFourDigitYear(y); return result !== -1 ? new Date(result, m, d) : null; } } DateIOService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateIOService, deps: [{ token: LocaleHelperService }], target: i0.ɵɵFactoryTarget.Injectable }); DateIOService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateIOService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateIOService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: LocaleHelperService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DateFormControlService { constructor() { this._touchedChange = new Subject(); this._dirtyChange = new Subject(); } get touchedChange() { return this._touchedChange.asObservable(); } get dirtyChange() { return this._dirtyChange.asObservable(); } markAsTouched() { this._touchedChange.next(); } markAsDirty() { this._dirtyChange.next(); } // friendly wrapper setDisabled(state) { this.disabled = state; } } DateFormControlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateFormControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DateFormControlService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateFormControlService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DateFormControlService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDay { constructor(_dateNavigationService, _toggleService, dateFormControlService, commonStrings) { this._dateNavigationService = _dateNavigationService; this._toggleService = _toggleService; this.dateFormControlService = dateFormControlService; this.commonStrings = commonStrings; } /** * DayViewModel input which is used to build the Day View. */ get dayView() { return this._dayView; } set dayView(day) { this._dayView = day; } get dayString() { return this.dayView.isSelected ? this.commonStrings.parse(this.commonStrings.keys.datepickerSelectedLabel, { FULL_DATE: this._dayView.dayModel.toDateString(), }) : this._dayView.dayModel.toDateString(); } /** * Updates the focusedDay in the DateNavigationService when the ClrDay is focused. */ onDayViewFocus() { this._dateNavigationService.focusedDay = this.dayView.dayModel; } /** * Updates the selectedDay when the ClrDay is selected and closes the datepicker popover. */ selectDay() { const day = this.dayView.dayModel; this._dateNavigationService.notifySelectedDayChanged(day); this.dateFormControlService.markAsDirty(); this._toggleService.open = false; } } ClrDay.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDay, deps: [{ token: DateNavigationService }, { token: ClrPopoverToggleService }, { token: DateFormControlService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDay.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDay, selector: "clr-day", inputs: { dayView: ["clrDayView", "dayView"] }, host: { properties: { "class.day": "true" } }, ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDay, decorators: [{ type: Component, args: [{ selector: 'clr-day', template: ` `, host: { '[class.day]': 'true' }, }] }], ctorParameters: function () { return [{ type: DateNavigationService }, { type: ClrPopoverToggleService }, { type: DateFormControlService }, { type: ClrCommonStringsService }]; }, propDecorators: { dayView: [{ type: Input, args: ['clrDayView'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrCalendar { constructor(_localeHelperService, _dateNavigationService, _datepickerFocusService, _dateIOService, _elRef) { this._localeHelperService = _localeHelperService; this._dateNavigationService = _dateNavigationService; this._datepickerFocusService = _datepickerFocusService; this._dateIOService = _dateIOService; this._elRef = _elRef; this._subs = []; this.generateCalendarView(); this.initializeSubscriptions(); } /** * Gets the locale days according to the TranslationWidth.Narrow format. */ get localeDays() { return this._localeHelperService.localeDays; } get calendar() { return this._dateNavigationService.displayedCalendar; } get selectedDay() { return this._dateNavigationService.selectedDay; } get focusedDay() { return this._dateNavigationService.focusedDay; } get today() { return this._dateNavigationService.today; } /** * Focuses on the focusable day when the Calendar View is initialized. */ ngAfterViewInit() { this._datepickerFocusService.focusCell(this._elRef); } /** * Unsubscribe from subscriptions. */ ngOnDestroy() { this._subs.forEach((sub) => sub.unsubscribe()); } /** * Delegates Keyboard arrow navigation to the DateNavigationService. */ onKeyDown(event) { if (event && this.focusedDay) { switch (normalizeKey(event.key)) { case Keys.ArrowUp: event.preventDefault(); this._dateNavigationService.incrementFocusDay(-1 * NO_OF_DAYS_IN_A_WEEK); break; case Keys.ArrowDown: event.preventDefault(); this._dateNavigationService.incrementFocusDay(NO_OF_DAYS_IN_A_WEEK); break; case Keys.ArrowLeft: event.preventDefault(); this._dateNavigationService.incrementFocusDay(-1); break; case Keys.ArrowRight: event.preventDefault(); this._dateNavigationService.incrementFocusDay(1); break; default: break; // No default case. ESLint x-( } } } /** * Initialize subscriptions to: * 1. update the calendar view model. * 2. update the focusable day in the calendar view model. * 3. focus on the focusable day in the calendar. */ initializeSubscriptions() { this._subs.push(this._dateNavigationService.displayedCalendarChange.subscribe(() => { this.generateCalendarView(); })); this._subs.push(this._dateNavigationService.focusedDayChange.subscribe((focusedDay) => { this.calendarViewModel.updateFocusableDay(focusedDay); })); this._subs.push(this._dateNavigationService.focusOnCalendarChange.subscribe(() => { this._datepickerFocusService.focusCell(this._elRef); })); } /** * Generates the Calendar View based on the calendar retrieved from the DateNavigationService. */ generateCalendarView() { this.calendarViewModel = new CalendarViewModel(this.calendar, this.selectedDay, this.focusedDay, this.today, this._localeHelperService.firstDayOfWeek, this._dateIOService.disabledDates); } } ClrCalendar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCalendar, deps: [{ token: LocaleHelperService }, { token: DateNavigationService }, { token: DatepickerFocusService }, { token: DateIOService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ClrCalendar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrCalendar, selector: "clr-calendar", host: { listeners: { "keydown": "onKeyDown($event)" } }, ngImport: i0, template: "\n \n \n \n \n \n \n
\n {{day.narrow}}\n
\n \n
\n", dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ClrDay, selector: "clr-day", inputs: ["clrDayView"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrCalendar, decorators: [{ type: Component, args: [{ selector: 'clr-calendar', template: "\n \n \n \n \n \n \n
\n {{day.narrow}}\n
\n \n
\n" }] }], ctorParameters: function () { return [{ type: LocaleHelperService }, { type: DateNavigationService }, { type: DatepickerFocusService }, { type: DateIOService }, { type: i0.ElementRef }]; }, propDecorators: { onKeyDown: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * TODO: * Using core functions like: * - pluckPixelValue * - getCssPropertyValue * * to get the value of the design token. * * Note: Memoization/Cache usage possible. */ // iPad mini screen width // http://stephen.io/mediaqueries/#iPadMini const DATEPICKER_ENABLE_BREAKPOINT = 768; const SMALL_BREAKPOINT = 576; const MEDIUM_BREAKPOINT = 768; const LARGE_BREAKPOINT = 992; const EXTRA_LARGE_BREAKPOINT = 1200; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatepickerEnabledService { constructor(_document) { this._document = _document; this._isUserAgentMobile = false; if (this._document) { this._isUserAgentMobile = MOBILE_USERAGENT_REGEX.test(_document.defaultView.navigator.userAgent); this._innerWidth = _document.defaultView.innerWidth; } } /** * Returns if the calendar should be active or not. * If the user agent is mobile and the screen width is less than DATEPICKER_ACTIVE_BREAKPOINT * then the calendar is inactive. */ get isEnabled() { // https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent // What they recommend is: //"In summary, we recommend looking for the string 'Mobi' // anywhere in the User Agent to detect a mobile device." if (this._document) { if (this._innerWidth < DATEPICKER_ENABLE_BREAKPOINT && this._isUserAgentMobile) { return false; } } return true; } } DatepickerEnabledService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatepickerEnabledService, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); DatepickerEnabledService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatepickerEnabledService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatepickerEnabledService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This service manages which view is visible in the datepicker popover. */ class ViewManagerService { constructor() { this.position = ClrPopoverPositions['bottom-left']; this._currentView = "DAYVIEW" /* DatepickerViewEnum.DAYVIEW */; } get isDayView() { return this._currentView === "DAYVIEW" /* DatepickerViewEnum.DAYVIEW */; } get isYearView() { return this._currentView === "YEARVIEW" /* DatepickerViewEnum.YEARVIEW */; } get isMonthView() { return this._currentView === "MONTHVIEW" /* DatepickerViewEnum.MONTHVIEW */; } changeToMonthView() { this._currentView = "MONTHVIEW" /* DatepickerViewEnum.MONTHVIEW */; } changeToYearView() { this._currentView = "YEARVIEW" /* DatepickerViewEnum.YEARVIEW */; } changeToDayView() { this._currentView = "DAYVIEW" /* DatepickerViewEnum.DAYVIEW */; } } ViewManagerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ViewManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ViewManagerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ViewManagerService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ViewManagerService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrMonthpicker { constructor(_viewManagerService, _localeHelperService, _dateNavigationService, _datepickerFocusService, _elRef) { this._viewManagerService = _viewManagerService; this._localeHelperService = _localeHelperService; this._dateNavigationService = _dateNavigationService; this._datepickerFocusService = _datepickerFocusService; this._elRef = _elRef; this._focusedMonthIndex = this.calendarMonthIndex; } /** * Gets the months array which is used to rendered the monthpicker view. * Months are in the TranslationWidth.Wide format. */ get monthNames() { return this._localeHelperService.localeMonthsWide; } /** * Gets the month value of the Calendar. */ get calendarMonthIndex() { return this._dateNavigationService.displayedCalendar.month; } /** * Focuses on the current calendar month when the View is initialized. */ ngAfterViewInit() { this._datepickerFocusService.focusCell(this._elRef); } /** * Handles the Keyboard arrow navigation for the monthpicker. */ onKeyDown(event) { // NOTE: Didn't move this to the date navigation service because // the logic is fairly simple and it didn't make sense for me // to create extra observables just to move this logic to the service. if (event) { const key = normalizeKey(event.key); if (key === Keys.ArrowUp && this._focusedMonthIndex > 0) { event.preventDefault(); this._focusedMonthIndex--; this._datepickerFocusService.focusCell(this._elRef); } else if (key === Keys.ArrowDown && this._focusedMonthIndex < 11) { event.preventDefault(); this._focusedMonthIndex++; this._datepickerFocusService.focusCell(this._elRef); } else if (key === Keys.ArrowRight && this._focusedMonthIndex < 6) { event.preventDefault(); this._focusedMonthIndex = this._focusedMonthIndex + 6; this._datepickerFocusService.focusCell(this._elRef); } else if (key === Keys.ArrowLeft && this._focusedMonthIndex > 5) { event.preventDefault(); this._focusedMonthIndex = this._focusedMonthIndex - 6; this._datepickerFocusService.focusCell(this._elRef); } } } /** * Calls the DateNavigationService to update the month value of the calendar. * Also changes the view to the daypicker. */ changeMonth(monthIndex) { this._dateNavigationService.changeMonth(monthIndex); this._viewManagerService.changeToDayView(); } /** * Compares the month passed to the focused month and returns the tab index. */ getTabIndex(monthIndex) { return monthIndex === this._focusedMonthIndex ? 0 : -1; } } ClrMonthpicker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMonthpicker, deps: [{ token: ViewManagerService }, { token: LocaleHelperService }, { token: DateNavigationService }, { token: DatepickerFocusService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ClrMonthpicker.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrMonthpicker, selector: "clr-monthpicker", host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.monthpicker": "true" } }, ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMonthpicker, decorators: [{ type: Component, args: [{ selector: 'clr-monthpicker', template: ` `, host: { '[class.monthpicker]': 'true', }, }] }], ctorParameters: function () { return [{ type: ViewManagerService }, { type: LocaleHelperService }, { type: DateNavigationService }, { type: DatepickerFocusService }, { type: i0.ElementRef }]; }, propDecorators: { onKeyDown: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const YEARS_TO_DISPLAY = 10; class YearRangeModel { constructor(year) { this.year = year; this.yearRange = []; this.generateYearRange(); } /** * Gets the number in the middle of the range. */ get middleYear() { return this.yearRange[Math.floor(this.yearRange.length / 2)]; } /** * Generates the YearRangeModel for the next decade. */ nextDecade() { return new YearRangeModel(this.year + 10); } /** * Generates the YearRangeModel for the previous decade. */ previousDecade() { return new YearRangeModel(this.year - 10); } /** * Generates the YearRangeModel for the current decade. */ currentDecade() { return new YearRangeModel(new Date().getFullYear()); } /** * Checks if the value is in the YearRangeModel. */ inRange(value) { return this.yearRange.indexOf(value) > -1; } /** * Generates the year range based on the year parameter. * eg: If 2018 is passed the output will be [2010, 2011, ..., 2019] */ generateYearRange() { const remainder = this.year % YEARS_TO_DISPLAY; const floor = this.year - remainder; const ceil = floor + YEARS_TO_DISPLAY; this.yearRange = this.generateRange(floor, ceil); } /** * Function which generate a range of numbers from floor to ceil. */ generateRange(floor, ceil) { return Array.from({ length: ceil - floor }, (_v, k) => k + floor); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrYearpicker { constructor(_dateNavigationService, _viewManagerService, _datepickerFocusService, _elRef, commonStrings) { this._dateNavigationService = _dateNavigationService; this._viewManagerService = _viewManagerService; this._datepickerFocusService = _datepickerFocusService; this._elRef = _elRef; this.commonStrings = commonStrings; this.yearRangeModel = new YearRangeModel(this.calendarYear); this._focusedYear = this.calendarYear; } /** * Gets the year which the user is currently on. */ get calendarYear() { return this._dateNavigationService.displayedCalendar.year; } /** * Focuses on the current calendar year when the View is initialized. */ ngAfterViewInit() { this._datepickerFocusService.focusCell(this._elRef); } /** * Handles the Keyboard arrow navigation for the yearpicker. */ onKeyDown(event) { // NOTE: Didn't move this to the date navigation service because // the logic is fairly simple and it didn't make sense for me // to create extra observables just to move this logic to the service. if (event) { const key = normalizeKey(event.key); if (key === Keys.ArrowUp) { event.preventDefault(); this.incrementFocusYearBy(-1); } else if (key === Keys.ArrowDown) { event.preventDefault(); this.incrementFocusYearBy(1); } else if (key === Keys.ArrowRight) { event.preventDefault(); this.incrementFocusYearBy(5); } else if (key === Keys.ArrowLeft) { event.preventDefault(); this.incrementFocusYearBy(-5); } } } /** * Calls the DateNavigationService to update the year value of the calendar. * Also changes the view to the daypicker. */ changeYear(year) { this._dateNavigationService.changeYear(year); this._viewManagerService.changeToDayView(); } /** * Updates the YearRangeModel to the previous decade. */ previousDecade() { this.yearRangeModel = this.yearRangeModel.previousDecade(); // Year in the yearpicker is not focused because while navigating to a different decade, // you want the focus to remain on the decade switcher arrows. } /** * Updates the YearRangeModel to the current decade. */ currentDecade() { if (!this.yearRangeModel.inRange(this._dateNavigationService.today.year)) { this.yearRangeModel = this.yearRangeModel.currentDecade(); } this._datepickerFocusService.focusCell(this._elRef); } /** * Updates the YearRangeModel to the next decade. */ nextDecade() { this.yearRangeModel = this.yearRangeModel.nextDecade(); // Year in the yearpicker is not focused because while navigating to a different decade, // you want the focus to remain on the decade switcher arrows. } /** * Compares the year passed to the focused year and returns the tab index. */ getTabIndex(year) { if (!this.yearRangeModel.inRange(this._focusedYear)) { if (this.yearRangeModel.inRange(this.calendarYear)) { this._focusedYear = this.calendarYear; } else { this._focusedYear = this.yearRangeModel.middleYear; } } return this._focusedYear === year ? 0 : -1; } /** * Increments the focus year by the value passed. Updates the YearRangeModel if the * new value is not in the current decade. */ incrementFocusYearBy(value) { this._focusedYear = this._focusedYear + value; if (!this.yearRangeModel.inRange(this._focusedYear)) { if (value > 0) { this.yearRangeModel = this.yearRangeModel.nextDecade(); } else { this.yearRangeModel = this.yearRangeModel.previousDecade(); } } this._datepickerFocusService.focusCell(this._elRef); } } ClrYearpicker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrYearpicker, deps: [{ token: DateNavigationService }, { token: ViewManagerService }, { token: DatepickerFocusService }, { token: i0.ElementRef }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrYearpicker.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrYearpicker, selector: "clr-yearpicker", host: { listeners: { "keydown": "onKeyDown($event)" }, properties: { "class.yearpicker": "true" } }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrYearpicker, decorators: [{ type: Component, args: [{ selector: 'clr-yearpicker', template: `
`, host: { '[class.yearpicker]': 'true', }, }] }], ctorParameters: function () { return [{ type: DateNavigationService }, { type: ViewManagerService }, { type: DatepickerFocusService }, { type: i0.ElementRef }, { type: ClrCommonStringsService }]; }, propDecorators: { onKeyDown: [{ type: HostListener, args: ['keydown', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDaypicker { constructor(_viewManagerService, _dateNavigationService, _localeHelperService, commonStrings) { this._viewManagerService = _viewManagerService; this._dateNavigationService = _dateNavigationService; this._localeHelperService = _localeHelperService; this.commonStrings = commonStrings; } get monthAttrString() { return this.commonStrings.parse(this.commonStrings.keys.datepickerSelectMonthText, { CALENDAR_MONTH: this.calendarMonth, }); } get yearAttrString() { return this.commonStrings.parse(this.commonStrings.keys.datepickerSelectYearText, { CALENDAR_YEAR: this.calendarYear.toString(), }); } /** * Returns the month value of the calendar in the TranslationWidth.Abbreviated format. */ get calendarMonth() { return this._localeHelperService.localeMonthsAbbreviated[this._dateNavigationService.displayedCalendar.month]; } /** * Returns the year value of the calendar. */ get calendarYear() { return this._dateNavigationService.displayedCalendar.year; } /** * Calls the ViewManagerService to change to the monthpicker view. */ changeToMonthView() { this._viewManagerService.changeToMonthView(); } /** * Calls the ViewManagerService to change to the yearpicker view. */ changeToYearView() { this._viewManagerService.changeToYearView(); } /** * Calls the DateNavigationService to move to the next month. */ nextMonth() { this._dateNavigationService.moveToNextMonth(); } /** * Calls the DateNavigationService to move to the previous month. */ previousMonth() { this._dateNavigationService.moveToPreviousMonth(); } /** * Calls the DateNavigationService to move to the current month. */ currentMonth() { this._dateNavigationService.moveToCurrentMonth(); } } ClrDaypicker.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDaypicker, deps: [{ token: ViewManagerService }, { token: DateNavigationService }, { token: LocaleHelperService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDaypicker.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDaypicker, selector: "clr-daypicker", host: { properties: { "class.daypicker": "true" } }, ngImport: i0, template: "
{{commonStrings.keys.modalContentStart}}
\n
\n
\n \n {{calendarMonth}}\n \n \n {{calendarYear}}\n \n
\n
\n \n \n \n \n \n \n \n \n \n
\n
\n\n
{{commonStrings.keys.modalContentEnd}}
\n", dependencies: [{ kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrCalendar, selector: "clr-calendar" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDaypicker, decorators: [{ type: Component, args: [{ selector: 'clr-daypicker', host: { '[class.daypicker]': 'true' }, template: "
{{commonStrings.keys.modalContentStart}}
\n
\n
\n \n {{calendarMonth}}\n \n \n {{calendarYear}}\n \n
\n
\n \n \n \n \n \n \n \n \n \n
\n
\n\n
{{commonStrings.keys.modalContentEnd}}
\n" }] }], ctorParameters: function () { return [{ type: ViewManagerService }, { type: DateNavigationService }, { type: LocaleHelperService }, { type: ClrCommonStringsService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatepickerViewManager { constructor(commonStrings, viewManagerService) { this.commonStrings = commonStrings; this.viewManagerService = viewManagerService; } /** * Returns if the current view is the monthpicker. */ get isMonthView() { return this.viewManagerService.isMonthView; } /** * Returns if the current view is the yearpicker. */ get isYearView() { return this.viewManagerService.isYearView; } /** * Returns if the current view is the daypicker. */ get isDayView() { return this.viewManagerService.isDayView; } } ClrDatepickerViewManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatepickerViewManager, deps: [{ token: ClrCommonStringsService }, { token: ViewManagerService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatepickerViewManager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatepickerViewManager, selector: "clr-datepicker-view-manager", host: { attributes: { "role": "dialog" }, properties: { "class.datepicker": "true", "attr.aria-modal": "true", "attr.aria-label": "commonStrings.keys.datepickerDialogLabel" } }, providers: [DatepickerFocusService], ngImport: i0, template: "\n\n\n\n\n", dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ClrMonthpicker, selector: "clr-monthpicker" }, { kind: "component", type: ClrYearpicker, selector: "clr-yearpicker" }, { kind: "component", type: ClrDaypicker, selector: "clr-daypicker" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatepickerViewManager, decorators: [{ type: Component, args: [{ selector: 'clr-datepicker-view-manager', providers: [DatepickerFocusService], host: { '[class.datepicker]': 'true', '[attr.aria-modal]': 'true', '[attr.aria-label]': 'commonStrings.keys.datepickerDialogLabel', role: 'dialog', }, template: "\n\n\n\n\n" }] }], ctorParameters: function () { return [{ type: ClrCommonStringsService }, { type: ViewManagerService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDateContainer extends ClrAbstractContainer { constructor(renderer, toggleService, dateNavigationService, datepickerEnabledService, dateFormControlService, dateIOService, commonStrings, focusService, viewManagerService, controlClassService, layoutService, ngControlService, ifControlStateService) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.renderer = renderer; this.toggleService = toggleService; this.dateNavigationService = dateNavigationService; this.datepickerEnabledService = datepickerEnabledService; this.dateFormControlService = dateFormControlService; this.dateIOService = dateIOService; this.commonStrings = commonStrings; this.focusService = focusService; this.viewManagerService = viewManagerService; this.controlClassService = controlClassService; this.layoutService = layoutService; this.ngControlService = ngControlService; this.ifControlStateService = ifControlStateService; this.focus = false; this.subscriptions.push(this.focusService.focusChange.subscribe(state => { this.focus = state; })); this.subscriptions.push(this.toggleService.openChange.subscribe(() => { this.dateFormControlService.markAsTouched(); })); } set clrPosition(position) { if (position && ClrPopoverPositions[position]) { this.viewManagerService.position = ClrPopoverPositions[position]; } } set actionButton(button) { this.toggleButton = button; } get popoverPosition() { return this.viewManagerService.position; } get open() { return this.toggleService.open; } /** * Returns if the Datepicker is enabled or not. If disabled, hides the datepicker trigger. */ get isEnabled() { return this.datepickerEnabledService.isEnabled; } /** * Return if Datepicker is diabled or not as Form Control */ get isInputDateDisabled() { /* clrForm wrapper or without clrForm */ return ((this.control && this.control.disabled) || (this.dateFormControlService && this.dateFormControlService.disabled)); } ngAfterViewInit() { this.subscriptions.push(this.toggleService.openChange.subscribe(open => { if (open) { this.initializeCalendar(); } else { this.toggleButton.nativeElement.focus(); } })); this.subscriptions.push(this.listenForDateChanges()); } /** * Return the label for the toggle button. * If there's a selected date, the date is included in the label. */ getToggleButtonLabel(day) { if (day) { const formattedDate = this.dateIOService.toLocaleDisplayFormatString(day.toDate()); return this.commonStrings.parse(this.commonStrings.keys.datepickerToggleChangeDateLabel, { SELECTED_DATE: formattedDate, }); } return this.commonStrings.keys.datepickerToggleChooseDateLabel; } listenForDateChanges() { // because date-input.ts initializes the input in ngAfterViewInit, // using a databound attribute to change the button labels results in ExpressionChangedAfterItHasBeenCheckedError. // so instead, update the attribute directly on the element return this.dateNavigationService.selectedDayChange .pipe(startWith(this.dateNavigationService.selectedDay)) .subscribe(day => { if (this.isEnabled) { const label = this.getToggleButtonLabel(day); const toggleEl = this.toggleButton.nativeElement; this.renderer.setAttribute(toggleEl, 'aria-label', label); this.renderer.setAttribute(toggleEl, 'title', label); } }); } /** * Processes the user input and Initializes the Calendar everytime the datepicker popover is open. */ initializeCalendar() { this.dateNavigationService.initializeCalendar(); } } ClrDateContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDateContainer, deps: [{ token: i0.Renderer2 }, { token: ClrPopoverToggleService }, { token: DateNavigationService }, { token: DatepickerEnabledService }, { token: DateFormControlService }, { token: DateIOService }, { token: ClrCommonStringsService }, { token: FocusService }, { token: ViewManagerService }, { token: ControlClassService }, { token: LayoutService, optional: true }, { token: NgControlService }, { token: IfControlStateService }], target: i0.ɵɵFactoryTarget.Component }); ClrDateContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDateContainer, selector: "clr-date-container", inputs: { clrPosition: "clrPosition" }, host: { properties: { "class.clr-date-container": "true", "class.clr-form-control-disabled": "isInputDateDisabled", "class.clr-form-control": "true", "class.clr-row": "addGrid()" } }, providers: [ ControlIdService, LocaleHelperService, ControlClassService, FocusService, NgControlService, DateIOService, DateNavigationService, DatepickerEnabledService, DateFormControlService, ViewManagerService, IfControlStateService, ], viewQueries: [{ propertyName: "actionButton", first: true, predicate: ["actionButton"], descendants: true }], usesInheritance: true, hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }, { kind: "directive", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "component", type: ClrDatepickerViewManager, selector: "clr-datepicker-view-manager" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDateContainer, decorators: [{ type: Component, args: [{ selector: 'clr-date-container', template: `
`, providers: [ ControlIdService, LocaleHelperService, ControlClassService, FocusService, NgControlService, DateIOService, DateNavigationService, DatepickerEnabledService, DateFormControlService, ViewManagerService, IfControlStateService, ], hostDirectives: [ClrPopoverHostDirective], host: { '[class.clr-date-container]': 'true', '[class.clr-form-control-disabled]': 'isInputDateDisabled', '[class.clr-form-control]': 'true', '[class.clr-row]': 'addGrid()', }, }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: ClrPopoverToggleService }, { type: DateNavigationService }, { type: DatepickerEnabledService }, { type: DateFormControlService }, { type: DateIOService }, { type: ClrCommonStringsService }, { type: FocusService }, { type: ViewManagerService }, { type: ControlClassService }, { type: LayoutService, decorators: [{ type: Optional }] }, { type: NgControlService }, { type: IfControlStateService }]; }, propDecorators: { clrPosition: [{ type: Input, args: ['clrPosition'] }], actionButton: [{ type: ViewChild, args: ['actionButton'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // There are four ways the datepicker value is set // 1. Value set by user typing into text input as a string ex: '01/28/2015' // 2. Value set explicitly by Angular Forms APIs as a string ex: '01/28/2015' // 3. Value set by user via datepicker UI as a Date Object // 4. Value set via `clrDate` input as a Date Object class ClrDateInput extends WrappedFormControl { constructor(viewContainerRef, injector, el, renderer, control, container, dateIOService, dateNavigationService, datepickerEnabledService, dateFormControlService, platformId, focusService, datepickerFocusService) { super(viewContainerRef, ClrDateContainer, injector, control, renderer, el); this.el = el; this.renderer = renderer; this.control = control; this.container = container; this.dateIOService = dateIOService; this.dateNavigationService = dateNavigationService; this.datepickerEnabledService = datepickerEnabledService; this.dateFormControlService = dateFormControlService; this.platformId = platformId; this.focusService = focusService; this.datepickerFocusService = datepickerFocusService; this.dateChange = new EventEmitter(false); this.index = 1; } set date(date) { if (this.previousDateChange !== date) { this.updateDate(this.getValidDateValueFromDate(date)); } if (!this.initialClrDateInputValue) { this.initialClrDateInputValue = date; } } set min(dateString) { this.dateIOService.setMinDate(dateString); this.triggerControlValidation(); } set max(dateString) { this.dateIOService.setMaxDate(dateString); this.triggerControlValidation(); } get disabled() { if (this.dateFormControlService) { return this.dateFormControlService.disabled; } return null; } set disabled(value) { if (this.dateFormControlService) { this.dateFormControlService.setDisabled(isBooleanAttributeSet(value)); } } get placeholderText() { return this.placeholder ? this.placeholder : this.dateIOService.placeholderText; } get inputType() { return isPlatformBrowser(this.platformId) && this.usingNativeDatepicker() ? 'date' : 'text'; } ngOnInit() { super.ngOnInit(); this.populateServicesFromContainerComponent(); this.subscriptions.push(this.listenForUserSelectedDayChanges(), this.listenForControlValueChanges(), this.listenForTouchChanges(), this.listenForDirtyChanges(), this.listenForInputRefocus()); } ngAfterViewInit() { // I don't know why I have to do this but after using the new HostWrapping Module I have to delay the processing // of the initial Input set by the user to here. If I do not 2 issues occur: // 1. The Input setter is called before ngOnInit. ngOnInit initializes the services without which the setter fails. // 2. The Renderer doesn't work before ngAfterViewInit (It used to before the new HostWrapping Module for some reason). // I need the renderer to set the value property on the input to make sure that if the user has supplied a Date // input object, we reflect it with the right date on the input field using the IO service. I am not sure if // these are major issues or not but just noting them down here. this.processInitialInputs(); } setFocusStates() { this.setFocus(true); } triggerValidation() { super.triggerValidation(); this.setFocus(false); } onValueChange(target) { const validDateValue = this.dateIOService.getDateValueFromDateString(target.value); if (this.usingClarityDatepicker() && validDateValue) { this.updateDate(validDateValue, true); } else if (this.usingNativeDatepicker()) { const [year, month, day] = target.value.split('-'); this.updateDate(new Date(+year, +month - 1, +day), true); } else { this.emitDateOutput(null); } } usingClarityDatepicker() { return this.datepickerEnabledService.isEnabled; } usingNativeDatepicker() { return !this.datepickerEnabledService.isEnabled; } setFocus(focus) { if (this.focusService) { this.focusService.focused = focus; } } triggerControlValidation() { if (this.datepickerHasFormControl()) { // Set `emitEvent` to false to prevent unnecessary value change event. Status change event will be emitted by `setErrors` below. this.control.control?.updateValueAndValidity({ emitEvent: false }); this.control.control?.setErrors(this.control.control.errors); } } populateServicesFromContainerComponent() { if (!this.container) { this.dateIOService = this.getProviderFromContainer(DateIOService); this.dateNavigationService = this.getProviderFromContainer(DateNavigationService); this.datepickerEnabledService = this.getProviderFromContainer(DatepickerEnabledService); this.dateFormControlService = this.getProviderFromContainer(DateFormControlService); } } processInitialInputs() { if (this.datepickerHasFormControl()) { this.updateDate(this.dateIOService.getDateValueFromDateString(this.control.value)); } else { this.updateDate(this.initialClrDateInputValue); } } updateDate(value, setByUserInteraction = false) { const date = this.getValidDateValueFromDate(value); if (setByUserInteraction) { this.emitDateOutput(date); } else { this.previousDateChange = date; } if (this.dateNavigationService) { this.dateNavigationService.selectedDay = date ? new DayModel(date.getFullYear(), date.getMonth(), date.getDate()) : null; } this.updateInput(date); } updateInput(date) { if (date) { const dateString = this.dateIOService.toLocaleDisplayFormatString(date); if (this.usingNativeDatepicker()) { // valueAsDate expects UTC, date from input is time-zoned date.setMinutes(date.getMinutes() - date.getTimezoneOffset()); this.renderer.setProperty(this.el.nativeElement, 'valueAsDate', date); } else if (this.datepickerHasFormControl() && dateString !== this.control.value) { this.control.control.setValue(dateString); } else { this.renderer.setProperty(this.el.nativeElement, 'value', dateString); } } else { this.renderer.setProperty(this.el.nativeElement, 'value', ''); } } getValidDateValueFromDate(date) { if (this.dateIOService) { const dateString = this.dateIOService.toLocaleDisplayFormatString(date); return this.dateIOService.getDateValueFromDateString(dateString); } else { return null; } } emitDateOutput(date) { if (!datesAreEqual(date, this.previousDateChange)) { this.dateChange.emit(date); this.previousDateChange = date; } else if (!date && this.previousDateChange) { this.dateChange.emit(null); this.previousDateChange = null; } } datepickerHasFormControl() { return !!this.control; } listenForControlValueChanges() { return of(this.datepickerHasFormControl()) .pipe(filter(hasControl => hasControl), switchMap(() => this.control.valueChanges), // only update date value if not being set by user filter(() => !this.datepickerFocusService.elementIsFocused(this.el.nativeElement))) .subscribe((value) => this.updateDate(this.dateIOService.getDateValueFromDateString(value))); } listenForUserSelectedDayChanges() { return this.dateNavigationService.selectedDayChange.subscribe(dayModel => this.updateDate(dayModel.toDate(), true)); } listenForTouchChanges() { return this.dateFormControlService.touchedChange .pipe(filter(() => this.datepickerHasFormControl())) .subscribe(() => this.control.control.markAsTouched()); } listenForDirtyChanges() { return this.dateFormControlService.dirtyChange .pipe(filter(() => this.datepickerHasFormControl())) .subscribe(() => this.control.control.markAsDirty()); } listenForInputRefocus() { return this.dateNavigationService.selectedDayChange .pipe(filter(date => !!date)) .subscribe(() => this.datepickerFocusService.focusInput(this.el.nativeElement)); } } ClrDateInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDateInput, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.NgControl, optional: true, self: true }, { token: ClrDateContainer, optional: true }, { token: DateIOService, optional: true }, { token: DateNavigationService, optional: true }, { token: DatepickerEnabledService, optional: true }, { token: DateFormControlService, optional: true }, { token: PLATFORM_ID }, { token: FocusService, optional: true }, { token: DatepickerFocusService }], target: i0.ɵɵFactoryTarget.Directive }); ClrDateInput.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDateInput, selector: "[clrDate]", inputs: { placeholder: "placeholder", date: ["clrDate", "date"], min: "min", max: "max", disabled: "disabled" }, outputs: { dateChange: "clrDateChange" }, host: { listeners: { "focus": "setFocusStates()", "blur": "triggerValidation()", "change": "onValueChange($event.target)" }, properties: { "class.clr-input": "true", "disabled": "this.disabled", "attr.placeholder": "this.placeholderText", "attr.type": "this.inputType" } }, providers: [DatepickerFocusService], usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDateInput, decorators: [{ type: Directive, args: [{ selector: '[clrDate]', host: { '[class.clr-input]': 'true', }, providers: [DatepickerFocusService], }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: ClrDateContainer, decorators: [{ type: Optional }] }, { type: DateIOService, decorators: [{ type: Optional }] }, { type: DateNavigationService, decorators: [{ type: Optional }] }, { type: DatepickerEnabledService, decorators: [{ type: Optional }] }, { type: DateFormControlService, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: FocusService, decorators: [{ type: Optional }] }, { type: DatepickerFocusService }]; }, propDecorators: { placeholder: [{ type: Input }], dateChange: [{ type: Output, args: ['clrDateChange'] }], date: [{ type: Input, args: ['clrDate'] }], min: [{ type: Input }], max: [{ type: Input }], disabled: [{ type: Input, args: ['disabled'] }, { type: HostBinding, args: ['disabled'] }], placeholderText: [{ type: HostBinding, args: ['attr.placeholder'] }], inputType: [{ type: HostBinding, args: ['attr.type'] }], setFocusStates: [{ type: HostListener, args: ['focus'] }], triggerValidation: [{ type: HostListener, args: ['blur'] }], onValueChange: [{ type: HostListener, args: ['change', ['$event.target']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDateInputValidator { constructor(dateIOService) { this.dateIOService = dateIOService; } validate(control) { if (this.dateIOService) { const value = this.dateIOService.getDateValueFromDateString(control.value); const minDate = this.dateIOService.disabledDates.minDate.toDate(); const maxDate = this.dateIOService.disabledDates.maxDate.toDate(); if (value && value < this.dateIOService.disabledDates.minDate.toDate()) { return { min: { min: minDate.toLocaleDateString(), actual: value.toLocaleDateString() } }; } else if (value && value > this.dateIOService.disabledDates.maxDate.toDate()) { return { max: { max: maxDate.toLocaleDateString(), actual: value.toLocaleDateString() } }; } } return null; } } ClrDateInputValidator.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDateInputValidator, deps: [{ token: DateIOService, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrDateInputValidator.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDateInputValidator, selector: "[clrDate]", providers: [{ provide: NG_VALIDATORS, useExisting: ClrDateInputValidator, multi: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDateInputValidator, decorators: [{ type: Directive, args: [{ selector: '[clrDate]', providers: [{ provide: NG_VALIDATORS, useExisting: ClrDateInputValidator, multi: true }], }] }], ctorParameters: function () { return [{ type: DateIOService, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_DATEPICKER_DIRECTIVES = [ ClrDay, ClrDateContainer, ClrDateInput, ClrDateInputValidator, ClrDatepickerViewManager, ClrMonthpicker, ClrYearpicker, ClrDaypicker, ClrCalendar, ]; class ClrDatepickerModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon, angleIcon, eventIcon, calendarIcon); } } ClrDatepickerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatepickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrDatepickerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrDatepickerModule, declarations: [ClrDay, ClrDateContainer, ClrDateInput, ClrDateInputValidator, ClrDatepickerViewManager, ClrMonthpicker, ClrYearpicker, ClrDaypicker, ClrCalendar], imports: [CommonModule, CdkTrapFocusModule, ClrHostWrappingModule, ClrConditionalModule, ClrPopoverModuleNext, ClrIconModule, ClrCommonFormsModule], exports: [ClrDay, ClrDateContainer, ClrDateInput, ClrDateInputValidator, ClrDatepickerViewManager, ClrMonthpicker, ClrYearpicker, ClrDaypicker, ClrCalendar] }); ClrDatepickerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatepickerModule, imports: [CommonModule, CdkTrapFocusModule, ClrHostWrappingModule, ClrConditionalModule, ClrPopoverModuleNext, ClrIconModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatepickerModule, decorators: [{ type: NgModule, args: [{ imports: [ CommonModule, CdkTrapFocusModule, ClrHostWrappingModule, ClrConditionalModule, ClrPopoverModuleNext, ClrIconModule, ClrCommonFormsModule, ], declarations: [CLR_DATEPICKER_DIRECTIVES], exports: [CLR_DATEPICKER_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const TOGGLE_SERVICE = new InjectionToken(undefined); function ToggleServiceFactory() { return new BehaviorSubject(false); } const TOGGLE_SERVICE_PROVIDER = { provide: TOGGLE_SERVICE, useFactory: ToggleServiceFactory }; class ClrPasswordContainer extends ClrAbstractContainer { constructor(ifControlStateService, layoutService, controlClassService, ngControlService, focusService, toggleService, commonStrings) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.focusService = focusService; this.toggleService = toggleService; this.commonStrings = commonStrings; this.show = false; this.focus = false; this._toggle = true; /* The unsubscribe is handle inside the ClrAbstractContainer */ this.subscriptions.push(this.focusService.focusChange.subscribe(state => { this.focus = state; })); } get clrToggle() { return this._toggle; } set clrToggle(state) { this._toggle = state; if (!state) { this.show = false; } } toggle() { this.show = !this.show; this.toggleService.next(this.show); } showPasswordText(label) { return this.commonStrings.parse(this.commonStrings.keys.passwordShow, { LABEL: label }); } hidePasswordText(label) { return this.commonStrings.parse(this.commonStrings.keys.passwordHide, { LABEL: label }); } } ClrPasswordContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPasswordContainer, deps: [{ token: IfControlStateService }, { token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }, { token: FocusService }, { token: TOGGLE_SERVICE }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrPasswordContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrPasswordContainer, selector: "clr-password-container", inputs: { clrToggle: "clrToggle" }, host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [ NgControlService, ControlIdService, ControlClassService, FocusService, TOGGLE_SERVICE_PROVIDER, IfControlStateService, ], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPasswordContainer, decorators: [{ type: Component, args: [{ selector: 'clr-password-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [ NgControlService, ControlIdService, ControlClassService, FocusService, TOGGLE_SERVICE_PROVIDER, IfControlStateService, ], }] }], ctorParameters: function () { return [{ type: IfControlStateService }, { type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }, { type: FocusService }, { type: i3.BehaviorSubject, decorators: [{ type: Inject, args: [TOGGLE_SERVICE] }] }, { type: ClrCommonStringsService }]; }, propDecorators: { clrToggle: [{ type: Input, args: ['clrToggle'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPassword extends WrappedFormControl { constructor(vcr, injector, control, renderer, el, focusService, toggleService) { super(vcr, ClrPasswordContainer, injector, control, renderer, el); this.focusService = focusService; this.toggleService = toggleService; this.index = 1; if (!this.focusService) { throw new Error('clrPassword requires being wrapped in '); } this.subscriptions.push(this.toggleService.subscribe(toggle => { renderer.setProperty(el.nativeElement, 'type', toggle ? 'text' : 'password'); })); } triggerFocus() { if (this.focusService) { this.focusService.focused = true; } } triggerValidation() { super.triggerValidation(); if (this.focusService) { this.focusService.focused = false; } } } ClrPassword.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPassword, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: FocusService, optional: true }, { token: TOGGLE_SERVICE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrPassword.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrPassword, selector: "[clrPassword]", host: { listeners: { "focus": "triggerFocus()", "blur": "triggerValidation()" }, properties: { "class.clr-input": "true" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPassword, decorators: [{ type: Directive, args: [{ selector: '[clrPassword]', host: { '[class.clr-input]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: FocusService, decorators: [{ type: Optional }] }, { type: i3.BehaviorSubject, decorators: [{ type: Optional }, { type: Inject, args: [TOGGLE_SERVICE] }] }]; }, propDecorators: { triggerFocus: [{ type: HostListener, args: ['focus'] }], triggerValidation: [{ type: HostListener, args: ['blur'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPasswordModule { constructor() { ClarityIcons.addIcons(eyeHideIcon, eyeIcon, exclamationCircleIcon, checkCircleIcon); } } ClrPasswordModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPasswordModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrPasswordModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrPasswordModule, declarations: [ClrPassword, ClrPasswordContainer], imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], exports: [ClrCommonFormsModule, ClrPassword, ClrPasswordContainer] }); ClrPasswordModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPasswordModule, imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPasswordModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], declarations: [ClrPassword, ClrPasswordContainer], exports: [ClrCommonFormsModule, ClrPassword, ClrPasswordContainer], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRadioWrapper { constructor() { // We need both _dynamic for HostWrapper and ContentChild(ClrLabel) in cases where // the user puts a radio inside a wrapper without a label, host wrapping doesn't apply // but we'd still need to insert a label this._dynamic = false; } ngOnInit() { if (this.label) { this.label.disableGrid(); } } } ClrRadioWrapper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioWrapper, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrRadioWrapper.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrRadioWrapper, selector: "clr-radio-wrapper", host: { properties: { "class.clr-radio-wrapper": "true" } }, providers: [ControlIdService], queries: [{ propertyName: "label", first: true, predicate: ClrLabel, descendants: true, static: true }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioWrapper, decorators: [{ type: Component, args: [{ selector: 'clr-radio-wrapper', template: ` `, host: { '[class.clr-radio-wrapper]': 'true', }, providers: [ControlIdService], }] }], propDecorators: { label: [{ type: ContentChild, args: [ClrLabel, { static: true }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRadio extends WrappedFormControl { constructor(vcr, injector, control, renderer, el) { super(vcr, ClrRadioWrapper, injector, control, renderer, el); } } ClrRadio.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadio, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrRadio.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrRadio, selector: "[clrRadio]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadio, decorators: [{ type: Directive, args: [{ selector: '[clrRadio]', }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRadioContainer extends ClrAbstractContainer { constructor(layoutService, controlClassService, ngControlService, ifControlStateService) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.layoutService = layoutService; this.controlClassService = controlClassService; this.ngControlService = ngControlService; this.ifControlStateService = ifControlStateService; this.inline = false; } /* * Here we want to support the following cases * clrInline - true by presence * clrInline="true|false" - unless it is explicitly false, strings are considered true * [clrInline]="true|false" - expect a boolean */ get clrInline() { return this.inline; } set clrInline(value) { if (typeof value === 'string') { this.inline = value === 'false' ? false : true; } else { this.inline = !!value; } } ngAfterContentInit() { this.setAriaRoles(); } setAriaRoles() { this.role = this.radios.length ? 'group' : null; } } ClrRadioContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioContainer, deps: [{ token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }, { token: IfControlStateService }], target: i0.ɵɵFactoryTarget.Component }); ClrRadioContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrRadioContainer, selector: "clr-radio-container", inputs: { clrInline: "clrInline" }, host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()", "attr.role": "role" } }, providers: [NgControlService, IfControlStateService, ControlClassService, ContainerIdService], queries: [{ propertyName: "radios", predicate: ClrRadio, descendants: true }], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioContainer, decorators: [{ type: Component, args: [{ selector: 'clr-radio-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', '[attr.role]': 'role', }, providers: [NgControlService, IfControlStateService, ControlClassService, ContainerIdService], }] }], ctorParameters: function () { return [{ type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }, { type: IfControlStateService }]; }, propDecorators: { radios: [{ type: ContentChildren, args: [ClrRadio, { descendants: true }] }], clrInline: [{ type: Input }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRadioModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrRadioModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrRadioModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioModule, declarations: [ClrRadio, ClrRadioContainer, ClrRadioWrapper], imports: [CommonModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrIconModule], exports: [ClrCommonFormsModule, ClrRadio, ClrRadioContainer, ClrRadioWrapper] }); ClrRadioModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioModule, imports: [CommonModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrIconModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRadioModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrIconModule], declarations: [ClrRadio, ClrRadioContainer, ClrRadioWrapper], exports: [ClrCommonFormsModule, ClrRadio, ClrRadioContainer, ClrRadioWrapper], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRangeContainer extends ClrAbstractContainer { constructor(layoutService, controlClassService, ngControlService, renderer, idService, ifControlStateService) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.renderer = renderer; this.idService = idService; this.ifControlStateService = ifControlStateService; this._hasProgress = false; } get hasProgress() { return this._hasProgress; } set hasProgress(val) { const valBool = !!val; if (valBool !== this._hasProgress) { this._hasProgress = valBool; } } getRangeProgressFillWidth() { const input = this.selectRangeElement(); if (!input) { return this.lastRangeProgressFillWidth; } const inputWidth = input.offsetWidth; const inputMinValue = +input.min; let inputMaxValue = +input.max; if (inputMinValue === 0 && inputMaxValue === 0) { inputMaxValue = 100; } const inputMiddle = (inputMinValue + inputMaxValue) / 2; const inputValue = !!this.control && this.control.value !== undefined ? this.control.value : inputMiddle; const valueAsPercent = ((inputValue - inputMinValue) * 100) / (inputMaxValue - inputMinValue); this.lastRangeProgressFillWidth = (valueAsPercent * inputWidth) / 100 + 'px'; return this.lastRangeProgressFillWidth; } selectRangeElement() { try { return this.renderer.selectRootElement('[clrRange]#' + this.idService.id); } catch { return undefined; } } } ClrRangeContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRangeContainer, deps: [{ token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }, { token: i0.Renderer2 }, { token: ControlIdService }, { token: IfControlStateService }], target: i0.ɵɵFactoryTarget.Component }); ClrRangeContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrRangeContainer, selector: "clr-range-container", inputs: { hasProgress: ["clrRangeHasProgress", "hasProgress"] }, host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRangeContainer, decorators: [{ type: Component, args: [{ selector: 'clr-range-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], }] }], ctorParameters: function () { return [{ type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }, { type: i0.Renderer2 }, { type: ControlIdService }, { type: IfControlStateService }]; }, propDecorators: { hasProgress: [{ type: Input, args: ['clrRangeHasProgress'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRange extends WrappedFormControl { constructor(vcr, injector, control, renderer, el) { super(vcr, ClrRangeContainer, injector, control, renderer, el); } } ClrRange.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRange, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrRange.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrRange, selector: "[clrRange]", host: { properties: { "class.clr-range": "true" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRange, decorators: [{ type: Directive, args: [{ selector: '[clrRange]', host: { '[class.clr-range]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRangeModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrRangeModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRangeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrRangeModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrRangeModule, declarations: [ClrRange, ClrRangeContainer], imports: [CommonModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrIconModule], exports: [ClrCommonFormsModule, ClrRange, ClrRangeContainer] }); ClrRangeModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRangeModule, imports: [CommonModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrIconModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRangeModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrCommonFormsModule, ClrHostWrappingModule, ClrIconModule], declarations: [ClrRange, ClrRangeContainer], exports: [ClrCommonFormsModule, ClrRange, ClrRangeContainer], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrSelectContainer extends ClrAbstractContainer { constructor(layoutService, controlClassService, ngControlService, ifControlStateService) { super(ifControlStateService, layoutService, controlClassService, ngControlService); this.layoutService = layoutService; this.controlClassService = controlClassService; this.ngControlService = ngControlService; this.ifControlStateService = ifControlStateService; this.multi = false; } ngOnInit() { /* The unsubscribe is handle inside the ClrAbstractContainer */ this.subscriptions.push(this.ngControlService.controlChanges.subscribe(control => { if (control) { this.multi = control.valueAccessor instanceof SelectMultipleControlValueAccessor; this.control = control; } })); } wrapperClass() { return this.multi ? 'clr-multiselect-wrapper' : 'clr-select-wrapper'; } } ClrSelectContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelectContainer, deps: [{ token: LayoutService, optional: true }, { token: ControlClassService }, { token: NgControlService }, { token: IfControlStateService }], target: i0.ɵɵFactoryTarget.Component }); ClrSelectContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrSelectContainer, selector: "clr-select-container", host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], queries: [{ propertyName: "multiple", first: true, predicate: SelectMultipleControlValueAccessor, descendants: true }], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelectContainer, decorators: [{ type: Component, args: [{ selector: 'clr-select-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], }] }], ctorParameters: function () { return [{ type: LayoutService, decorators: [{ type: Optional }] }, { type: ControlClassService }, { type: NgControlService }, { type: IfControlStateService }]; }, propDecorators: { multiple: [{ type: ContentChild, args: [SelectMultipleControlValueAccessor, { static: false }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrSelect extends WrappedFormControl { constructor(vcr, injector, control, renderer, el) { super(vcr, ClrSelectContainer, injector, control, renderer, el); this.index = 1; } } ClrSelect.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelect, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrSelect.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrSelect, selector: "[clrSelect]", host: { properties: { "class.clr-select": "true" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelect, decorators: [{ type: Directive, args: [{ selector: '[clrSelect]', host: { '[class.clr-select]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrSelectModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrSelectModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrSelectModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrSelectModule, declarations: [ClrSelect, ClrSelectContainer], imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], exports: [ClrCommonFormsModule, ClrSelect, ClrSelectContainer] }); ClrSelectModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelectModule, imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSelectModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], declarations: [ClrSelect, ClrSelectContainer], exports: [ClrCommonFormsModule, ClrSelect, ClrSelectContainer], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTextareaContainer extends ClrAbstractContainer { } ClrTextareaContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextareaContainer, deps: null, target: i0.ɵɵFactoryTarget.Component }); ClrTextareaContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTextareaContainer, selector: "clr-textarea-container", host: { properties: { "class.clr-form-control": "true", "class.clr-form-control-disabled": "control?.disabled", "class.clr-row": "addGrid()" } }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextareaContainer, decorators: [{ type: Component, args: [{ selector: 'clr-textarea-container', template: `
`, host: { '[class.clr-form-control]': 'true', '[class.clr-form-control-disabled]': 'control?.disabled', '[class.clr-row]': 'addGrid()', }, providers: [IfControlStateService, NgControlService, ControlIdService, ControlClassService], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTextarea extends WrappedFormControl { constructor(vcr, injector, control, renderer, el) { super(vcr, ClrTextareaContainer, injector, control, renderer, el); this.index = 1; } } ClrTextarea.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextarea, deps: [{ token: i0.ViewContainerRef }, { token: i0.Injector }, { token: i1.NgControl, optional: true, self: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrTextarea.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrTextarea, selector: "[clrTextarea]", host: { properties: { "class.clr-textarea": "true" } }, usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextarea, decorators: [{ type: Directive, args: [{ selector: '[clrTextarea]', host: { '[class.clr-textarea]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Injector }, { type: i1.NgControl, decorators: [{ type: Self }, { type: Optional }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTextareaModule { constructor() { ClarityIcons.addIcons(exclamationCircleIcon, checkCircleIcon); } } ClrTextareaModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextareaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrTextareaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrTextareaModule, declarations: [ClrTextarea, ClrTextareaContainer], imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], exports: [ClrCommonFormsModule, ClrTextarea, ClrTextareaContainer] }); ClrTextareaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextareaModule, imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule, ClrCommonFormsModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTextareaModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, FormsModule, ClrIconModule, ClrCommonFormsModule], declarations: [ClrTextarea, ClrTextareaContainer], exports: [ClrCommonFormsModule, ClrTextarea, ClrTextareaContainer], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrFormsModule { } ClrFormsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrFormsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrFormsModule, imports: [CommonModule], exports: [ClrCommonFormsModule, ClrCheckboxModule, ClrComboboxModule, ClrDatepickerModule, ClrInputModule, ClrPasswordModule, ClrRadioModule, ClrSelectModule, ClrTextareaModule, ClrRangeModule, ClrDatalistModule] }); ClrFormsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFormsModule, imports: [CommonModule, ClrCommonFormsModule, ClrCheckboxModule, ClrComboboxModule, ClrDatepickerModule, ClrInputModule, ClrPasswordModule, ClrRadioModule, ClrSelectModule, ClrTextareaModule, ClrRangeModule, ClrDatalistModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrFormsModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], exports: [ ClrCommonFormsModule, ClrCheckboxModule, ClrComboboxModule, ClrDatepickerModule, ClrInputModule, ClrPasswordModule, ClrRadioModule, ClrSelectModule, ClrTextareaModule, ClrRangeModule, ClrDatalistModule, ], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrExpandableAnimationModule { } ClrExpandableAnimationModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrExpandableAnimationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrExpandableAnimationModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrExpandableAnimationModule, declarations: [ClrExpandableAnimation], imports: [CommonModule], exports: [ClrExpandableAnimation] }); ClrExpandableAnimationModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrExpandableAnimationModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrExpandableAnimationModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [EXPANDABLE_ANIMATION_DIRECTIVES], exports: [EXPANDABLE_ANIMATION_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This is just a copy of CdkDrag so it can be used independent of the rest of the CdkDragDropModule. */ class CdkDragModule_CdkDrag extends CdkDrag { } CdkDragModule_CdkDrag.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkDragModule_CdkDrag, deps: null, target: i0.ɵɵFactoryTarget.Directive }); CdkDragModule_CdkDrag.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: CdkDragModule_CdkDrag, selector: "[cdkDrag]", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkDragModule_CdkDrag, decorators: [{ type: Directive, args: [{ selector: '[cdkDrag]', }] }] }); /** * This module allows us to avoid importing all of CdkDragDropModule which results in a smaller application bundle. */ class CdkDragModule { } CdkDragModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkDragModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); CdkDragModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: CdkDragModule, declarations: [CdkDragModule_CdkDrag], exports: [CdkDragModule_CdkDrag] }); CdkDragModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkDragModule }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: CdkDragModule, decorators: [{ type: NgModule, args: [{ declarations: [CdkDragModule_CdkDrag], exports: [CdkDragModule_CdkDrag], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class OutsideClick { constructor(host, renderer, ngZone) { this.strict = false; this.outsideClick = new EventEmitter(false); ngZone.runOutsideAngular(() => { this.documentClickListener = renderer.listen('document', 'click', (event) => { // Compare the element in the DOM on which the mouse was clicked // with the current actionMenu native HTML element. if (host.nativeElement === event.target) { return; } if (!this.strict && host.nativeElement.contains(event.target)) { return; } // We'll run change detection only if the click event actually happened outside of // the host element. ngZone.run(() => { this.outsideClick.emit(event); }); }); }); } ngOnDestroy() { this.documentClickListener(); } } OutsideClick.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OutsideClick, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); OutsideClick.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: OutsideClick, selector: "[clrOutsideClick]", inputs: { strict: ["clrStrict", "strict"] }, outputs: { outsideClick: "clrOutsideClick" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: OutsideClick, decorators: [{ type: Directive, args: [{ selector: '[clrOutsideClick]', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { strict: [{ type: Input, args: ['clrStrict'] }], outsideClick: [{ type: Output, args: ['clrOutsideClick'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const OUSTIDE_CLICK_DIRECTIVES = [OutsideClick]; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrOutsideClickModule { } ClrOutsideClickModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOutsideClickModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrOutsideClickModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrOutsideClickModule, declarations: [OutsideClick], imports: [CommonModule], exports: [OutsideClick] }); ClrOutsideClickModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOutsideClickModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrOutsideClickModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [OUSTIDE_CLICK_DIRECTIVES], exports: [OUSTIDE_CLICK_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class CustomFilter { } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * This provider implements some form of synchronous debouncing through a lock pattern * to avoid emitting multiple state changes for a single user action. */ class StateDebouncer { constructor() { /* * This is the lock, to only emit once all the changes have finished processing */ this.nbChanges = 0; /** * The Observable that lets other classes subscribe to global state changes */ this._change = new Subject(); } // We do not want to expose the Subject itself, but the Observable which is read-only get change() { return this._change.asObservable(); } changeStart() { this.nbChanges++; } changeDone() { if (--this.nbChanges === 0) { this._change.next(); } } } StateDebouncer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StateDebouncer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); StateDebouncer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StateDebouncer }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StateDebouncer, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class Page { constructor(stateDebouncer) { this.stateDebouncer = stateDebouncer; this.activated = false; /** * Page size, a value of 0 means no pagination */ this._size = 0; /** * Current page */ this._current = 1; /** * The Observable that lets other classes subscribe to page changes */ this._change = new Subject(); this.preventEmit = false; this._sizeChange = new Subject(); } get size() { return this._size; } set size(size) { const oldSize = this._size; if (size !== oldSize) { if (!this.preventEmit) { this.stateDebouncer.changeStart(); } this._size = size; if (size === 0) { this._current = 1; } else { // Yeap. That's the formula to keep the first item from the old page still // displayed in the new one. this._current = Math.floor((oldSize / size) * (this._current - 1)) + 1; } // We always emit an event even if the current page index didn't change, because // the size changing means the items inside the page are different if (!this.preventEmit) { this._change.next(this._current); this._sizeChange.next(this._size); this.stateDebouncer.changeDone(); } } this.preventEmit = false; } get totalItems() { return this._totalItems || 0; // remains 0 if not set to avoid breaking change } set totalItems(total) { this._totalItems = total; // If we have less items than before, we might need to change the current page if (this.current > this.last) { this.current = this.last; } } get last() { if (this._last) { return this._last; } // If the last page isn't known, we compute it from the last item's index if (this.size > 0 && this.totalItems) { return Math.ceil(this.totalItems / this.size); } return 1; } set last(page) { this._last = page; } // We do not want to expose the Subject itself, but the Observable which is read-only get change() { return this._change.asObservable(); } get sizeChange() { return this._sizeChange.asObservable(); } get current() { return this._current; } set current(page) { if (page !== this._current) { this.stateDebouncer.changeStart(); this._current = page; this._change.next(page); this.stateDebouncer.changeDone(); } } /** * Index of the first item displayed on the current page, starting at 0, -1 if none displayed */ get firstItem() { if (this._totalItems === 0) { return -1; } if (this.size === 0) { return 0; } return (this.current - 1) * this.size; } /** * Index of the last item displayed on the current page, starting at 0, -1 if none displayed */ get lastItem() { if (this._totalItems === 0) { return -1; } if (this.size === 0) { return this.totalItems - 1; } let lastInPage = this.current * this.size - 1; if (this.totalItems) { lastInPage = Math.min(lastInPage, this.totalItems - 1); } return lastInPage; } /** * Moves to the previous page if it exists */ previous() { if (this.current > 1) { this.current--; } } /** * Moves to the next page if it exists */ next() { if (this.current < this.last) { this.current++; } } /** * Resets the page size to 0 */ resetPageSize(preventEmit = false) { this.preventEmit = preventEmit; this.size = 0; } } Page.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Page, deps: [{ token: StateDebouncer }], target: i0.ɵɵFactoryTarget.Injectable }); Page.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Page }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Page, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: StateDebouncer }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class FiltersProvider { constructor(_page, stateDebouncer) { this._page = _page; this.stateDebouncer = stateDebouncer; /** * This subject is the list of filters that changed last, not the whole list. * We emit a list rather than just one filter to allow batch changes to several at once. */ this._change = new Subject(); /** * List of all filters, whether they're active or not */ this._all = []; } // We do not want to expose the Subject itself, but the Observable which is read-only get change() { return this._change.asObservable(); } /** * Tests if at least one filter is currently active */ hasActiveFilters() { // We do not use getActiveFilters() because this function will be called much more often // and stopping the loop early might be relevant. for (const { filter } of this._all) { if (filter && filter.isActive()) { return true; } } return false; } /** * Returns a list of all currently active filters */ getActiveFilters() { const ret = []; for (const { filter } of this._all) { if (filter && filter.isActive()) { ret.push(filter); } } return ret; } /** * Registers a filter, and returns a deregistration function */ add(filter) { const subscription = filter.changes.subscribe(() => this.resetPageAndEmitFilterChange([filter])); let hasUnregistered = false; const registered = new RegisteredFilter(filter, () => { if (hasUnregistered) { return; } subscription.unsubscribe(); const matchIndex = this._all.findIndex(item => item.filter === filter); if (matchIndex >= 0) { this._all.splice(matchIndex, 1); } if (filter.isActive()) { this.resetPageAndEmitFilterChange([]); } hasUnregistered = true; }); this._all.push(registered); if (filter.isActive()) { this.resetPageAndEmitFilterChange([filter]); } return registered; } /** * Accepts an item if it is accepted by all currently active filters */ accepts(item) { for (const { filter } of this._all) { if (filter && filter.isActive() && !filter.accepts(item)) { return false; } } return true; } resetPageAndEmitFilterChange(filters) { this.stateDebouncer.changeStart(); // filtering may change the page number such that current page number doesn't exist in the filtered dataset. // So here we always set the current page to 1 so that it'll fetch first page's data with the given filter. this._page.current = 1; this._change.next(filters); this.stateDebouncer.changeDone(); } } FiltersProvider.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FiltersProvider, deps: [{ token: Page }, { token: StateDebouncer }], target: i0.ɵɵFactoryTarget.Injectable }); FiltersProvider.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FiltersProvider }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: FiltersProvider, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: Page }, { type: StateDebouncer }]; } }); class RegisteredFilter { constructor(filter, unregister) { this.filter = filter; this.unregister = unregister; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridFilterRegistrar { constructor(filters) { this.filters = filters; } get filter() { return this.registered && this.registered.filter; } ngOnDestroy() { this.deleteFilter(); } setFilter(filter) { // If we previously had another filter, we unregister it this.deleteFilter(); if (filter instanceof RegisteredFilter) { this.registered = filter; } else if (filter) { this.registered = this.filters.add(filter); } } deleteFilter() { if (this.registered) { this.registered.unregister(); delete this.registered; } } } DatagridFilterRegistrar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridFilterRegistrar, deps: [{ token: FiltersProvider }], target: i0.ɵɵFactoryTarget.Directive }); DatagridFilterRegistrar.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridFilterRegistrar, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridFilterRegistrar, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: FiltersProvider }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Custom filter that can be added in any column to override the default object property string filter. * The reason this is not just an input on DatagridColumn is because we need the filter's template to be projected, * since it can be anything (not just a text input). */ class ClrDatagridFilter extends DatagridFilterRegistrar { constructor(_filters, commonStrings, smartToggleService, platformId, elementRef) { super(_filters); this.commonStrings = commonStrings; this.smartToggleService = smartToggleService; this.platformId = platformId; this.elementRef = elementRef; this.openChange = new EventEmitter(false); this.ariaExpanded = false; this.popoverId = uniqueIdFactory(); // Smart Popover this.smartPosition = { axis: ClrAxis.VERTICAL, side: ClrSide.AFTER, anchor: ClrAlignment.END, content: ClrAlignment.END, }; this._open = false; this.subs = []; this.subs.push(smartToggleService.openChange.subscribe(change => { this.open = change; this.ariaExpanded = change; })); } get open() { return this._open; } set open(open) { open = !!open; if (this.open !== open) { this.smartToggleService.open = open; this.openChange.emit(open); if (!open && isPlatformBrowser(this.platformId)) { this.anchor.nativeElement.focus(); } // keep track of the state this._open = open; } } set customFilter(filter) { this.setFilter(filter); } /** * Indicates if the filter is currently active */ get active() { return !!this.filter && this.filter.isActive(); } ngOnChanges() { this.setToggleButtonAriaLabel(); } ngOnDestroy() { super.ngOnDestroy(); this.subs.forEach(sub => sub.unsubscribe()); } /** * This is not in a getter to prevent "expression has changed after it was checked" errors. * And it's more performant this way since it only runs on change. */ setToggleButtonAriaLabel() { const columnElement = this.elementRef.nativeElement?.closest('clr-dg-column'); const columnTitleElement = columnElement?.querySelector('.datagrid-column-title'); const columnTitle = columnTitleElement?.textContent.trim().toLocaleLowerCase(); this.toggleButtonAriaLabel = this.commonStrings.parse(this.commonStrings.keys.datagridFilterAriaLabel, { COLUMN: columnTitle || '', }); } } ClrDatagridFilter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridFilter, deps: [{ token: FiltersProvider }, { token: ClrCommonStringsService }, { token: ClrPopoverToggleService }, { token: PLATFORM_ID }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridFilter.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridFilter, selector: "clr-dg-filter", inputs: { open: ["clrDgFilterOpen", "open"], customFilter: ["clrDgFilter", "customFilter"] }, outputs: { openChange: "clrDgFilterOpenChange" }, providers: [{ provide: CustomFilter, useExisting: ClrDatagridFilter }], viewQueries: [{ propertyName: "anchor", first: true, predicate: ["anchor"], descendants: true, read: ElementRef }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: ClrPopoverCloseButton, selector: "[clrPopoverCloseButton]", outputs: ["clrPopoverOnCloseChange"] }, { kind: "directive", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridFilter, decorators: [{ type: Component, args: [{ selector: 'clr-dg-filter', // We register this component as a CustomFilter, for the parent column to detect it. providers: [{ provide: CustomFilter, useExisting: ClrDatagridFilter }], template: ` `, }] }], ctorParameters: function () { return [{ type: FiltersProvider }, { type: ClrCommonStringsService }, { type: ClrPopoverToggleService }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: i0.ElementRef }]; }, propDecorators: { openChange: [{ type: Output, args: ['clrDgFilterOpenChange'] }], anchor: [{ type: ViewChild, args: ['anchor', { read: ElementRef }] }], open: [{ type: Input, args: ['clrDgFilterOpen'] }], customFilter: [{ type: Input, args: ['clrDgFilter'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Generic accessor for deep object properties * that can be specified as simple dot-separated strings. */ class NestedProperty { constructor(prop) { this.prop = prop; if (prop.indexOf('.') >= 0) { this.splitProp = prop.split('.'); } } // Safe getter for a deep object property, will not throw an error but return // undefined if one of the intermediate properties is null or undefined. getPropValue(item) { if (this.splitProp) { let value = item; for (const nestedProp of this.splitProp) { if (value === null || typeof value === 'undefined' || typeof value[nestedProp] === 'undefined') { return undefined; } value = value[nestedProp]; } return value; } else { return item[this.prop]; } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridPropertyNumericFilter { constructor(prop, exact = false) { this.prop = prop; this.exact = exact; this.nestedProp = new NestedProperty(prop); } accepts(item, low, high) { const propValue = this.nestedProp.getPropValue(item); if (propValue === undefined) { return false; } if (low !== null && (typeof propValue !== 'number' || propValue < low)) { return false; } if (high !== null && (typeof propValue !== 'number' || propValue > high)) { return false; } return true; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridNumericFilterImpl { constructor(filterFn) { this.filterFn = filterFn; /** * The Observable required as part of the Filter interface */ this._changes = new Subject(); /** * Internal values and accessor */ this._low = null; this._high = null; } // We do not want to expose the Subject itself, but the Observable which is read-only get changes() { return this._changes.asObservable(); } get value() { return [this._low, this._high]; } set value(vals) { const low = vals[0]; const high = vals[1]; if (low !== this._low || high !== this._high) { this._low = low; this._high = high; this._changes.next([this._low, this._high]); } } get low() { return this._low; } set low(low) { if (low !== this._low) { this._low = low; this._changes.next([this._low, this._high]); } } get high() { return this._high; } set high(high) { if (high !== this._high) { this._high = high; this._changes.next([this._low, this._high]); } } get state() { if (this.filterFn instanceof DatagridPropertyNumericFilter) { return { property: this.filterFn.prop, low: this._low, high: this._high, }; } return this; } /** * Indicates if the filter is currently active, (at least one input is set) */ isActive() { return this._low !== null || this.high !== null; } /** * Tests if an item matches a search text */ accepts(item) { // We have a filter function in case someone wants to implement a numeric // filter that always passes nulls or similar return this.filterFn.accepts(item, this._low, this._high); } equals(other) { if (other instanceof DatagridNumericFilterImpl) { if (other.filterFn instanceof DatagridPropertyNumericFilter) { return (this.filterFn instanceof DatagridPropertyNumericFilter && other.filterFn.prop === this.filterFn.prop && other.low === this._low && other.high === this._high); } return other === this; } return false; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridNumericFilter extends DatagridFilterRegistrar { constructor(filters, domAdapter, commonStrings, popoverToggleService, ngZone) { super(filters); this.domAdapter = domAdapter; this.commonStrings = commonStrings; this.popoverToggleService = popoverToggleService; this.ngZone = ngZone; this.filterValueChange = new EventEmitter(); /** * Indicates if the filter dropdown is open */ this.open = false; this.subscriptions = []; } /** * Common setter for the input values */ get value() { return [this.filter.low, this.filter.high]; } set value(values) { if (this.filter && Array.isArray(values)) { if (values && (values[0] !== this.filter.low || values[1] !== this.filter.high)) { if (typeof values[0] === 'number') { this.filter.low = values[0]; } else { this.filter.low = null; } if (typeof values[1] === 'number') { this.filter.high = values[1]; } else { this.filter.high = null; } this.filterValueChange.emit(values); } } else { this.initFilterValues = values; } } /** * Customizable filter logic based on high and low values */ set customNumericFilter(value) { if (value instanceof RegisteredFilter) { this.setFilter(value); } else { this.setFilter(new DatagridNumericFilterImpl(value)); } if (this.initFilterValues) { this.value = this.initFilterValues; // This initFilterValues should be used only once after the filter registration // So deleting this property value to prevent it from being used again // if this customStringFilter property is set again delete this.initFilterValues; } } get maxPlaceholderValue() { return this.maxPlaceholder || this.commonStrings.keys.maxValue; } get minPlaceholderValue() { return this.minPlaceholder || this.commonStrings.keys.minValue; } get low() { if (typeof this.filter.low === 'number' && isFinite(this.filter.low)) { return this.filter.low; } else { // There's not a low limit return null; } } set low(low) { if (typeof low === 'number' && low !== this.filter.low) { this.filter.low = low; this.filterValueChange.emit([this.filter.low, this.filter.high]); } else if (typeof low !== 'number') { this.filter.low = null; this.filterValueChange.emit([this.filter.low, this.filter.high]); } } get high() { if (typeof this.filter.high === 'number' && isFinite(this.filter.high)) { return this.filter.high; } else { // There's not a high limit return null; } } set high(high) { if (typeof high === 'number' && high !== this.filter.high) { this.filter.high = high; this.filterValueChange.emit([this.filter.low, this.filter.high]); } else if (typeof high !== 'number') { this.filter.high = null; this.filterValueChange.emit([this.filter.low, this.filter.high]); } } ngAfterViewInit() { this.subscriptions.push(this.popoverToggleService.openChange.subscribe(openChange => { this.open = openChange; // Note: this is being run outside of the Angular zone because `element.focus()` doesn't require // running change detection. this.ngZone.runOutsideAngular(() => { // The animation frame in used because when this executes, the input isn't displayed. // Note: `element.focus()` causes re-layout and this may lead to frame drop on slower devices. // `setTimeout` is a macrotask and macrotasks are executed within the current rendering frame. // Animation tasks are executed within the next rendering frame. requestAnimationFrame(() => { this.domAdapter.focus(this.input.nativeElement); }); }); })); } ngOnDestroy() { super.ngOnDestroy(); this.subscriptions.forEach(sub => { sub.unsubscribe(); }); } } DatagridNumericFilter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridNumericFilter, deps: [{ token: FiltersProvider }, { token: DomAdapter }, { token: ClrCommonStringsService }, { token: ClrPopoverToggleService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); DatagridNumericFilter.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: DatagridNumericFilter, selector: "clr-dg-numeric-filter", inputs: { minPlaceholder: ["clrFilterMinPlaceholder", "minPlaceholder"], maxPlaceholder: ["clrFilterMaxPlaceholder", "maxPlaceholder"], value: ["clrFilterValue", "value"], customNumericFilter: ["clrDgNumericFilter", "customNumericFilter"] }, outputs: { filterValueChange: "clrFilterValueChange" }, providers: [{ provide: CustomFilter, useExisting: DatagridNumericFilter }], viewQueries: [{ propertyName: "input", first: true, predicate: ["input_low"], descendants: true }, { propertyName: "filterContainer", first: true, predicate: ClrDatagridFilter, descendants: true }], usesInheritance: true, ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClrDatagridFilter, selector: "clr-dg-filter", inputs: ["clrDgFilterOpen", "clrDgFilter"], outputs: ["clrDgFilterOpenChange"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridNumericFilter, decorators: [{ type: Component, args: [{ selector: 'clr-dg-numeric-filter', providers: [{ provide: CustomFilter, useExisting: DatagridNumericFilter }], template: ` `, }] }], ctorParameters: function () { return [{ type: FiltersProvider }, { type: DomAdapter }, { type: ClrCommonStringsService }, { type: ClrPopoverToggleService }, { type: i0.NgZone }]; }, propDecorators: { minPlaceholder: [{ type: Input, args: ['clrFilterMinPlaceholder'] }], maxPlaceholder: [{ type: Input, args: ['clrFilterMaxPlaceholder'] }], filterValueChange: [{ type: Output, args: ['clrFilterValueChange'] }], input: [{ type: ViewChild, args: ['input_low'] }], filterContainer: [{ type: ViewChild, args: [ClrDatagridFilter] }], value: [{ type: Input, args: ['clrFilterValue'] }], customNumericFilter: [{ type: Input, args: ['clrDgNumericFilter'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridPropertyStringFilter { constructor(prop, exact = false) { this.prop = prop; this.exact = exact; this.nestedProp = new NestedProperty(prop); } accepts(item, search) { const propValue = this.nestedProp.getPropValue(item); if (typeof propValue === 'undefined') { return false; } else if (this.exact) { return ('' + propValue).toLowerCase() === search; } else { return ('' + propValue).toLowerCase().indexOf(search) >= 0; } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridStringFilterImpl { constructor(filterFn) { this.filterFn = filterFn; /** * The Observable required as part of the Filter interface */ this._changes = new Subject(); /** * Input value converted to lowercase */ this._lowerCaseValue = ''; /** * Raw input value */ this._rawValue = ''; } // We do not want to expose the Subject itself, but the Observable which is read-only get changes() { return this._changes.asObservable(); } get lowerCaseValue() { return this._lowerCaseValue; } get state() { if (this.filterFn instanceof DatagridPropertyStringFilter) { return { property: this.filterFn.prop, value: this.value, }; } return this; } get value() { return this._rawValue; } /** * Common setter for the input value */ set value(value) { if (!value) { value = ''; } if (value !== this._rawValue) { this._rawValue = value; this._lowerCaseValue = value.toLowerCase().trim(); this._changes.next(value); } } /** * Indicates if the filter is currently active, meaning the input is not empty */ isActive() { return !!this.value; } /** * Tests if an item matches a search text */ accepts(item) { // We always test with the lowercase value of the input, to stay case insensitive return this.filterFn.accepts(item, this.lowerCaseValue); } equals(other) { if (other instanceof DatagridStringFilterImpl) { if (other.filterFn instanceof DatagridPropertyStringFilter) { return (this.filterFn instanceof DatagridPropertyStringFilter && other.filterFn.prop === this.filterFn.prop && other.value === this.value); } return other === this; } return false; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridStringFilter extends DatagridFilterRegistrar { constructor(filters, domAdapter, commonStrings, smartToggleService, ngZone) { super(filters); this.domAdapter = domAdapter; this.commonStrings = commonStrings; this.smartToggleService = smartToggleService; this.ngZone = ngZone; this.filterValueChange = new EventEmitter(); /** * Indicates if the filter dropdown is open */ this.open = false; this.subs = []; } /** * Customizable filter logic based on a search text */ set customStringFilter(value) { if (value instanceof RegisteredFilter) { this.setFilter(value); } else { this.setFilter(new DatagridStringFilterImpl(value)); } if (this.initFilterValue) { this.value = this.initFilterValue; // This initFilterValue should be used only once after the filter registration // So deleting this property value to prevent it from being used again // if this customStringFilter property is set again delete this.initFilterValue; } } /** * Common setter for the input value */ get value() { return this.filter.value; } set value(value) { if (this.filter && typeof value === 'string') { if (!value) { value = ''; } if (value !== this.filter.value) { this.filter.value = value; this.filterValueChange.emit(value); } } else { this.initFilterValue = value; } } get placeholderValue() { return this.placeholder || this.commonStrings.keys.filterItems; } ngAfterViewInit() { this.subs.push(this.smartToggleService.openChange.subscribe(openChange => { this.open = openChange; // Note: this is being run outside of the Angular zone because `element.focus()` doesn't require // running change detection. this.ngZone.runOutsideAngular(() => { // The animation frame in used because when this executes, the input isn't displayed. // Note: `element.focus()` causes re-layout and this may lead to frame drop on slower devices. // `setTimeout` is a macrotask and macrotasks are executed within the current rendering frame. // Animation tasks are executed within the next rendering frame. requestAnimationFrame(() => { this.domAdapter.focus(this.input.nativeElement); }); }); })); } ngOnDestroy() { super.ngOnDestroy(); this.subs.forEach(sub => sub.unsubscribe()); } } DatagridStringFilter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridStringFilter, deps: [{ token: FiltersProvider }, { token: DomAdapter }, { token: ClrCommonStringsService }, { token: ClrPopoverToggleService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); DatagridStringFilter.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: DatagridStringFilter, selector: "clr-dg-string-filter", inputs: { placeholder: ["clrFilterPlaceholder", "placeholder"], customStringFilter: ["clrDgStringFilter", "customStringFilter"], value: ["clrFilterValue", "value"] }, outputs: { filterValueChange: "clrFilterValueChange" }, providers: [{ provide: CustomFilter, useExisting: DatagridStringFilter }], viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true }, { propertyName: "filterContainer", first: true, predicate: ClrDatagridFilter, descendants: true }], usesInheritance: true, ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClrDatagridFilter, selector: "clr-dg-filter", inputs: ["clrDgFilterOpen", "clrDgFilter"], outputs: ["clrDgFilterOpenChange"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridStringFilter, decorators: [{ type: Component, args: [{ selector: 'clr-dg-string-filter', providers: [{ provide: CustomFilter, useExisting: DatagridStringFilter }], template: ` `, }] }], ctorParameters: function () { return [{ type: FiltersProvider }, { type: DomAdapter }, { type: ClrCommonStringsService }, { type: ClrPopoverToggleService }, { type: i0.NgZone }]; }, propDecorators: { placeholder: [{ type: Input, args: ['clrFilterPlaceholder'] }], filterValueChange: [{ type: Output, args: ['clrFilterValueChange'] }], input: [{ type: ViewChild, args: ['input'] }], filterContainer: [{ type: ViewChild, args: [ClrDatagridFilter] }], customStringFilter: [{ type: Input, args: ['clrDgStringFilter'] }], value: [{ type: Input, args: ['clrFilterValue'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridWillyWonka extends WillyWonka { } DatagridWillyWonka.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridWillyWonka, deps: null, target: i0.ɵɵFactoryTarget.Directive }); DatagridWillyWonka.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridWillyWonka, selector: "clr-datagrid", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridWillyWonka, decorators: [{ type: Directive, args: [{ selector: 'clr-datagrid', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class RowActionService { constructor() { this.actionableCount = 0; } /** * false means no rows with action */ get hasActionableRow() { return this.actionableCount > 0; } register() { this.actionableCount++; } unregister() { this.actionableCount--; } } RowActionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RowActionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); RowActionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RowActionService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RowActionService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ActionableOompaLoompa extends OompaLoompa { constructor(cdr, willyWonka, rowActions) { if (!willyWonka) { throw new Error('clr-dg-row should only be used inside of a clr-datagrid'); } super(cdr, willyWonka); this.rowActions = rowActions; } get flavor() { return this.rowActions.hasActionableRow; } } ActionableOompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ActionableOompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: DatagridWillyWonka, optional: true }, { token: RowActionService }], target: i0.ɵɵFactoryTarget.Directive }); ActionableOompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ActionableOompaLoompa, selector: "clr-datagrid, clr-dg-row", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ActionableOompaLoompa, decorators: [{ type: Directive, args: [{ selector: 'clr-datagrid, clr-dg-row', }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DatagridWillyWonka, decorators: [{ type: Optional }] }, { type: RowActionService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ModalStackService { constructor(platformId) { this.platformId = platformId; this.modalStack = []; this.keyUpEventListener = this.onKeyUp.bind(this); } trackModalOpen(openedModal) { if (this.modalStack.includes(openedModal) === false) { this.modalStack.unshift(openedModal); } if (isPlatformBrowser(this.platformId)) { document.body.addEventListener('keyup', this.keyUpEventListener); } } trackModalClose(closedModal) { const closedModalIndex = this.modalStack.indexOf(closedModal); if (closedModalIndex > -1) { this.modalStack.splice(closedModalIndex, 1); } if (this.modalStack.length === 0 && isPlatformBrowser(this.platformId)) { document.body.removeEventListener('keyup', this.keyUpEventListener); } } onKeyUp(event) { if (this.modalStack.length && normalizeKey(event.key) === Keys.Escape) { // We blur the active element because escaping with an input element in focus could cause // an ExpressionChangedAfterItHasBeenCheckedError for the touched state. (CDE-1662) document.activeElement.blur(); this.modalStack[0].close(); } } } ModalStackService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ModalStackService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); ModalStackService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ModalStackService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ModalStackService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DetailService { constructor(modalStackService) { this.modalStackService = modalStackService; this.toggleState = false; this._enabled = false; this._state = new BehaviorSubject(this.toggleState); } get enabled() { return this._enabled; } set enabled(state) { this._enabled = state; } get state() { return this.cache; } get stateChange() { return this._state.asObservable(); } get isOpen() { return this.toggleState === true; } open(item, button) { this.cache = item; this.button = button; this.toggleState = true; this._state.next(this.toggleState); this.modalStackService.trackModalOpen(this); } close() { this.toggleState = false; this._state.next(this.toggleState); this.modalStackService.trackModalClose(this); if (this.button) { this.button.focus(); this.button = null; } } toggle(item, button) { if (this.isRowOpen(item) || !item) { this.close(); } else { this.open(item, button); } } isRowOpen(item) { return !!(this.toggleState && this.cache === item); } } DetailService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DetailService, deps: [{ token: ModalStackService }], target: i0.ɵɵFactoryTarget.Injectable }); DetailService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DetailService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DetailService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: ModalStackService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ExpandableRowsCount { constructor(detailService) { this.detailService = detailService; this.expandableCount = 0; } /** * false means no rows with action * check if details are on, and disable rows entirely */ get hasExpandableRow() { return !this.detailService.enabled && this.expandableCount > 0; } register() { this.expandableCount++; } unregister() { this.expandableCount--; } } ExpandableRowsCount.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ExpandableRowsCount, deps: [{ token: DetailService }], target: i0.ɵɵFactoryTarget.Injectable }); ExpandableRowsCount.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ExpandableRowsCount }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ExpandableRowsCount, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: DetailService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ExpandableOompaLoompa extends OompaLoompa { constructor(cdr, willyWonka, expandableCount) { if (!willyWonka) { throw new Error('clr-dg-row should only be used inside of a clr-datagrid'); } super(cdr, willyWonka); this.expandableCount = expandableCount; } get flavor() { return this.expandableCount.hasExpandableRow; } } ExpandableOompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ExpandableOompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: DatagridWillyWonka, optional: true }, { token: ExpandableRowsCount }], target: i0.ɵɵFactoryTarget.Directive }); ExpandableOompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ExpandableOompaLoompa, selector: "clr-datagrid, clr-dg-row", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ExpandableOompaLoompa, decorators: [{ type: Directive, args: [{ selector: 'clr-datagrid, clr-dg-row', }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: DatagridWillyWonka, decorators: [{ type: Optional }] }, { type: ExpandableRowsCount }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridPropertyComparator { constructor(prop) { this.prop = prop; this.nestedProp = new NestedProperty(prop); } compare(a, b) { let propA = this.nestedProp.getPropValue(a); let propB = this.nestedProp.getPropValue(b); if (typeof propA === 'string') { propA = propA.toLowerCase(); } if (typeof propB === 'string') { propB = propB.toLowerCase(); } if (typeof propA === 'undefined' || propA === null) { if (typeof propB === 'undefined' || propB === null) { return 0; } else { return 1; } } else { if (typeof propB === 'undefined' || propB === null) { return -1; } else if (propA < propB) { return -1; } else if (propA > propB) { return 1; } else { return 0; } } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Enumeration representing the sorting order of a datagrid column. It is a constant Enum, * i.e. each value needs to be treated as a `number`, starting at index 0. * * @export * @enum {number} */ var ClrDatagridSortOrder; (function (ClrDatagridSortOrder) { ClrDatagridSortOrder[ClrDatagridSortOrder["UNSORTED"] = 0] = "UNSORTED"; ClrDatagridSortOrder[ClrDatagridSortOrder["ASC"] = 1] = "ASC"; ClrDatagridSortOrder[ClrDatagridSortOrder["DESC"] = -1] = "DESC"; })(ClrDatagridSortOrder || (ClrDatagridSortOrder = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class WrappedColumn { constructor() { this._dynamic = false; } ngAfterViewInit() { // Create the cells view in memory, not the DOM. this.columnView = this.templateRef.createEmbeddedView(null); } ngOnDestroy() { this.columnView.destroy(); } } WrappedColumn.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedColumn, deps: [], target: i0.ɵɵFactoryTarget.Component }); WrappedColumn.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: WrappedColumn, selector: "dg-wrapped-column", viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["columnPortal"], descendants: true }], ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedColumn, decorators: [{ type: Component, args: [{ selector: 'dg-wrapped-column', template: ` `, }] }], propDecorators: { templateRef: [{ type: ViewChild, args: ['columnPortal'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class Sort { constructor(stateDebouncer) { this.stateDebouncer = stateDebouncer; /** * Ascending order if false, descending if true */ this._reverse = false; /** * The Observable that lets other classes subscribe to sort changes */ this._change = new Subject(); } get comparator() { return this._comparator; } set comparator(value) { this.stateDebouncer.changeStart(); this._comparator = value; this.emitChange(); this.stateDebouncer.changeDone(); } get reverse() { return this._reverse; } set reverse(value) { this.stateDebouncer.changeStart(); this._reverse = value; this.emitChange(); this.stateDebouncer.changeDone(); } // We do not want to expose the Subject itself, but the Observable which is read-only get change() { return this._change.asObservable(); } /** * Sets a comparator as the current one, or toggles reverse if the comparator is already used. The * optional forceReverse input parameter allows to override that toggling behavior by sorting in * reverse order if `true`. * * @memberof Sort */ toggle(sortBy, forceReverse) { this.stateDebouncer.changeStart(); // We modify private properties directly, to batch the change event if (this.comparator === sortBy) { this._reverse = typeof forceReverse !== 'undefined' ? forceReverse || !this._reverse : !this._reverse; } else { this._comparator = sortBy; this._reverse = typeof forceReverse !== 'undefined' ? forceReverse : false; } this.emitChange(); this.stateDebouncer.changeDone(); } /** * Clears the current sorting order */ clear() { this.comparator = null; } /** * Compares two objects according to the current comparator */ compare(a, b) { return (this.reverse ? -1 : 1) * this.comparator.compare(a, b); } emitChange() { this._change.next(this); } } Sort.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Sort, deps: [{ token: StateDebouncer }], target: i0.ɵɵFactoryTarget.Injectable }); Sort.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Sort }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Sort, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: StateDebouncer }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var DatagridRenderStep; (function (DatagridRenderStep) { DatagridRenderStep[DatagridRenderStep["ALIGN_COLUMNS"] = 0] = "ALIGN_COLUMNS"; DatagridRenderStep[DatagridRenderStep["CALCULATE_MODE_ON"] = 1] = "CALCULATE_MODE_ON"; DatagridRenderStep[DatagridRenderStep["CALCULATE_MODE_OFF"] = 2] = "CALCULATE_MODE_OFF"; DatagridRenderStep[DatagridRenderStep["CLEAR_WIDTHS"] = 3] = "CLEAR_WIDTHS"; DatagridRenderStep[DatagridRenderStep["COMPUTE_COLUMN_WIDTHS"] = 4] = "COMPUTE_COLUMN_WIDTHS"; })(DatagridRenderStep || (DatagridRenderStep = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridRenderOrganizer { constructor() { this._renderStep = new Subject(); this.alreadySized = false; } get renderStep() { return this._renderStep.asObservable(); } filterRenderSteps(step) { return this.renderStep.pipe(filter(testStep => step === testStep)); } resize() { this._renderStep.next(DatagridRenderStep.CALCULATE_MODE_ON); if (this.alreadySized) { this._renderStep.next(DatagridRenderStep.CLEAR_WIDTHS); } this._renderStep.next(DatagridRenderStep.COMPUTE_COLUMN_WIDTHS); this._renderStep.next(DatagridRenderStep.ALIGN_COLUMNS); this.alreadySized = true; this._renderStep.next(DatagridRenderStep.CALCULATE_MODE_OFF); } } DatagridRenderOrganizer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridRenderOrganizer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DatagridRenderOrganizer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridRenderOrganizer }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridRenderOrganizer, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const MIN_COLUMN_WIDTH = 96; // This service allows DatagridHeaderRenderer and ClrDatagridColumnSeparator // to share column resize data with each other. class ColumnResizerService { constructor(el, domAdapter, organizer) { this.el = el; this.domAdapter = domAdapter; this.organizer = organizer; this._resizedBy = 0; } get resizedBy() { return this._resizedBy; } get minColumnWidth() { return this.domAdapter.minWidth(this.el.nativeElement) || MIN_COLUMN_WIDTH; } get maxResizeRange() { return this.widthBeforeResize - this.minColumnWidth; } get widthAfterResize() { return this.widthBeforeResize + this._resizedBy; } startResize() { this._resizedBy = 0; this.isWithinMaxResizeRange = true; this.widthBeforeResize = this.domAdapter.clientRect(this.el.nativeElement).width; } endResize() { this.organizer.resize(); } calculateResize(resizedBy) { // calculates the resize amount within the allowed range if (resizedBy < -this.maxResizeRange) { this._resizedBy = -this.maxResizeRange; this.isWithinMaxResizeRange = false; } else { this._resizedBy = resizedBy; this.isWithinMaxResizeRange = true; } } } ColumnResizerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ColumnResizerService, deps: [{ token: i0.ElementRef }, { token: DomAdapter }, { token: DatagridRenderOrganizer }], target: i0.ɵɵFactoryTarget.Injectable }); ColumnResizerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ColumnResizerService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ColumnResizerService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: DomAdapter }, { type: DatagridRenderOrganizer }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * @description * Internal datagrid service that holds a reference to the clr-dg-table element and exposes a method to get height. */ class TableSizeService { constructor(platformId) { this.platformId = platformId; } get tableRef() { return this._tableRef; } set tableRef(element) { this._tableRef = element; } set table(table) { if (isPlatformBrowser(this.platformId) && table.nativeElement) { this.tableRef = table.nativeElement.querySelector('.datagrid-table'); } } // Used when resizing columns to show the column border being dragged. getColumnDragHeight() { if (!this.tableRef) { return null; } return `${this.tableRef.clientHeight}px`; } } TableSizeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TableSizeService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); TableSizeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TableSizeService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TableSizeService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // Default resize length on each keyboard move event const KEYBOARD_RESIZE_LENGTH = 12; class ClrDatagridColumnSeparator { constructor(columnResizerService, renderer, ngZone, tableSizeService, commonString, document) { this.columnResizerService = columnResizerService; this.renderer = renderer; this.ngZone = ngZone; this.tableSizeService = tableSizeService; this.commonString = commonString; this.document = document; this.columnSeparatorId = uniqueIdFactory(); this.resizeStartedOnKeyDown = false; this.unlisteners = []; } get descriptionId() { return `${this.columnSeparatorId}-aria-describedby`; } get resizeTrackerEl() { return this.resizeTrackerRef.nativeElement; } get columnHandleEl() { return this.columnHandleRef.nativeElement; } ngAfterViewInit() { this.ngZone.runOutsideAngular(() => { this.unlisteners.push(this.renderer.listen(this.columnHandleEl, 'keydown', event => { this.showTrackerOnFirstKeyDown(event); this.moveTrackerOnKeyDown(event); })); this.unlisteners.push(this.renderer.listen(this.columnHandleEl, 'keyup', event => { this.hideTrackerOnKeyUp(event); })); }); } ngOnDestroy() { this.unlisteners.forEach(unlistener => unlistener()); } showTracker() { this.columnResizerService.startResize(); const tableHeight = this.tableSizeService.getColumnDragHeight(); this.renderer.setStyle(this.resizeTrackerEl, 'height', tableHeight); this.renderer.setStyle(this.resizeTrackerEl, 'display', 'block'); } moveTracker(movedBy) { this.columnResizerService.calculateResize(movedBy); this.renderer.setStyle(this.resizeTrackerEl, 'transform', `translateX(${this.columnResizerService.resizedBy}px)`); this.renderer.setStyle(this.document.body, 'cursor', 'col-resize'); this.redFlagTracker(); } hideTracker() { this.columnResizerService.endResize(); this.renderer.setStyle(this.resizeTrackerEl, 'display', 'none'); this.renderer.setStyle(this.resizeTrackerEl, 'transform', `translateX(0px)`); this.renderer.setStyle(this.columnHandleEl, 'transform', `translateX(0px)`); this.renderer.setStyle(this.document.body, 'cursor', 'auto'); } showTrackerOnFirstKeyDown(event) { if (!this.resizeStartedOnKeyDown && (this.isArrowLeftKeyEvent(event) || this.isArrowRightKeyEvent(event))) { this.resizeStartedOnKeyDown = true; this.renderer.addClass(this.resizeTrackerEl, 'on-arrow-key-resize'); this.showTracker(); } } moveTrackerOnKeyDown(event) { if (this.isArrowLeftKeyEvent(event)) { event.stopPropagation(); this.moveTracker(this.columnResizerService.resizedBy - KEYBOARD_RESIZE_LENGTH); } else if (this.isArrowRightKeyEvent(event)) { event.stopPropagation(); this.moveTracker(this.columnResizerService.resizedBy + KEYBOARD_RESIZE_LENGTH); } } hideTrackerOnKeyUp(event) { if (this.resizeStartedOnKeyDown && (this.isArrowLeftKeyEvent(event) || this.isArrowRightKeyEvent(event))) { this.resizeStartedOnKeyDown = false; this.renderer.removeClass(this.resizeTrackerEl, 'on-arrow-key-resize'); this.hideTracker(); this.columnHandleEl.focus(); } } redFlagTracker() { if (this.isWithinMaxResizeRange !== this.columnResizerService.isWithinMaxResizeRange) { this.isWithinMaxResizeRange = this.columnResizerService.isWithinMaxResizeRange; if (!this.isWithinMaxResizeRange) { this.renderer.addClass(this.resizeTrackerEl, 'exceeded-max'); } else { this.renderer.removeClass(this.resizeTrackerEl, 'exceeded-max'); } } } isArrowLeftKeyEvent(event) { return normalizeKey(event.key) === Keys.ArrowLeft; } isArrowRightKeyEvent(event) { return normalizeKey(event.key) === Keys.ArrowRight; } } ClrDatagridColumnSeparator.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumnSeparator, deps: [{ token: ColumnResizerService }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: TableSizeService }, { token: ClrCommonStringsService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridColumnSeparator.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridColumnSeparator, selector: "clr-dg-column-separator", host: { properties: { "class.datagrid-column-separator": "true" } }, viewQueries: [{ propertyName: "resizeTrackerRef", first: true, predicate: ["resizeTracker"], descendants: true }, { propertyName: "columnHandleRef", first: true, predicate: ["columnHandle"], descendants: true }], ngImport: i0, template: ` {{ commonString.keys.columnSeparatorDescription }}
`, isInline: true, dependencies: [{ kind: "directive", type: CdkDragModule_CdkDrag, selector: "[cdkDrag]" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumnSeparator, decorators: [{ type: Component, args: [{ selector: 'clr-dg-column-separator', template: ` {{ commonString.keys.columnSeparatorDescription }}
`, host: { '[class.datagrid-column-separator]': 'true', }, }] }], ctorParameters: function () { return [{ type: ColumnResizerService }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: TableSizeService }, { type: ClrCommonStringsService }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { resizeTrackerRef: [{ type: ViewChild, args: ['resizeTracker'] }], columnHandleRef: [{ type: ViewChild, args: ['columnHandle'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridColumn extends DatagridFilterRegistrar { constructor(_sort, filters, vcr, detailService, changeDetectorRef) { super(filters); this._sort = _sort; this.vcr = vcr; this.detailService = detailService; this.changeDetectorRef = changeDetectorRef; this.sortOrderChange = new EventEmitter(); this.filterValueChange = new EventEmitter(); this.showSeparator = true; /** * A custom filter for this column that can be provided in the projected content */ this.customFilter = false; /* * What type is this column? This defaults to STRING, but can also be * set to NUMBER. Unsupported types default to STRING. Users can set it * via the [clrDgColType] input by setting it to 'string' or 'number'. */ this._colType = 'string'; /** * Indicates how the column is currently sorted */ this._sortOrder = ClrDatagridSortOrder.UNSORTED; /** * Subscription to the sort service changes */ this.subscriptions = []; this.subscriptions.push(this.listenForSortingChanges()); this.subscriptions.push(this.listenForDetailPaneChanges()); } // TODO: We might want to make this an enum in the future get colType() { return this._colType; } set colType(value) { this._colType = value; } get field() { return this._field; } set field(field) { if (typeof field === 'string') { this._field = field; if (!this._sortBy) { this._sortBy = new DatagridPropertyComparator(field); } } } get sortBy() { return this._sortBy; } set sortBy(comparator) { if (typeof comparator === 'string') { this._sortBy = new DatagridPropertyComparator(comparator); } else { if (comparator) { this._sortBy = comparator; } else { if (this.field) { this._sortBy = new DatagridPropertyComparator(this.field); } else { delete this._sortBy; } } } } get sortOrder() { return this._sortOrder; } set sortOrder(value) { if (typeof value === 'undefined') { return; } // only if the incoming order is different from the current one if (this._sortOrder === value) { return; } switch (value) { // the Unsorted case happens when the current state is either Asc or Desc default: case ClrDatagridSortOrder.UNSORTED: this._sort.clear(); break; case ClrDatagridSortOrder.ASC: this.sort(false); break; case ClrDatagridSortOrder.DESC: this.sort(true); break; } } set updateFilterValue(newValue) { if (this.filter) { if (this.filter instanceof DatagridStringFilterImpl) { if (!newValue || typeof newValue !== 'string') { newValue = ''; } if (newValue !== this.filter.value) { this.filter.value = newValue; } } else if (this.filter instanceof DatagridNumericFilterImpl) { if (!newValue || !(newValue instanceof Array)) { newValue = [null, null]; } if (newValue.length === 2 && (newValue[0] !== this.filter.value[0] || newValue[1] !== this.filter.value[1])) { this.filter.value = newValue; } } } else { this.initFilterValue = newValue; } } set projectedFilter(custom) { if (custom) { this.deleteFilter(); this.customFilter = true; } } /** * Indicates if the column is sortable */ get sortable() { return !!this._sortBy; } get ariaSort() { switch (this._sortOrder) { default: case ClrDatagridSortOrder.UNSORTED: return 'none'; case ClrDatagridSortOrder.ASC: return 'ascending'; case ClrDatagridSortOrder.DESC: return 'descending'; } } get sortDirection() { return this._sortDirection; } /** * @NOTE type `any` here is to let us pass templateStrictMode, because in our code we try to handle * two types of filters String and Number with the same variable but both of them work with different * format we got an error for casting. We could not cast anything inside the template so to not mess the * casting, the last type is set to `any` * * Orignial types: string | [number, number] */ get filterValue() { if (this.filter instanceof DatagridStringFilterImpl || this.filter instanceof DatagridNumericFilterImpl) { return this.filter.value; } return null; } set filterValue(newValue) { if (this.filter instanceof DatagridStringFilterImpl || this.filter instanceof DatagridNumericFilterImpl) { this.updateFilterValue = newValue; this.filterValueChange.emit(this.filter.value); } } get _view() { return this.wrappedInjector.get(WrappedColumn, this.vcr).columnView; } ngOnInit() { this.wrappedInjector = new HostWrapper(WrappedColumn, this.vcr); } ngOnChanges(changes) { if (changes.colType && changes.colType.currentValue && changes.colType.currentValue !== changes.colType.previousValue) { if (!this.customFilter && !this.filter && this.colType && this.field) { this.setupDefaultFilter(this.field, this.colType); } } if (changes.field && changes.field.currentValue && changes.field.currentValue !== changes.field.previousValue) { if (!this.customFilter && this.colType) { this.setupDefaultFilter(this.field, this.colType); } } } ngOnDestroy() { super.ngOnDestroy(); this.subscriptions.forEach(s => s.unsubscribe()); } /** * Sorts the datagrid based on this column */ sort(reverse) { if (!this.sortable) { return; } this._sort.toggle(this._sortBy, reverse); // setting the private variable to not retrigger the setter logic this._sortOrder = this._sort.reverse ? ClrDatagridSortOrder.DESC : ClrDatagridSortOrder.ASC; // Sets the correct icon for current sort order this._sortDirection = this._sortOrder === ClrDatagridSortOrder.DESC ? 'down' : 'up'; this.sortOrderChange.emit(this._sortOrder); } listenForDetailPaneChanges() { return this.detailService.stateChange.subscribe(state => { if (this.showSeparator !== !state) { this.showSeparator = !state; // Have to manually change because of OnPush this.changeDetectorRef.markForCheck(); } }); } listenForSortingChanges() { return this._sort.change.subscribe(sort => { // Need to manually mark the component to be checked // for both activating and deactivating sorting this.changeDetectorRef.markForCheck(); // We're only listening to make sure we emit an event when the column goes from sorted to unsorted if (this.sortOrder !== ClrDatagridSortOrder.UNSORTED && sort.comparator !== this._sortBy) { this._sortOrder = ClrDatagridSortOrder.UNSORTED; this.sortOrderChange.emit(this._sortOrder); this._sortDirection = null; } }); } setupDefaultFilter(field, colType) { if (colType === 'number') { this.setFilter(new DatagridNumericFilterImpl(new DatagridPropertyNumericFilter(field))); } else if (colType === 'string') { this.setFilter(new DatagridStringFilterImpl(new DatagridPropertyStringFilter(field))); } if (this.filter && this.initFilterValue) { this.updateFilterValue = this.initFilterValue; // This initFilterValue should be used only once after the filter registration // So deleting this property value to prevent it from being used again // if this field property is set again delete this.initFilterValue; } } } ClrDatagridColumn.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumn, deps: [{ token: Sort }, { token: FiltersProvider }, { token: i0.ViewContainerRef }, { token: DetailService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridColumn.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridColumn, selector: "clr-dg-column", inputs: { filterStringPlaceholder: ["clrFilterStringPlaceholder", "filterStringPlaceholder"], filterNumberMaxPlaceholder: ["clrFilterNumberMaxPlaceholder", "filterNumberMaxPlaceholder"], filterNumberMinPlaceholder: ["clrFilterNumberMinPlaceholder", "filterNumberMinPlaceholder"], colType: ["clrDgColType", "colType"], field: ["clrDgField", "field"], sortBy: ["clrDgSortBy", "sortBy"], sortOrder: ["clrDgSortOrder", "sortOrder"], updateFilterValue: ["clrFilterValue", "updateFilterValue"] }, outputs: { sortOrderChange: "clrDgSortOrderChange", filterValueChange: "clrFilterValueChange" }, host: { attributes: { "role": "columnheader" }, properties: { "class.datagrid-column": "true", "attr.aria-sort": "ariaSort" } }, queries: [{ propertyName: "projectedFilter", first: true, predicate: CustomFilter, descendants: true }], usesInheritance: true, usesOnChanges: true, hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrDatagridColumnSeparator, selector: "clr-dg-column-separator" }, { kind: "component", type: DatagridNumericFilter, selector: "clr-dg-numeric-filter", inputs: ["clrFilterMinPlaceholder", "clrFilterMaxPlaceholder", "clrFilterValue", "clrDgNumericFilter"], outputs: ["clrFilterValueChange"] }, { kind: "component", type: DatagridStringFilter, selector: "clr-dg-string-filter", inputs: ["clrFilterPlaceholder", "clrDgStringFilter", "clrFilterValue"], outputs: ["clrFilterValueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumn, decorators: [{ type: Component, args: [{ selector: 'clr-dg-column', template: `
`, hostDirectives: [ClrPopoverHostDirective], host: { '[class.datagrid-column]': 'true', '[attr.aria-sort]': 'ariaSort', role: 'columnheader', }, changeDetection: ChangeDetectionStrategy.OnPush, }] }], ctorParameters: function () { return [{ type: Sort }, { type: FiltersProvider }, { type: i0.ViewContainerRef }, { type: DetailService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { filterStringPlaceholder: [{ type: Input, args: ['clrFilterStringPlaceholder'] }], filterNumberMaxPlaceholder: [{ type: Input, args: ['clrFilterNumberMaxPlaceholder'] }], filterNumberMinPlaceholder: [{ type: Input, args: ['clrFilterNumberMinPlaceholder'] }], sortOrderChange: [{ type: Output, args: ['clrDgSortOrderChange'] }], filterValueChange: [{ type: Output, args: ['clrFilterValueChange'] }], colType: [{ type: Input, args: ['clrDgColType'] }], field: [{ type: Input, args: ['clrDgField'] }], sortBy: [{ type: Input, args: ['clrDgSortBy'] }], sortOrder: [{ type: Input, args: ['clrDgSortOrder'] }], updateFilterValue: [{ type: Input, args: ['clrFilterValue'] }], projectedFilter: [{ type: ContentChild, args: [CustomFilter] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class Items { constructor(_filters, _sort, _page) { this._filters = _filters; this._sort = _sort; this._page = _page; /** * Indicates if the data is currently loading */ this.loading = false; /** * Whether we should use smart items for this datagrid or let the user handle * everything. */ this._smart = false; /** * List of items currently displayed */ this._displayed = []; /** * The Observable that lets other classes subscribe to items changes */ this._change = new Subject(); this._allChanges = new Subject(); /** * Tracking function to identify objects. Default is reference equality. * * @deprecated in v15 and scheduled for removal in v17 (CDE-71) */ this.iteratorTrackBy = (_index, item) => item; } get smart() { return this._smart; } get all() { return this._all; } set all(items) { this._all = items; this.emitAllChanges(items); if (this.smart) { this._filterItems(); } else { this._displayed = items; this.emitChange(); } } get displayed() { // Ideally we could return an immutable array, but we don't have it in Clarity yet. return this._displayed; } // We do not want to expose the Subject itself, but the Observable which is read-only get change() { return this._change.asObservable(); } get allChanges() { return this._allChanges.asObservable(); } /** * Checks if we don't have data to process yet, to abort early operations */ get uninitialized() { return !this._all; } /** * Cleans up our subscriptions to other providers */ destroy() { if (this._filtersSub) { this._filtersSub.unsubscribe(); } if (this._sortSub) { this._sortSub.unsubscribe(); } if (this._pageSub) { this._pageSub.unsubscribe(); } } smartenUp() { this._smart = true; /* * These observers trigger a chain of function: filter -> sort -> paginate * An observer up the chain re-triggers all the operations that follow it. */ this._filtersSub = this._filters.change.subscribe(() => this._filterItems()); this._sortSub = this._sort.change.subscribe(() => { // Special case, if the datagrid went from sorted to unsorted, we have to re-filter // to get the original order back if (!this._sort.comparator) { this._filterItems(); } else { this._sortItems(); } }); this._pageSub = this._page.change.subscribe(() => this._changePage()); } /** * Manually recompute the list of displayed items */ refresh() { if (this.smart) { this._filterItems(); } } canTrackBy() { // all items are needed unless `datagridTrackBy` is set because `iteratorTrackBy` requires the item's index return !!this.datagridTrackBy || Array.isArray(this.all); } trackBy(item, index) { if (this.datagridTrackBy) { return this.datagridTrackBy(item); } else if (Array.isArray(this.all)) { index = index ?? this.all.indexOf(item); return this.iteratorTrackBy(index, item); } else { throw new Error('improper call to Items#trackBy'); } } emitChange() { this._change.next(this.displayed); } emitAllChanges(items) { this._allChanges.next(items); } /** * FiltersProvider items from the raw list */ _filterItems() { if (this.uninitialized) { return; } if (this._filters.hasActiveFilters()) { this._filtered = this._all.filter(item => this._filters.accepts(item)); } else { // Work on a shallow copy of the array, to not modify the user's model this._filtered = this._all.slice(); } this._page.totalItems = this._filtered.length; this._sortItems(); } /** * Sorts items in the filtered list */ _sortItems() { if (this.uninitialized) { return; } if (this._sort.comparator) { this._filtered.sort((a, b) => this._sort.compare(a, b)); } this._changePage(); } /** * Extracts the current page from the sorted list */ _changePage() { // If we know we have pagination but the page size hasn't been set yet, we wait for it. if (this.uninitialized || (this._page.activated && this._page.size === 0)) { return; } if (this._page.size > 0) { this._displayed = this._filtered.slice(this._page.firstItem, this._page.lastItem + 1); } else { this._displayed = this._filtered; } this.emitChange(); } } Items.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Items, deps: [{ token: FiltersProvider }, { token: Sort }, { token: Page }], target: i0.ɵɵFactoryTarget.Injectable }); Items.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Items }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Items, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: FiltersProvider }, { type: Sort }, { type: Page }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridItems { constructor(template, differs, items, vcr) { this.template = template; this.differs = differs; this.items = items; this.vcr = vcr; this.differ = null; this.subscriptions = []; items.smartenUp(); this.iterableProxy = new NgForOf(this.vcr, this.template, this.differs); this.subscriptions.push(items.change.subscribe(newItems => { this.iterableProxy.ngForOf = newItems; this.iterableProxy.ngDoCheck(); })); } set rawItems(items) { this._rawItems = items ? items : []; // local copy for ngOnChange diffing } set trackBy(value) { this.items.iteratorTrackBy = value; this.iterableProxy.ngForTrackBy = value; } /** * Asserts the correct type of the template context that the directive will render. * See https://angular.io/guide/structural-directives#typing-the-directives-context * * The presence of this method is a signal to the Ivy template type-check compiler that the * structural directive renders its template with a specific context type. */ static ngTemplateContextGuard(_dir, _ctx) { return true; } ngDoCheck() { if (!this.differ) { this.differ = this.differs.find(this._rawItems).create(this.iterableProxy.ngForTrackBy); } if (this.differ) { const changes = this.differ.diff(this._rawItems); if (changes) { // TODO: not very efficient right now, // but premature optimization is the root of all evil. this.items.all = this._rawItems; } } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrDatagridItems.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridItems, deps: [{ token: i0.TemplateRef }, { token: i0.IterableDiffers }, { token: Items }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrDatagridItems.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridItems, selector: "[clrDgItems][clrDgItemsOf]", inputs: { rawItems: ["clrDgItemsOf", "rawItems"], trackBy: ["clrDgItemsTrackBy", "trackBy"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridItems, decorators: [{ type: Directive, args: [{ selector: '[clrDgItems][clrDgItemsOf]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.IterableDiffers }, { type: Items }, { type: i0.ViewContainerRef }]; }, propDecorators: { rawItems: [{ type: Input, args: ['clrDgItemsOf'] }], trackBy: [{ type: Input, args: ['clrDgItemsTrackBy'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridPlaceholder { constructor(items) { this.items = items; } /** * Tests if the datagrid is empty, meaning it doesn't contain any items */ get emptyDatagrid() { return !this.items.loading && (!this.items.displayed || this.items.displayed.length === 0); } } ClrDatagridPlaceholder.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridPlaceholder, deps: [{ token: Items }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridPlaceholder.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridPlaceholder, selector: "clr-dg-placeholder", host: { properties: { "class.datagrid-placeholder-container": "true" } }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridPlaceholder, decorators: [{ type: Component, args: [{ selector: 'clr-dg-placeholder', template: `
`, host: { '[class.datagrid-placeholder-container]': 'true' }, }] }], ctorParameters: function () { return [{ type: Items }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class SignpostFocusManager { set triggerEl(value) { this._triggerEl = value; } focusTrigger() { if (this._triggerEl) { this._triggerEl.focus(); } } } SignpostFocusManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SignpostFocusManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); SignpostFocusManager.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SignpostFocusManager }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SignpostFocusManager, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class SignpostIdService { constructor() { this._id = new Subject(); } get id() { return this._id.asObservable(); } setId(id) { this._id.next(id); } } SignpostIdService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SignpostIdService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); SignpostIdService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SignpostIdService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SignpostIdService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /********* * * @description * A Directive added to the ClrSignpost Trigger button that will call the ClrSignpost.toggle() function to hide/show the * ClrSignpostContent. * */ class ClrSignpostTrigger { constructor(toggleService, el, commonStrings, signpostIdService, signpostFocusManager, document, platformId) { this.toggleService = toggleService; this.el = el; this.commonStrings = commonStrings; this.signpostIdService = signpostIdService; this.signpostFocusManager = signpostFocusManager; this.platformId = platformId; this.ariaExpanded = false; this.subscriptions = []; this.document = document; } ngOnInit() { this.signpostFocusManager.triggerEl = this.el.nativeElement; this.subscriptions.push(this.toggleService.openChange.subscribe((isOpen) => { this.ariaExpanded = isOpen; const prevIsOpen = this.isOpen; this.isOpen = isOpen; // openChange fires false on initialization because signpost starts as closed by default // but we shouldn't focus on that initial false value // we should focus back only if it's closed after being opened if (!this.isOpen && prevIsOpen) { this.focusOnClose(); } }), this.signpostIdService.id.subscribe(idChange => (this.ariaControl = idChange))); this.addDefaultAriaLabel(this.el.nativeElement); } ngOnDestroy() { this.subscriptions.forEach((sub) => sub.unsubscribe()); } /********** * * @description * click handler for the ClrSignpost trigger button used to hide/show ClrSignpostContent. */ onSignpostTriggerClick(event) { this.toggleService.toggleWithEvent(event); } addDefaultAriaLabel(el) { if (!el.hasAttribute('aria-label')) { el.setAttribute('aria-label', this.commonStrings.keys.signpostToggle); } } focusOnClose() { if (!isPlatformBrowser(this.platformId)) { return; } // we have to set the focus back on the trigger only if the focus is reset back to the body element // if the focus is on another element, we are not allowed to move that focus back to this trigger again. if (!this.isOpen && this.document.activeElement === this.document.body) { this.signpostFocusManager.focusTrigger(); } } } ClrSignpostTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostTrigger, deps: [{ token: ClrPopoverToggleService }, { token: i0.ElementRef }, { token: ClrCommonStringsService }, { token: SignpostIdService }, { token: SignpostFocusManager }, { token: DOCUMENT }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Directive }); ClrSignpostTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrSignpostTrigger, selector: "[clrSignpostTrigger]", host: { listeners: { "click": "onSignpostTriggerClick($event)" }, properties: { "attr.aria-expanded": "ariaExpanded", "attr.aria-controls": "ariaControl", "class.active": "isOpen" }, classAttribute: "signpost-trigger" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostTrigger, decorators: [{ type: Directive, args: [{ selector: '[clrSignpostTrigger]', host: { class: 'signpost-trigger', '[attr.aria-expanded]': 'ariaExpanded', '[attr.aria-controls]': 'ariaControl', '[class.active]': 'isOpen', }, }] }], ctorParameters: function () { return [{ type: ClrPopoverToggleService }, { type: i0.ElementRef }, { type: ClrCommonStringsService }, { type: SignpostIdService }, { type: SignpostFocusManager }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; }, propDecorators: { onSignpostTriggerClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /********* * * @class ClrSignpost * * @description * Class used to configure and control the state of a ClrSignpost and its associated ClrSignpostContent. * It supports the clrPosition with a 'right-middle' default. * */ class ClrSignpost { constructor(commonStrings) { this.commonStrings = commonStrings; /********** * @property useCustomTrigger * * @description * Flag used to determine if we need to use the default trigger or a user supplied trigger element. * */ this.useCustomTrigger = false; } /********** * @property signPostTrigger * * @description * Uses ContentChild to check for a user supplied element with the ClrSignpostTrigger on it. * */ set customTrigger(trigger) { this.useCustomTrigger = !!trigger; } } ClrSignpost.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpost, deps: [{ token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrSignpost.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrSignpost, selector: "clr-signpost", host: { properties: { "class.signpost": "true" } }, providers: [SignpostFocusManager, SignpostIdService], queries: [{ propertyName: "customTrigger", first: true, predicate: ClrSignpostTrigger, descendants: true }], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrSignpostTrigger, selector: "[clrSignpostTrigger]" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpost, decorators: [{ type: Component, args: [{ selector: 'clr-signpost', template: ` `, host: { '[class.signpost]': 'true' }, providers: [SignpostFocusManager, SignpostIdService], hostDirectives: [ClrPopoverHostDirective], }] }], ctorParameters: function () { return [{ type: ClrCommonStringsService }]; }, propDecorators: { customTrigger: [{ type: ContentChild, args: [ClrSignpostTrigger] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class WrappedCell { constructor() { this._dynamic = false; } ngAfterViewInit() { this.cellView = this.templateRef.createEmbeddedView(null); } ngOnDestroy() { this.cellView.destroy(); } } WrappedCell.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedCell, deps: [], target: i0.ɵɵFactoryTarget.Component }); WrappedCell.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: WrappedCell, selector: "dg-wrapped-cell", viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["cellPortal"], descendants: true }], ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedCell, decorators: [{ type: Component, args: [{ selector: 'dg-wrapped-cell', template: ` `, }] }], propDecorators: { templateRef: [{ type: ViewChild, args: ['cellPortal'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridCell { constructor(vcr) { this.vcr = vcr; } get _view() { return this.wrappedInjector.get(WrappedCell, this.vcr).cellView; } ngOnInit() { this.wrappedInjector = new HostWrapper(WrappedCell, this.vcr); } } ClrDatagridCell.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridCell, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridCell.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridCell, selector: "clr-dg-cell", host: { attributes: { "role": "gridcell" }, properties: { "class.datagrid-cell": "true", "class.datagrid-signpost-trigger": "signpost.length > 0" } }, queries: [{ propertyName: "signpost", predicate: ClrSignpost }], ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridCell, decorators: [{ type: Component, args: [{ selector: 'clr-dg-cell', template: ``, host: { '[class.datagrid-cell]': 'true', '[class.datagrid-signpost-trigger]': 'signpost.length > 0', role: 'gridcell', }, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { signpost: [{ type: ContentChildren, args: [ClrSignpost] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbRow$1 = 0; class DatagridIfExpandService extends IfExpandService { constructor() { super(); this.expandableId = ''; this._replace = new BehaviorSubject(false); this._animate = new Subject(); nbRow$1++; this.expandableId = 'clr-dg-expandable-row-' + nbRow$1; } // due to the es5 spec if the set is overridden on base class the getter must also be overridden get expanded() { return this._expanded; } set expanded(value) { value = !!value; if (value !== this._expanded) { this._expanded = value; this._animate.next(); this._expandChange.next(value); } } get replace() { return this._replace.asObservable(); } get animate() { return this._animate.asObservable(); } loadingStateChange(state) { super.loadingStateChange(state); if (state !== ClrLoadingState.LOADING) { this._animate.next(); } } setReplace(replaceValue) { this._replace.next(replaceValue); } } DatagridIfExpandService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridIfExpandService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); DatagridIfExpandService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridIfExpandService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridIfExpandService, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var DatagridDisplayMode; (function (DatagridDisplayMode) { DatagridDisplayMode[DatagridDisplayMode["DISPLAY"] = 0] = "DISPLAY"; DatagridDisplayMode[DatagridDisplayMode["CALCULATE"] = 1] = "CALCULATE"; })(DatagridDisplayMode || (DatagridDisplayMode = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var SelectionType; (function (SelectionType) { SelectionType[SelectionType["None"] = 0] = "None"; SelectionType[SelectionType["Single"] = 1] = "Single"; SelectionType[SelectionType["Multi"] = 2] = "Multi"; })(SelectionType || (SelectionType = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class WrappedRow { constructor() { this._dynamic = false; } ngAfterViewInit() { // Create the cells view in memory, not the DOM. this.rowView = this.templateRef.createEmbeddedView(null); } ngOnDestroy() { this.rowView.destroy(); } } WrappedRow.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedRow, deps: [], target: i0.ɵɵFactoryTarget.Component }); WrappedRow.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: WrappedRow, selector: "dg-wrapped-row", viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["rowPortal"], descendants: true }], ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WrappedRow, decorators: [{ type: Component, args: [{ selector: 'dg-wrapped-row', template: ` `, }] }], propDecorators: { templateRef: [{ type: ViewChild, args: ['rowPortal'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbSelection = 0; class Selection { constructor(_items, _filters) { this._items = _items; this._filters = _filters; this.preserveSelection = false; /** * Shift key state, for use in range selection. */ this.shiftPressed = false; /** @deprecated since 2.0, remove in 3.0 */ this.rowSelectionMode = false; this.prevSelectionRefs = []; // Refs of selected items this.lockedRefs = []; // Ref of locked items this.valueCollector = new Subject(); this._selectionType = SelectionType.None; /** * The Observable that lets other classes subscribe to selection changes */ this._change = new Subject(); /** * Subscriptions to the other providers changes. */ this.subscriptions = []; this.id = 'clr-dg-selection' + nbSelection++; this.subscriptions.push(this._filters.change.subscribe(() => { if (!this._selectable || this.preserveSelection) { return; } this.clearSelection(); })); this.subscriptions.push(this._items.allChanges.subscribe(updatedItems => { // Reset the lockedRefs; const updateLockedRef = []; switch (this.selectionType) { case SelectionType.None: { break; } case SelectionType.Single: { let newSingle; let selectionUpdated = false; // if the currentSingle has been set before data was loaded, we look up and save the ref from current data set if (this.currentSingle && !this.prevSingleSelectionRef) { if (this._items.canTrackBy()) { this.prevSingleSelectionRef = this._items.trackBy(this.currentSingle); } } updatedItems.forEach((item, index) => { const ref = this._items.trackBy(item, index); // If one of the updated items is the previously selectedSingle, set it as the new one if (this.prevSingleSelectionRef === ref) { newSingle = item; selectionUpdated = true; } if (this.lockedRefs.indexOf(ref) > -1) { updateLockedRef.push(ref); } }); // If we're using smart datagrids, we expect all items to be present in the updatedItems array. // Therefore, we should delete the currentSingle if it used to be defined but doesn't exist anymore. // No explicit "delete" is required, since newSingle would be undefined at this point. // Marking it as selectionUpdated here will set currentSingle to undefined below in the setTimeout. if (this._items.smart && !newSingle) { selectionUpdated = true; } // TODO: Discussed this with Eudes and this is fine for now. // But we need to figure out a different pattern for the // child triggering the parent change detection problem. // Using setTimeout for now to fix this. setTimeout(() => { if (selectionUpdated) { this.currentSingle = newSingle; } }, 0); break; } case SelectionType.Multi: { let leftOver = this.current.slice(); let selectionUpdated = false; // if the current has been set before data was loaded, we look up and save the ref from current data set if (this.current.length > 0 && this.prevSelectionRefs.length !== this.current.length) { if (this._items.canTrackBy()) { this.prevSelectionRefs = []; this.current.forEach(item => { this.prevSelectionRefs.push(this._items.trackBy(item)); }); } } // Duplicate loop, when the issue is issue#2342 is revisited keep in mind that // we need to go over every updated item and check to see if there are valid to be // locked or not and update it. When only add items that are found in the lockedRefs back. // // The both loops below that goes over updatedItems could be combined into one. updatedItems.forEach((item, index) => { const ref = this._items.trackBy(item, index); if (this.lockedRefs.indexOf(ref) > -1) { updateLockedRef.push(ref); } }); // TODO: revisit this when we work on https://github.com/vmware/clarity/issues/2342 // currently, the selection is cleared when filter is applied, so the logic inside // the if statement below results in broken behavior. if (leftOver.length > 0) { updatedItems.forEach((item, index) => { const ref = this._items.trackBy(item, index); // Look in current selected refs array if item is selected, and update actual value const selectedIndex = this.prevSelectionRefs.indexOf(ref); if (selectedIndex > -1) { leftOver[selectedIndex] = item; selectionUpdated = true; } }); // Filter out any unmatched items if we're using smart datagrids where we expect all items to be // present if (this._items.smart) { leftOver = leftOver.filter(selected => updatedItems.indexOf(selected) > -1); if (this.current.length !== leftOver.length) { selectionUpdated = true; } } // TODO: Discussed this with Eudes and this is fine for now. // But we need to figure out a different pattern for the // child triggering the parent change detection problem. // Using setTimeout for now to fix this. setTimeout(() => { if (selectionUpdated) { this.current = leftOver; } }, 0); } break; } default: { break; } } // Sync locked items this.lockedRefs = updateLockedRef; })); this.subscriptions.push(this.valueCollector.pipe(debounceTime(0)).subscribe(() => this.emitChange())); } get selectionType() { return this._selectionType; } set selectionType(value) { if (value === this.selectionType) { return; } this._selectionType = value; if (value === SelectionType.None) { delete this.current; } else { this.updateCurrent([], false); } } get current() { return this._current; } set current(value) { this.updateCurrent(value, true); } get currentSingle() { return this._currentSingle; } set currentSingle(value) { if (value === this._currentSingle) { return; } this._currentSingle = value; if (this._items.canTrackBy() && value) { this.prevSingleSelectionRef = this._items.trackBy(value); } this.emitChange(); } // We do not want to expose the Subject itself, but the Observable which is read-only get change() { return this._change.asObservable(); } get _selectable() { return this._selectionType === SelectionType.Multi || this._selectionType === SelectionType.Single; } clearSelection() { this._current = []; this.prevSelectionRefs = []; this.prevSingleSelectionRef = null; this._currentSingle = null; this.emitChange(); } /** * Cleans up our subscriptions to other providers */ destroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } updateCurrent(value, emit) { this._current = value; if (emit) { this.valueCollector.next(value); } } /** * Checks if an item is currently selected */ isSelected(item) { if (this._selectionType === SelectionType.Single) { return this.currentSingle === item; } else if (this._selectionType === SelectionType.Multi) { return this.current.indexOf(item) >= 0; } return false; } /** * Selects or deselects an item */ setSelected(item, selected) { const index = this.current ? this.current.indexOf(item) : -1; switch (this._selectionType) { case SelectionType.None: break; case SelectionType.Single: // in single selection, set currentSingle method should be used break; case SelectionType.Multi: if (index >= 0 && !selected) { this.deselectItem(index); } else if (index < 0 && selected) { this.selectItem(item); } break; default: break; } } /** * Checks if all currently displayed items are selected */ isAllSelected() { if (this._selectionType !== SelectionType.Multi || !this._items.displayed) { return false; } // make sure to exclude the locked items from the list when counting const displayedItems = this._items.displayed.filter(item => { return this.isLocked(item) === false; }); const nbDisplayed = displayedItems.length; if (nbDisplayed < 1) { return false; } const temp = displayedItems.filter(item => this.current.indexOf(item) > -1); return temp.length === displayedItems.length; } /** * Lock and unlock item */ lockItem(item, lock) { if (this.canItBeLocked()) { const ref = this._items.trackBy(item); if (lock === true) { // Add to lockedRef this.lockedRefs.push(ref); } else { // Remove from lockedRef this.lockedRefs = this.lockedRefs.filter(lockedItem => ref !== lockedItem); } } } /** * Check is item locked or not by searching into lockedRefs for entry */ isLocked(item) { /** * The check for selectionType will boost the performance by NOT searching * into the array when there is no need for that. */ if (this.canItBeLocked()) { const ref = this._items.trackBy(item); return this.lockedRefs.indexOf(ref) > -1; } return false; } /** * Selects or deselects all currently displayed items */ toggleAll() { if (this._selectionType === SelectionType.None || this._selectionType === SelectionType.Single) { return; } /** * If every currently displayed item is already selected, we clear them. * If at least one item isn't selected, we select every currently displayed item. */ if (this.isAllSelected()) { this._items.displayed.forEach(item => { const currentIndex = this.current.indexOf(item); if (currentIndex > -1 && this.isLocked(item) === false) { this.deselectItem(currentIndex); } }); } else { this._items.displayed.forEach(item => { if (this.current.indexOf(item) < 0 && this.isLocked(item) === false) { this.selectItem(item); } }); } } /** * Selects an item */ selectItem(item) { this.current = this.current.concat(item); if (this._items.canTrackBy()) { // Push selected ref onto array this.prevSelectionRefs.push(this._items.trackBy(item)); } } /** * Deselects an item */ deselectItem(indexOfItem) { this.current = this.current.slice(0, indexOfItem).concat(this.current.slice(indexOfItem + 1)); if (indexOfItem < this.prevSelectionRefs.length) { // Keep selected refs array in sync const removedItems = this.prevSelectionRefs.splice(indexOfItem, 1); // locked reference is no longer needed (if any) this.lockedRefs = this.lockedRefs.filter(locked => locked !== removedItems[0]); } } /** * Make sure that it could be locked */ canItBeLocked() { return this._selectionType !== SelectionType.None && this._items.canTrackBy(); } emitChange() { if (this._selectionType === SelectionType.Single) { this._change.next(this.currentSingle); } else if (this._selectionType === SelectionType.Multi) { this._change.next(this.current); } } } Selection.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Selection, deps: [{ token: Items }, { token: FiltersProvider }], target: i0.ɵɵFactoryTarget.Injectable }); Selection.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Selection }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: Selection, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: Items }, { type: FiltersProvider }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DisplayModeService { constructor(renderOrganizer) { this._view = new BehaviorSubject(DatagridDisplayMode.DISPLAY); this.subscriptions = []; this.subscriptions.push(renderOrganizer .filterRenderSteps(DatagridRenderStep.CALCULATE_MODE_ON) .subscribe(() => this._view.next(DatagridDisplayMode.CALCULATE))); this.subscriptions.push(renderOrganizer .filterRenderSteps(DatagridRenderStep.CALCULATE_MODE_OFF) .subscribe(() => this._view.next(DatagridDisplayMode.DISPLAY))); } get view() { return this._view.asObservable(); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } DisplayModeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DisplayModeService, deps: [{ token: DatagridRenderOrganizer }], target: i0.ɵɵFactoryTarget.Injectable }); DisplayModeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DisplayModeService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DisplayModeService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: DatagridRenderOrganizer }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridSelectionCellDirective { constructor(selection) { this.selection = selection; } onSelectionCellClick(event) { // We want to effectively expand the selection click target to the entire selection cell. // If row selection is enabled, do nothing because the entire selection cell is already clickable. if (this.selection.rowSelectionMode) { return; } // If click was outside the label/input, forward the click to the input. if (event.target.tagName !== 'LABEL' && event.target.tagName !== 'INPUT') { event.target.querySelector('input').click(); } } } ClrDatagridSelectionCellDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridSelectionCellDirective, deps: [{ token: Selection }], target: i0.ɵɵFactoryTarget.Directive }); ClrDatagridSelectionCellDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridSelectionCellDirective, selector: ".datagrid-select", host: { listeners: { "click": "onSelectionCellClick($event)" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridSelectionCellDirective, decorators: [{ type: Directive, args: [{ selector: '.datagrid-select', }] }], ctorParameters: function () { return [{ type: Selection }]; }, propDecorators: { onSelectionCellClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbRow = 0; class ClrDatagridRow { constructor(selection, rowActionService, globalExpandable, expand, detailService, displayMode, vcr, renderer, el, commonStrings, items, document) { this.selection = selection; this.rowActionService = rowActionService; this.globalExpandable = globalExpandable; this.expand = expand; this.detailService = detailService; this.displayMode = displayMode; this.vcr = vcr; this.renderer = renderer; this.el = el; this.commonStrings = commonStrings; this.items = items; this.document = document; this.selectedChanged = new EventEmitter(false); this.expandedChange = new EventEmitter(false); this.displayCells = false; this.expandAnimationTrigger = false; /* reference to the enum so that template can access */ this.SELECTION_TYPE = SelectionType; /** * @internal */ this.itemChanges = new ReplaySubject(1); this._selected = false; this._detailOpenLabel = ''; this._detailCloseLabel = ''; this._rowAriaLabel = ''; this.subscriptions = []; // By default, every item is selectable; it becomes not selectable only if it's explicitly set to false this._selectable = true; nbRow++; this.id = 'clr-dg-row' + nbRow; this.radioId = 'clr-dg-row-rd' + nbRow; this.checkboxId = 'clr-dg-row-cb' + nbRow; this.expandableId = expand.expandableId; this.subscriptions.push(combineLatest(this.expand.replace, this.expand.expandChange).subscribe(([expandReplaceValue, expandChangeValue]) => { if (expandReplaceValue && expandChangeValue) { // replaced and expanding this.replaced = true; this.renderer.addClass(this.el.nativeElement, 'datagrid-row-replaced'); } else { this.replaced = false; // Handles these cases: not replaced and collapsing & replaced and // collapsing and not replaced and expanding. this.renderer.removeClass(this.el.nativeElement, 'datagrid-row-replaced'); } })); } /** * Model of the row, to use for selection */ get item() { return this._item; } set item(item) { this._item = item; this.itemChanges.next(item); this.clrDgSelectable = this._selectable; } get clrDgSelectable() { return !this.selection.isLocked(this.item); } set clrDgSelectable(value) { if (this.item) { this.selection.lockItem(this.item, value === 'false' || value === false); } // Store this value locally, to be initialized when item is initialized this._selectable = value; } /** * Indicates if the row is selected */ get selected() { if (this.selection.selectionType === SelectionType.None) { return this._selected; } else { return this.selection.isSelected(this.item); } } set selected(value) { if (this.selection.selectionType === SelectionType.None) { this._selected = value; } else { if (value && this.selection.selectionType === SelectionType.Multi) { this.rangeSelect(); } else { this.selection.rangeStart = null; } this.selection.setSelected(this.item, value); } } get expanded() { return this.expand.expanded; } set expanded(value) { this.expand.expanded = value; } get clrDgDetailOpenLabel() { return this._detailOpenLabel ? this._detailOpenLabel : this.commonStrings.keys.open; } set clrDgDetailOpenLabel(label) { this._detailOpenLabel = label; } get clrDgDetailCloseLabel() { return this._detailCloseLabel ? this._detailCloseLabel : this.commonStrings.keys.close; } set clrDgDetailCloseLabel(label) { this._detailCloseLabel = label; } // CDE-151: Rename this field to clrDgRowSelectionLabel in v16 get clrDgRowAriaLabel() { return this._rowAriaLabel ? this._rowAriaLabel : this.commonStrings.keys.select; } set clrDgRowAriaLabel(label) { this._rowAriaLabel = label; } get _view() { return this.wrappedInjector.get(WrappedRow, this.vcr).rowView; } ngOnInit() { this.wrappedInjector = new HostWrapper(WrappedRow, this.vcr); this.selection.lockItem(this.item, this.clrDgSelectable === false); } ngAfterContentInit() { this.dgCells.changes.subscribe(() => { this.dgCells.forEach(cell => { if (!cell._view.destroyed) { this._scrollableCells.insert(cell._view); } }); }); } ngAfterViewInit() { this.subscriptions.push(this.displayMode.view.subscribe(viewChange => { // Listen for view changes and move cells around depending on the current displayType // remove cell views from display view for (let i = this._scrollableCells.length; i > 0; i--) { this._scrollableCells.detach(); } // remove cell views from calculated view for (let i = this._calculatedCells.length; i > 0; i--) { this._calculatedCells.detach(); } if (viewChange === DatagridDisplayMode.CALCULATE) { this.displayCells = false; this.dgCells.forEach(cell => { if (!cell._view.destroyed) { this._calculatedCells.insert(cell._view); } }); } else { this.displayCells = true; this.dgCells.forEach(cell => { if (!cell._view.destroyed) { this._scrollableCells.insert(cell._view); } }); } }), this.expand.animate.subscribe(() => { this.expandAnimationTrigger = !this.expandAnimationTrigger; })); } ngOnDestroy() { this.subscriptions.forEach((sub) => sub.unsubscribe()); } toggle(selected = !this.selected) { if (selected !== this.selected) { this.selected = selected; this.selectedChanged.emit(selected); } } toggleExpand() { if (this.expand.expandable) { this.expandAnimation.updateStartHeight(); this.expanded = !this.expanded; this.expandedChange.emit(this.expanded); } } /** * The default behavior in Chrome and Firefox for shift-clicking on a label is to perform text-selection. * This prevents our intended range-selection, because this text-selection overrides our shift-click event. * We need to clear the stored selection range when shift-clicking. This will override the mostly unused shift-click * selection browser functionality, which is inconsistently implemented in browsers anyway. */ clearRanges(event) { if (event.shiftKey) { this.document.getSelection().removeAllRanges(); // Firefox is too persistent about its text-selection behaviour. So we need to add a preventDefault(); // We should not try to enforce this on the other browsers, though, because their toggle cycle does not get canceled by // the preventDefault() and they toggle the checkbox second time, effectively retrurning it to not-selected. if (window.navigator.userAgent.indexOf('Firefox') !== -1) { event.preventDefault(); this.toggle(true); } } } /** * @deprecated related to clrDgRowSelection, which is deprecated */ selectRow(selected = !this.selected, $event) { // The label also captures clicks that bubble up to the row event listener, causing // this handler to run twice. This exits early to prevent toggling the checkbox twice. if ($event.target.tagName === 'LABEL') { return; } if (this.selection.selectionType === this.SELECTION_TYPE.Single) { this.selection.currentSingle = this.item; } else { this.toggle(selected); } } rangeSelect() { const items = this.items.displayed; if (!items) { return; } const startIx = items.indexOf(this.selection.rangeStart); if (this.selection.rangeStart && this.selection.current.includes(this.selection.rangeStart) && this.selection.shiftPressed && startIx !== -1) { const endIx = items.indexOf(this.item); // Using Set to remove duplicates const newSelection = new Set(this.selection.current.concat(items.slice(Math.min(startIx, endIx), Math.max(startIx, endIx) + 1))); this.selection.clearSelection(); this.selection.current.push(...newSelection); } else { // page number has changed or // no Shift was pressed or // rangeStart not yet set this.selection.rangeStart = this.item; } } } ClrDatagridRow.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridRow, deps: [{ token: Selection }, { token: RowActionService }, { token: ExpandableRowsCount }, { token: DatagridIfExpandService }, { token: DetailService }, { token: DisplayModeService }, { token: i0.ViewContainerRef }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: ClrCommonStringsService }, { token: Items }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridRow.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridRow, selector: "clr-dg-row", inputs: { item: ["clrDgItem", "item"], clrDgSelectable: "clrDgSelectable", selected: ["clrDgSelected", "selected"], expanded: ["clrDgExpanded", "expanded"], clrDgDetailOpenLabel: "clrDgDetailOpenLabel", clrDgDetailCloseLabel: "clrDgDetailCloseLabel", clrDgRowAriaLabel: "clrDgRowAriaLabel" }, outputs: { selectedChanged: "clrDgSelectedChange", expandedChange: "clrDgExpandedChange" }, host: { attributes: { "role": "rowgroup" }, properties: { "class.datagrid-row": "true", "class.datagrid-selected": "selected", "attr.aria-owns": "id" } }, providers: [ DatagridIfExpandService, { provide: IfExpandService, useExisting: DatagridIfExpandService }, { provide: LoadingListener, useExisting: DatagridIfExpandService }, ], queries: [{ propertyName: "dgCells", predicate: ClrDatagridCell }], viewQueries: [{ propertyName: "expandAnimation", first: true, predicate: ClrExpandableAnimation, descendants: true }, { propertyName: "detailButton", first: true, predicate: ["detailButton"], descendants: true }, { propertyName: "_stickyCells", first: true, predicate: ["stickyCells"], descendants: true, read: ViewContainerRef }, { propertyName: "_scrollableCells", first: true, predicate: ["scrollableCells"], descendants: true, read: ViewContainerRef }, { propertyName: "_calculatedCells", first: true, predicate: ["calculatedCells"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "\n\n \n \n \n \n\n\n\n \n\n\n\n\n\n\n \n\n\n\n \n
\n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {{ commonStrings.keys.loading }}\n \n \n \n \n \n \n \n \n \n \n
\n
\n \n \n
\n \n \n \n
\n \n
\n\n\n", dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: ClrCheckbox, selector: "[clrCheckbox],[clrToggle]" }, { kind: "component", type: ClrCheckboxWrapper, selector: "clr-checkbox-wrapper,clr-toggle-wrapper" }, { kind: "directive", type: ClrRadio, selector: "[clrRadio]" }, { kind: "component", type: ClrRadioWrapper, selector: "clr-radio-wrapper" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClrExpandableAnimation, selector: "clr-expandable-animation", inputs: ["clrExpandTrigger"] }, { kind: "component", type: ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }, { kind: "directive", type: ClrDatagridSelectionCellDirective, selector: ".datagrid-select" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridRow, decorators: [{ type: Component, args: [{ selector: 'clr-dg-row', host: { '[class.datagrid-row]': 'true', '[class.datagrid-selected]': 'selected', '[attr.aria-owns]': 'id', role: 'rowgroup', }, providers: [ DatagridIfExpandService, { provide: IfExpandService, useExisting: DatagridIfExpandService }, { provide: LoadingListener, useExisting: DatagridIfExpandService }, ], template: "\n\n \n \n \n \n\n\n\n \n\n\n\n\n\n\n \n\n\n\n \n
\n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n {{ commonStrings.keys.loading }}\n \n \n \n \n \n \n \n \n \n \n
\n
\n \n \n
\n \n \n \n
\n \n
\n\n\n" }] }], ctorParameters: function () { return [{ type: Selection }, { type: RowActionService }, { type: ExpandableRowsCount }, { type: DatagridIfExpandService }, { type: DetailService }, { type: DisplayModeService }, { type: i0.ViewContainerRef }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: ClrCommonStringsService }, { type: Items }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { selectedChanged: [{ type: Output, args: ['clrDgSelectedChange'] }], expandedChange: [{ type: Output, args: ['clrDgExpandedChange'] }], dgCells: [{ type: ContentChildren, args: [ClrDatagridCell] }], expandAnimation: [{ type: ViewChild, args: [ClrExpandableAnimation] }], detailButton: [{ type: ViewChild, args: ['detailButton'] }], _stickyCells: [{ type: ViewChild, args: ['stickyCells', { read: ViewContainerRef }] }], _scrollableCells: [{ type: ViewChild, args: ['scrollableCells', { read: ViewContainerRef }] }], _calculatedCells: [{ type: ViewChild, args: ['calculatedCells', { read: ViewContainerRef }] }], item: [{ type: Input, args: ['clrDgItem'] }], clrDgSelectable: [{ type: Input, args: ['clrDgSelectable'] }], selected: [{ type: Input, args: ['clrDgSelected'] }], expanded: [{ type: Input, args: ['clrDgExpanded'] }], clrDgDetailOpenLabel: [{ type: Input }], clrDgDetailCloseLabel: [{ type: Input }], clrDgRowAriaLabel: [{ type: Input }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var DatagridColumnChanges; (function (DatagridColumnChanges) { DatagridColumnChanges[DatagridColumnChanges["WIDTH"] = 0] = "WIDTH"; DatagridColumnChanges[DatagridColumnChanges["HIDDEN"] = 1] = "HIDDEN"; })(DatagridColumnChanges || (DatagridColumnChanges = {})); const ALL_COLUMN_CHANGES = Object.keys(DatagridColumnChanges) .map(key => DatagridColumnChanges[key]) .filter(key => key === parseInt(key, 10)); // extracts only integer keys /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ColumnsService { constructor() { this.columns = []; this._cache = []; } get columnStates() { return this.columns.map(column => column.value); } get hasHideableColumns() { return this.columnStates.filter(state => state.hideable).length > 0; } cache() { this._cache = this.columns.map(subject => { const value = { ...subject.value }; delete value.changes; return value; }); } hasCache() { return !!this._cache.length; } resetToLastCache() { this._cache.forEach((state, index) => { // Just emit the exact value from the cache this.columns[index].next({ ...state, changes: ALL_COLUMN_CHANGES }); }); this._cache = []; } // Helper method to emit a change to a column only when there is an actual diff to process for that column emitStateChangeAt(columnIndex, diff) { if (!this.columns[columnIndex]) { return; } this.emitStateChange(this.columns[columnIndex], diff); } emitStateChange(column, diff) { column.next({ ...column.value, ...diff }); } } ColumnsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ColumnsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ColumnsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ColumnsService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ColumnsService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * This provider aggregates state changes from the various providers of the Datagrid */ class StateProvider { constructor(filters, sort, page, debouncer) { this.filters = filters; this.sort = sort; this.page = page; this.debouncer = debouncer; /** * The Observable that lets other classes subscribe to global state changes */ this.change = this.debouncer.change.pipe(map(() => this.state)); } /* * By making this a getter, we open the possibility for a setter in the future. * It's been requested a couple times. */ get state() { const state = {}; if (this.page.size > 0) { state.page = { from: this.page.firstItem, to: this.page.lastItem, size: this.page.size, current: this.page.current, }; } if (this.sort.comparator) { if (this.sort.comparator instanceof DatagridPropertyComparator) { /* * Special case for the default object property comparator, * we give the property name instead of the actual comparator. */ state.sort = { by: this.sort.comparator.prop, reverse: this.sort.reverse }; } else { state.sort = { by: this.sort.comparator, reverse: this.sort.reverse }; } } const activeFilters = this.filters.getActiveFilters(); if (activeFilters.length > 0) { state.filters = []; for (const filter of activeFilters) { if (filter.state) { state.filters.push(filter.state); } else { state.filters.push(filter); } } } return state; } } StateProvider.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StateProvider, deps: [{ token: FiltersProvider }, { token: Sort }, { token: Page }, { token: StateDebouncer }], target: i0.ɵɵFactoryTarget.Injectable }); StateProvider.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StateProvider }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: StateProvider, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: FiltersProvider }, { type: Sort }, { type: Page }, { type: StateDebouncer }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function getTabableItems(el) { const tabableSelector = [ 'a[href]', 'area[href]', 'input:not([disabled])', 'button:not([disabled])', 'select:not([disabled])', 'textarea:not([disabled])', 'iframe', 'object', 'embed', '*[tabindex]', '*[contenteditable=true]', '[role=button]:not([disabled])', ].join(','); return Array.from(el.querySelectorAll(tabableSelector)); } class KeyNavigationGridController { constructor(zone) { this.zone = zone; this.listenersAdded = false; this.destroy$ = new Subject(); this.config = { keyGridRows: '[role=row]:not(.datagrid-placeholder)', keyGridCells: '[role=gridcell]:not(.datagrid-hidden-column):not(.datagrid-placeholder-content), [role=columnheader]:not(.datagrid-hidden-column):not(.datagrid-placeholder-content), .datagrid-detail-caret', keyGrid: '[role=grid]', }; } get grid() { return this.host?.querySelector(this.config.keyGrid); } get rows() { return this.host?.querySelectorAll(this.config.keyGridRows); } get cells() { return this.host?.querySelectorAll(this.config.keyGridCells); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } addListeners() { if (this.listenersAdded) { return; } this.zone.runOutsideAngular(() => { fromEvent(this.grid, 'mousedown') .pipe(takeUntil(this.destroy$)) .subscribe((e) => { // preserve right click for context menus & keyboard mouse control https://apple.stackexchange.com/questions/32715/how-do-i-open-the-context-menu-from-a-mac-keyboard if (e.buttons === 1 && !e.ctrlKey) { const activeCell = this.cells ? Array.from(this.cells).find(c => c === e.target || c === e.target.closest(this.config.keyGridCells)) : null; if (activeCell) { this.setActiveCell(activeCell); } } }); fromEvent(this.grid, 'keydown') .pipe(takeUntil(this.destroy$)) .subscribe((e) => { // Skip column resize events if (e.target.classList.contains('drag-handle') && (e.code === 'ArrowLeft' || e.code === 'ArrowRight')) { return; } if (e.code === 'ArrowUp' || e.code === 'ArrowDown' || e.code === 'ArrowLeft' || e.code === 'ArrowRight' || e.code === 'End' || e.code === 'Home' || e.code === 'PageUp' || e.code === 'PageDown') { const { x, y } = this.getNextItemCoordinate(e); const activeItem = this.rows ? Array.from(this.rows[y].querySelectorAll(this.config.keyGridCells))[x] : null; if (activeItem) { this.setActiveCell(activeItem); } e.preventDefault(); } }); }); this.listenersAdded = true; } initializeKeyGrid(host) { this.host = host; this.addListeners(); this.resetKeyGrid(); } resetKeyGrid() { this.cells?.forEach((i) => i.setAttribute('tabindex', '-1')); const firstCell = this.cells ? this.cells[0] : null; firstCell?.setAttribute('tabindex', '0'); } setActiveCell(activeCell) { const prior = this.cells ? Array.from(this.cells).find(c => c.getAttribute('tabindex') === '0') : null; if (prior) { prior.setAttribute('tabindex', '-1'); } activeCell.setAttribute('tabindex', '0'); const items = getTabableItems(activeCell); const item = activeCell.getAttribute('role') !== 'columnheader' && items[0] ? items[0] : activeCell; item.focus(); } getNextItemCoordinate(e) { let currentCell = this.cells ? Array.from(this.cells).find(i => i.getAttribute('tabindex') === '0') : null; if (e.code === 'Tab') { currentCell = document.activeElement; } const currentRow = this.rows && currentCell ? Array.from(this.rows).find(r => r.contains(currentCell)) : null; const numOfRows = this.rows ? this.rows.length - 1 : 0; const numOfColumns = this.cells ? this.cells.length / this.rows.length - 1 : 0; let x = currentRow && currentCell ? Array.from(currentRow.querySelectorAll(this.config.keyGridCells)).indexOf(currentCell) : 0; let y = currentRow && currentCell && this.rows ? Array.from(this.rows).indexOf(currentRow) : 0; const dir = this.host.dir; const inlineStart = dir === 'rtl' ? 'ArrowRight' : 'ArrowLeft'; const inlineEnd = dir === 'rtl' ? 'ArrowLeft' : 'ArrowRight'; const itemsPerPage = Math.floor(this.host?.querySelector('.datagrid').clientHeight / this.rows[0].clientHeight) - 1 || 0; if (e.code === 'ArrowUp' && y !== 0) { y = y - 1; } else if (e.code === 'ArrowDown' && y < numOfRows) { y = y + 1; } else if (e.code === inlineStart && x !== 0) { x = x - 1; } else if (e.code === inlineEnd && x < numOfColumns) { x = x + 1; } else if (e.code === 'End') { x = numOfColumns; if (e.ctrlKey) { y = numOfRows; } } else if (e.code === 'Home') { x = 0; if (e.ctrlKey) { y = 0; } } else if (e.code === 'PageUp') { y = y - itemsPerPage > 0 ? y - itemsPerPage : 0; } else if (e.code === 'PageDown') { y = y + itemsPerPage < numOfRows ? y + itemsPerPage : numOfRows; } return { x, y }; } } KeyNavigationGridController.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: KeyNavigationGridController, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); KeyNavigationGridController.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: KeyNavigationGridController }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: KeyNavigationGridController, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.NgZone }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagrid { constructor(organizer, items, expandableRows, selection, rowActionService, stateProvider, displayMode, renderer, detailService, document, el, page, commonStrings, columnsService, keyNavigation, zone) { this.organizer = organizer; this.items = items; this.expandableRows = expandableRows; this.selection = selection; this.rowActionService = rowActionService; this.stateProvider = stateProvider; this.displayMode = displayMode; this.renderer = renderer; this.detailService = detailService; this.document = document; this.el = el; this.page = page; this.commonStrings = commonStrings; this.columnsService = columnsService; this.keyNavigation = keyNavigation; this.zone = zone; this.clrDgSingleSelectionAriaLabel = this.commonStrings.keys.singleSelectionAriaLabel; this.clrDgSingleActionableAriaLabel = this.commonStrings.keys.singleActionableAriaLabel; this.clrDetailExpandableAriaLabel = this.commonStrings.keys.detailExpandableAriaLabel; // Allows disabling of the auto focus on page/state changes (excludes focus management inside of popups) this.clrDgDisablePageFocus = false; this.selectedChanged = new EventEmitter(false); this.singleSelectedChanged = new EventEmitter(false); /** * Output emitted whenever the data needs to be refreshed, based on user action or external ones */ this.refresh = new EventEmitter(false); /* reference to the enum so that template can access */ this.SELECTION_TYPE = SelectionType; /** * Subscriptions to all the services and queries changes */ this._subscriptions = []; const datagridId = uniqueIdFactory(); this.selectAllId = 'clr-dg-select-all-' + datagridId; this.detailService.id = datagridId; } /** * Freezes the datagrid while data is loading */ get loading() { return this.items.loading; } set loading(value) { this.items.loading = value; } /** * Array of all selected items */ set selected(value) { if (value) { this.selection.selectionType = SelectionType.Multi; } else { this.selection.selectionType = SelectionType.None; } this.selection.updateCurrent(value, false); } /** * Selected item in single-select mode */ set singleSelected(value) { this.selection.selectionType = SelectionType.Single; // the clrDgSingleSelected is updated in one of two cases: // 1. an explicit value is passed // 2. is being set to null or undefined, where previously it had a value if (value) { this.selection.currentSingle = value; } else if (this.selection.currentSingle) { this.selection.currentSingle = null; } } set clrDgPreserveSelection(state) { this.selection.preserveSelection = state; } /** * @deprecated since 2.0, remove in 3.0 * * Selection/Deselection on row click mode */ set rowSelectionMode(value) { this.selection.rowSelectionMode = value; } set trackBy(value) { this.items.datagridTrackBy = value; } /** * Indicates if all currently displayed items are selected */ get allSelected() { return this.selection.isAllSelected(); } set allSelected(_value) { /** * This is a setter but we ignore the value. * It's strange, but it lets us have an indeterminate state where only * some of the items are selected. */ this.selection.toggleAll(); } ngAfterContentInit() { if (!this.items.smart) { this.items.all = this.rows.map((row) => row.item); } const rowItemsChanges = this.rows.changes.pipe(switchMap((rows) => merge( // immediate update of(rows.map(row => row.item)), // subsequent updates once per tick combineLatest(rows.map(row => row.itemChanges)).pipe(debounceTime(0))))); this._subscriptions.push(rowItemsChanges.subscribe(all => { if (!this.items.smart) { this.items.all = all; } }), this.rows.changes.subscribe(() => { // Remove any projected rows from the displayedRows container // Necessary with Ivy off. See https://github.com/vmware/clarity/issues/4692 for (let i = this._displayedRows.length - 1; i >= 0; i--) { if (this._displayedRows.get(i).destroyed) { this._displayedRows.remove(i); } } this.rows.forEach(row => { this._displayedRows.insert(row._view); }); // Try to update only when there is something cached and its open. if (this.detailService.state && this.detailService.isOpen) { const row = this.items.canTrackBy() ? this.rows.find(row => this.items.trackBy(row.item) === this.items.trackBy(this.detailService.state)) : undefined; /** * Reopen updated row or close it */ row ? this.detailService.open(row.item, row.detailButton.nativeElement) : this.detailService.close(); } })); } /** * Our setup happens in the view of some of our components, so we wait for it to be done before starting */ ngAfterViewInit() { this.keyNavigation.initializeKeyGrid(this.el.nativeElement); // TODO: determine if we can get rid of provider wiring in view init so that subscriptions can be done earlier this.refresh.emit(this.stateProvider.state); this._subscriptions.push(this.stateProvider.change.subscribe(state => this.refresh.emit(state)), this.selection.change.subscribe(s => { if (this.selection.selectionType === SelectionType.Single) { this.singleSelectedChanged.emit(s); } else if (this.selection.selectionType === SelectionType.Multi) { this.selectedChanged.emit(s); } }), // Reinitialize arrow key navigation on page changes this.page.change.subscribe(() => { this.keyNavigation.resetKeyGrid(); if (!this.clrDgDisablePageFocus) { this.datagridTable.nativeElement.focus(); } }), // Reinitialize arrow key navigation on hide/unhide columns combineLatest(this.columnsService.columns).subscribe(() => this.keyNavigation?.resetKeyGrid()), // A subscription that listens for displayMode changes on the datagrid this.displayMode.view.subscribe(viewChange => { // Remove any projected columns from the projectedDisplayColumns container for (let i = this._projectedDisplayColumns.length; i > 0; i--) { this._projectedDisplayColumns.detach(); } // Remove any projected columns from the projectedCalculationColumns container for (let i = this._projectedCalculationColumns.length; i > 0; i--) { this._projectedCalculationColumns.detach(); } // Remove any projected rows from the calculationRows container for (let i = this._calculationRows.length; i > 0; i--) { this._calculationRows.detach(); } // Remove any projected rows from the displayedRows container for (let i = this._displayedRows.length; i > 0; i--) { this._displayedRows.detach(); } if (viewChange === DatagridDisplayMode.DISPLAY) { // Set state, style for the datagrid to DISPLAY and insert row & columns into containers this.renderer.removeClass(this.el.nativeElement, 'datagrid-calculate-mode'); this.columns.forEach(column => { this._projectedDisplayColumns.insert(column._view); }); this.rows.forEach(row => { this._displayedRows.insert(row._view); }); } else { // Set state, style for the datagrid to CALCULATE and insert row & columns into containers this.renderer.addClass(this.el.nativeElement, 'datagrid-calculate-mode'); this.columns.forEach(column => { this._projectedCalculationColumns.insert(column._view); }); this.rows.forEach(row => { this._calculationRows.insert(row._view); }); } })); // We need to preserve shift state, so it can be used on selection change, regardless of the input event // that triggered the change. This helps us to easily resolve the k/b only case together with the mouse selection case. this.zone.runOutsideAngular(() => { this._subscriptions.push(fromEvent(this.document.body, 'keydown').subscribe((event) => { if (event.key === 'Shift') { this.selection.shiftPressed = true; } }), fromEvent(this.document.body, 'keyup').subscribe((event) => { if (event.key === 'Shift') { this.selection.shiftPressed = false; } })); }); } ngOnDestroy() { this._subscriptions.forEach((sub) => sub.unsubscribe()); } resize() { this.organizer.resize(); } /** * Public method to re-trigger the computation of displayed items manually */ dataChanged() { this.items.refresh(); } } ClrDatagrid.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagrid, deps: [{ token: DatagridRenderOrganizer }, { token: Items }, { token: ExpandableRowsCount }, { token: Selection }, { token: RowActionService }, { token: StateProvider }, { token: DisplayModeService }, { token: i0.Renderer2 }, { token: DetailService }, { token: DOCUMENT }, { token: i0.ElementRef }, { token: Page }, { token: ClrCommonStringsService }, { token: ColumnsService }, { token: KeyNavigationGridController }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagrid.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagrid, selector: "clr-datagrid", inputs: { clrDgSingleSelectionAriaLabel: "clrDgSingleSelectionAriaLabel", clrDgSingleActionableAriaLabel: "clrDgSingleActionableAriaLabel", clrDetailExpandableAriaLabel: "clrDetailExpandableAriaLabel", clrDgDisablePageFocus: "clrDgDisablePageFocus", loading: ["clrDgLoading", "loading"], selected: ["clrDgSelected", "selected"], singleSelected: ["clrDgSingleSelected", "singleSelected"], clrDgPreserveSelection: "clrDgPreserveSelection", rowSelectionMode: ["clrDgRowSelection", "rowSelectionMode"], trackBy: ["clrDgItemsTrackBy", "trackBy"] }, outputs: { selectedChanged: "clrDgSelectedChange", singleSelectedChanged: "clrDgSingleSelectedChange", refresh: "clrDgRefresh" }, host: { properties: { "class.datagrid-host": "true", "class.datagrid-detail-open": "detailService.isOpen" } }, providers: [ Selection, Sort, FiltersProvider, Page, Items, DatagridRenderOrganizer, RowActionService, ExpandableRowsCount, StateDebouncer, DetailService, StateProvider, TableSizeService, ColumnsService, DisplayModeService, KeyNavigationGridController, ], queries: [{ propertyName: "iterator", first: true, predicate: ClrDatagridItems, descendants: true }, { propertyName: "placeholder", first: true, predicate: ClrDatagridPlaceholder, descendants: true }, { propertyName: "columns", predicate: ClrDatagridColumn }, { propertyName: "rows", predicate: ClrDatagridRow }], viewQueries: [{ propertyName: "datagridTable", first: true, predicate: ["datagridTable"], descendants: true, read: ElementRef }, { propertyName: "scrollableColumns", first: true, predicate: ["scrollableColumns"], descendants: true, read: ViewContainerRef }, { propertyName: "_projectedDisplayColumns", first: true, predicate: ["projectedDisplayColumns"], descendants: true, read: ViewContainerRef }, { propertyName: "_projectedCalculationColumns", first: true, predicate: ["projectedCalculationColumns"], descendants: true, read: ViewContainerRef }, { propertyName: "_displayedRows", first: true, predicate: ["displayedRows"], descendants: true, read: ViewContainerRef }, { propertyName: "_calculationRows", first: true, predicate: ["calculationRows"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "\n\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n
\n \n \n \n \n
\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n
\n
\n \n
\n
\n
\n
\n \n \n \n \n
\n \n \n \n
\n Loading\n
\n \n \n\n\n
\n
\n \n
\n \n
\n", dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }, { kind: "component", type: ClrDatagridPlaceholder, selector: "clr-dg-placeholder" }, { kind: "directive", type: ClrDatagridSelectionCellDirective, selector: ".datagrid-select" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagrid, decorators: [{ type: Component, args: [{ selector: 'clr-datagrid', providers: [ Selection, Sort, FiltersProvider, Page, Items, DatagridRenderOrganizer, RowActionService, ExpandableRowsCount, StateDebouncer, DetailService, StateProvider, TableSizeService, ColumnsService, DisplayModeService, KeyNavigationGridController, ], host: { '[class.datagrid-host]': 'true', '[class.datagrid-detail-open]': 'detailService.isOpen', }, template: "\n\n\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n
\n \n \n \n \n
\n\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n
\n
\n \n
\n
\n
\n
\n \n \n \n \n
\n \n \n \n
\n Loading\n
\n \n \n\n\n
\n
\n \n
\n \n
\n" }] }], ctorParameters: function () { return [{ type: DatagridRenderOrganizer }, { type: Items }, { type: ExpandableRowsCount }, { type: Selection }, { type: RowActionService }, { type: StateProvider }, { type: DisplayModeService }, { type: i0.Renderer2 }, { type: DetailService }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }, { type: i0.ElementRef }, { type: Page }, { type: ClrCommonStringsService }, { type: ColumnsService }, { type: KeyNavigationGridController }, { type: i0.NgZone }]; }, propDecorators: { clrDgSingleSelectionAriaLabel: [{ type: Input }], clrDgSingleActionableAriaLabel: [{ type: Input }], clrDetailExpandableAriaLabel: [{ type: Input }], clrDgDisablePageFocus: [{ type: Input }], selectedChanged: [{ type: Output, args: ['clrDgSelectedChange'] }], singleSelectedChanged: [{ type: Output, args: ['clrDgSingleSelectedChange'] }], refresh: [{ type: Output, args: ['clrDgRefresh'] }], iterator: [{ type: ContentChild, args: [ClrDatagridItems] }], placeholder: [{ type: ContentChild, args: [ClrDatagridPlaceholder] }], columns: [{ type: ContentChildren, args: [ClrDatagridColumn] }], rows: [{ type: ContentChildren, args: [ClrDatagridRow] }], datagridTable: [{ type: ViewChild, args: ['datagridTable', { read: ElementRef }] }], scrollableColumns: [{ type: ViewChild, args: ['scrollableColumns', { read: ViewContainerRef }] }], _projectedDisplayColumns: [{ type: ViewChild, args: ['projectedDisplayColumns', { read: ViewContainerRef }] }], _projectedCalculationColumns: [{ type: ViewChild, args: ['projectedCalculationColumns', { read: ViewContainerRef }] }], _displayedRows: [{ type: ViewChild, args: ['displayedRows', { read: ViewContainerRef }] }], _calculationRows: [{ type: ViewChild, args: ['calculationRows', { read: ViewContainerRef }] }], loading: [{ type: Input, args: ['clrDgLoading'] }], selected: [{ type: Input, args: ['clrDgSelected'] }], singleSelected: [{ type: Input, args: ['clrDgSingleSelected'] }], clrDgPreserveSelection: [{ type: Input }], rowSelectionMode: [{ type: Input, args: ['clrDgRowSelection'] }], trackBy: [{ type: Input, args: ['clrDgItemsTrackBy'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridActionBar { } ClrDatagridActionBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridActionBar, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridActionBar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridActionBar, selector: "clr-dg-action-bar", host: { properties: { "class.datagrid-action-bar": "true" } }, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridActionBar, decorators: [{ type: Component, args: [{ selector: 'clr-dg-action-bar', template: ``, host: { '[class.datagrid-action-bar]': 'true' }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let clrDgActionId = 0; class ClrDatagridActionOverflow { constructor(rowActionService, commonStrings, platformId, zone, smartToggleService) { this.rowActionService = rowActionService; this.commonStrings = commonStrings; this.platformId = platformId; this.zone = zone; this.smartToggleService = smartToggleService; this.openChange = new EventEmitter(false); this.popoverId = uniqueIdFactory(); this.smartPosition = { axis: ClrAxis.HORIZONTAL, side: ClrSide.AFTER, anchor: ClrAlignment.CENTER, content: ClrAlignment.CENTER, }; this._open = false; this.subscriptions = []; this.rowActionService.register(); this.subscriptions.push(this.smartToggleService.openChange.subscribe(openState => { this.open = openState; }), this.smartToggleService.popoverVisible.subscribe(visible => { if (visible) { this.initializeFocus(); } })); this.popoverId = 'clr-action-menu' + clrDgActionId++; } get open() { return this._open; } set open(open) { const openState = !!open; if (!!openState !== this.open) { // prevents chocolate mess this.smartToggleService.open = openState; this.openChange.emit(openState); this._open = openState; } } ngOnDestroy() { this.rowActionService.unregister(); this.subscriptions.forEach(sub => sub.unsubscribe()); } closeOverflowContent(event) { this.smartToggleService.toggleWithEvent(event); } initializeFocus() { if (isPlatformBrowser(this.platformId)) { const buttons = Array.from(document.querySelectorAll('button.action-item')); if (buttons.length) { this.keyFocus.current = 0; this.keyFocus.focusableItems = buttons; this.keyFocus.focusCurrent(); } } } } ClrDatagridActionOverflow.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridActionOverflow, deps: [{ token: RowActionService }, { token: ClrCommonStringsService }, { token: PLATFORM_ID }, { token: i0.NgZone }, { token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridActionOverflow.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridActionOverflow, selector: "clr-dg-action-overflow", inputs: { buttonLabel: ["clrDgActionOverflowButtonLabel", "buttonLabel"], open: ["clrDgActionOverflowOpen", "open"] }, outputs: { openChange: "clrDgActionOverflowOpenChange" }, viewQueries: [{ propertyName: "keyFocus", first: true, predicate: ClrKeyFocus, descendants: true }], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }, { kind: "component", type: ClrKeyFocus, selector: "[clrKeyFocus]", inputs: ["clrDirection", "clrFocusOnLoad", "clrKeyFocus"], outputs: ["clrFocusChange"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridActionOverflow, decorators: [{ type: Component, args: [{ selector: 'clr-dg-action-overflow', hostDirectives: [ClrPopoverHostDirective], template: `
`, }] }], ctorParameters: function () { return [{ type: RowActionService }, { type: ClrCommonStringsService }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: i0.NgZone }, { type: ClrPopoverToggleService }]; }, propDecorators: { buttonLabel: [{ type: Input, args: ['clrDgActionOverflowButtonLabel'] }], openChange: [{ type: Output, args: ['clrDgActionOverflowOpenChange'] }], keyFocus: [{ type: ViewChild, args: [ClrKeyFocus] }], open: [{ type: Input, args: ['clrDgActionOverflowOpen'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const columnToggleTrackByFn = index => index; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridItemsTrackBy { constructor(_items) { this._items = _items; } set trackBy(value) { /** * This is a workaround to prevent the items `trackBy` function from * being replaced when the "manage columns" button is clicked. This is * not a complete solution. If there is another `ngForTrackBy` function * within the datagrid in application code, it could sill replace the * items `trackBy` function whether it is the row iterator or not. */ if (value === columnToggleTrackByFn) { return; } if (this._items) { this._items.iteratorTrackBy = value; } } } ClrDatagridItemsTrackBy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridItemsTrackBy, deps: [{ token: Items, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrDatagridItemsTrackBy.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridItemsTrackBy, selector: "[ngForTrackBy]", inputs: { trackBy: ["ngForTrackBy", "trackBy"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridItemsTrackBy, decorators: [{ type: Directive, args: [{ selector: '[ngForTrackBy]', }] }], ctorParameters: function () { return [{ type: Items, decorators: [{ type: Optional }] }]; }, propDecorators: { trackBy: [{ type: Input, args: ['ngForTrackBy'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridColumnToggleButton { constructor(commonStrings, columnsService) { this.commonStrings = commonStrings; this.columnsService = columnsService; this.allSelected = new EventEmitter(); } get clrAllSelected() { return this.allSelected.asObservable(); } get allHideablesVisible() { return this.hideableColumns().filter(column => column.value.hidden).length === 0; } selectAll() { this.hideableColumns().forEach(hideableColumn => this.columnsService.emitStateChange(hideableColumn, { hidden: false, changes: [DatagridColumnChanges.HIDDEN], })); this.allSelected.next(true); } hideableColumns() { return this.columnsService.columns.filter(column => column.value.hideable); } } ClrDatagridColumnToggleButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumnToggleButton, deps: [{ token: ClrCommonStringsService }, { token: ColumnsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridColumnToggleButton.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridColumnToggleButton, selector: "clr-dg-column-toggle-button", outputs: { clrAllSelected: "clrAllSelected" }, ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumnToggleButton, decorators: [{ type: Component, args: [{ selector: 'clr-dg-column-toggle-button', template: ` `, }] }], ctorParameters: function () { return [{ type: ClrCommonStringsService }, { type: ColumnsService }]; }, propDecorators: { clrAllSelected: [{ type: Output, args: ['clrAllSelected'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridColumnToggle { constructor(commonStrings, columnsService, popoverToggleService) { this.commonStrings = commonStrings; this.columnsService = columnsService; this.popoverId = uniqueIdFactory(); // Smart Popover this.smartPosition = { axis: ClrAxis.VERTICAL, side: ClrSide.BEFORE, anchor: ClrAlignment.START, content: ClrAlignment.START, }; // Without tracking the checkboxes get rerendered on model update, which leads // to loss of focus after checkbox toggle. this.trackByFn = columnToggleTrackByFn; this.subscription = popoverToggleService.openChange.subscribe(change => (this.openState = change)); } get allColumnsVisible() { return this._allColumnsVisible; } set allColumnsVisible(value) { this._allColumnsVisible = value; } get hideableColumnStates() { const hideables = this.columnsService.columns.filter(column => column.value.hideable); return hideables.map(column => column.value); } get hasOnlyOneVisibleColumn() { const nbNonHideableColumns = this.columnsService.columns.length - this.hideableColumnStates.length; // this should only return true when there is no non-hideable columns. return (nbNonHideableColumns === 0 && this.hideableColumnStates.filter(columnState => !columnState.hidden).length === 1); } ngOnDestroy() { this.subscription.unsubscribe(); } toggleColumnState(columnState, event) { const columnToToggle = this.columnsService.columns.filter(column => column.value === columnState)[0]; this.columnsService.emitStateChange(columnToToggle, { hidden: event, changes: [DatagridColumnChanges.HIDDEN], }); } toggleSwitchPanel() { this.openState = !this.openState; } allColumnsSelected() { this.allSelectedElement.nativeElement.focus(); } } ClrDatagridColumnToggle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumnToggle, deps: [{ token: ClrCommonStringsService }, { token: ColumnsService }, { token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridColumnToggle.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridColumnToggle, selector: "clr-dg-column-toggle", host: { properties: { "class.column-switch-wrapper": "true", "class.active": "openState" } }, viewQueries: [{ propertyName: "allSelectedElement", first: true, predicate: ["allSelected"], descendants: true, read: ElementRef }], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: ClrCheckbox, selector: "[clrCheckbox],[clrToggle]" }, { kind: "component", type: ClrCheckboxWrapper, selector: "clr-checkbox-wrapper,clr-toggle-wrapper" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ClrPopoverAnchor, selector: "[clrPopoverAnchor]" }, { kind: "directive", type: ClrPopoverCloseButton, selector: "[clrPopoverCloseButton]", outputs: ["clrPopoverOnCloseChange"] }, { kind: "directive", type: ClrPopoverOpenCloseButton, selector: "[clrPopoverOpenCloseButton]", outputs: ["clrPopoverOpenCloseChange"] }, { kind: "directive", type: ClrPopoverContent, selector: "[clrPopoverContent]", inputs: ["clrPopoverContent", "clrPopoverContentAt", "clrPopoverContentOutsideClickToClose", "clrPopoverContentScrollToClose"] }, { kind: "directive", type: ClrDatagridItemsTrackBy, selector: "[ngForTrackBy]", inputs: ["ngForTrackBy"] }, { kind: "component", type: ClrDatagridColumnToggleButton, selector: "clr-dg-column-toggle-button", outputs: ["clrAllSelected"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridColumnToggle, decorators: [{ type: Component, args: [{ selector: 'clr-dg-column-toggle', template: ` `, host: { '[class.column-switch-wrapper]': 'true', '[class.active]': 'openState' }, hostDirectives: [ClrPopoverHostDirective], }] }], ctorParameters: function () { return [{ type: ClrCommonStringsService }, { type: ColumnsService }, { type: ClrPopoverToggleService }]; }, propDecorators: { allSelectedElement: [{ type: ViewChild, args: ['allSelected', { read: ElementRef }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridDetailHeader { constructor(detailService, commonStrings) { this.detailService = detailService; this.commonStrings = commonStrings; } get titleId() { return `${this.detailService.id}-title`; } } ClrDatagridDetailHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridDetailHeader, deps: [{ token: DetailService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridDetailHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridDetailHeader, selector: "clr-dg-detail-header", host: { properties: { "class.datagrid-detail-header": "true" } }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridDetailHeader, decorators: [{ type: Component, args: [{ selector: 'clr-dg-detail-header', host: { '[class.datagrid-detail-header]': 'true', }, template: `
`, }] }], ctorParameters: function () { return [{ type: DetailService }, { type: ClrCommonStringsService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridDetail { constructor(detailService, commonStrings) { this.detailService = detailService; this.commonStrings = commonStrings; } close() { this.detailService.close(); } } ClrDatagridDetail.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridDetail, deps: [{ token: DetailService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridDetail.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridDetail, selector: "clr-dg-detail", host: { properties: { "class.datagrid-detail-pane": "true" } }, queries: [{ propertyName: "header", first: true, predicate: ClrDatagridDetailHeader, descendants: true }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridDetail, decorators: [{ type: Component, args: [{ selector: 'clr-dg-detail', host: { '[class.datagrid-detail-pane]': 'true', }, // We put the *ngIf on the cdkTrapFocus so it doesn't always exist on the page // have to test for presence of header for aria-describedby because it was causing unit tests to crash template: ` `, }] }], ctorParameters: function () { return [{ type: DetailService }, { type: ClrCommonStringsService }]; }, propDecorators: { header: [{ type: ContentChild, args: [ClrDatagridDetailHeader] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridDetailBody { } ClrDatagridDetailBody.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridDetailBody, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridDetailBody.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridDetailBody, selector: "clr-dg-detail-body", host: { properties: { "class.datagrid-detail-body": "true" } }, ngImport: i0, template: `
`, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridDetailBody, decorators: [{ type: Component, args: [{ selector: 'clr-dg-detail-body', template: `
`, host: { '[class.datagrid-detail-body]': 'true', }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * I don't think this deserves to be in IfExpanded itself, * so I'm adding a second directive on the same selector for now just for the datagrid */ class DatagridDetailRegisterer { constructor(expandableRowsCount) { this.expandableRowsCount = expandableRowsCount; if (this.expandableRowsCount) { this.expandableRowsCount.register(); } } ngOnDestroy() { if (this.expandableRowsCount) { this.expandableRowsCount.unregister(); } } } DatagridDetailRegisterer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridDetailRegisterer, deps: [{ token: ExpandableRowsCount, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); DatagridDetailRegisterer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridDetailRegisterer, selector: "[clrIfExpanded]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridDetailRegisterer, decorators: [{ type: Directive, args: [{ selector: '[clrIfExpanded]', }] }], ctorParameters: function () { return [{ type: ExpandableRowsCount, decorators: [{ type: Optional }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridFooter { constructor(selection, detailService, columnsService, commonStrings) { this.selection = selection; this.detailService = detailService; this.columnsService = columnsService; this.commonStrings = commonStrings; /* reference to the enum so that template can access */ this.SELECTION_TYPE = SelectionType; } get hasHideableColumns() { return this.columnsService.hasHideableColumns; } } ClrDatagridFooter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridFooter, deps: [{ token: Selection }, { token: DetailService }, { token: ColumnsService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridFooter.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridFooter, selector: "clr-dg-footer", host: { properties: { "class.datagrid-footer": "true" } }, ngImport: i0, template: `
{{ commonStrings.keys.selectedRows }}
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: ClrCheckbox, selector: "[clrCheckbox],[clrToggle]" }, { kind: "component", type: ClrCheckboxWrapper, selector: "clr-checkbox-wrapper,clr-toggle-wrapper" }, { kind: "component", type: ClrDatagridColumnToggle, selector: "clr-dg-column-toggle" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridFooter, decorators: [{ type: Component, args: [{ selector: 'clr-dg-footer', template: `
{{ commonStrings.keys.selectedRows }}
`, host: { '[class.datagrid-footer]': 'true', }, }] }], ctorParameters: function () { return [{ type: Selection }, { type: DetailService }, { type: ColumnsService }, { type: ClrCommonStringsService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const COLUMN_STATE = new InjectionToken('COLUMN_STATE'); function columnStateFactory() { return new BehaviorSubject({ changes: [], }); } const COLUMN_STATE_PROVIDER = { provide: COLUMN_STATE, useFactory: columnStateFactory, }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * * @description * A structural directive meant to be used inside a clr-dg-column component. * * * * User ID * * * * It sets up state and properties so that columns can be manges for hide/show by a service and an internal * datagrid toggle component. * */ class ClrDatagridHideableColumn { constructor(titleTemplateRef, viewContainerRef, columnsService, columnState) { this.titleTemplateRef = titleTemplateRef; this.viewContainerRef = viewContainerRef; this.columnsService = columnsService; this.columnState = columnState; this.hiddenChange = new EventEmitter(); this.subscriptions = []; this.viewContainerRef.createEmbeddedView(this.titleTemplateRef); if (!this.columnState) { throw new Error('The *clrDgHideableColumn directive can only be used inside of a clr-dg-column component.'); } } /** * * @description * Setter fn for the @Input with the same name as this structural directive. * It allows the user to pre-configure the column's hide/show state. { hidden: true } * It's more verbose but has more Clarity. * * @example * *clrDgHideableColumn * *clrDgHideableColumn={hidden: false} * *clrDgHideableColumn={hidden: true} * */ set clrDgHideableColumn(value) { if (typeof value === 'string') { this.clrDgHidden = false; return; } this.clrDgHidden = value && value.hidden ? value.hidden : false; } set clrDgHidden(hidden) { this._hidden = hidden ? hidden : false; this.columnsService.emitStateChange(this.columnState, { hidden: this._hidden, changes: [DatagridColumnChanges.HIDDEN], }); } ngOnInit() { this.columnsService.emitStateChange(this.columnState, { hideable: true, titleTemplateRef: this.titleTemplateRef, hidden: this._hidden, changes: [DatagridColumnChanges.HIDDEN], }); this.subscriptions.push(this.columnState.subscribe((state) => { if (state.changes && state.changes.indexOf(DatagridColumnChanges.HIDDEN) > -1) { this.hiddenChange.emit(state.hidden); // Can emit through @Output when desugared syntax is used } })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrDatagridHideableColumn.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridHideableColumn, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: ColumnsService }, { token: COLUMN_STATE, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); ClrDatagridHideableColumn.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridHideableColumn, selector: "[clrDgHideableColumn]", inputs: { clrDgHideableColumn: "clrDgHideableColumn", clrDgHidden: "clrDgHidden" }, outputs: { hiddenChange: "clrDgHiddenChange" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridHideableColumn, decorators: [{ type: Directive, args: [{ selector: '[clrDgHideableColumn]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: ColumnsService }, { type: i3.BehaviorSubject, decorators: [{ type: Optional }, { type: Inject, args: [COLUMN_STATE] }] }]; }, propDecorators: { hiddenChange: [{ type: Output, args: ['clrDgHiddenChange'] }], clrDgHideableColumn: [{ type: Input, args: ['clrDgHideableColumn'] }], clrDgHidden: [{ type: Input, args: ['clrDgHidden'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrIfDetail { constructor(templateRef, viewContainer, detailService) { this.templateRef = templateRef; this.viewContainer = viewContainer; this.detailService = detailService; this.stateChange = new EventEmitter(null); this.subscriptions = []; this.skip = false; // This keeps us from resetting the input and calling the toggle twice this.detailService.enabled = true; } set state(model) { if (!this.skip) { this.detailService.toggle(model); } this.skip = false; } ngOnInit() { this.subscriptions.push(this.detailService.stateChange.subscribe(state => { if (state === true) { this.togglePanel(true); } else { this.togglePanel(false); } })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } togglePanel(showPanel) { let stateChangeParams = null; if (showPanel === true) { const embeddedViewContext = { $implicit: this.detailService.state }; if (this.embeddedViewRef) { this.embeddedViewRef.context = embeddedViewContext; } else { this.embeddedViewRef = this.viewContainer.createEmbeddedView(this.templateRef, embeddedViewContext); } this.skip = true; stateChangeParams = this.detailService.state; } else { this.viewContainer.clear(); this.embeddedViewRef = null; } this.stateChange.emit(stateChangeParams); } } ClrIfDetail.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfDetail, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: DetailService }], target: i0.ɵɵFactoryTarget.Directive }); ClrIfDetail.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrIfDetail, selector: "[clrIfDetail]", inputs: { state: ["clrIfDetail", "state"] }, outputs: { stateChange: "clrIfDetailChange" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrIfDetail, decorators: [{ type: Directive, args: [{ selector: '[clrIfDetail]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: DetailService }]; }, propDecorators: { stateChange: [{ type: Output, args: ['clrIfDetailChange'] }], state: [{ type: Input, args: ['clrIfDetail'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridPageSize { constructor(page) { this.page = page; this.pageSizeOptionsId = uniqueIdFactory(); } ngOnInit() { if (!this.pageSizeOptions || this.pageSizeOptions.length === 0) { this.pageSizeOptions = [this.page.size]; } } } ClrDatagridPageSize.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridPageSize, deps: [{ token: Page }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridPageSize.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridPageSize, selector: "clr-dg-page-size", inputs: { pageSizeOptions: ["clrPageSizeOptions", "pageSizeOptions"], pageSizeOptionsId: ["clrPageSizeOptionsId", "pageSizeOptionsId"] }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: ClrLabel, selector: "label", inputs: ["for"] }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridPageSize, decorators: [{ type: Component, args: [{ selector: 'clr-dg-page-size', template: `
`, }] }], ctorParameters: function () { return [{ type: Page }]; }, propDecorators: { pageSizeOptions: [{ type: Input, args: ['clrPageSizeOptions'] }], pageSizeOptionsId: [{ type: Input, args: ['clrPageSizeOptionsId'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDatagridPagination { constructor(page, commonStrings, detailService) { this.page = page; this.commonStrings = commonStrings; this.detailService = detailService; this.currentChanged = new EventEmitter(false); this.page.activated = true; } /** * Page size */ get pageSize() { return this.page.size; } set pageSize(size) { // todo(v16): Remove this check. The property type used to be `string | number`. I kept this check to maintain the no-op if you pass a string. if (typeof size === 'number') { this.page.size = size; } } /** * Total items (needed to guess the last page) */ get totalItems() { return this.page.totalItems; } set totalItems(total) { // todo(v16): Remove this check. The property type used to be `string | number`. I kept this check to maintain the no-op if you pass a string. if (typeof total === 'number') { this.page.totalItems = total; } } /** * Last page */ get lastPage() { return this.page.last; } set lastPage(last) { // todo(v16): Remove this check. The property type used to be `string | number`. I kept this check to maintain the no-op if you pass a string. if (typeof last === 'number') { this.page.last = last; } } /** * Current page */ get currentPage() { return this.page.current; } set currentPage(page) { // todo(v16): Remove this check. The property type used to be `string | number`. I kept this check to maintain the no-op if you pass a string. if (typeof page === 'number') { this.page.current = page; } } /** * Index of the first item displayed on the current page, starting at 0, -1 if none displayed */ get firstItem() { return this.page.firstItem; } /** * Index of the last item displayed on the current page, starting at 0, -1 if none displayed */ get lastItem() { return this.page.lastItem; } /** * Conditionally adds page numbers before and after the current page */ get middlePages() { const middlePages = []; if (this.page.current > 1) { middlePages.push(this.page.current - 1); } middlePages.push(this.page.current); if (this.page.current < this.page.last) { middlePages.push(this.page.current + 1); } return middlePages; } /********** * Subscription to the Page service for page changes. * Note: this only emits after the datagrid is initialized/stabalized and the page changes. */ ngOnInit() { /* * Default page size is 10. * The reason we set it here and not in the provider itself is because * we don't want pagination if this component isn't present in the datagrid. */ if (!this.page.size) { this.page.size = 10; } this._pageSubscription = this.page.change.subscribe(current => this.currentChanged.emit(current)); } ngOnDestroy() { this.page.resetPageSize(true); if (this._pageSubscription) { this._pageSubscription.unsubscribe(); } } /** * Moves to the previous page if it exists */ previous() { this.page.previous(); } /** * Moves to the next page if it exists */ next() { this.page.next(); } verifyCurrentPage(event) { const parsed = parseInt(event.target.value, 10); if (parsed !== this.page.current) { event.target.value = this.page.current; } } /** * We only update the pagination's current page on enter. */ updateCurrentPage(event) { const parsed = parseInt(event.target.value, 10); // if the input value, is not a number, we don't update the page if (!isNaN(parsed)) { if (parsed < 1) { this.page.current = 1; } else if (parsed > this.page.last) { this.page.current = this.page.last; } else { this.page.current = parsed; } } /** * Set the input's value to the new current page. This is needed because the code * above may have changed the value from what the user entered in. */ this.currentPageInputRef.nativeElement.value = this.page.current; } } ClrDatagridPagination.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridPagination, deps: [{ token: Page }, { token: ClrCommonStringsService }, { token: DetailService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridPagination.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridPagination, selector: "clr-dg-pagination", inputs: { disableCurrentPageInput: ["clrDgPageInputDisabled", "disableCurrentPageInput"], pageSize: ["clrDgPageSize", "pageSize"], totalItems: ["clrDgTotalItems", "totalItems"], lastPage: ["clrDgLastPage", "lastPage"], currentPage: ["clrDgPage", "currentPage"] }, outputs: { currentChanged: "clrDgPageChange" }, host: { properties: { "class.pagination": "true" } }, queries: [{ propertyName: "_pageSizeComponent", first: true, predicate: ClrDatagridPageSize, descendants: true }], viewQueries: [{ propertyName: "currentPageInputRef", first: true, predicate: ["currentPageInput"], descendants: true }], ngImport: i0, template: `
{{ page.current }}  / {{ page.last }}
{{ page.firstItem + 1 }}-{{ page.lastItem + 1 }} / {{ page.totalItems }}
{{ page.current }}
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridPagination, decorators: [{ type: Component, args: [{ selector: 'clr-dg-pagination', template: `
{{ page.current }}  / {{ page.last }}
{{ page.firstItem + 1 }}-{{ page.lastItem + 1 }} / {{ page.totalItems }}
{{ page.current }}
`, host: { '[class.pagination]': 'true' }, }] }], ctorParameters: function () { return [{ type: Page }, { type: ClrCommonStringsService }, { type: DetailService }]; }, propDecorators: { disableCurrentPageInput: [{ type: Input, args: ['clrDgPageInputDisabled'] }], currentChanged: [{ type: Output, args: ['clrDgPageChange'] }], _pageSizeComponent: [{ type: ContentChild, args: [ClrDatagridPageSize] }], currentPageInputRef: [{ type: ViewChild, args: ['currentPageInput'] }], pageSize: [{ type: Input, args: ['clrDgPageSize'] }], totalItems: [{ type: Input, args: ['clrDgTotalItems'] }], lastPage: [{ type: Input, args: ['clrDgLastPage'] }], currentPage: [{ type: Input, args: ['clrDgPage'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Generic bland container serving various purposes for Datagrid. * For instance, it can help span a text over multiple rows in detail view. */ class ClrDatagridRowDetail { constructor(selection, rowActionService, expand, expandableRows, commonStrings) { this.selection = selection; this.rowActionService = rowActionService; this.expand = expand; this.expandableRows = expandableRows; this.commonStrings = commonStrings; this.replacedRow = false; /* reference to the enum so that template can access it */ this.SELECTION_TYPE = SelectionType; this.subscriptions = []; } set replace(value) { this.expand.setReplace(!!value); } get beginningOfExpandableContentAriaText() { return (this._beginningOfExpandableContentAriaText || `${this.commonStrings.keys.datagridExpandableBeginningOf} ${this.commonStrings.keys.datagridExpandableRowContent}`); } get endOfExpandableContentAriaText() { return (this._endOfExpandableContentAriaText || `${this.commonStrings.keys.datagridExpandableEndOf} ${this.commonStrings.keys.datagridExpandableRowContent}`); } ngAfterContentInit() { this.subscriptions.push(this.expand.replace.subscribe(replaceChange => { this.replacedRow = replaceChange; })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrDatagridRowDetail.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridRowDetail, deps: [{ token: Selection }, { token: RowActionService }, { token: DatagridIfExpandService }, { token: ExpandableRowsCount }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrDatagridRowDetail.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDatagridRowDetail, selector: "clr-dg-row-detail", inputs: { _beginningOfExpandableContentAriaText: ["clrRowDetailBeginningAriaText", "_beginningOfExpandableContentAriaText"], _endOfExpandableContentAriaText: ["clrRowDetailEndAriaText", "_endOfExpandableContentAriaText"], replace: ["clrDgReplace", "replace"] }, host: { attributes: { "role": "gridcell" }, properties: { "class.datagrid-row-flex": "true", "class.datagrid-row-detail": "true", "class.datagrid-container": "cells.length === 0", "attr.id": "expand.expandableId" } }, queries: [{ propertyName: "cells", predicate: ClrDatagridCell }], ngImport: i0, template: `
{{ beginningOfExpandableContentAriaText }} {{ commonStrings.keys.datagridExpandableRowsHelperText }}
{{ endOfExpandableContentAriaText }}
`, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridRowDetail, decorators: [{ type: Component, args: [{ selector: 'clr-dg-row-detail', template: `
{{ beginningOfExpandableContentAriaText }} {{ commonStrings.keys.datagridExpandableRowsHelperText }}
{{ endOfExpandableContentAriaText }}
`, host: { '[class.datagrid-row-flex]': 'true', '[class.datagrid-row-detail]': 'true', '[class.datagrid-container]': 'cells.length === 0', '[attr.id]': 'expand.expandableId', role: 'gridcell', }, }] }], ctorParameters: function () { return [{ type: Selection }, { type: RowActionService }, { type: DatagridIfExpandService }, { type: ExpandableRowsCount }, { type: ClrCommonStringsService }]; }, propDecorators: { _beginningOfExpandableContentAriaText: [{ type: Input, args: ['clrRowDetailBeginningAriaText'] }], _endOfExpandableContentAriaText: [{ type: Input, args: ['clrRowDetailEndAriaText'] }], cells: [{ type: ContentChildren, args: [ClrDatagridCell] }], replace: [{ type: Input, args: ['clrDgReplace'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // @TODO The top two are not used now, which is probably a performance drag that was broken along the way. // There was a previous pattern to hide everything to do computation then display, for Firefox, needs revisiting. const NO_LAYOUT_CLASS = 'datagrid-no-layout'; const COMPUTE_WIDTH_CLASS = 'datagrid-computing-columns-width'; const STRICT_WIDTH_CLASS = 'datagrid-fixed-width'; const HIDDEN_COLUMN_CLASS = 'datagrid-hidden-column'; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridCellRenderer { constructor(el, renderer, organizer) { this.el = el; this.renderer = renderer; this.subscriptions = []; this.subscriptions.push(organizer.filterRenderSteps(DatagridRenderStep.CLEAR_WIDTHS).subscribe(() => this.clearWidth())); } // @TODO(JEREMY) Work out how to dedupe some of this code between header and cell renderers set columnState(columnState) { if (this.stateSubscription) { this.stateSubscription.unsubscribe(); } this.runAllChanges = ALL_COLUMN_CHANGES; this.stateSubscription = columnState.subscribe(state => this.stateChanges(state)); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); if (this.stateSubscription) { this.stateSubscription.unsubscribe(); } } stateChanges(state) { if (this.runAllChanges) { state.changes = this.runAllChanges; delete this.runAllChanges; } if (state.changes && state.changes.length) { state.changes.forEach(change => { switch (change) { case DatagridColumnChanges.WIDTH: this.setWidth(state); break; case DatagridColumnChanges.HIDDEN: this.setHidden(state); break; default: break; } }); } } clearWidth() { this.renderer.removeClass(this.el.nativeElement, STRICT_WIDTH_CLASS); this.renderer.setStyle(this.el.nativeElement, 'width', null); } setWidth(state) { if (state.strictWidth) { this.renderer.addClass(this.el.nativeElement, STRICT_WIDTH_CLASS); } else { this.renderer.removeClass(this.el.nativeElement, STRICT_WIDTH_CLASS); } this.renderer.setStyle(this.el.nativeElement, 'width', state.width + 'px'); } setHidden(state) { if (state.hidden) { this.renderer.addClass(this.el.nativeElement, HIDDEN_COLUMN_CLASS); } else { this.renderer.removeClass(this.el.nativeElement, HIDDEN_COLUMN_CLASS); } } } DatagridCellRenderer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridCellRenderer, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DatagridRenderOrganizer }], target: i0.ɵɵFactoryTarget.Directive }); DatagridCellRenderer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridCellRenderer, selector: "clr-dg-cell", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridCellRenderer, decorators: [{ type: Directive, args: [{ selector: 'clr-dg-cell', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DatagridRenderOrganizer }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridHeaderRenderer { constructor(el, renderer, organizer, domAdapter, columnResizerService, columnsService, columnState) { this.el = el; this.renderer = renderer; this.organizer = organizer; this.domAdapter = domAdapter; this.columnResizerService = columnResizerService; this.columnsService = columnsService; this.columnState = columnState; this.resizeEmitter = new EventEmitter(); /** * Indicates if the column has a strict width, so it doesn't shrink or expand based on the content. */ this.widthSet = false; this.autoSet = false; this.subscriptions = []; this.subscriptions.push(this.organizer.filterRenderSteps(DatagridRenderStep.CLEAR_WIDTHS).subscribe(() => this.clearWidth())); this.subscriptions.push(columnState.subscribe(state => this.stateChanges(state))); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } getColumnWidthState() { const strictWidth = this.detectStrictWidth(); return { width: this.computeWidth(strictWidth), strictWidth: strictWidth, }; } setColumnState(index) { this.columnsService.columns[index] = this.columnState; } stateChanges(state) { if (state.changes && state.changes.length) { state.changes.forEach(change => { switch (change) { case DatagridColumnChanges.WIDTH: this.setWidth(state); break; case DatagridColumnChanges.HIDDEN: this.setHidden(state); break; default: break; } }); } } clearWidth() { // remove the width only if we set it, and it is not changed by dragging. if (this.widthSet && !this.columnResizerService.resizedBy) { this.renderer.setStyle(this.el.nativeElement, 'width', null); } if (this.autoSet) { this.renderer.removeClass(this.el.nativeElement, STRICT_WIDTH_CLASS); } } detectStrictWidth() { if (this.columnResizerService.resizedBy) { return this.columnResizerService.widthAfterResize; } else if (this.autoSet) { return 0; } else { return this.domAdapter.userDefinedWidth(this.el.nativeElement); } } computeWidth(strictWidth) { let width = strictWidth; if (!width) { width = this.domAdapter.scrollWidth(this.el.nativeElement); } return width; } setWidth(state) { if (state.strictWidth) { if (this.columnResizerService.resizedBy) { this.resizeEmitter.emit(state.width); this.renderer.setStyle(this.el.nativeElement, 'width', state.width + 'px'); this.widthSet = false; } // Don't set width if there is a user-defined one. Just add the strict width class. this.renderer.addClass(this.el.nativeElement, STRICT_WIDTH_CLASS); this.autoSet = false; } else { this.renderer.removeClass(this.el.nativeElement, STRICT_WIDTH_CLASS); this.renderer.setStyle(this.el.nativeElement, 'width', state.width + 'px'); this.widthSet = true; this.autoSet = true; } } setHidden(state) { if (state.hidden) { this.renderer.addClass(this.el.nativeElement, HIDDEN_COLUMN_CLASS); } else { this.renderer.removeClass(this.el.nativeElement, HIDDEN_COLUMN_CLASS); } } } DatagridHeaderRenderer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridHeaderRenderer, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DatagridRenderOrganizer }, { token: DomAdapter }, { token: ColumnResizerService }, { token: ColumnsService }, { token: COLUMN_STATE }], target: i0.ɵɵFactoryTarget.Directive }); DatagridHeaderRenderer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridHeaderRenderer, selector: "clr-dg-column", outputs: { resizeEmitter: "clrDgColumnResize" }, providers: [ColumnResizerService, COLUMN_STATE_PROVIDER], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridHeaderRenderer, decorators: [{ type: Directive, args: [{ selector: 'clr-dg-column', providers: [ColumnResizerService, COLUMN_STATE_PROVIDER], }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DatagridRenderOrganizer }, { type: DomAdapter }, { type: ColumnResizerService }, { type: ColumnsService }, { type: i3.BehaviorSubject, decorators: [{ type: Inject, args: [COLUMN_STATE] }] }]; }, propDecorators: { resizeEmitter: [{ type: Output, args: ['clrDgColumnResize'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class NoopDomAdapter { userDefinedWidth(_element) { return 0; } scrollBarWidth(_element) { return 0; } scrollWidth(_element) { return 0; } computedHeight(_element) { return 0; } clientRect(_element) { return { top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0, }; } minWidth(_element) { return 0; } focus(_element) { // Do nothing } } NoopDomAdapter.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NoopDomAdapter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); NoopDomAdapter.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NoopDomAdapter }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NoopDomAdapter, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DatagridRowRenderer { constructor(columnsService) { this.columnsService = columnsService; this.subscriptions = []; } ngAfterContentInit() { this.setColumnState(); // case #3 and #4 this.subscriptions.push(this.cells.changes.subscribe(() => { this.setColumnState(); // case #2 // Note on case #2: In the case of dynamic columns, when one column (header/cell together) gets deleted, // this.cells.changes emits before this.columnsService.columns gets updated in MainRenderer // when this.headers.changes emits as well. So that means there will be n+1 column state providers // when this.cells.changes emits. Hence, we should quit earlier there. But this method will be called // right after again when this.headers.changes emits. By then, there will be the same number of column state // providers as column headers. })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } setColumnState() { // This method runs in four cases: // 1. When the initial rows appear on the first page. // In this case, the method will be called in DatagridMainRenderer. // 2. When columns (corresponding header/cells) get added and deleted. // In this case, the method will be called in DatagridMainRenderer. (Read the note on this case above). // 3. When rows load asynchronously. // In this case, the method will be called in this class. // 4. When rows load after switching pages. // In this case, the method will be called in this class (Basically, same as the case 3). if (this.cells.length === this.columnsService.columns.length) { this.cells.forEach((cell, index) => { if (this.columnsService.columns[index]) { cell.columnState = this.columnsService.columns[index]; } }); } } } DatagridRowRenderer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridRowRenderer, deps: [{ token: ColumnsService }], target: i0.ɵɵFactoryTarget.Directive }); DatagridRowRenderer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridRowRenderer, selector: "clr-dg-row, clr-dg-row-detail", queries: [{ propertyName: "cells", predicate: DatagridCellRenderer }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridRowRenderer, decorators: [{ type: Directive, args: [{ selector: 'clr-dg-row, clr-dg-row-detail', }] }], ctorParameters: function () { return [{ type: ColumnsService }]; }, propDecorators: { cells: [{ type: ContentChildren, args: [DatagridCellRenderer] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // Fixes build error // @dynamic (https://github.com/angular/angular/issues/19698#issuecomment-338340211) const domAdapterFactory = (platformId) => { if (isPlatformBrowser(platformId)) { return new DomAdapter(); } else { return new NoopDomAdapter(); } }; // Fixes build error // @dynamic (https://github.com/angular/angular/issues/19698#issuecomment-338340211) class DatagridMainRenderer { constructor(organizer, items, page, domAdapter, el, renderer, detailService, tableSizeService, columnsService, ngZone) { this.organizer = organizer; this.items = items; this.page = page; this.domAdapter = domAdapter; this.el = el; this.renderer = renderer; this.detailService = detailService; this.tableSizeService = tableSizeService; this.columnsService = columnsService; this.ngZone = ngZone; this._heightSet = false; this.shouldStabilizeColumns = true; this.subscriptions = []; /** * Indicates if we want to re-compute columns width. This should only happen: * 1) When headers change, with columns being added or removed * 2) When rows are lazily loaded for the first time */ this.columnsSizesStable = false; this.subscriptions.push(this.organizer .filterRenderSteps(DatagridRenderStep.COMPUTE_COLUMN_WIDTHS) .subscribe(() => this.computeHeadersWidth())); this.subscriptions.push(this.page.sizeChange.subscribe(() => { if (this._heightSet) { this.resetDatagridHeight(); } })); this.subscriptions.push(this.detailService.stateChange.subscribe(state => this.toggleDetailPane(state))); this.subscriptions.push(this.items.change.subscribe(() => (this.shouldStabilizeColumns = true))); } ngAfterContentInit() { this.setupColumns(); this.subscriptions.push(this.headers.changes.subscribe(() => { // TODO: only re-stabilize if a column was added or removed. Reordering is fine. // Need to setup columns before stabalizing them this.setupColumns(); this.columnsSizesStable = false; this.stabilizeColumns(); })); } // Initialize and set Table width for horizontal scrolling here. ngAfterViewInit() { this.tableSizeService.table = this.el; } ngAfterViewChecked() { if (this.shouldStabilizeColumns) { this.stabilizeColumns(); } if (this.shouldComputeHeight()) { this.ngZone.runOutsideAngular(() => { setTimeout(() => { this.computeDatagridHeight(); }); }); } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } toggleDetailPane(state) { if (this.headers) { if (state && !this.columnsService.hasCache()) { this.columnsService.cache(); this.headers.forEach((_header, index) => { if (index > 0) { this.columnsService.emitStateChangeAt(index, { changes: [DatagridColumnChanges.HIDDEN], hidden: state, }); } }); } else if (!state) { this.columnsService.resetToLastCache(); } } } setupColumns() { this.headers.forEach((header, index) => header.setColumnState(index)); this.columnsService.columns.splice(this.headers.length); // Trim any old columns this.rows.forEach(row => row.setColumnState()); } shouldComputeHeight() { if (!this._heightSet && this.page.size > 0) { if (this.items.displayed.length === this.page.size) { return true; } } return false; } /** * Computes the height of the datagrid. * * NOTE: We had to choose to set the height instead of the min-height because * IE 11 requires the height on the parent for the children flex grow/shrink properties to work. * When we used min-height, 1 1 auto doesn't used to work in IE11 :-( * But this doesn't affect the fix. It works in both fixed & variable height datagrids. * * Refer: http://stackoverflow.com/questions/24396205/flex-grow-not-working-in-internet-explorer-11-0 */ computeDatagridHeight() { // IE doesn't return correct value for getComputedStyle(element).getPropertyValue("height") const value = this.domAdapter.clientRect(this.el.nativeElement).height; this.renderer.setStyle(this.el.nativeElement, 'height', value + 'px'); this._heightSet = true; } resetDatagridHeight() { this.renderer.setStyle(this.el.nativeElement, 'height', ''); this._heightSet = false; } /** * Makes each header compute its width. */ computeHeadersWidth() { const nbColumns = this.headers.length; let allStrict = true; this.headers.forEach((header, index) => { // On the last header column check whether all columns have strict widths. // If all columns have strict widths, remove the strict width from the last column and make it the column's // minimum width so that when all previous columns shrink, it will get a flexible width and cover the empty // gap in the Datagrid. const state = { changes: [DatagridColumnChanges.WIDTH], ...header.getColumnWidthState(), }; if (!state.strictWidth) { allStrict = false; } if (nbColumns === index + 1 && allStrict) { state.strictWidth = 0; } this.columnsService.emitStateChangeAt(index, state); }); } /** * Triggers a whole re-rendring cycle to set column sizes, if needed. */ stabilizeColumns() { this.shouldStabilizeColumns = false; if (this.columnsSizesStable) { // Nothing to do. return; } // Resize when the rows are loaded. if (this.items.displayed.length > 0) { this.organizer.resize(); this.columnsSizesStable = true; } } } DatagridMainRenderer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridMainRenderer, deps: [{ token: DatagridRenderOrganizer }, { token: Items }, { token: Page }, { token: DomAdapter }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DetailService }, { token: TableSizeService }, { token: ColumnsService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); DatagridMainRenderer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: DatagridMainRenderer, selector: "clr-datagrid", providers: [{ provide: DomAdapter, useFactory: domAdapterFactory, deps: [PLATFORM_ID] }], queries: [{ propertyName: "headers", predicate: DatagridHeaderRenderer }, { propertyName: "rows", predicate: DatagridRowRenderer, descendants: true }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DatagridMainRenderer, decorators: [{ type: Directive, args: [{ selector: 'clr-datagrid', providers: [{ provide: DomAdapter, useFactory: domAdapterFactory, deps: [PLATFORM_ID] }], }] }], ctorParameters: function () { return [{ type: DatagridRenderOrganizer }, { type: Items }, { type: Page }, { type: DomAdapter }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DetailService }, { type: TableSizeService }, { type: ColumnsService }, { type: i0.NgZone }]; }, propDecorators: { headers: [{ type: ContentChildren, args: [DatagridHeaderRenderer] }], rows: [{ type: ContentChildren, args: [DatagridRowRenderer, { descendants: true }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_DATAGRID_DIRECTIVES = [ // Core ClrDatagrid, ClrDatagridActionBar, ClrDatagridActionOverflow, ClrDatagridCell, ClrDatagridColumn, ClrDatagridColumnSeparator, ClrDatagridDetail, ClrDatagridDetailBody, ClrDatagridDetailHeader, ClrDatagridFilter, ClrDatagridFooter, ClrDatagridHideableColumn, ClrDatagridItems, ClrDatagridItemsTrackBy, ClrDatagridPageSize, ClrDatagridPagination, ClrDatagridPlaceholder, ClrDatagridRow, ClrDatagridRowDetail, ClrDatagridSelectionCellDirective, ClrIfDetail, DatagridDetailRegisterer, WrappedCell, WrappedColumn, WrappedRow, // Renderers DatagridCellRenderer, DatagridHeaderRenderer, DatagridMainRenderer, DatagridRowRenderer, // Chocolate ActionableOompaLoompa, DatagridWillyWonka, ExpandableOompaLoompa, // Built-in shortcuts DatagridNumericFilter, DatagridStringFilter, ]; const CLR_DATAGRID_INTERNAL_DIRECTIVES = [ClrDatagridColumnToggle, ClrDatagridColumnToggleButton]; class ClrDatagridModule { constructor() { ClarityIcons.addIcons(ellipsisVerticalIcon, viewColumnsIcon, windowCloseIcon, arrowIcon, timesIcon, stepForward2Icon, angleDoubleIcon, filterGridCircleIcon, filterGridIcon); } } ClrDatagridModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrDatagridModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridModule, declarations: [ // Core ClrDatagrid, ClrDatagridActionBar, ClrDatagridActionOverflow, ClrDatagridCell, ClrDatagridColumn, ClrDatagridColumnSeparator, ClrDatagridDetail, ClrDatagridDetailBody, ClrDatagridDetailHeader, ClrDatagridFilter, ClrDatagridFooter, ClrDatagridHideableColumn, ClrDatagridItems, ClrDatagridItemsTrackBy, ClrDatagridPageSize, ClrDatagridPagination, ClrDatagridPlaceholder, ClrDatagridRow, ClrDatagridRowDetail, ClrDatagridSelectionCellDirective, ClrIfDetail, DatagridDetailRegisterer, WrappedCell, WrappedColumn, WrappedRow, // Renderers DatagridCellRenderer, DatagridHeaderRenderer, DatagridMainRenderer, DatagridRowRenderer, // Chocolate ActionableOompaLoompa, DatagridWillyWonka, ExpandableOompaLoompa, // Built-in shortcuts DatagridNumericFilter, DatagridStringFilter, ClrDatagridColumnToggle, ClrDatagridColumnToggleButton], imports: [CommonModule, CdkDragModule, CdkTrapFocusModule, ClrIconModule, ClrFormsModule, FormsModule, ClrLoadingModule, ClrConditionalModule, ClrOutsideClickModule, ClrExpandableAnimationModule, ClrSpinnerModule, ClrPopoverModuleNext, ClrKeyFocusModule], exports: [ // Core ClrDatagrid, ClrDatagridActionBar, ClrDatagridActionOverflow, ClrDatagridCell, ClrDatagridColumn, ClrDatagridColumnSeparator, ClrDatagridDetail, ClrDatagridDetailBody, ClrDatagridDetailHeader, ClrDatagridFilter, ClrDatagridFooter, ClrDatagridHideableColumn, ClrDatagridItems, ClrDatagridItemsTrackBy, ClrDatagridPageSize, ClrDatagridPagination, ClrDatagridPlaceholder, ClrDatagridRow, ClrDatagridRowDetail, ClrDatagridSelectionCellDirective, ClrIfDetail, DatagridDetailRegisterer, WrappedCell, WrappedColumn, WrappedRow, // Renderers DatagridCellRenderer, DatagridHeaderRenderer, DatagridMainRenderer, DatagridRowRenderer, // Chocolate ActionableOompaLoompa, DatagridWillyWonka, ExpandableOompaLoompa, // Built-in shortcuts DatagridNumericFilter, DatagridStringFilter] }); ClrDatagridModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridModule, imports: [CommonModule, CdkDragModule, CdkTrapFocusModule, ClrIconModule, ClrFormsModule, FormsModule, ClrLoadingModule, ClrConditionalModule, ClrOutsideClickModule, ClrExpandableAnimationModule, ClrSpinnerModule, ClrPopoverModuleNext, ClrKeyFocusModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDatagridModule, decorators: [{ type: NgModule, args: [{ imports: [ CommonModule, CdkDragModule, CdkTrapFocusModule, ClrIconModule, ClrFormsModule, FormsModule, ClrLoadingModule, ClrConditionalModule, ClrOutsideClickModule, ClrExpandableAnimationModule, ClrSpinnerModule, ClrPopoverModuleNext, ClrKeyFocusModule, ], declarations: [CLR_DATAGRID_DIRECTIVES, CLR_DATAGRID_INTERNAL_DIRECTIVES], exports: [CLR_DATAGRID_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStackViewCustomTags { } ClrStackViewCustomTags.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewCustomTags, deps: [], target: i0.ɵɵFactoryTarget.Directive }); ClrStackViewCustomTags.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrStackViewCustomTags, selector: "clr-stack-content", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewCustomTags, decorators: [{ type: Directive, args: [{ selector: 'clr-stack-content', }] }] }); class ClrStackViewLabel { constructor() { this._generatedId = null; this._id = null; } get id() { return this._id; } set id(val) { if (typeof val === 'string' && val !== '') { this._id = val; } else { this._id = this._generatedId + ''; } } ngOnInit() { this._generatedId = 'clr-stack-label-' + uniqueIdFactory(); if (!this.id) { this._id = this._generatedId + ''; } } } ClrStackViewLabel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewLabel, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrStackViewLabel.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrStackViewLabel, selector: "clr-stack-label", inputs: { id: "id" }, host: { properties: { "attr.id": "id" } }, ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewLabel, decorators: [{ type: Component, args: [{ selector: 'clr-stack-label', template: '', host: { '[attr.id]': 'id', }, }] }], propDecorators: { id: [{ type: Input }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStackBlock { /* * This would be more efficient with @ContentChildren, with the parent ClrStackBlock * querying for children StackBlocks, but this feature is not available when downgrading * the component for Angular 1. */ constructor(parent, commonStrings) { this.parent = parent; this.commonStrings = commonStrings; this.expanded = false; this.expandable = false; this.expandedChange = new EventEmitter(false); this.focused = false; this.uniqueId = uniqueIdFactory(); this._changedChildren = 0; this._fullyInitialized = false; this._changed = false; if (parent) { parent.addChild(); } } set setChangedValue(value) { this._changed = value; if (this.parent && this._fullyInitialized) { if (value) { this.parent._changedChildren++; } else { this.parent._changedChildren--; } } } get getChangedValue() { return this._changed || (this._changedChildren > 0 && !this.expanded); } get onStackLabelFocus() { return this.expandable && !this.expanded && this.focused; } get labelledById() { return this.stackBlockTitle.id; } get headingLevel() { if (this.ariaLevel) { return this.ariaLevel + ''; } return this.parent ? '4' : '3'; } get caretDirection() { return this.expanded ? 'down' : 'right'; } get role() { return this.expandable ? 'button' : null; } get tabIndex() { return this.expandable ? '0' : null; } get ariaExpanded() { if (!this.expandable) { return null; } else { return this.expanded ? 'true' : 'false'; } } ngOnInit() { // in order to access the parent ClrStackBlock's properties, // the child ClrStackBlock has to be fully initialized at first. this._fullyInitialized = true; } addChild() { this.expandable = true; } toggleExpand(event) { if (eventIsInputEvent(event)) { return; } if (this.expandable) { this.expanded = !this.expanded; this.expandedChange.emit(this.expanded); } } getStackChildrenId() { return this.expanded ? `clr-stack-children-${this.uniqueId}` : null; } preventDefaultIfNotInputEvent(event) { if (eventIsInputEvent(event)) { return; } event.preventDefault(); } } ClrStackBlock.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackBlock, deps: [{ token: ClrStackBlock, optional: true, skipSelf: true }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrStackBlock.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrStackBlock, selector: "clr-stack-block", inputs: { expanded: ["clrSbExpanded", "expanded"], expandable: ["clrSbExpandable", "expandable"], ariaLevel: ["clrStackViewLevel", "ariaLevel"], setChangedValue: ["clrSbNotifyChange", "setChangedValue"] }, outputs: { expandedChange: "clrSbExpandedChange" }, host: { properties: { "class.stack-block": "true", "attr.role": "\"heading\"", "attr.aria-level": "headingLevel", "class.stack-block-expanded": "this.expanded", "class.stack-block-expandable": "this.expandable", "class.stack-block-changed": "this.getChangedValue", "class.on-focus": "this.onStackLabelFocus" } }, queries: [{ propertyName: "stackBlockTitle", first: true, predicate: ClrStackViewLabel, descendants: true }], ngImport: i0, template: `
{{ commonStrings.keys.stackViewChanged }}
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrExpandableAnimation, selector: "clr-expandable-animation", inputs: ["clrExpandTrigger"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackBlock, decorators: [{ type: Component, args: [{ selector: 'clr-stack-block', template: `
{{ commonStrings.keys.stackViewChanged }}
`, host: { '[class.stack-block]': 'true', '[attr.role]': '"heading"', '[attr.aria-level]': 'headingLevel', }, styles: [":host{display:block}\n"] }] }], ctorParameters: function () { return [{ type: ClrStackBlock, decorators: [{ type: SkipSelf }, { type: Optional }] }, { type: ClrCommonStringsService }]; }, propDecorators: { expanded: [{ type: Input, args: ['clrSbExpanded'] }, { type: HostBinding, args: ['class.stack-block-expanded'] }], expandable: [{ type: Input, args: ['clrSbExpandable'] }, { type: HostBinding, args: ['class.stack-block-expandable'] }], ariaLevel: [{ type: Input, args: ['clrStackViewLevel'] }], expandedChange: [{ type: Output, args: ['clrSbExpandedChange'] }], stackBlockTitle: [{ type: ContentChild, args: [ClrStackViewLabel] }], setChangedValue: [{ type: Input, args: ['clrSbNotifyChange'] }], getChangedValue: [{ type: HostBinding, args: ['class.stack-block-changed'] }], onStackLabelFocus: [{ type: HostBinding, args: ['class.on-focus'] }] } }); function eventIsInputEvent(event) { const targetElement = event?.target; return targetElement?.tagName === 'INPUT'; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStackContentInput { constructor() { this.uniqueId = uniqueIdFactory(); } } ClrStackContentInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackContentInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); ClrStackContentInput.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrStackContentInput, selector: "[clrStackInput]", host: { properties: { "class.clr-input": "true", "attr.aria-labelledby": "uniqueId" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackContentInput, decorators: [{ type: Directive, args: [{ selector: '[clrStackInput]', host: { '[class.clr-input]': 'true', '[attr.aria-labelledby]': 'uniqueId', }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStackView { } ClrStackView.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackView, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrStackView.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrStackView, selector: "clr-stack-view", ngImport: i0, template: `
`, isInline: true, styles: [":host{display:block}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackView, decorators: [{ type: Component, args: [{ selector: 'clr-stack-view', template: `
`, styles: [":host{display:block}\n"] }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrStackHeader { constructor(stackView) { this.stackView = stackView; } } ClrStackHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackHeader, deps: [{ token: ClrStackView }], target: i0.ɵɵFactoryTarget.Component }); ClrStackHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrStackHeader, selector: "clr-stack-header", ngImport: i0, template: `

`, isInline: true, styles: [":host{display:block}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackHeader, decorators: [{ type: Component, args: [{ selector: 'clr-stack-header', template: `

`, styles: [":host{display:block}\n"] }] }], ctorParameters: function () { return [{ type: ClrStackView }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_STACK_VIEW_DIRECTIVES = [ ClrStackView, ClrStackHeader, ClrStackBlock, ClrStackContentInput, ClrStackViewLabel, ClrStackViewCustomTags, ]; class ClrStackViewModule { constructor() { ClarityIcons.addIcons(angleIcon); } } ClrStackViewModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrStackViewModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewModule, declarations: [ClrStackView, ClrStackHeader, ClrStackBlock, ClrStackContentInput, ClrStackViewLabel, ClrStackViewCustomTags], imports: [CommonModule, FormsModule, ClrIconModule, ClrExpandableAnimationModule], exports: [ClrStackView, ClrStackHeader, ClrStackBlock, ClrStackContentInput, ClrStackViewLabel, ClrStackViewCustomTags] }); ClrStackViewModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewModule, imports: [CommonModule, FormsModule, ClrIconModule, ClrExpandableAnimationModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrStackViewModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, FormsModule, ClrIconModule, ClrExpandableAnimationModule], declarations: [CLR_STACK_VIEW_DIRECTIVES], exports: [CLR_STACK_VIEW_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TreeFeaturesService { constructor() { this.selectable = false; this.eager = true; this.childrenFetched = new Subject(); } } TreeFeaturesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TreeFeaturesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); TreeFeaturesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TreeFeaturesService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TreeFeaturesService, decorators: [{ type: Injectable }] }); function treeFeaturesFactory(existing) { return existing || new TreeFeaturesService(); } const TREE_FEATURES_PROVIDER = { provide: TreeFeaturesService, useFactory: treeFeaturesFactory, /* * The Optional + SkipSelf pattern ensures that in case of nested components, only the root one will * instantiate a new service and all its children will reuse the root's instance. * If there are several roots (in this case, several independent trees on a page), each root will instantiate * its own service so they won't interfere with one another. * * TL;DR - Optional + SkipSelf = 1 instance of TreeFeaturesService per tree. */ deps: [[new Optional(), new SkipSelf(), TreeFeaturesService]], }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Internal component, do not export! * This is part of the hack to get around https://github.com/angular/angular/issues/15998 */ class RecursiveChildren { constructor(featuresService, expandService) { this.featuresService = featuresService; this.expandService = expandService; if (expandService) { this.subscription = this.expandService.expandChange.subscribe(value => { if (!value && this.parent && !this.featuresService.eager && this.featuresService.recursion) { // In the case of lazy-loading recursive trees, we clear the children on collapse. // This is better in case they change between two user interaction, and that way // the app itself can decide whether to cache them or not. this.parent.clearChildren(); } }); } } shouldRender() { return (this.featuresService.recursion && // In the smart case, we eagerly render all the recursive children // to make sure two-way bindings for selection are available. // They will be hidden with CSS by the parent. (this.featuresService.eager || !this.expandService || this.expandService.expanded)); } getContext(node) { return { $implicit: node.model, clrModel: node, }; } ngOnDestroy() { if (this.subscription) { this.subscription.unsubscribe(); } } } RecursiveChildren.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RecursiveChildren, deps: [{ token: TreeFeaturesService }, { token: IfExpandService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); RecursiveChildren.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: RecursiveChildren, selector: "clr-recursive-children", inputs: { parent: "parent", children: "children" }, host: { properties: { "attr.role": "\"group\"" } }, ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RecursiveChildren, decorators: [{ type: Component, args: [{ selector: 'clr-recursive-children', template: ` `, host: { '[attr.role]': '"group"', // Safari + VO needs direct relationship between treeitem and group; no element should exist between them }, }] }], ctorParameters: function () { return [{ type: TreeFeaturesService }, { type: IfExpandService, decorators: [{ type: Optional }] }]; }, propDecorators: { parent: [{ type: Input, args: ['parent'] }], children: [{ type: Input, args: ['children'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function isPromise(o) { // Shamelessly copied from every open-source project out there. return o && typeof o.then === 'function'; } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // TODO: I'd like this to be a CheckedState enum for the checkboxes in the future. var ClrSelectedState; (function (ClrSelectedState) { // WARNING! Unselected has the value 0, // so it's actually the only one that will evaluate to false if cast to a boolean. // Don't mess with the order! ClrSelectedState[ClrSelectedState["UNSELECTED"] = 0] = "UNSELECTED"; ClrSelectedState[ClrSelectedState["SELECTED"] = 1] = "SELECTED"; ClrSelectedState[ClrSelectedState["INDETERMINATE"] = 2] = "INDETERMINATE"; })(ClrSelectedState || (ClrSelectedState = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TreeNodeModel { constructor() { this.loading$ = new BehaviorSubject(false); this.selected = new BehaviorSubject(ClrSelectedState.UNSELECTED); /* * Being able to push this down to the RecursiveTreeNodeModel would require too much work on the angular components * right now for them to know which kind of model they are using. So I'm lifting the public properties to this * abstract parent class for now and we can revisit it later, when we're not facing such a close deadline. */ this._loading = false; } get loading() { return this._loading; } set loading(isLoading) { this._loading = isLoading; this.loading$.next(isLoading); } destroy() { // Just to be safe this.selected.complete(); } // Propagate by default when eager, don't propagate in the lazy-loaded tree. setSelected(state, propagateUp, propagateDown) { if (state === this.selected.value) { return; } this.selected.next(state); if (propagateDown && state !== ClrSelectedState.INDETERMINATE && this.children) { this.children.forEach(child => child.setSelected(state, false, true)); } if (propagateUp && this.parent) { this.parent._updateSelectionFromChildren(); } } toggleSelection(propagate) { // Both unselected and indeterminate toggle to selected const newState = this.selected.value === ClrSelectedState.SELECTED ? ClrSelectedState.UNSELECTED : ClrSelectedState.SELECTED; // NOTE: we always propagate selection up in this method because it is only called when the user takes an action. // It should never be called from lifecycle hooks or app-provided inputs. this.setSelected(newState, true, propagate); } /* * Internal, but needs to be called by other nodes */ _updateSelectionFromChildren() { const newState = this.computeSelectionStateFromChildren(); if (newState === this.selected.value) { return; } this.selected.next(newState); if (this.parent) { this.parent._updateSelectionFromChildren(); } } computeSelectionStateFromChildren() { let oneSelected = false; let oneUnselected = false; // Using a good old for loop to exit as soon as we can tell, for better performance on large trees. for (const child of this.children) { switch (child.selected.value) { case ClrSelectedState.INDETERMINATE: return ClrSelectedState.INDETERMINATE; case ClrSelectedState.SELECTED: oneSelected = true; if (oneUnselected) { return ClrSelectedState.INDETERMINATE; } break; case ClrSelectedState.UNSELECTED: default: // Default is the same as unselected, in case an undefined somehow made it all the way here. oneUnselected = true; if (oneSelected) { return ClrSelectedState.INDETERMINATE; } break; } } if (!oneSelected) { return ClrSelectedState.UNSELECTED; } else if (!oneUnselected) { return ClrSelectedState.SELECTED; } else { return ClrSelectedState.UNSELECTED; } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * A recursive model is built received from the app and traversed to create the corresponding components. * Recursive = Model dictates the tree node components */ class RecursiveTreeNodeModel extends TreeNodeModel { constructor(model, parent, getChildren, featuresService) { super(); this.getChildren = getChildren; this.featuresService = featuresService; this.childrenFetched = false; this._children = []; this.model = model; this.parent = parent; } get children() { this.fetchChildren(); return this._children; } set children(value) { this._children = value; } destroy() { if (this.subscription) { this.subscription.unsubscribe(); } super.destroy(); } clearChildren() { this._children.forEach(child => child.destroy()); delete this._children; this.childrenFetched = false; } fetchChildren() { if (this.childrenFetched) { return; } const asyncChildren = this.getChildren(this.model); if (isPromise(asyncChildren)) { this.loading = true; asyncChildren.then(raw => { this._children = this.wrapChildren(raw); this.loading = false; }); } else if (isObservable(asyncChildren)) { this.loading = true; this.subscription = asyncChildren.subscribe(raw => { this._children = this.wrapChildren(raw); this.loading = false; }); } else if (asyncChildren) { // Synchronous case this._children = this.wrapChildren(asyncChildren); } else { this._children = []; } this.childrenFetched = true; if (this.featuresService) { this.featuresService.childrenFetched.next(); } } wrapChildren(rawModels) { return rawModels.map(m => new RecursiveTreeNodeModel(m, this, this.getChildren, this.featuresService)); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrRecursiveForOf { constructor(template, featuresService, cdr) { this.template = template; this.featuresService = featuresService; this.cdr = cdr; } // I'm using OnChanges instead of OnInit to easily keep up to date with dynamic trees. Maybe optimizable later. ngOnChanges() { let wrapped; if (Array.isArray(this.nodes)) { wrapped = this.nodes.map(node => new RecursiveTreeNodeModel(node, null, this.getChildren, this.featuresService)); } else { wrapped = [new RecursiveTreeNodeModel(this.nodes, null, this.getChildren, this.featuresService)]; } if (!this.childrenFetchSubscription) { this.childrenFetchSubscription = this.featuresService.childrenFetched.pipe(debounceTime(0)).subscribe(() => { this.cdr.detectChanges(); }); } this.featuresService.recursion = { template: this.template, root: wrapped, }; } ngOnDestroy() { if (this.childrenFetchSubscription) { this.childrenFetchSubscription.unsubscribe(); } } } ClrRecursiveForOf.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRecursiveForOf, deps: [{ token: i0.TemplateRef }, { token: TreeFeaturesService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrRecursiveForOf.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrRecursiveForOf, selector: "[clrRecursiveFor][clrRecursiveForOf]", inputs: { nodes: ["clrRecursiveForOf", "nodes"], getChildren: ["clrRecursiveForGetChildren", "getChildren"] }, usesOnChanges: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrRecursiveForOf, decorators: [{ type: Directive, args: [{ selector: '[clrRecursiveFor][clrRecursiveForOf]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: TreeFeaturesService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { nodes: [{ type: Input, args: ['clrRecursiveForOf'] }], getChildren: [{ type: Input, args: ['clrRecursiveForGetChildren'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TreeFocusManagerService { constructor() { this._focusRequest = new Subject(); this._focusChange = new Subject(); } get focusRequest() { return this._focusRequest.asObservable(); } get focusChange() { return this._focusChange.asObservable(); } focusNode(model) { if (model) { this._focusRequest.next(model.nodeId); } } broadcastFocusedNode(nodeId) { if (this.focusedNodeId !== nodeId) { this.focusedNodeId = nodeId; this._focusChange.next(nodeId); } } focusParent(model) { if (model) { this.focusNode(model.parent); } } focusFirstVisibleNode() { const focusModel = this.rootNodeModels && this.rootNodeModels[0]; this.focusNode(focusModel); } focusLastVisibleNode() { this.focusNode(this.findLastVisibleInTree()); } focusNodeAbove(model) { this.focusNode(this.findNodeAbove(model)); } focusNodeBelow(model) { this.focusNode(this.findNodeBelow(model)); } focusNodeStartsWith(searchString, model) { this.focusNode(this.findClosestNodeStartsWith(searchString, model)); } findSiblings(model) { // the method will return not only sibling models but also itself among them if (model.parent) { return model.parent.children; } else { return this.rootNodeModels; } } findLastVisibleInNode(model) { // the method will traverse through until it finds the last visible node from the given node if (!model) { return null; } if (model.expanded && model.children.length > 0) { const children = model.children; const lastChild = children[children.length - 1]; return this.findLastVisibleInNode(lastChild); } else { return model; } } findNextFocusable(model) { if (!model) { return null; } const siblings = this.findSiblings(model); const selfIndex = siblings.indexOf(model); if (selfIndex < siblings.length - 1) { return siblings[selfIndex + 1]; } else if (selfIndex === siblings.length - 1) { return this.findNextFocusable(model.parent); } return null; } findLastVisibleInTree() { const lastRootNode = this.rootNodeModels && this.rootNodeModels.length && this.rootNodeModels[this.rootNodeModels.length - 1]; return this.findLastVisibleInNode(lastRootNode); } findNodeAbove(model) { if (!model) { return null; } const siblings = this.findSiblings(model); const selfIndex = siblings.indexOf(model); if (selfIndex === 0) { return model.parent; } else if (selfIndex > 0) { return this.findLastVisibleInNode(siblings[selfIndex - 1]); } return null; } findNodeBelow(model) { if (!model) { return null; } if (model.expanded && model.children.length > 0) { return model.children[0]; } else { return this.findNextFocusable(model); } } findDescendentNodeStartsWith(searchString, model) { if (model.expanded && model.children.length > 0) { for (const childModel of model.children) { const found = this.findNodeStartsWith(searchString, childModel); if (found) { return found; } } } return null; } findSiblingNodeStartsWith(searchString, model) { const siblings = this.findSiblings(model); const selfIndex = siblings.indexOf(model); // Look from sibling nodes for (let i = selfIndex + 1; i < siblings.length; i++) { const siblingModel = siblings[i]; const found = this.findNodeStartsWith(searchString, siblingModel); if (found) { return found; } } return null; } findRootNodeStartsWith(searchString, model) { for (const rootModel of this.rootNodeModels) { // Don't look from a parent yet if (model.parent && model.parent === rootModel) { continue; } const found = this.findNodeStartsWith(searchString, rootModel); if (found) { return found; } } return null; } findNodeStartsWith(searchString, model) { if (!model) { return null; } if (model.textContent.startsWith(searchString)) { return model; } return this.findDescendentNodeStartsWith(searchString, model); } findClosestNodeStartsWith(searchString, model) { if (!model) { return null; } const foundFromDescendents = this.findDescendentNodeStartsWith(searchString, model); if (foundFromDescendents) { return foundFromDescendents; } const foundFromSiblings = this.findSiblingNodeStartsWith(searchString, model); if (foundFromSiblings) { return foundFromSiblings; } const foundFromRootNodes = this.findRootNodeStartsWith(searchString, model); if (foundFromRootNodes) { return foundFromRootNodes; } // Now look from its own direct parent return this.findNodeStartsWith(searchString, model.parent); } } TreeFocusManagerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TreeFocusManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); TreeFocusManagerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TreeFocusManagerService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TreeFocusManagerService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * A declarative model is built by traversing the Angular component tree. * Declarative = Tree node components dictate the model */ class DeclarativeTreeNodeModel extends TreeNodeModel { constructor(parent) { super(); this.parent = parent; if (parent) { parent._addChild(this); } this.children = []; } destroy() { if (this.parent) { this.parent._removeChild(this); } super.destroy(); } _addChild(child) { this.children.push(child); } _removeChild(child) { const index = this.children.indexOf(child); if (index > -1) { this.children.splice(index, 1); } } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTreeNodeLink { constructor(el) { this.el = el; } get active() { return this.el.nativeElement.classList.contains('active'); } activate() { if (this.el.nativeElement && this.el.nativeElement.click) { this.el.nativeElement.click(); } } } ClrTreeNodeLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeNodeLink, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrTreeNodeLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrTreeNodeLink, selector: ".clr-treenode-link", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeNodeLink, decorators: [{ type: Directive, args: [{ selector: '.clr-treenode-link', }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const LVIEW_CONTEXT_INDEX = 8; // If the user types multiple keys without allowing 200ms to pass between them, // then those keys are sent together in one request. const TREE_TYPE_AHEAD_TIMEOUT = 200; class ClrTreeNode { constructor(platformId, parent, featuresService, expandService, commonStrings, focusManager, elementRef, injector) { this.platformId = platformId; this.featuresService = featuresService; this.expandService = expandService; this.commonStrings = commonStrings; this.focusManager = focusManager; this.elementRef = elementRef; this.selectedChange = new EventEmitter(false); this.expandedChange = new EventEmitter(); this.STATES = ClrSelectedState; this.isModelLoading = false; this.nodeId = uniqueIdFactory(); this.contentContainerTabindex = -1; this.skipEmitChange = false; this.typeAheadKeyBuffer = ''; this.typeAheadKeyEvent = new Subject(); this.subscriptions = []; if (this.featuresService.recursion) { // I'm completely stuck, we have to hack into private properties until either // https://github.com/angular/angular/issues/14935 or https://github.com/angular/angular/issues/15998 // are fixed // This is for non-ivy implementations if (injector.view) { this._model = injector.view.context.clrModel; } else { // Ivy puts this on a specific index of a _lView property this._model = injector._lView[LVIEW_CONTEXT_INDEX].clrModel; } } else { // Force cast for now, not sure how to tie the correct type here to featuresService.recursion this._model = new DeclarativeTreeNodeModel(parent ? parent._model : null); } this._model.nodeId = this.nodeId; } get selected() { return this._model.selected.value; } set selected(value) { this.featuresService.selectable = true; // Gracefully handle falsy states like null or undefined because it's just easier than answering questions. // This shouldn't happen with strict typing on the app's side, but it's not up to us. if (value === null || typeof value === 'undefined') { value = ClrSelectedState.UNSELECTED; } // We match booleans to the corresponding ClrSelectedState if (typeof value === 'boolean') { value = value ? ClrSelectedState.SELECTED : ClrSelectedState.UNSELECTED; } // We propagate only if the tree is in smart mode, and skip emitting the output when we set the input // See https://github.com/vmware/clarity/issues/3073 this.skipEmitChange = true; this._model.setSelected(value, this.featuresService.eager, this.featuresService.eager); this.skipEmitChange = false; } // I'm caving on this, for tree nodes I think we can tolerate having a two-way binding on the component // rather than enforce the clrIfExpanded structural directive for dynamic cases. Mostly because for the smart // case, you can't use a structural directive, it would need to go on an ng-container. get expanded() { return this.expandService.expanded; } set expanded(value) { this.expandService.expanded = value; } set clrForTypeAhead(value) { this._model.textContent = trimAndLowerCase(value || this.elementRef.nativeElement.textContent); } get ariaSelected() { if (this.isSelectable()) { return this._model.selected.value === ClrSelectedState.SELECTED; } else if (this.treeNodeLink?.active) { return true; } else { return null; } } get treeNodeLink() { return this.treeNodeLinkList && this.treeNodeLinkList.first; } get isParent() { return this._model.children && this._model.children.length > 0; } ngOnInit() { this._model.expanded = this.expanded; this.subscriptions.push(this._model.selected.pipe(filter(() => !this.skipEmitChange)).subscribe(value => { this.selectedChange.emit(value); })); this.subscriptions.push(this.expandService.expandChange.subscribe(value => { this.expandedChange.emit(value); this._model.expanded = value; })); this.subscriptions.push(this.focusManager.focusRequest.subscribe(nodeId => { if (this.nodeId === nodeId) { this.focusTreeNode(); } }), this.focusManager.focusChange.subscribe(nodeId => { this.checkTabIndex(nodeId); })); this.subscriptions.push(this._model.loading$.pipe(debounceTime(0)).subscribe(isLoading => (this.isModelLoading = isLoading))); } ngAfterContentInit() { this.subscriptions.push(this.typeAheadKeyEvent.pipe(debounceTime(TREE_TYPE_AHEAD_TIMEOUT)).subscribe((bufferedKeys) => { this.focusManager.focusNodeStartsWith(bufferedKeys, this._model); // reset once bufferedKeys are used this.typeAheadKeyBuffer = ''; })); } ngAfterViewInit() { if (!this._model.textContent) { this._model.textContent = trimAndLowerCase(this.elementRef.nativeElement.textContent); } } ngOnDestroy() { this._model.destroy(); this.subscriptions.forEach(sub => sub.unsubscribe()); } isExpandable() { if (typeof this.expandable !== 'undefined') { return this.expandable; } return !!this.expandService.expandable || this.isParent; } isSelectable() { return this.featuresService.selectable; } focusTreeNode() { const containerEl = this.contentContainer.nativeElement; if (isPlatformBrowser(this.platformId) && document.activeElement !== containerEl) { this.setTabIndex(0); containerEl.focus(); containerEl.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } } broadcastFocusOnContainer() { this.focusManager.broadcastFocusedNode(this.nodeId); } onKeyDown(event) { // Two reasons to prevent default behavior: // 1. to prevent scrolling on arrow keys // 2. Assistive Technology focus differs from Keyboard focus behavior. // By default, pressing arrow key makes AT focus go into the nested content of the item. preventArrowKeyScroll(event); // https://www.w3.org/TR/wai-aria-practices-1.1/#keyboard-interaction-22 switch (normalizeKey(event.key)) { case Keys.ArrowUp: this.focusManager.focusNodeAbove(this._model); break; case Keys.ArrowDown: this.focusManager.focusNodeBelow(this._model); break; case Keys.ArrowRight: this.expandOrFocusFirstChild(); break; case Keys.ArrowLeft: this.collapseOrFocusParent(); break; case Keys.Home: event.preventDefault(); this.focusManager.focusFirstVisibleNode(); break; case Keys.End: event.preventDefault(); this.focusManager.focusLastVisibleNode(); break; case Keys.Enter: this.toggleExpandOrTriggerDefault(); break; case Keys.Space: case Keys.Spacebar: // to prevent scrolling on space key in this specific case event.preventDefault(); this.toggleExpandOrTriggerDefault(); break; default: if (this._model.textContent && isKeyEitherLetterOrNumber(event)) { this.typeAheadKeyBuffer += event.key; this.typeAheadKeyEvent.next(this.typeAheadKeyBuffer); return; } break; } // if non-letter keys are pressed, do reset. this.typeAheadKeyBuffer = ''; } setTabIndex(value) { this.contentContainerTabindex = value; this.contentContainer.nativeElement.setAttribute('tabindex', value); } checkTabIndex(nodeId) { if (isPlatformBrowser(this.platformId) && this.nodeId !== nodeId && this.contentContainerTabindex !== -1) { this.setTabIndex(-1); } } toggleExpandOrTriggerDefault() { if (this.isExpandable() && !this.isSelectable()) { this.expandService.expanded = !this.expanded; } else { this.triggerDefaultAction(); } } expandOrFocusFirstChild() { if (this.expanded) { // if the node is already expanded and has children, focus its very first child if (this.isParent) { this.focusManager.focusNodeBelow(this._model); } } else { // we must check if the node is expandable, in order to set .expanded to true from false // because we shouldn't set .expanded to true if it's not expandable node if (this.isExpandable()) { this.expandService.expanded = true; } } } collapseOrFocusParent() { if (this.expanded) { this.expandService.expanded = false; } else { this.focusManager.focusParent(this._model); } } triggerDefaultAction() { if (this.treeNodeLink) { this.treeNodeLink.activate(); } else { if (this.isSelectable()) { this._model.toggleSelection(this.featuresService.eager); } } } } ClrTreeNode.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeNode, deps: [{ token: PLATFORM_ID }, { token: ClrTreeNode, optional: true, skipSelf: true }, { token: TreeFeaturesService }, { token: IfExpandService }, { token: ClrCommonStringsService }, { token: TreeFocusManagerService }, { token: i0.ElementRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component }); ClrTreeNode.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTreeNode, selector: "clr-tree-node", inputs: { expandable: ["clrExpandable", "expandable"], selected: ["clrSelected", "selected"], expanded: ["clrExpanded", "expanded"], clrForTypeAhead: "clrForTypeAhead" }, outputs: { selectedChange: "clrSelectedChange", expandedChange: "clrExpandedChange" }, host: { properties: { "class.clr-tree-node": "true" } }, providers: [TREE_FEATURES_PROVIDER, IfExpandService, { provide: LoadingListener, useExisting: IfExpandService }], queries: [{ propertyName: "treeNodeLinkList", predicate: ClrTreeNodeLink }], viewQueries: [{ propertyName: "contentContainer", first: true, predicate: ["contentContainer"], descendants: true, read: ElementRef, static: true }], ngImport: i0, template: "\n\n\n \n \n \n
\n \n
\n
\n \n \n
\n
\n \n
\n\n \n \n
\n selected\n unselected\n
\n
\n\n\n \n \n \n\n", dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: RecursiveChildren, selector: "clr-recursive-children", inputs: ["parent", "children"] }], animations: [ trigger('toggleChildrenAnim', [ transition('collapsed => expanded', [style({ height: 0 }), animate(200, style({ height: '*' }))]), transition('expanded => collapsed', [style({ height: '*' }), animate(200, style({ height: 0 }))]), state('expanded', style({ height: '*', 'overflow-y': 'visible' })), state('collapsed', style({ height: 0 })), ]), ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeNode, decorators: [{ type: Component, args: [{ selector: 'clr-tree-node', providers: [TREE_FEATURES_PROVIDER, IfExpandService, { provide: LoadingListener, useExisting: IfExpandService }], animations: [ trigger('toggleChildrenAnim', [ transition('collapsed => expanded', [style({ height: 0 }), animate(200, style({ height: '*' }))]), transition('expanded => collapsed', [style({ height: '*' }), animate(200, style({ height: 0 }))]), state('expanded', style({ height: '*', 'overflow-y': 'visible' })), state('collapsed', style({ height: 0 })), ]), ], host: { '[class.clr-tree-node]': 'true', }, template: "\n\n\n \n \n \n
\n \n
\n
\n \n \n
\n
\n \n
\n\n \n \n
\n selected\n unselected\n
\n
\n\n\n \n \n \n\n" }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: ClrTreeNode, decorators: [{ type: Optional }, { type: SkipSelf }] }, { type: TreeFeaturesService }, { type: IfExpandService }, { type: ClrCommonStringsService }, { type: TreeFocusManagerService }, { type: i0.ElementRef }, { type: i0.Injector }]; }, propDecorators: { expandable: [{ type: Input, args: ['clrExpandable'] }], selectedChange: [{ type: Output, args: ['clrSelectedChange'] }], expandedChange: [{ type: Output, args: ['clrExpandedChange'] }], contentContainer: [{ type: ViewChild, args: ['contentContainer', { read: ElementRef, static: true }] }], treeNodeLinkList: [{ type: ContentChildren, args: [ClrTreeNodeLink, { descendants: false }] }], selected: [{ type: Input, args: ['clrSelected'] }], expanded: [{ type: Input, args: ['clrExpanded'] }], clrForTypeAhead: [{ type: Input, args: ['clrForTypeAhead'] }] } }); function trimAndLowerCase(value) { return value.toLocaleLowerCase().trim(); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTree { constructor(featuresService, focusManagerService, { nativeElement }, renderer, ngZone) { this.featuresService = featuresService; this.focusManagerService = focusManagerService; this.subscriptions = []; const subscription = ngZone.runOutsideAngular(() => fromEvent(nativeElement, 'focusin').subscribe((event) => { if (event.target === nativeElement) { // After discussing with the team, I've made it so that when the tree receives focus, the first visible node will be focused. // This will prevent from the page scrolling abruptly to the first selected node if it exist in a deeply nested tree. this.focusManagerService.focusFirstVisibleNode(); // when the first child gets focus, // tree should no longer have tabindex of 0. renderer.removeAttribute(nativeElement, 'tabindex'); } })); this.subscriptions.push(subscription); } set lazy(value) { this.featuresService.eager = !value; } get isMultiSelectable() { return this.featuresService.selectable && this.rootNodes.length > 0; } ngAfterContentInit() { this.setRootNodes(); this.subscriptions.push(this.rootNodes.changes.subscribe(() => { this.setRootNodes(); })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } setRootNodes() { // if node has no parent, it's a root node // for recursive tree, this.rootNodes registers also nested children // so we have to use filter to extract the ones that are truly root nodes this.focusManagerService.rootNodeModels = this.rootNodes.map(node => node._model).filter(node => !node.parent); } } ClrTree.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTree, deps: [{ token: TreeFeaturesService }, { token: TreeFocusManagerService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); ClrTree.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTree, selector: "clr-tree", inputs: { lazy: ["clrLazy", "lazy"] }, host: { attributes: { "tabindex": "0" }, properties: { "attr.role": "\"tree\"", "attr.aria-multiselectable": "isMultiSelectable" } }, providers: [TREE_FEATURES_PROVIDER, TreeFocusManagerService], queries: [{ propertyName: "rootNodes", predicate: ClrTreeNode }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: RecursiveChildren, selector: "clr-recursive-children", inputs: ["parent", "children"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTree, decorators: [{ type: Component, args: [{ selector: 'clr-tree', template: ` `, providers: [TREE_FEATURES_PROVIDER, TreeFocusManagerService], host: { tabindex: '0', '[attr.role]': '"tree"', '[attr.aria-multiselectable]': 'isMultiSelectable', }, }] }], ctorParameters: function () { return [{ type: TreeFeaturesService }, { type: TreeFocusManagerService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { rootNodes: [{ type: ContentChildren, args: [ClrTreeNode] }], lazy: [{ type: Input, args: ['clrLazy'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_TREE_VIEW_DIRECTIVES = [ClrTree, ClrTreeNode, ClrRecursiveForOf, ClrTreeNodeLink]; class ClrTreeViewModule { constructor() { ClarityIcons.addIcons(angleIcon); } } ClrTreeViewModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeViewModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrTreeViewModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeViewModule, declarations: [ClrTree, ClrTreeNode, ClrRecursiveForOf, ClrTreeNodeLink, RecursiveChildren], imports: [CommonModule, ClrIconModule, ClrLoadingModule], exports: [ClrTree, ClrTreeNode, ClrRecursiveForOf, ClrTreeNodeLink] }); ClrTreeViewModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeViewModule, imports: [CommonModule, ClrIconModule, ClrLoadingModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTreeViewModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrLoadingModule], declarations: [CLR_TREE_VIEW_DIRECTIVES, RecursiveChildren], exports: [CLR_TREE_VIEW_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDataModule { } ClrDataModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDataModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrDataModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrDataModule, exports: [ClrDatagridModule, ClrStackViewModule, ClrTreeViewModule] }); ClrDataModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDataModule, imports: [ClrDatagridModule, ClrStackViewModule, ClrTreeViewModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDataModule, decorators: [{ type: NgModule, args: [{ exports: [ClrDatagridModule, ClrStackViewModule, ClrTreeViewModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function wrapObservable(observable, onSubscribe, onUnsubscribe) { return Observable.create((observer) => { onSubscribe(observer); const subscription = observable.subscribe(observer); return () => { subscription.unsubscribe(); if (onUnsubscribe) { onUnsubscribe(observer); } }; }); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class DropdownFocusHandler { constructor(renderer, parent, toggleService, focusService, platformId) { this.renderer = renderer; this.parent = parent; this.toggleService = toggleService; this.focusService = focusService; this.platformId = platformId; this.id = uniqueIdFactory(); this.focusBackOnTriggerWhenClosed = false; this._unlistenFuncs = []; this.resetChildren(); this.moveToFirstItemWhenOpen(); if (!this.parent) { this.handleRootFocus(); } } get trigger() { return this._trigger; } set trigger(el) { this._trigger = el; if (this.parent) { this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowright', event => this.toggleService.toggleWithEvent(event))); } else { this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowup', event => this.toggleService.toggleWithEvent(event))); this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.arrowdown', event => this.toggleService.toggleWithEvent(event))); this.focusService.listenToArrowKeys(el); } } get container() { return this._container; } set container(el) { this._container = el; // whether root container or not, tab key should always toggle (i.e. close) the container this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.tab', event => this.toggleService.toggleWithEvent(event))); if (this.parent) { // if it's a nested container, pressing escape has the same effect as pressing left key, which closes the current // popup and moves up to its parent. Here, we stop propagation so that the parent container // doesn't receive the escape keydown this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.escape', event => { this.focusService.move(ArrowKeyDirection.LEFT); event.stopPropagation(); })); } else { // The root container is the only one we register to the focus service, others do not need focus this.focusService.registerContainer(el); // The root container will simply close the container when escape key is pressed this._unlistenFuncs.push(this.renderer.listen(el, 'keydown.escape', event => this.toggleService.toggleWithEvent(event))); // When the user moves focus outside of the menu, we close the dropdown this._unlistenFuncs.push(this.renderer.listen(el, 'blur', event => { // we clear out any existing focus on the items this.children.pipe(take(1)).subscribe(items => items.forEach(item => item.blur())); // event.relatedTarget is null in IE11. In that case we use document.activeElement which correctly points // to the element we want to check. Note that other browsers might point document.activeElement to the // wrong element. This is ok, because all the other browsers we support relies on event.relatedTarget. const target = event.relatedTarget || document.activeElement; // If the user clicks on an item which triggers the blur, we don't want to close it since it may open a submenu. // In the case of needing to close it (i.e. user selected an item and the dropdown menu is set to close on // selection), dropdown-item.ts handles it. if (target && isPlatformBrowser(this.platformId)) { if (el.contains(target) || target === this.trigger) { return; } } // We let the user move focus to where the want, we don't force the focus back on the trigger this.focusBackOnTriggerWhenClosed = false; this.toggleService.open = false; })); } } ngOnDestroy() { this._unlistenFuncs.forEach((unlisten) => unlisten()); this.focusService.detachListeners(); } /** * If the dropdown was opened by clicking on the trigger, we automatically move to the first item */ moveToFirstItemWhenOpen() { const subscription = this.toggleService.openChange.subscribe(open => { if (open && this.toggleService.originalEvent) { // Even if we properly waited for ngAfterViewInit, the container still wouldn't be attached to the DOM. // So setTimeout is the only way to wait for the container to be ready to move focus to first item. setTimeout(() => { this.focusService.moveTo(this); if (this.parent) { this.focusService.move(ArrowKeyDirection.RIGHT); } else { this.focusService.move(ArrowKeyDirection.DOWN); } }); } }); this._unlistenFuncs.push(() => subscription.unsubscribe()); } /** * Focus on the menu when it opens, and focus back on the root trigger when the whole dropdown becomes closed */ handleRootFocus() { const subscription = this.toggleService.openChange.subscribe(open => { if (!open) { // We reset the state of the focus service both on initialization and when closing. this.focusService.reset(this); // But we only actively focus the trigger when closing, not on initialization. if (this.focusBackOnTriggerWhenClosed) { this.focus(); } } this.focusBackOnTriggerWhenClosed = open; }); this._unlistenFuncs.push(() => subscription.unsubscribe()); } focus() { if (this.trigger && isPlatformBrowser(this.platformId)) { this.trigger.focus(); } } blur() { if (this.trigger && isPlatformBrowser(this.platformId)) { this.trigger.blur(); } } activate() { if (isPlatformBrowser(this.platformId)) { this.trigger.click(); } } resetChildren() { this.children = new ReplaySubject(1); if (this.parent) { this.right = this.openAndGetChildren().pipe(map(all => all[0])); } else { this.down = this.openAndGetChildren().pipe(map(all => all[0])); this.up = this.openAndGetChildren().pipe(map(all => all[all.length - 1])); } } addChildren(children) { Linkers.linkVertical(children); if (this.parent) { Linkers.linkParent(children, this.closeAndGetThis(), ArrowKeyDirection.LEFT); } this.children.next(children); } openAndGetChildren() { return wrapObservable(this.children, () => (this.toggleService.open = true)); } closeAndGetThis() { return wrapObservable(of(this), () => (this.toggleService.open = false)); } } DropdownFocusHandler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DropdownFocusHandler, deps: [{ token: i0.Renderer2 }, { token: DropdownFocusHandler, optional: true, skipSelf: true }, { token: ClrPopoverToggleService }, { token: FocusService$1 }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); DropdownFocusHandler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DropdownFocusHandler }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: DropdownFocusHandler, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: DropdownFocusHandler, decorators: [{ type: SkipSelf }, { type: Optional }] }, { type: ClrPopoverToggleService }, { type: FocusService$1 }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); const DROPDOWN_FOCUS_HANDLER_PROVIDER = customFocusableItemProvider(DropdownFocusHandler); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class RootDropdownService { constructor() { this._changes = new Subject(); } get changes() { return this._changes.asObservable(); } closeMenus() { this._changes.next(false); } } RootDropdownService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RootDropdownService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); RootDropdownService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RootDropdownService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: RootDropdownService, decorators: [{ type: Injectable }] }); function clrRootDropdownFactory(existing) { return existing || new RootDropdownService(); } const ROOT_DROPDOWN_PROVIDER = { provide: RootDropdownService, useFactory: clrRootDropdownFactory, deps: [[new Optional(), new SkipSelf(), RootDropdownService]], }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDropdown { constructor(parent, toggleService, focusHandler, cdr, dropdownService) { this.parent = parent; this.toggleService = toggleService; this.focusHandler = focusHandler; this.cdr = cdr; this.isMenuClosable = true; this.subscriptions = []; this.subscriptions.push(dropdownService.changes.subscribe(value => (this.toggleService.open = value))); this.subscriptions.push(toggleService.openChange.subscribe(() => this.cdr.markForCheck())); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } } ClrDropdown.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdown, deps: [{ token: ClrDropdown, optional: true, skipSelf: true }, { token: ClrPopoverToggleService }, { token: DropdownFocusHandler }, { token: i0.ChangeDetectorRef }, { token: RootDropdownService }], target: i0.ɵɵFactoryTarget.Component }); ClrDropdown.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDropdown, selector: "clr-dropdown", inputs: { isMenuClosable: ["clrCloseMenuOnItemClick", "isMenuClosable"] }, host: { properties: { "class.dropdown": "true", "class.open": "toggleService.open" } }, providers: [ROOT_DROPDOWN_PROVIDER, FOCUS_SERVICE_PROVIDER, DROPDOWN_FOCUS_HANDLER_PROVIDER], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdown, decorators: [{ type: Component, args: [{ selector: 'clr-dropdown', template: '', host: { '[class.dropdown]': 'true', '[class.open]': 'toggleService.open', }, providers: [ROOT_DROPDOWN_PROVIDER, FOCUS_SERVICE_PROVIDER, DROPDOWN_FOCUS_HANDLER_PROVIDER], hostDirectives: [ClrPopoverHostDirective], }] }], ctorParameters: function () { return [{ type: ClrDropdown, decorators: [{ type: SkipSelf }, { type: Optional }] }, { type: ClrPopoverToggleService }, { type: DropdownFocusHandler }, { type: i0.ChangeDetectorRef }, { type: RootDropdownService }]; }, propDecorators: { isMenuClosable: [{ type: Input, args: ['clrCloseMenuOnItemClick'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class BasicFocusableItem { constructor(el, renderer, platformId) { this.el = el; this.renderer = renderer; this.platformId = platformId; this.id = uniqueIdFactory(); this.disabled = false; renderer.setAttribute(el.nativeElement, 'id', this.id); renderer.setAttribute(el.nativeElement, 'tabindex', '-1'); } focus() { if (isPlatformBrowser(this.platformId)) { this.renderer.setAttribute(this.el.nativeElement, 'tabindex', '0'); this.el.nativeElement.focus(); this.el.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' }); } } blur() { if (isPlatformBrowser(this.platformId)) { this.renderer.setAttribute(this.el.nativeElement, 'tabindex', '-1'); this.el.nativeElement.blur(); } } activate() { if (isPlatformBrowser(this.platformId)) { this.el.nativeElement.click(); } } } BasicFocusableItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: BasicFocusableItem, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); BasicFocusableItem.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: BasicFocusableItem }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: BasicFocusableItem, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; } }); const BASIC_FOCUSABLE_ITEM_PROVIDER = [ { provide: FocusableItem, useClass: BasicFocusableItem, }, ]; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDropdownItem { constructor(dropdown, _dropdownService, focusableItem) { this.dropdown = dropdown; this._dropdownService = _dropdownService; this.focusableItem = focusableItem; } get disabled() { return this.focusableItem.disabled; } set disabled(value) { // Empty string attribute evaluates to false but should disable the item, so we need to add a special case for it. this.focusableItem.disabled = !!value || value === ''; } /** * Let you overwrite the focusable auto increment id. */ get dropdownItemId() { return this.focusableItem.id; } set dropdownItemId(value) { this.focusableItem.id = value; } onDropdownItemClick() { // Move focus back to the root dropdown trigger. // This is done BEFORE the dropdown is closed so that focus gets moved properly if a modal is opened. if (this.dropdown.isMenuClosable && !this.disabled && this.dropdown.toggleService.open) { const rootDropdown = this.findRootDropdown(); rootDropdown.focusHandler.focus(); // Prevent moving focus back to the trigger when the dropdown menu is closed. // Without this line, focus could be "stolen" from a modal that was opened from a dropdown item. rootDropdown.focusHandler.focusBackOnTriggerWhenClosed = false; } // Ensure that the dropdown is closed after custom dropdown item click event handlers have run. setTimeout(() => { if (this.dropdown.isMenuClosable && !this.disabled) { this._dropdownService.closeMenus(); } }); } onSpaceKeydown($event) { this.stopImmediatePropagationIfDisabled($event); } onEnterKeydown($event) { this.stopImmediatePropagationIfDisabled($event); } stopImmediatePropagationIfDisabled($event) { if (this.disabled) { $event.preventDefault(); // prevent click event $event.stopImmediatePropagation(); } } findRootDropdown() { let rootDropdown = this.dropdown; while (rootDropdown.parent) { rootDropdown = rootDropdown.parent; } return rootDropdown; } } ClrDropdownItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownItem, deps: [{ token: ClrDropdown }, { token: RootDropdownService }, { token: FocusableItem }], target: i0.ɵɵFactoryTarget.Directive }); ClrDropdownItem.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDropdownItem, selector: "[clrDropdownItem]", inputs: { disabled: ["clrDisabled", "disabled"], dropdownItemId: ["id", "dropdownItemId"] }, host: { listeners: { "click": "onDropdownItemClick()", "keydown.space": "onSpaceKeydown($event)", "keydown.enter": "onEnterKeydown($event)" }, properties: { "class.disabled": "disabled", "class.dropdown-item": "true", "attr.role": "\"menuitem\"", "attr.aria-disabled": "disabled", "attr.id": "dropdownItemId" } }, providers: [BASIC_FOCUSABLE_ITEM_PROVIDER], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownItem, decorators: [{ type: Directive, args: [{ selector: '[clrDropdownItem]', host: { '[class.disabled]': 'disabled', '[class.dropdown-item]': 'true', '[attr.role]': '"menuitem"', '[attr.aria-disabled]': 'disabled', '[attr.id]': 'dropdownItemId', }, providers: [BASIC_FOCUSABLE_ITEM_PROVIDER], }] }], ctorParameters: function () { return [{ type: ClrDropdown }, { type: RootDropdownService }, { type: FocusableItem }]; }, propDecorators: { disabled: [{ type: Input, args: ['clrDisabled'] }], dropdownItemId: [{ type: Input, args: ['id'] }], onDropdownItemClick: [{ type: HostListener, args: ['click'] }], onSpaceKeydown: [{ type: HostListener, args: ['keydown.space', ['$event']] }], onEnterKeydown: [{ type: HostListener, args: ['keydown.enter', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var Point; (function (Point) { Point[Point["RIGHT_CENTER"] = 0] = "RIGHT_CENTER"; Point[Point["RIGHT_TOP"] = 1] = "RIGHT_TOP"; Point[Point["RIGHT_BOTTOM"] = 2] = "RIGHT_BOTTOM"; Point[Point["TOP_CENTER"] = 3] = "TOP_CENTER"; Point[Point["TOP_RIGHT"] = 4] = "TOP_RIGHT"; Point[Point["TOP_LEFT"] = 5] = "TOP_LEFT"; Point[Point["BOTTOM_CENTER"] = 6] = "BOTTOM_CENTER"; Point[Point["BOTTOM_RIGHT"] = 7] = "BOTTOM_RIGHT"; Point[Point["BOTTOM_LEFT"] = 8] = "BOTTOM_LEFT"; Point[Point["LEFT_CENTER"] = 9] = "LEFT_CENTER"; Point[Point["LEFT_TOP"] = 10] = "LEFT_TOP"; Point[Point["LEFT_BOTTOM"] = 11] = "LEFT_BOTTOM"; })(Point || (Point = {})); const POSITION_RELATIVE = 'relative'; const POSITION_ABSOLUTE = 'absolute'; const POSITION_FIXED = 'fixed'; const OVERFLOW_SCROLL = 'scroll'; const OVERFLOW_AUTO = 'auto'; class Popover { constructor(element) { this.element = element; this.boundOnScrollListener = this.emitScrollEvent.bind(this); /* * Containers up to the first positioned one will have an event on scroll */ this.scrollableElements = []; // Browsers don't agree with what to do if some of these are not specified, so we set them all to be safe. element.style.position = POSITION_ABSOLUTE; element.style.top = 0; element.style.bottom = 'auto'; element.style.left = 0; element.style.right = 'auto'; } // TODO: need a way to account for parameters that change dynamically (positioning). anchor(anchor, anchorAlign, popoverAlign, { offsetX = 0, offsetY = 0, useAnchorParent = false } = {}) { // TODO: we are assuming here that the popover is inside or next to the anchor. // We'd need to go up the popover tree too otherwise this.addScrollEventListeners(anchor); if (useAnchorParent) { anchor = anchor.parentNode; } // explicitly override anchor's style to static anchor.style.position = 'static'; const anchorRect = anchor.getBoundingClientRect(); const popoverRect = this.element.getBoundingClientRect(); // position of left top corner of anchor + the offset let leftDiff = anchorRect.left - popoverRect.left + offsetX; let topDiff = anchorRect.top - popoverRect.top + offsetY; // first, adjust positioning based on anchor's align point switch (anchorAlign) { case Point.LEFT_TOP: case Point.TOP_LEFT: break; case Point.TOP_CENTER: leftDiff += anchorRect.width / 2; break; case Point.TOP_RIGHT: leftDiff += anchorRect.width; break; case Point.RIGHT_TOP: leftDiff += anchorRect.width; break; case Point.LEFT_BOTTOM: topDiff += anchorRect.height; break; case Point.BOTTOM_LEFT: topDiff += anchorRect.height; break; case Point.BOTTOM_CENTER: topDiff += anchorRect.height; leftDiff += anchorRect.width / 2; break; case Point.BOTTOM_RIGHT: topDiff += anchorRect.height; leftDiff += anchorRect.width; break; case Point.RIGHT_BOTTOM: topDiff += anchorRect.height; leftDiff += anchorRect.width; break; case Point.LEFT_CENTER: topDiff += anchorRect.height / 2; break; case Point.RIGHT_CENTER: topDiff += anchorRect.height / 2; leftDiff += anchorRect.width; break; default: } // second, adjust positioning based on popover's align point switch (popoverAlign) { case Point.LEFT_TOP: case Point.TOP_LEFT: break; case Point.TOP_CENTER: leftDiff -= popoverRect.width / 2; break; case Point.TOP_RIGHT: leftDiff -= popoverRect.width; break; case Point.RIGHT_TOP: leftDiff -= popoverRect.width; break; case Point.LEFT_BOTTOM: topDiff -= popoverRect.height; break; case Point.BOTTOM_LEFT: topDiff -= popoverRect.height; break; case Point.BOTTOM_CENTER: topDiff -= popoverRect.height; leftDiff -= popoverRect.width / 2; break; case Point.BOTTOM_RIGHT: topDiff -= popoverRect.height; leftDiff -= popoverRect.width; break; case Point.RIGHT_BOTTOM: topDiff -= popoverRect.height; leftDiff -= popoverRect.width; break; case Point.LEFT_CENTER: topDiff -= popoverRect.height / 2; break; case Point.RIGHT_CENTER: topDiff -= popoverRect.height / 2; leftDiff -= popoverRect.width; break; default: } // Third, adjust with popover's margins based on the two align points. // Here, we make an assumption that popover is primarily positioned outside the // anchor with minor offset. Without this assumption, it's impossible to apply // the popover's margins in a predictable way. For example, assume that a popover // and its anchor are exactly the same size. if a popover is positioned inside the // anchor (which is technically possible), then it becomes impossible to know what to do // if the popover has a non-zero margin value all around (because applying the margin in // all four directions will result in no margin visually, which isn't what we want). // Therefore, our logic makes assumptions about margins of interest given the points, // and only covers the cases where popover is outside the anchor. const popoverComputedStyle = getComputedStyle(this.element); const marginLeft = parseInt(popoverComputedStyle.marginLeft, 10); const marginRight = parseInt(popoverComputedStyle.marginRight, 10); const marginTop = parseInt(popoverComputedStyle.marginTop, 10); const marginBottom = parseInt(popoverComputedStyle.marginBottom, 10); switch (anchorAlign) { case Point.LEFT_TOP: case Point.TOP_LEFT: case Point.TOP_RIGHT: case Point.RIGHT_TOP: if (popoverAlign === Point.BOTTOM_RIGHT || popoverAlign === Point.RIGHT_BOTTOM) { topDiff -= marginBottom; leftDiff -= marginRight; } if (popoverAlign === Point.BOTTOM_LEFT || popoverAlign === Point.LEFT_BOTTOM) { topDiff -= marginTop; leftDiff += marginLeft; } if (popoverAlign === Point.TOP_LEFT || popoverAlign === Point.LEFT_TOP) { topDiff += marginTop; leftDiff += marginLeft; } if (popoverAlign === Point.TOP_RIGHT || popoverAlign === Point.RIGHT_TOP) { topDiff += marginTop; leftDiff -= marginRight; } break; case Point.LEFT_BOTTOM: case Point.BOTTOM_LEFT: case Point.BOTTOM_RIGHT: case Point.RIGHT_BOTTOM: if (popoverAlign === Point.BOTTOM_LEFT || popoverAlign === Point.LEFT_BOTTOM) { topDiff -= marginBottom; leftDiff += marginLeft; } if (popoverAlign === Point.BOTTOM_RIGHT || popoverAlign === Point.RIGHT_BOTTOM) { topDiff -= marginBottom; leftDiff -= marginRight; } if (popoverAlign === Point.TOP_LEFT || popoverAlign === Point.LEFT_TOP) { topDiff += marginTop; leftDiff += marginLeft; } if (popoverAlign === Point.TOP_RIGHT || popoverAlign === Point.RIGHT_TOP) { topDiff += marginTop; leftDiff -= marginRight; } break; case Point.TOP_CENTER: topDiff -= marginBottom; leftDiff += marginLeft; leftDiff -= marginRight; break; case Point.BOTTOM_CENTER: topDiff += marginTop; leftDiff += marginLeft; leftDiff -= marginRight; break; case Point.LEFT_CENTER: topDiff += marginTop; topDiff -= marginBottom; leftDiff -= marginRight; break; case Point.RIGHT_CENTER: topDiff += marginTop; topDiff -= marginBottom; leftDiff += marginLeft; break; default: } this.element.style.transform = `translateX(${Math.round(leftDiff)}px) translateY(${Math.round(topDiff)}px)`; return this._scroll.asObservable(); } release() { this.element.style.transform = ''; this.removeScrollEventListeners(); } isPositioned(container) { const position = getComputedStyle(container).position; return position === POSITION_RELATIVE || position === POSITION_ABSOLUTE || position === POSITION_FIXED; } emitScrollEvent() { this._scroll.next(); } addScrollEventListeners(e) { this._scroll = new Subject(); const anchor = e; let current = e; while (current && current !== document) { if (this.scrolls(current)) { current.addEventListener('scroll', this.boundOnScrollListener); this.scrollableElements.push(current); } if (current !== anchor && this.isPositioned(current)) { break; } current = current.parentNode; } } removeScrollEventListeners() { for (const elem of this.scrollableElements) { elem.removeEventListener('scroll', this.boundOnScrollListener); } this.scrollableElements.length = 0; if (this._scroll) { this._scroll.complete(); delete this._scroll; } } scrolls(container) { const computedStyles = getComputedStyle(container); return (computedStyles.overflowX === OVERFLOW_SCROLL || computedStyles.overflowX === OVERFLOW_AUTO || computedStyles.overflowY === OVERFLOW_SCROLL || computedStyles.overflowY === OVERFLOW_AUTO); } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class AbstractPopover { constructor(injector, parentHost) { this.parentHost = parentHost; /* * Until https://github.com/angular/angular/issues/8785 is supported, we don't have any way to instantiate * a separate directive on the host. So let's do dirty but performant for now. */ this.closeOnOutsideClick = false; this.popoverOptions = {}; this.updateAnchor = false; this.documentESCListener = null; this.closeOnOutsideClickCallback = event => { // The anchor element containing the click event origin means, the click wasn't triggered outside. if (this.anchorElem.contains(event.target)) { return; } this.toggleService.open = false; }; this.el = injector.get(ElementRef); this.toggleService = injector.get(ClrPopoverToggleService); this.renderer = injector.get(Renderer2); this.ngZone = injector.get(NgZone); this.ref = injector.get(ChangeDetectorRef); // Default anchor is the parent host this.anchorElem = parentHost.nativeElement; this.popoverInstance = new Popover(this.el.nativeElement); this.subscription = this.toggleService.openChange.subscribe(change => { if (change) { this.anchor(); this.attachESCListener(); } else { this.release(); this.detachESCListener(); } }); if (this.toggleService.open) { this.anchor(); this.attachESCListener(); } } /* * Fallback to hide when *clrIfOpen is not being used */ get isOffScreen() { return this.toggleService.open ? false : true; } ngAfterViewChecked() { if (this.updateAnchor) { this.updateAnchor = false; this.popoverInstance .anchor(this.anchorElem, this.anchorPoint, this.popoverPoint, this.popoverOptions) .subscribe(() => { // if a scroll event is detected, close the popover this.toggleService.open = false; }); this.attachOutsideClickListener(); } } ngOnDestroy() { this.release(); this.detachESCListener(); this.subscription.unsubscribe(); } anchor() { this.updateAnchor = true; } release() { this.detachOutsideClickListener(); this.popoverInstance.release(); } attachESCListener() { if (this.popoverOptions.ignoreGlobalESCListener) { return; } this.ngZone.runOutsideAngular(() => { this.documentESCListener = this.renderer.listen('document', 'keydown', event => { if (event && event.key) { if (normalizeKey(event.key) === Keys.Escape) { this.ngZone.run(() => { this.toggleService.open = false; this.ref.markForCheck(); }); } } }); }); } detachESCListener() { if (this.documentESCListener) { this.documentESCListener(); this.documentESCListener = null; } } attachOutsideClickListener() { if (this.closeOnOutsideClick && this.toggleService.open) { if (document && document.addEventListener) { // To listen outside click, the listener should catch the event during the capturing phase. // We have to do this ugly document check as Renderer2.listen doesn't allow passive/useCapture listen. document.addEventListener('click', this.closeOnOutsideClickCallback, true); } } } detachOutsideClickListener() { if (this.closeOnOutsideClick) { if (document && document.removeEventListener) { document.removeEventListener('click', this.closeOnOutsideClickCallback, true); } } } } AbstractPopover.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AbstractPopover, deps: [{ token: i0.Injector }, { token: i0.ElementRef, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); AbstractPopover.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: AbstractPopover, host: { properties: { "class.is-off-screen": "this.isOffScreen" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AbstractPopover, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ElementRef, decorators: [{ type: SkipSelf }] }]; }, propDecorators: { isOffScreen: [{ type: HostBinding, args: ['class.is-off-screen'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDropdownMenu extends AbstractPopover { constructor(injector, parentHost, nested, focusHandler) { if (!parentHost) { throw new Error('clr-dropdown-menu should only be used inside of a clr-dropdown'); } super(injector, parentHost); if (!nested) { // Default positioning for normal dropdown is bottom-left this.anchorPoint = Point.BOTTOM_LEFT; this.popoverPoint = Point.LEFT_TOP; } else { // Default positioning for nested dropdown is right-top this.anchorPoint = Point.RIGHT_TOP; this.popoverPoint = Point.LEFT_TOP; } this.popoverOptions.allowMultipleOpen = true; this.popoverOptions.ignoreGlobalESCListener = true; this.closeOnOutsideClick = true; this.focusHandler = focusHandler; } set position(position) { // set the popover values based on menu position switch (position) { case 'top-right': this.anchorPoint = Point.TOP_RIGHT; this.popoverPoint = Point.RIGHT_BOTTOM; break; case 'top-left': this.anchorPoint = Point.TOP_LEFT; this.popoverPoint = Point.LEFT_BOTTOM; break; case 'bottom-right': this.anchorPoint = Point.BOTTOM_RIGHT; this.popoverPoint = Point.RIGHT_TOP; break; case 'bottom-left': this.anchorPoint = Point.BOTTOM_LEFT; this.popoverPoint = Point.LEFT_TOP; break; case 'right-top': this.anchorPoint = Point.RIGHT_TOP; this.popoverPoint = Point.LEFT_TOP; break; case 'right-bottom': this.anchorPoint = Point.RIGHT_BOTTOM; this.popoverPoint = Point.LEFT_BOTTOM; break; case 'left-top': this.anchorPoint = Point.LEFT_TOP; this.popoverPoint = Point.RIGHT_TOP; break; case 'left-bottom': this.anchorPoint = Point.LEFT_BOTTOM; this.popoverPoint = Point.RIGHT_BOTTOM; break; default: this.anchorPoint = Point.BOTTOM_LEFT; this.popoverPoint = Point.LEFT_TOP; break; } } ngAfterContentInit() { this.focusHandler.container = this.el.nativeElement; this.items.changes.subscribe(() => this.focusHandler.addChildren(this.items.toArray())); // I saw this on GitHub as a solution to avoid code duplication because of missed QueryList changes this.items.notifyOnChanges(); } ngOnDestroy() { super.ngOnDestroy(); this.focusHandler.resetChildren(); } } ClrDropdownMenu.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownMenu, deps: [{ token: i0.Injector }, { token: POPOVER_HOST_ANCHOR, optional: true }, { token: ClrDropdownMenu, optional: true, skipSelf: true }, { token: DropdownFocusHandler }], target: i0.ɵɵFactoryTarget.Component }); ClrDropdownMenu.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrDropdownMenu, selector: "clr-dropdown-menu", inputs: { position: ["clrPosition", "position"] }, host: { properties: { "class.dropdown-menu": "true", "attr.role": "\"menu\"" } }, queries: [{ propertyName: "items", predicate: FocusableItem }], usesInheritance: true, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownMenu, decorators: [{ type: Component, args: [{ selector: 'clr-dropdown-menu', template: ``, host: { '[class.dropdown-menu]': 'true', '[attr.role]': '"menu"', }, }] }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ElementRef, decorators: [{ type: Optional }, { type: Inject, args: [POPOVER_HOST_ANCHOR] }] }, { type: ClrDropdownMenu, decorators: [{ type: Optional }, { type: SkipSelf }] }, { type: DropdownFocusHandler }]; }, propDecorators: { items: [{ type: ContentChildren, args: [FocusableItem] }], position: [{ type: Input, args: ['clrPosition'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrDropdownTrigger { constructor(dropdown, toggleService, el, focusHandler) { this.toggleService = toggleService; this.isRootLevelToggle = true; // if the containing dropdown has a parent, then this is not the root level one if (dropdown.parent) { this.isRootLevelToggle = false; } focusHandler.trigger = el.nativeElement; } get active() { return this.toggleService.open; } onDropdownTriggerClick(event) { this.toggleService.toggleWithEvent(event); } } ClrDropdownTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownTrigger, deps: [{ token: ClrDropdown }, { token: ClrPopoverToggleService }, { token: i0.ElementRef }, { token: DropdownFocusHandler }], target: i0.ɵɵFactoryTarget.Directive }); ClrDropdownTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrDropdownTrigger, selector: "[clrDropdownTrigger],[clrDropdownToggle]", host: { listeners: { "click": "onDropdownTriggerClick($event)" }, properties: { "class.dropdown-toggle": "isRootLevelToggle", "class.dropdown-item": "!isRootLevelToggle", "class.expandable": "!isRootLevelToggle", "class.active": "active", "attr.aria-haspopup": "\"menu\"", "attr.aria-expanded": "active" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownTrigger, decorators: [{ type: Directive, args: [{ // We support both selectors for legacy reasons selector: '[clrDropdownTrigger],[clrDropdownToggle]', host: { '[class.dropdown-toggle]': 'isRootLevelToggle', '[class.dropdown-item]': '!isRootLevelToggle', '[class.expandable]': '!isRootLevelToggle', '[class.active]': 'active', '[attr.aria-haspopup]': '"menu"', '[attr.aria-expanded]': 'active', }, }] }], ctorParameters: function () { return [{ type: ClrDropdown }, { type: ClrPopoverToggleService }, { type: i0.ElementRef }, { type: DropdownFocusHandler }]; }, propDecorators: { onDropdownTriggerClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_DROPDOWN_DIRECTIVES = [ClrDropdown, ClrDropdownMenu, ClrDropdownTrigger, ClrDropdownItem]; class ClrDropdownModule { } ClrDropdownModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrDropdownModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownModule, declarations: [ClrDropdown, ClrDropdownMenu, ClrDropdownTrigger, ClrDropdownItem], imports: [CommonModule], exports: [ClrDropdown, ClrDropdownMenu, ClrDropdownTrigger, ClrDropdownItem, ClrConditionalModule, ClrIconModule] }); ClrDropdownModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownModule, imports: [CommonModule, ClrConditionalModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrDropdownModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_DROPDOWN_DIRECTIVES], exports: [CLR_DROPDOWN_DIRECTIVES, ClrConditionalModule, ClrIconModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // @TODO Make this an enum const ALERT_TYPES = ['info', 'warning', 'danger', 'success']; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class AlertIconAndTypesService { constructor(commonStrings) { this.commonStrings = commonStrings; this.defaultIconShape = 'info-circle'; this._alertIconShape = ''; this._alertType = 'info'; } get alertType() { return this._alertType; } set alertType(val) { if (ALERT_TYPES.indexOf(val) > -1) { this._alertType = val; } } get alertIconShape() { if ('' === this._alertIconShape) { return this.iconInfoFromType(this._alertType).shape; } return this._alertIconShape; } set alertIconShape(val) { if (!val) { this._alertIconShape = ''; } else if (val !== this._alertIconShape) { this._alertIconShape = val; } } get alertIconTitle() { return this.iconInfoFromType(this._alertType).title; } iconInfoFromType(type) { const returnObj = { shape: '', cssClass: '', title: '' }; switch (type) { case 'warning': returnObj.shape = 'exclamation-triangle'; returnObj.cssClass = 'alert-warning'; returnObj.title = this.commonStrings.keys.warning; break; case 'danger': returnObj.shape = 'exclamation-circle'; returnObj.cssClass = 'alert-danger'; returnObj.title = this.commonStrings.keys.danger; break; case 'success': returnObj.shape = 'check-circle'; returnObj.cssClass = 'alert-success'; returnObj.title = this.commonStrings.keys.success; break; default: returnObj.shape = this.defaultIconShape; returnObj.cssClass = 'alert-info'; returnObj.title = this.commonStrings.keys.info; break; } return returnObj; } } AlertIconAndTypesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AlertIconAndTypesService, deps: [{ token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Injectable }); AlertIconAndTypesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AlertIconAndTypesService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: AlertIconAndTypesService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: ClrCommonStringsService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class MultiAlertService { constructor() { this._change = new Subject(); } /** * The Observable that lets other classes subscribe to changes */ get changes() { return this._change.asObservable(); } get current() { return this._current; } set current(index) { if (index !== this._current) { this._current = index; this._change.next(index); } } get activeAlerts() { return this.allAlerts && this.allAlerts.filter(alert => !alert._closed); } get currentAlert() { return this.activeAlerts && this.activeAlerts[this.current]; } set currentAlert(alert) { this.current = this.activeAlerts.indexOf(alert); } get count() { return (this.activeAlerts && this.activeAlerts.length) || 0; } manage(alerts) { if (this.subscription) { this.subscription.unsubscribe(); } this.allAlerts = alerts; // After receiving alerts' QueryList, // we are picking index 0 as current by default if a user hasn't any index this.current = typeof this._current === 'number' ? this._current : 0; // we have to also broadcast that initial index this._change.next(this.current); this.subscription = this.allAlerts.changes.subscribe(() => { if (this.current >= this.allAlerts.length) { this.current = Math.max(0, this.allAlerts.length - 1); } }); } next() { this._current = this.current === this.activeAlerts.length - 1 ? 0 : this.current + 1; this._change.next(this._current); } previous() { if (this.activeAlerts.length === 0) { return; } this._current = this.current === 0 ? this.activeAlerts.length - 1 : this.current - 1; this._change.next(this._current); } open() { if (this.activeAlerts.length === 0) { return; } if (!this.currentAlert) { this._current = 0; } this._change.next(this._current); } close(isCurrentAlert) { if (this.activeAlerts.length === 0) { return; } if (isCurrentAlert) { this._current = Math.max(0, this.current - 1); } this._change.next(this._current); } destroy() { if (this.subscription) { this.subscription.unsubscribe(); } } } MultiAlertService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MultiAlertService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); MultiAlertService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MultiAlertService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MultiAlertService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAlert { constructor(iconService, cdr, multiAlertService, commonStrings) { this.iconService = iconService; this.cdr = cdr; this.multiAlertService = multiAlertService; this.commonStrings = commonStrings; this.isSmall = false; this.closable = true; this.isAppLevel = false; this.clrCloseButtonAriaLabel = this.commonStrings.keys.alertCloseButtonAriaLabel; this._closedChanged = new EventEmitter(false); this._closed = false; this.subscriptions = []; } get alertType() { return this.iconService.alertType; } set alertType(val) { this.iconService.alertType = val; } set alertIconShape(value) { this.iconService.alertIconShape = value; } set closed(value) { if (value && !this._closed) { this.close(); } else if (!value && this._closed) { this.open(); } } get alertClass() { return this.iconService.iconInfoFromType(this.iconService.alertType).cssClass; } get hidden() { return this._hidden; } set hidden(value) { if (value !== this._hidden) { this._hidden = value; this.cdr.detectChanges(); } } ngOnInit() { if (this.multiAlertService) { this.subscriptions.push(this.multiAlertService.changes.subscribe(() => { this.hidden = this.multiAlertService.currentAlert !== this; })); } } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); } open() { this._closed = false; if (this.multiAlertService) { this.multiAlertService.open(); } this._closedChanged.emit(false); } close() { if (!this.closable) { return; } const isCurrentAlert = this.multiAlertService?.currentAlert === this; this._closed = true; if (this.multiAlertService?.activeAlerts) { this.multiAlertService.close(isCurrentAlert); } this._closedChanged.emit(true); } } ClrAlert.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlert, deps: [{ token: AlertIconAndTypesService }, { token: i0.ChangeDetectorRef }, { token: MultiAlertService, optional: true }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrAlert.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAlert, selector: "clr-alert", inputs: { isSmall: ["clrAlertSizeSmall", "isSmall"], closable: ["clrAlertClosable", "closable"], isAppLevel: ["clrAlertAppLevel", "isAppLevel"], clrCloseButtonAriaLabel: "clrCloseButtonAriaLabel", alertType: ["clrAlertType", "alertType"], alertIconShape: ["clrAlertIcon", "alertIconShape"], closed: ["clrAlertClosed", "closed"] }, outputs: { _closedChanged: "clrAlertClosedChange" }, providers: [AlertIconAndTypesService], ngImport: i0, template: "\n\n\n
\n \n
\n \n\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlert, decorators: [{ type: Component, args: [{ selector: 'clr-alert', providers: [AlertIconAndTypesService], template: "\n\n\n
\n \n
\n \n\n", styles: [":host{display:block}\n"] }] }], ctorParameters: function () { return [{ type: AlertIconAndTypesService }, { type: i0.ChangeDetectorRef }, { type: MultiAlertService, decorators: [{ type: Optional }] }, { type: ClrCommonStringsService }]; }, propDecorators: { isSmall: [{ type: Input, args: ['clrAlertSizeSmall'] }], closable: [{ type: Input, args: ['clrAlertClosable'] }], isAppLevel: [{ type: Input, args: ['clrAlertAppLevel'] }], clrCloseButtonAriaLabel: [{ type: Input }], _closedChanged: [{ type: Output, args: ['clrAlertClosedChange'] }], alertType: [{ type: Input, args: ['clrAlertType'] }], alertIconShape: [{ type: Input, args: ['clrAlertIcon'] }], closed: [{ type: Input, args: ['clrAlertClosed'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAlertItem { constructor(iconService) { this.iconService = iconService; } } ClrAlertItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertItem, deps: [{ token: AlertIconAndTypesService }], target: i0.ɵɵFactoryTarget.Component }); ClrAlertItem.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAlertItem, selector: "clr-alert-item", host: { classAttribute: "alert-item" }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertItem, decorators: [{ type: Component, args: [{ selector: 'clr-alert-item', template: `
`, host: { class: 'alert-item' }, }] }], ctorParameters: function () { return [{ type: AlertIconAndTypesService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * @remark * This directive is used only of selectin alert text. */ class ClrAlertText { } ClrAlertText.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertText, deps: [], target: i0.ɵɵFactoryTarget.Directive }); ClrAlertText.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrAlertText, selector: ".alert-text", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertText, decorators: [{ type: Directive, args: [{ selector: '.alert-text', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAlertsPager { constructor(multiAlertService, commonStrings) { this.multiAlertService = multiAlertService; this.commonStrings = commonStrings; this.currentAlertChange = new EventEmitter(false); this.currentAlertIndexChange = new EventEmitter(); } /** * Input/Output to support two way binding on current alert instance */ get currentAlert() { return this.multiAlertService.currentAlert; } set currentAlert(alert) { if (alert) { this.multiAlertService.currentAlert = alert; } } /** * Input/Output to support two way binding on current alert index */ get currentAlertIndex() { return this.multiAlertService.current; } set currentAlertIndex(index) { this.multiAlertService.current = index; } get previousAlertAriaLabel() { const CURRENT = this.currentAlertIndex + 1; return this.commonStrings.parse(this.commonStrings.keys.alertPreviousAlertAriaLabel, { CURRENT: (CURRENT === 1 ? this.multiAlertService.count : CURRENT - 1).toString(), COUNT: this.multiAlertService.count.toString(), }); } get nextAlertAriaLabel() { const CURRENT = this.currentAlertIndex + 1; return this.commonStrings.parse(this.commonStrings.keys.alertNextAlertAriaLabel, { CURRENT: (CURRENT === this.multiAlertService.count ? 1 : CURRENT + 1).toString(), COUNT: this.multiAlertService.count.toString(), }); } ngOnInit() { this.multiAlertServiceChanges = this.multiAlertService.changes.subscribe(index => { this.currentAlertIndexChange.emit(index); this.currentAlertChange.emit(this.multiAlertService.activeAlerts[index]); }); } ngOnDestroy() { this.multiAlertServiceChanges.unsubscribe(); } pageUp() { this.multiAlertService.next(); } pageDown() { this.multiAlertService.previous(); } } ClrAlertsPager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertsPager, deps: [{ token: MultiAlertService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrAlertsPager.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAlertsPager, selector: "clr-alerts-pager", inputs: { currentAlert: ["clrCurrentAlert", "currentAlert"], currentAlertIndex: ["clrCurrentAlertIndex", "currentAlertIndex"] }, outputs: { currentAlertChange: "clrCurrentAlertChange", currentAlertIndexChange: "clrCurrentAlertIndexChange" }, host: { properties: { "class.alerts-pager": "true" } }, ngImport: i0, template: "\n\n
\n
\n \n
\n
{{this.multiAlertService.current+1}} / {{this.multiAlertService.count}}
\n
\n \n
\n
\n", dependencies: [{ kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertsPager, decorators: [{ type: Component, args: [{ selector: 'clr-alerts-pager', host: { '[class.alerts-pager]': 'true' }, template: "\n\n
\n
\n \n
\n
{{this.multiAlertService.current+1}} / {{this.multiAlertService.count}}
\n
\n \n
\n
\n" }] }], ctorParameters: function () { return [{ type: MultiAlertService }, { type: ClrCommonStringsService }]; }, propDecorators: { currentAlertChange: [{ type: Output, args: ['clrCurrentAlertChange'] }], currentAlertIndexChange: [{ type: Output, args: ['clrCurrentAlertIndexChange'] }], currentAlert: [{ type: Input, args: ['clrCurrentAlert'] }], currentAlertIndex: [{ type: Input, args: ['clrCurrentAlertIndex'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAlerts { constructor(multiAlertService) { this.multiAlertService = multiAlertService; this.currentAlertChange = new EventEmitter(false); this.currentAlertIndexChange = new EventEmitter(false); this.subscriptions = []; } set allAlerts(value) { this.multiAlertService.manage(value); // provide alerts } /** * Input/Output to support two way binding on current alert index */ set _inputCurrentIndex(index) { if (Number.isInteger(index) && index >= 0) { this.multiAlertService.current = index; } } get currentAlertIndex() { return this.multiAlertService.current; } set currentAlertIndex(index) { this.multiAlertService.current = index; } /** * Input/Output to support two way binding on current alert instance */ get currentAlert() { return this.multiAlertService.currentAlert; } set currentAlert(alert) { if (alert) { this.multiAlertService.currentAlert = alert; } } /** * Ensure we are only dealing with alerts that have not been closed yet */ get alerts() { return this.allAlerts.filter(alert => { return alert.hidden === false; }); } get currentAlertType() { if (this.multiAlertService.currentAlert) { return this.multiAlertService.currentAlert.alertType; } return ''; } ngAfterContentInit() { this.subscriptions.push(this.multiAlertService.changes.subscribe(index => { this.currentAlertIndexChange.next(index); this.currentAlertChange.next(this.multiAlertService.currentAlert); })); } ngOnDestroy() { this.subscriptions.forEach(sub => sub.unsubscribe()); this.multiAlertService.destroy(); } } ClrAlerts.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlerts, deps: [{ token: MultiAlertService }], target: i0.ɵɵFactoryTarget.Component }); ClrAlerts.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrAlerts, selector: "clr-alerts", inputs: { _inputCurrentIndex: ["clrCurrentAlertIndex", "_inputCurrentIndex"], currentAlert: ["clrCurrentAlert", "currentAlert"] }, outputs: { currentAlertChange: "clrCurrentAlertChange", currentAlertIndexChange: "clrCurrentAlertIndexChange" }, host: { properties: { "class.alerts": "true", "class.alert-danger": "this.currentAlertType == 'danger'", "class.alert-info": "this.currentAlertType == 'info'", "class.alert-success": "this.currentAlertType == 'success'", "class.alert-warning": "this.currentAlertType == 'warning'" } }, providers: [MultiAlertService], queries: [{ propertyName: "allAlerts", predicate: ClrAlert }], ngImport: i0, template: "\n\n 1\" [clrCurrentAlertIndex]=\"currentAlertIndex\">\n\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ClrAlertsPager, selector: "clr-alerts-pager", inputs: ["clrCurrentAlert", "clrCurrentAlertIndex"], outputs: ["clrCurrentAlertChange", "clrCurrentAlertIndexChange"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlerts, decorators: [{ type: Component, args: [{ selector: 'clr-alerts', providers: [MultiAlertService], host: { '[class.alerts]': 'true', '[class.alert-danger]': "this.currentAlertType == 'danger'", '[class.alert-info]': "this.currentAlertType == 'info'", '[class.alert-success]': "this.currentAlertType == 'success'", '[class.alert-warning]': "this.currentAlertType == 'warning'", }, template: "\n\n 1\" [clrCurrentAlertIndex]=\"currentAlertIndex\">\n\n", styles: [":host{display:block}\n"] }] }], ctorParameters: function () { return [{ type: MultiAlertService }]; }, propDecorators: { currentAlertChange: [{ type: Output, args: ['clrCurrentAlertChange'] }], currentAlertIndexChange: [{ type: Output, args: ['clrCurrentAlertIndexChange'] }], allAlerts: [{ type: ContentChildren, args: [ClrAlert] }], _inputCurrentIndex: [{ type: Input, args: ['clrCurrentAlertIndex'] }], currentAlert: [{ type: Input, args: ['clrCurrentAlert'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_ALERT_DIRECTIVES = [ClrAlert, ClrAlertItem, ClrAlerts, ClrAlertsPager, ClrAlertText]; class ClrAlertModule { constructor() { ClarityIcons.addIcons(checkCircleIcon, infoCircleIcon, exclamationCircleIcon, exclamationTriangleIcon, windowCloseIcon); } } ClrAlertModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrAlertModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertModule, declarations: [ClrAlert, ClrAlertItem, ClrAlerts, ClrAlertsPager, ClrAlertText], imports: [CommonModule, ClrIconModule, ClrDropdownModule], exports: [ClrAlert, ClrAlertItem, ClrAlerts, ClrAlertsPager, ClrAlertText] }); ClrAlertModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertModule, imports: [CommonModule, ClrIconModule, ClrDropdownModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAlertModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrDropdownModule], declarations: [CLR_ALERT_DIRECTIVES], exports: [CLR_ALERT_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrEmphasisModule { } ClrEmphasisModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrEmphasisModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrEmphasisModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrEmphasisModule, exports: [ClrAlertModule] }); ClrEmphasisModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrEmphasisModule, imports: [ClrAlertModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrEmphasisModule, decorators: [{ type: NgModule, args: [{ exports: [ClrAlertModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ResponsiveNavCodes { } ResponsiveNavCodes.NAV_LEVEL_1 = 1; ResponsiveNavCodes.NAV_LEVEL_2 = 2; ResponsiveNavCodes.NAV_CLOSE_ALL = 'NAV_CLOSE_ALL'; ResponsiveNavCodes.NAV_OPEN = 'NAV_OPEN'; ResponsiveNavCodes.NAV_CLOSE = 'NAV_CLOSE'; ResponsiveNavCodes.NAV_TOGGLE = 'NAV_TOGGLE'; ResponsiveNavCodes.NAV_CLASS_HAMBURGER_MENU = 'open-hamburger-menu'; ResponsiveNavCodes.NAV_CLASS_OVERFLOW_MENU = 'open-overflow-menu'; ResponsiveNavCodes.NAV_CLASS_TRIGGER_1 = 'header-hamburger-trigger'; ResponsiveNavCodes.NAV_CLASS_TRIGGER_2 = 'header-overflow-trigger'; ResponsiveNavCodes.NAV_CLASS_LEVEL_1 = 'clr-nav-level-1'; ResponsiveNavCodes.NAV_CLASS_LEVEL_2 = 'clr-nav-level-2'; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ResponsiveNavControlMessage { constructor(_controlCode, _navLevel) { this._controlCode = _controlCode; this._navLevel = _navLevel; } get controlCode() { return this._controlCode; } get navLevel() { return this._navLevel; } } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ResponsiveNavigationService { constructor() { this.responsiveNavList = []; this.registerNavSubject = new ReplaySubject(); this.controlNavSubject = new Subject(); this.closeAllNavs(); // We start with all navs closed } get registeredNavs() { return this.registerNavSubject.asObservable(); } get navControl() { return this.controlNavSubject.asObservable(); } registerNav(navLevel) { if (!navLevel || this.isNavRegistered(navLevel)) { return; } this.responsiveNavList.push(navLevel); this.registerNavSubject.next(this.responsiveNavList); } isNavRegistered(navLevel) { if (this.responsiveNavList.indexOf(navLevel) > -1) { console.error('Multiple clr-nav-level ' + navLevel + ' attributes found. Please make sure that only one exists'); return true; } return false; } unregisterNav(navLevel) { const index = this.responsiveNavList.indexOf(navLevel); if (index > -1) { this.responsiveNavList.splice(index, 1); this.registerNavSubject.next(this.responsiveNavList); } } sendControlMessage(controlCode, navLevel) { const message = new ResponsiveNavControlMessage(controlCode, navLevel); this.controlNavSubject.next(message); } closeAllNavs() { const message = new ResponsiveNavControlMessage(ResponsiveNavCodes.NAV_CLOSE_ALL, -999); this.controlNavSubject.next(message); } } ResponsiveNavigationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ResponsiveNavigationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ResponsiveNavigationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ResponsiveNavigationService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ResponsiveNavigationService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrMainContainer { constructor(elRef, responsiveNavService) { this.elRef = elRef; this.responsiveNavService = responsiveNavService; } ngOnInit() { this._classList = this.elRef.nativeElement.classList; this._subscription = this.responsiveNavService.navControl.subscribe({ next: (message) => { this.processMessage(message); }, }); } processMessage(message) { let navClass = ResponsiveNavCodes.NAV_CLASS_HAMBURGER_MENU; if (message.controlCode === ResponsiveNavCodes.NAV_CLOSE_ALL) { this._classList.remove(ResponsiveNavCodes.NAV_CLASS_HAMBURGER_MENU); this._classList.remove(ResponsiveNavCodes.NAV_CLASS_OVERFLOW_MENU); } else if (message.navLevel === ResponsiveNavCodes.NAV_LEVEL_1) { this.controlNav(message.controlCode, navClass); } else if (message.navLevel === ResponsiveNavCodes.NAV_LEVEL_2) { navClass = ResponsiveNavCodes.NAV_CLASS_OVERFLOW_MENU; this.controlNav(message.controlCode, navClass); } } controlNav(controlCode, navClass) { if (controlCode === ResponsiveNavCodes.NAV_OPEN) { this._classList.add(navClass); } else if (controlCode === ResponsiveNavCodes.NAV_CLOSE) { this._classList.remove(navClass); } else if (controlCode === ResponsiveNavCodes.NAV_TOGGLE) { this._classList.toggle(navClass); } } ngOnDestroy() { this._subscription.unsubscribe(); } } ClrMainContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMainContainer, deps: [{ token: i0.ElementRef }, { token: ResponsiveNavigationService }], target: i0.ɵɵFactoryTarget.Directive }); ClrMainContainer.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrMainContainer, selector: "clr-main-container", host: { properties: { "class.main-container": "true" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMainContainer, decorators: [{ type: Directive, args: [{ selector: 'clr-main-container', host: { '[class.main-container]': 'true' }, }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: ResponsiveNavigationService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_LAYOUT_DIRECTIVES = [ClrMainContainer]; class ClrMainContainerModule { } ClrMainContainerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMainContainerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrMainContainerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrMainContainerModule, declarations: [ClrMainContainer], imports: [CommonModule, ClrIconModule], exports: [ClrMainContainer] }); ClrMainContainerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMainContainerModule, imports: [CommonModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrMainContainerModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule], declarations: [CLR_LAYOUT_DIRECTIVES], exports: [CLR_LAYOUT_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrAriaCurrentLink { constructor(rla) { this.rla = rla; } ngOnInit() { this.subscription = this.rla.isActiveChange.subscribe(isActive => { this.ariaCurrent = isActive ? 'page' : undefined; }); } ngOnDestroy() { this.subscription.unsubscribe(); } } ClrAriaCurrentLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAriaCurrentLink, deps: [{ token: i1$1.RouterLinkActive }], target: i0.ɵɵFactoryTarget.Directive }); ClrAriaCurrentLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrAriaCurrentLink, selector: "[clrAriaCurrentLink]", host: { properties: { "attr.aria-current": "ariaCurrent" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrAriaCurrentLink, decorators: [{ type: Directive, args: [{ selector: '[clrAriaCurrentLink]', host: { '[attr.aria-current]': 'ariaCurrent' }, }] }], ctorParameters: function () { return [{ type: i1$1.RouterLinkActive }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class MainContainerWillyWonka extends WillyWonka { } MainContainerWillyWonka.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MainContainerWillyWonka, deps: null, target: i0.ɵɵFactoryTarget.Directive }); MainContainerWillyWonka.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: MainContainerWillyWonka, selector: "clr-main-container", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: MainContainerWillyWonka, decorators: [{ type: Directive, args: [{ selector: 'clr-main-container', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class NavDetectionOompaLoompa extends OompaLoompa { constructor(cdr, willyWonka, responsiveNavService) { if (!willyWonka) { throw new Error('clr-header should only be used inside of a clr-main-container'); } super(cdr, willyWonka); this.responsiveNavService = responsiveNavService; } // NavDetectionOompaLoompa is the addition of the nav levels // Since we support 2 levels, the possibilities are 0, 1 or 3 (1 + 2) get flavor() { return this.responsiveNavService.responsiveNavList.reduce((sum, navLevel) => sum + navLevel, 0); } } NavDetectionOompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NavDetectionOompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: MainContainerWillyWonka, optional: true }, { token: ResponsiveNavigationService }], target: i0.ɵɵFactoryTarget.Directive }); NavDetectionOompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: NavDetectionOompaLoompa, selector: "clr-header", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: NavDetectionOompaLoompa, decorators: [{ type: Directive, args: [{ selector: 'clr-header', }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: MainContainerWillyWonka, decorators: [{ type: Optional }] }, { type: ResponsiveNavigationService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrHeader { constructor(responsiveNavService, commonStrings) { this.responsiveNavService = responsiveNavService; this.commonStrings = commonStrings; this.role = 'banner'; this.isNavLevel1OnPage = false; this.isNavLevel2OnPage = false; this.openNavLevel = null; this.responsiveNavCodes = ResponsiveNavCodes; this._subscription = this.responsiveNavService.registeredNavs.subscribe({ next: (navLevelList) => { this.initializeNavTriggers(navLevelList); }, }); this._subscription.add(this.responsiveNavService.navControl .pipe(filter(({ controlCode }) => controlCode === ResponsiveNavCodes.NAV_CLOSE || controlCode === ResponsiveNavCodes.NAV_CLOSE_ALL)) .subscribe(() => { this.openNavLevel = null; })); } get responsiveNavCommonString() { const myCommonStrings = this.commonStrings.keys; if (this.openNavLevel !== this.responsiveNavCodes.NAV_LEVEL_1) { return myCommonStrings.responsiveNavToggleOpen; } else { return myCommonStrings.responsiveNavToggleClose; } } get responsiveOverflowCommonString() { const myCommonStrings = this.commonStrings.keys; if (this.openNavLevel !== this.responsiveNavCodes.NAV_LEVEL_2) { return myCommonStrings.responsiveNavOverflowOpen; } else { return myCommonStrings.responsiveNavOverflowClose; } } // reset triggers. handles cases when an application has different nav levels on different pages. resetNavTriggers() { this.isNavLevel1OnPage = false; this.isNavLevel2OnPage = false; } // decides which triggers to show on the header initializeNavTriggers(navList) { this.resetNavTriggers(); if (navList.length > 2) { console.error('More than 2 Nav Levels detected.'); return; } navList.forEach(navLevel => { if (navLevel === ResponsiveNavCodes.NAV_LEVEL_1) { this.isNavLevel1OnPage = true; } else if (navLevel === ResponsiveNavCodes.NAV_LEVEL_2) { this.isNavLevel2OnPage = true; } }); } // closes the nav that is open closeOpenNav() { this.responsiveNavService.closeAllNavs(); } /** * @deprecated Will be removed in with @clr/angular v15.0.0 * * Use `openNav(navLevel)` instead to open the navigation and ResponsiveNavService to close it. */ toggleNav(navLevel) { if (this.openNavLevel === navLevel) { this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_CLOSE, navLevel); return; } this.openNav(navLevel); } openNav(navLevel) { this.openNavLevel = navLevel; this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_OPEN, navLevel); } ngOnDestroy() { this._subscription.unsubscribe(); } } ClrHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrHeader, deps: [{ token: ResponsiveNavigationService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrHeader, selector: "clr-header", inputs: { role: "role" }, host: { properties: { "class.header": "true", "attr.role": "this.role" } }, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrHeader, decorators: [{ type: Component, args: [{ selector: 'clr-header', template: `
`, host: { '[class.header]': 'true' }, }] }], ctorParameters: function () { return [{ type: ResponsiveNavigationService }, { type: ClrCommonStringsService }]; }, propDecorators: { role: [{ type: Input }, { type: HostBinding, args: ['attr.role'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const createCdsCloseButton = (document, ariaLabel) => { const cdsCloseButton = document.createElement('cds-internal-close-button'); cdsCloseButton.setAttribute('icon-size', '32'); cdsCloseButton.setAttribute('aria-label', ariaLabel); cdsCloseButton.setAttribute('aria-hidden', 'true'); cdsCloseButton.setAttribute('type', 'button'); /** * The button is hidden by default based on our Desktop-first approach. */ cdsCloseButton.setAttribute('hidden', 'true'); cdsCloseButton.className = 'clr-nav-close'; return cdsCloseButton; }; class ClrNavLevel { constructor(platformId, cdkTrapFocus, responsiveNavService, elementRef, renderer, injector) { this.cdkTrapFocus = cdkTrapFocus; this.responsiveNavService = responsiveNavService; this.elementRef = elementRef; this.renderer = renderer; this._isOpen = false; if (isPlatformBrowser(platformId)) { this._document = injector.get(DOCUMENT); } this._subscription = responsiveNavService.navControl .pipe(filter(x => x.navLevel === this.level), filter(({ controlCode }) => (controlCode === ResponsiveNavCodes.NAV_OPEN && !this.isOpen) || (controlCode === ResponsiveNavCodes.NAV_CLOSE && this.isOpen))) .subscribe(({ controlCode }) => { if (controlCode === ResponsiveNavCodes.NAV_OPEN) { this.open(); return; } this.close(); }); this._subscription.add(responsiveNavService.navControl .pipe(filter(({ controlCode }) => controlCode === ResponsiveNavCodes.NAV_CLOSE_ALL)) .subscribe(() => this.close())); } get level() { return this._level; } // getter to access the responsive navigation codes from the template get responsiveNavCodes() { return ResponsiveNavCodes; } get isOpen() { return this._isOpen; } ngOnInit() { this.cdkTrapFocus.enabled = false; if (!this.closeButtonAriaLabel) { this.closeButtonAriaLabel = this._level === ResponsiveNavCodes.NAV_LEVEL_1 ? commonStringsDefault.responsiveNavToggleClose : commonStringsDefault.responsiveNavOverflowClose; } if (this.level !== ResponsiveNavCodes.NAV_LEVEL_1 && this.level !== ResponsiveNavCodes.NAV_LEVEL_2) { console.error('Nav Level can only be 1 or 2'); return; } this.responsiveNavService.registerNav(this.level); this.addNavClass(this.level); } ngAfterViewInit() { const closeButton = createCdsCloseButton(this._document, this.closeButtonAriaLabel); this.renderer.listen(closeButton, 'click', this.close.bind(this)); this.renderer.insertBefore(this.elementRef.nativeElement, closeButton, this.elementRef.nativeElement.firstChild); // Adding the button at the top of the nav if (this._document.body.clientWidth < LARGE_BREAKPOINT) { /** * Close if the document body is smaller than the large breakpoint for example: * - Refreshing the page * - Browser window size is changed when opening the applicaiton * - Browser zoom is turned on and zoomed to a size that makes the document smaller than the large breakpoint */ this.close(); } } ngOnDestroy() { this.responsiveNavService.unregisterNav(this.level); this._subscription.unsubscribe(); } onResize(event) { const target = event.target; if (target.innerWidth < LARGE_BREAKPOINT && this.isOpen) { this.close(); return; } this.showNavigation(); } // TODO: Figure out whats the best way to do this. Possible methods // 1. HostListener (current solution) // 2. Directives on the .nav-link class. We discussed on moving away from class selectors but I forget the reason // why onMouseClick(target) { let current = target; // Get the element in the DOM on which the mouse was clicked const navHost = this.elementRef.nativeElement; // Get the current nav native HTML element // Start checking if current and navHost are equal. // If not traverse to the parentNode and check again. while (current) { if (current === navHost) { return; } else if (current.classList.contains('nav-link') && this._document.body.clientWidth < LARGE_BREAKPOINT) { this.close(); return; } current = current.parentNode; } } addNavClass(level) { const navHostClassList = this.elementRef.nativeElement.classList; if (level === ResponsiveNavCodes.NAV_LEVEL_1) { navHostClassList.add(ResponsiveNavCodes.NAV_CLASS_LEVEL_1); } else if (level === ResponsiveNavCodes.NAV_LEVEL_2) { navHostClassList.add(ResponsiveNavCodes.NAV_CLASS_LEVEL_2); } } open() { this._isOpen = true; this.showNavigation(); this.cdkTrapFocus.enabled = true; this.showCloseButton(); this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_OPEN, this.level); } close() { this._isOpen = false; this.hideNavigation(); this.cdkTrapFocus.enabled = false; this.hideCloseButton(); this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_CLOSE, this.level); } hideNavigation() { this.renderer.setAttribute(this.elementRef.nativeElement, 'aria-hidden', 'true'); this.renderer.setAttribute(this.elementRef.nativeElement, 'hidden', 'true'); } showNavigation() { this.renderer.setAttribute(this.elementRef.nativeElement, 'aria-hidden', 'false'); this.renderer.removeAttribute(this.elementRef.nativeElement, 'hidden'); } hideCloseButton() { this.renderer.setAttribute(this.elementRef.nativeElement, 'aria-hidden', 'true'); this.renderer.setAttribute(this.elementRef.nativeElement.querySelector('.clr-nav-close'), 'hidden', 'true'); } showCloseButton() { this.renderer.setAttribute(this.elementRef.nativeElement.querySelector('.clr-nav-close'), 'aria-hidden', 'false'); this.renderer.removeAttribute(this.elementRef.nativeElement.querySelector('.clr-nav-close'), 'hidden'); } } ClrNavLevel.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrNavLevel, deps: [{ token: PLATFORM_ID }, { token: ClrStandaloneCdkTrapFocus }, { token: ResponsiveNavigationService }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Directive }); ClrNavLevel.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrNavLevel, selector: "[clr-nav-level]", inputs: { _level: ["clr-nav-level", "_level"], closeButtonAriaLabel: ["closeAriaLabel", "closeButtonAriaLabel"] }, host: { listeners: { "window:resize": "onResize($event)", "click": "onMouseClick($event.target)" } }, hostDirectives: [{ directive: ClrStandaloneCdkTrapFocus }], ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrNavLevel, decorators: [{ type: Directive, args: [{ selector: '[clr-nav-level]', hostDirectives: [ClrStandaloneCdkTrapFocus], }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: ClrStandaloneCdkTrapFocus }, { type: ResponsiveNavigationService }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.Injector }]; }, propDecorators: { _level: [{ type: Input, args: ['clr-nav-level'] }], closeButtonAriaLabel: [{ type: Input, args: ['closeAriaLabel'] }], onResize: [{ type: HostListener, args: ['window:resize', ['$event']] }], onMouseClick: [{ type: HostListener, args: ['click', ['$event.target']] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_NAVIGATION_DIRECTIVES = [ ClrHeader, ClrNavLevel, ClrAriaCurrentLink, NavDetectionOompaLoompa, MainContainerWillyWonka, ]; class ClrNavigationModule { } ClrNavigationModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrNavigationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrNavigationModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrNavigationModule, declarations: [ClrHeader, ClrNavLevel, ClrAriaCurrentLink, NavDetectionOompaLoompa, MainContainerWillyWonka], imports: [CommonModule, ClrIconModule, ClrDropdownModule], exports: [ClrHeader, ClrNavLevel, ClrAriaCurrentLink, NavDetectionOompaLoompa, MainContainerWillyWonka] }); ClrNavigationModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrNavigationModule, imports: [CommonModule, ClrIconModule, ClrDropdownModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrNavigationModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrDropdownModule], declarations: [CLR_NAVIGATION_DIRECTIVES], exports: [CLR_NAVIGATION_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TemplateRefContainer { } TemplateRefContainer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TemplateRefContainer, deps: [], target: i0.ɵɵFactoryTarget.Component }); TemplateRefContainer.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: TemplateRefContainer, selector: "ng-component", viewQueries: [{ propertyName: "template", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TemplateRefContainer, decorators: [{ type: Component, args: [{ template: ` `, }] }], propDecorators: { template: [{ type: ViewChild, args: [TemplateRef] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const TEMPLATE_REF_DIRECTIVES = [TemplateRefContainer]; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTemplateRefModule { } ClrTemplateRefModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTemplateRefModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrTemplateRefModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrTemplateRefModule, declarations: [TemplateRefContainer], imports: [CommonModule], exports: [TemplateRefContainer] }); ClrTemplateRefModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTemplateRefModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTemplateRefModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [TEMPLATE_REF_DIRECTIVES], exports: [TEMPLATE_REF_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TabsWillyWonka extends WillyWonka { } TabsWillyWonka.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TabsWillyWonka, deps: null, target: i0.ɵɵFactoryTarget.Directive }); TabsWillyWonka.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: TabsWillyWonka, selector: "clr-tabs", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TabsWillyWonka, decorators: [{ type: Directive, args: [{ selector: 'clr-tabs', }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ActiveOompaLoompa extends OompaLoompa { constructor(cdr, willyWonka, id, ifActive) { if (!willyWonka) { throw new Error('clrTabLink and clr-tab-content should only be used inside of a clr-tabs'); } super(cdr, willyWonka); this.ifActive = ifActive; this.id = id; } get flavor() { return this.ifActive.current === this.id; } } ActiveOompaLoompa.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ActiveOompaLoompa, deps: [{ token: i0.ChangeDetectorRef }, { token: TabsWillyWonka, optional: true }, { token: IF_ACTIVE_ID }, { token: IfActiveService }], target: i0.ɵɵFactoryTarget.Directive }); ActiveOompaLoompa.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ActiveOompaLoompa, selector: "[clrTabLink], clr-tab-content", usesInheritance: true, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ActiveOompaLoompa, decorators: [{ type: Directive, args: [{ selector: '[clrTabLink], clr-tab-content', }] }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: TabsWillyWonka, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: [IF_ACTIVE_ID] }] }, { type: IfActiveService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var TabsLayout; (function (TabsLayout) { TabsLayout["HORIZONTAL"] = "horizontal"; TabsLayout["VERTICAL"] = "vertical"; })(TabsLayout || (TabsLayout = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TabsService { constructor() { this.layout = TabsLayout.HORIZONTAL; this._children = []; } get children() { return this._children; } get activeTab() { return this.children.find((tab) => { return tab.active; }); } get overflowTabs() { if (this.layout === TabsLayout.VERTICAL) { return []; } else { return this.children.filter((tab) => tab.tabLink.inOverflow === true); } } register(tab) { this._children.push(tab); } unregister(tab) { const index = this.children.indexOf(tab); if (index > -1) { this.children.splice(index, 1); } } } TabsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TabsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); TabsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TabsService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TabsService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbTabContentComponents = 0; class ClrTabContent { constructor(ifActiveService, id, tabsService) { this.ifActiveService = ifActiveService; this.id = id; this.tabsService = tabsService; if (!this.tabContentId) { this.tabContentId = 'clr-tab-content-' + nbTabContentComponents++; } } get active() { return this.ifActiveService.current === this.id; } get ariaLabelledBy() { return this.tabsService.children.find(tab => tab.tabContent === this)?.tabLink?.tabLinkId; } // The template must be applied on the top-down phase of view-child initialization to prevent // components in the content from initializing before a content container exists. // Some child components need their container for sizing calculations. set templateRef(value) { this.viewRef = this.tabsService.tabContentViewContainer.createEmbeddedView(value); } ngOnDestroy() { const index = this.tabsService.tabContentViewContainer.indexOf(this.viewRef); if (index > -1) { this.tabsService.tabContentViewContainer.remove(index); } } } ClrTabContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabContent, deps: [{ token: IfActiveService }, { token: IF_ACTIVE_ID }, { token: TabsService }], target: i0.ɵɵFactoryTarget.Component }); ClrTabContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTabContent, selector: "clr-tab-content", inputs: { tabContentId: ["id", "tabContentId"] }, viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["tabContentProjectedRef"], descendants: true, static: true }], ngImport: i0, template: `
`, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabContent, decorators: [{ type: Component, args: [{ selector: 'clr-tab-content', template: `
`, }] }], ctorParameters: function () { return [{ type: IfActiveService }, { type: undefined, decorators: [{ type: Inject, args: [IF_ACTIVE_ID] }] }, { type: TabsService }]; }, propDecorators: { tabContentId: [{ type: Input, args: ['id'] }], templateRef: [{ type: ViewChild, args: ['tabContentProjectedRef', { static: true }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbTabsComponent = 0; const TABS_ID = new InjectionToken('TABS_ID'); function tokenFactory() { return 'clr-tabs-' + nbTabsComponent++; } const TABS_ID_PROVIDER = { provide: TABS_ID, useFactory: tokenFactory, }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let nbTabLinkComponents = 0; class ClrTabLink { constructor(ifActiveService, id, el, cfr, viewContainerRef, tabsService, tabsId) { this.ifActiveService = ifActiveService; this.id = id; this.el = el; this.cfr = cfr; this.viewContainerRef = viewContainerRef; this.tabsService = tabsService; this.tabsId = tabsId; if (!this.tabLinkId) { this.tabLinkId = 'clr-tab-link-' + nbTabLinkComponents++; } // Tab links can be rendered in one of two places: in the main area or inside the overflow dropdown menu. // Here, we create a container so that its template can be used to create embeddedView on the fly. // See TabsService's renderView() method and how it's used in Tabs class for an example. const factory = this.cfr.resolveComponentFactory(TemplateRefContainer); this.templateRefContainer = this.viewContainerRef.createComponent(factory, undefined, undefined, [ [this.el.nativeElement], ]).instance; } get inOverflow() { return this._inOverflow && this.tabsService.layout !== TabsLayout.VERTICAL; } set inOverflow(inOverflow) { this._inOverflow = inOverflow; } get addLinkClasses() { return !this.inOverflow; } get ariaControls() { return this.tabsService.children.find(tab => tab.tabLink === this)?.tabContent?.tabContentId; } get active() { return this.ifActiveService.current === this.id; } get tabindex() { return this.active ? 0 : -1; } activate() { this.ifActiveService.current = this.id; } } ClrTabLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabLink, deps: [{ token: IfActiveService }, { token: IF_ACTIVE_ID }, { token: i0.ElementRef }, { token: i0.ComponentFactoryResolver }, { token: i0.ViewContainerRef }, { token: TabsService }, { token: TABS_ID }], target: i0.ɵɵFactoryTarget.Directive }); ClrTabLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrTabLink, selector: "[clrTabLink]", inputs: { tabLinkId: ["id", "tabLinkId"], inOverflow: ["clrTabLinkInOverflow", "inOverflow"] }, host: { attributes: { "role": "tab", "type": "button" }, listeners: { "click": "activate()" }, properties: { "class.btn": "true", "id": "this.tabLinkId", "class.btn-link": "this.addLinkClasses", "class.nav-link": "this.addLinkClasses", "attr.aria-controls": "this.ariaControls", "class.active": "this.active", "attr.aria-selected": "this.active", "attr.tabindex": "this.tabindex" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabLink, decorators: [{ type: Directive, args: [{ selector: '[clrTabLink]', host: { '[class.btn]': 'true', role: 'tab', type: 'button', }, }] }], ctorParameters: function () { return [{ type: IfActiveService }, { type: undefined, decorators: [{ type: Inject, args: [IF_ACTIVE_ID] }] }, { type: i0.ElementRef }, { type: i0.ComponentFactoryResolver }, { type: i0.ViewContainerRef }, { type: TabsService }, { type: undefined, decorators: [{ type: Inject, args: [TABS_ID] }] }]; }, propDecorators: { tabLinkId: [{ type: Input, args: ['id'] }, { type: HostBinding, args: ['id'] }], inOverflow: [{ type: Input, args: ['clrTabLinkInOverflow'] }], addLinkClasses: [{ type: HostBinding, args: ['class.btn-link'] }, { type: HostBinding, args: ['class.nav-link'] }], ariaControls: [{ type: HostBinding, args: ['attr.aria-controls'] }], active: [{ type: HostBinding, args: ['class.active'] }, { type: HostBinding, args: ['attr.aria-selected'] }], tabindex: [{ type: HostBinding, args: ['attr.tabindex'] }], activate: [{ type: HostListener, args: ['click'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTab { constructor(ifActiveService, id, tabsService) { this.ifActiveService = ifActiveService; this.id = id; this.tabsService = tabsService; tabsService.register(this); } get active() { return this.ifActiveService.current === this.id; } ngOnDestroy() { this.tabsService.unregister(this); } } ClrTab.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTab, deps: [{ token: IfActiveService }, { token: IF_ACTIVE_ID }, { token: TabsService }], target: i0.ɵɵFactoryTarget.Component }); ClrTab.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTab, selector: "clr-tab", providers: [IF_ACTIVE_ID_PROVIDER], queries: [{ propertyName: "tabLink", first: true, predicate: ClrTabLink, descendants: true, static: true }, { propertyName: "tabContent", first: true, predicate: ClrTabContent, descendants: true, static: true }], ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTab, decorators: [{ type: Component, args: [{ selector: 'clr-tab', template: ``, providers: [IF_ACTIVE_ID_PROVIDER], }] }], ctorParameters: function () { return [{ type: IfActiveService }, { type: undefined, decorators: [{ type: Inject, args: [IF_ACTIVE_ID] }] }, { type: TabsService }]; }, propDecorators: { tabLink: [{ type: ContentChild, args: [ClrTabLink, { static: true }] }], tabContent: [{ type: ContentChild, args: [ClrTabContent, { static: true }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTabOverflowContent { } ClrTabOverflowContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabOverflowContent, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrTabOverflowContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTabOverflowContent, selector: "clr-tab-overflow-content", host: { properties: { "class.dropdown-menu": "true" } }, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabOverflowContent, decorators: [{ type: Component, args: [{ selector: 'clr-tab-overflow-content', template: ``, host: { '[class.dropdown-menu]': 'true', }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTabs { constructor(ifActiveService, toggleService, tabsService, tabsId, commonStrings) { this.ifActiveService = ifActiveService; this.toggleService = toggleService; this.tabsService = tabsService; this.tabsId = tabsId; this.commonStrings = commonStrings; this.tabLinkElements = []; // in order to check focus is triggered by click // we are using this _mousedown flag this._mousedown = false; this.subscriptions = []; this._tabLinkDirectives = []; } get layout() { return this.tabsService.layout; } set layout(layout) { if (Object.keys(TabsLayout) .map(key => { return TabsLayout[key]; }) .indexOf(layout) >= 0) { this.tabsService.layout = layout; } } get tabLinkDirectives() { return this._tabLinkDirectives; } get activeTabInOverflow() { return this.tabsService.overflowTabs.indexOf(this.tabsService.activeTab) > -1; } get activeTabPosition() { return this._tabLinkDirectives.findIndex(link => link.active); } get isCurrentInOverflow() { return this.keyFocus.current >= this.overflowPosition; } get isVertical() { return this.layout === TabsLayout.VERTICAL; } set tabOverflowEl(value) { this._tabOverflowEl = value && value.nativeElement; if (this.toggleService.open && value) { // only when tab overflow view element is registered, // we need to move the focus to the first item this.keyFocus.focusCurrent(); } } get overflowPosition() { return this._tabLinkDirectives.filter(link => !link.inOverflow).length; } set tabContentViewContainer(value) { this.tabsService.tabContentViewContainer = value; } ngAfterContentInit() { this.subscriptions.push(this.listenForTabLinkChanges()); if (typeof this.ifActiveService.current === 'undefined' && this.tabLinkDirectives[0]) { this.tabLinkDirectives[0].activate(); } // set initial current position this.keyFocus.current = this.activeTabPosition; } ngOnDestroy() { this.subscriptions.forEach(sub => { sub.unsubscribe(); }); } toggleOverflowOnPosition(position) { // we need to check current position to determine // whether we need to open the tab overflow or not this.toggleService.open = position >= this.overflowPosition; } resetKeyFocusCurrentToActive(event) { const keyFocusContainsFocus = this.keyFocus.nativeElement.contains(event.relatedTarget); if (!keyFocusContainsFocus && this.keyFocus.current !== this.activeTabPosition) { this.keyFocus.current = this.activeTabPosition; } } toggleOverflowOnClick() { if (this.isCurrentInOverflow && this.toggleService.open) { this.keyFocus.moveTo(this.overflowPosition - 1); } else { this.keyFocus.moveTo(this.overflowPosition); } // once click handler completes running, // reset the _mousedown flag this._mousedown = false; } openOverflowOnFocus() { // This method should be called only on keyboard generated focus // when the active tab is in the overflow if (!this._mousedown && !this.toggleService.open) { this.keyFocus.moveTo(this.activeTabPosition); } } closeOnFocusOut(event) { if (!this._tabOverflowEl.contains(event.relatedTarget) && this.toggleService.open && !this._mousedown) { this.toggleService.open = false; // if the focus is out of overflow and lands on the active tab link // which is currently visible, set the key focus current to activeTabPosition if (this.tabLinkElements[this.activeTabPosition] === event.relatedTarget) { this.keyFocus.current = this.activeTabPosition; } } } closeOnEscapeKey() { // Move current to the last visible focusable item this.keyFocus.moveTo(this.overflowPosition - 1); } closeOnOutsideClick(event, tabOverflowTrigger) { // Exit early if the event target is the trigger element itself or element that's inside the trigger element. // This is because we have another handler on the tabOverflowTrigger element itself. // As this handler method is on the document level so the event bubbles up to it and conflicts // with the tabOverflowTrigger handler resulting in opening the tab overflow and closing it right away consecutively. if (event.target === tabOverflowTrigger || tabOverflowTrigger.contains(event.target)) { return; } // Move current to the last visible focusable item if (!this._tabOverflowEl.contains(event.target) && this.isCurrentInOverflow) { this.keyFocus.moveTo(this.overflowPosition - 1); } } listenForTabLinkChanges() { return this.tabs.changes.pipe(startWith(this.tabs.map(tab => tab.tabLink))).subscribe(() => { this._tabLinkDirectives = this.tabs.map(tab => tab.tabLink); this.tabLinkElements = this._tabLinkDirectives.map(tab => tab.el.nativeElement); }); } } ClrTabs.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabs, deps: [{ token: IfActiveService }, { token: ClrPopoverToggleService }, { token: TabsService }, { token: TABS_ID }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrTabs.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTabs, selector: "clr-tabs", inputs: { layout: ["clrLayout", "layout"] }, host: { properties: { "class.tabs-vertical": "this.isVertical" } }, providers: [IfActiveService, TabsService, TABS_ID_PROVIDER], queries: [{ propertyName: "tabs", predicate: ClrTab }], viewQueries: [{ propertyName: "keyFocus", first: true, predicate: ClrKeyFocus, descendants: true, static: true }, { propertyName: "tabOverflowEl", first: true, predicate: ClrTabOverflowContent, descendants: true, read: ElementRef }, { propertyName: "tabContentViewContainer", first: true, predicate: ["tabContentViewContainer"], descendants: true, read: ViewContainerRef, static: true }], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrKeyFocus, selector: "[clrKeyFocus]", inputs: ["clrDirection", "clrFocusOnLoad", "clrKeyFocus"], outputs: ["clrFocusChange"] }, { kind: "component", type: ClrTabOverflowContent, selector: "clr-tab-overflow-content" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabs, decorators: [{ type: Component, args: [{ selector: 'clr-tabs', template: ` `, providers: [IfActiveService, TabsService, TABS_ID_PROVIDER], hostDirectives: [ClrPopoverHostDirective], }] }], ctorParameters: function () { return [{ type: IfActiveService }, { type: ClrPopoverToggleService }, { type: TabsService }, { type: undefined, decorators: [{ type: Inject, args: [TABS_ID] }] }, { type: ClrCommonStringsService }]; }, propDecorators: { keyFocus: [{ type: ViewChild, args: [ClrKeyFocus, { static: true }] }], tabs: [{ type: ContentChildren, args: [ClrTab] }], layout: [{ type: Input, args: ['clrLayout'] }], isVertical: [{ type: HostBinding, args: ['class.tabs-vertical'] }], tabOverflowEl: [{ type: ViewChild, args: [ClrTabOverflowContent, { read: ElementRef }] }], tabContentViewContainer: [{ type: ViewChild, args: ['tabContentViewContainer', { static: true, read: ViewContainerRef }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_TABS_DIRECTIVES = [ ClrTabContent, ClrTab, ClrTabs, ClrTabOverflowContent, ClrTabLink, TabsWillyWonka, ActiveOompaLoompa, ]; class ClrTabsModule { constructor() { ClarityIcons.addIcons(ellipsisHorizontalIcon); } } ClrTabsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrTabsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrTabsModule, declarations: [ClrTabContent, ClrTab, ClrTabs, ClrTabOverflowContent, ClrTabLink, TabsWillyWonka, ActiveOompaLoompa], imports: [CommonModule, ClrConditionalModule, ClrIconModule, ClrTemplateRefModule, ClrKeyFocusModule], exports: [ClrTabContent, ClrTab, ClrTabs, ClrTabOverflowContent, ClrTabLink, TabsWillyWonka, ActiveOompaLoompa, ClrConditionalModule] }); ClrTabsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabsModule, imports: [CommonModule, ClrConditionalModule, ClrIconModule, ClrTemplateRefModule, ClrKeyFocusModule, ClrConditionalModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTabsModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrConditionalModule, ClrIconModule, ClrTemplateRefModule, ClrKeyFocusModule], declarations: [CLR_TABS_DIRECTIVES], exports: [CLR_TABS_DIRECTIVES, ClrConditionalModule], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class VerticalNavGroupRegistrationService { constructor() { this.navGroupCount = 0; } registerNavGroup() { this.navGroupCount++; } unregisterNavGroup() { this.navGroupCount--; } } VerticalNavGroupRegistrationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavGroupRegistrationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); VerticalNavGroupRegistrationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavGroupRegistrationService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavGroupRegistrationService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class VerticalNavIconService { constructor() { this._icons = 0; } get hasIcons() { return this._icons > 0; } registerIcon() { this._icons++; } unregisterIcon() { this._icons--; } } VerticalNavIconService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavIconService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); VerticalNavIconService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavIconService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavIconService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class VerticalNavService { constructor() { this._animateOnCollapsed = new Subject(); this._collapsedChanged = new Subject(); this._collapsed = false; this._collapsible = false; } get animateOnCollapsed() { return this._animateOnCollapsed.asObservable(); } get collapsedChanged() { return this._collapsedChanged.asObservable(); } get collapsed() { return this._collapsed; } set collapsed(value) { value = !!value; if (this.collapsible && this._collapsed !== value) { this.updateCollapseBehavior(value); } } get collapsible() { return this._collapsible; } set collapsible(value) { value = !!value; if (this._collapsible !== value) { if (!value && this.collapsed) { this.updateCollapseBehavior(false); } this._collapsible = value; } } updateCollapseBehavior(value) { this._animateOnCollapsed.next(value); this._collapsed = value; this._collapsedChanged.next(value); } } VerticalNavService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); VerticalNavService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrVerticalNav { constructor(_navService, _navIconService, _navGroupRegistrationService, commonStrings) { this._navService = _navService; this._navIconService = _navIconService; this._navGroupRegistrationService = _navGroupRegistrationService; this.commonStrings = commonStrings; this._collapsedChanged = new EventEmitter(true); this._sub = this._navService.collapsedChanged.subscribe(value => { this._collapsedChanged.emit(value); }); } get collapsible() { return this._navService.collapsible; } set collapsible(value) { this._navService.collapsible = value; } get collapsed() { return this._navService.collapsed; } set collapsed(value) { this._navService.collapsed = value; } get hasNavGroups() { return this._navGroupRegistrationService.navGroupCount > 0; } get hasIcons() { return this._navIconService.hasIcons; } get ariaExpanded() { if (!this.collapsible) { return null; } return !this.collapsed ? 'true' : 'false'; } ngOnDestroy() { this._sub.unsubscribe(); } toggleByButton() { this.collapsed = !this.collapsed; } } ClrVerticalNav.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNav, deps: [{ token: VerticalNavService }, { token: VerticalNavIconService }, { token: VerticalNavGroupRegistrationService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrVerticalNav.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrVerticalNav, selector: "clr-vertical-nav", inputs: { collapsible: ["clrVerticalNavCollapsible", "collapsible"], collapsed: ["clrVerticalNavCollapsed", "collapsed"] }, outputs: { _collapsedChanged: "clrVerticalNavCollapsedChange" }, host: { properties: { "class.is-collapsed": "collapsed", "class.has-nav-groups": "hasNavGroups", "class.has-icons": "hasIcons" }, classAttribute: "clr-vertical-nav" }, providers: [VerticalNavService, VerticalNavIconService, VerticalNavGroupRegistrationService], ngImport: i0, template: "\n\n\n \n\n
\n \n \n
\n", dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNav, decorators: [{ type: Component, args: [{ selector: 'clr-vertical-nav', providers: [VerticalNavService, VerticalNavIconService, VerticalNavGroupRegistrationService], host: { class: 'clr-vertical-nav', '[class.is-collapsed]': 'collapsed', '[class.has-nav-groups]': 'hasNavGroups', '[class.has-icons]': 'hasIcons', }, template: "\n\n\n \n\n
\n \n \n
\n" }] }], ctorParameters: function () { return [{ type: VerticalNavService }, { type: VerticalNavIconService }, { type: VerticalNavGroupRegistrationService }, { type: ClrCommonStringsService }]; }, propDecorators: { _collapsedChanged: [{ type: Output, args: ['clrVerticalNavCollapsedChange'] }], collapsible: [{ type: Input, args: ['clrVerticalNavCollapsible'] }], collapsed: [{ type: Input, args: ['clrVerticalNavCollapsed'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class VerticalNavGroupService { constructor() { this._expandChange = new Subject(); } get expandChange() { return this._expandChange.asObservable(); } expand() { this._expandChange.next(true); } } VerticalNavGroupService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavGroupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); VerticalNavGroupService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavGroupService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: VerticalNavGroupService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const EXPANDED_STATE = 'expanded'; const COLLAPSED_STATE = 'collapsed'; class ClrVerticalNavGroup { constructor(_itemExpand, _navGroupRegistrationService, _navGroupService, _navService, commonStrings) { this._itemExpand = _itemExpand; this._navGroupRegistrationService = _navGroupRegistrationService; this._navGroupService = _navGroupService; this._navService = _navService; this.commonStrings = commonStrings; this.expandedChange = new EventEmitter(true); this.wasExpanded = false; this._subscriptions = []; this._expandAnimationState = COLLAPSED_STATE; this._navGroupRegistrationService.registerNavGroup(); // FIXME: This subscription handles a corner case // Vertical Nav collapse requires the animation to run first and then // remove the nodes from the DOM. If the user directly sets the input // on the clrIfExpanded directive, we have no chance to run the animation // and wait for it to complete. This subscription makes sure that the // animation states are correct for that edge case. this._subscriptions.push(this._itemExpand.expandChange.subscribe(value => { if (value && this.expandAnimationState === COLLAPSED_STATE) { if (this._navService.collapsed) { this._navService.collapsed = false; } this.expandAnimationState = EXPANDED_STATE; } else if (!value && this.expandAnimationState === EXPANDED_STATE) { this.expandAnimationState = COLLAPSED_STATE; } })); // 1. If the nav is collapsing, close the open nav group + save its state // 2. If the nav is expanding, expand the nav group if the previous state was expanded this._subscriptions.push(this._navService.animateOnCollapsed.subscribe((goingToCollapse) => { if (goingToCollapse && this.expanded) { this.wasExpanded = true; this.expandAnimationState = COLLAPSED_STATE; } else if (!goingToCollapse && this.wasExpanded) { this.expandGroup(); this.wasExpanded = false; } })); // If a link is clicked, expand the nav group this._subscriptions.push(this._navGroupService.expandChange.subscribe((expand) => { if (expand && !this.expanded) { this.expandGroup(); } })); } get expanded() { return this._itemExpand.expanded; } set expanded(value) { if (this._itemExpand.expanded !== value) { this._itemExpand.expanded = value; this.expandedChange.emit(value); } } set userExpandedInput(value) { value = !!value; if (this.expanded !== value) { // We have to call toggleExpand because some cases require animations to occur first // Directly setting the Expand service value skips the animation and can result in // nodes in the DOM but the nav group still being collapsed this.toggleExpand(); } } get expandAnimationState() { return this._expandAnimationState; } set expandAnimationState(value) { if (value !== this._expandAnimationState) { this._expandAnimationState = value; } } ngAfterContentInit() { // This makes sure that if someone marks a nav group expanded in a collapsed nav // the expanded property is switched back to collapsed state. if (this._navService.collapsed && this.expanded) { this.wasExpanded = true; this.expandAnimationState = COLLAPSED_STATE; } } ngOnDestroy() { this._subscriptions.forEach((sub) => sub.unsubscribe()); this._navGroupRegistrationService.unregisterNavGroup(); } expandGroup() { this.expanded = true; // Expanded animation occurs after Expand.expand is set to true this.expandAnimationState = EXPANDED_STATE; } collapseGroup() { // If a Vertical Nav Group toggle button is clicked while the Vertical Nav is in Collapsed state, // the Vertical Nav should be expanded first. this.expandAnimationState = COLLAPSED_STATE; } // closes a group after the collapse animation expandAnimationDone($event) { if ($event.toState === COLLAPSED_STATE) { this.expanded = false; } } toggleExpand() { if (this.expanded) { this.collapseGroup(); } else { // If nav is collasped, first open the nav if (this._navService.collapsed) { this._navService.collapsed = false; } // then expand the nav group this.expandGroup(); } } } ClrVerticalNavGroup.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavGroup, deps: [{ token: IfExpandService }, { token: VerticalNavGroupRegistrationService }, { token: VerticalNavGroupService }, { token: VerticalNavService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrVerticalNavGroup.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrVerticalNavGroup, selector: "clr-vertical-nav-group", inputs: { userExpandedInput: ["clrVerticalNavGroupExpanded", "userExpandedInput"] }, outputs: { expandedChange: "clrVerticalNavGroupExpandedChange" }, host: { properties: { "class.is-expanded": "this.expanded" }, classAttribute: "nav-group" }, providers: [IfExpandService, VerticalNavGroupService], ngImport: i0, template: "\n\n
\n \n \n
\n\n
\n \n
\n", dependencies: [{ kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }], animations: [ trigger('clrExpand', [ state(EXPANDED_STATE, style({ height: '*' })), state(COLLAPSED_STATE, style({ height: 0, visibility: 'hidden' })), transition(`${EXPANDED_STATE} <=> ${COLLAPSED_STATE}`, animate('0.2s ease-in-out')), ]), ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavGroup, decorators: [{ type: Component, args: [{ selector: 'clr-vertical-nav-group', providers: [IfExpandService, VerticalNavGroupService], animations: [ trigger('clrExpand', [ state(EXPANDED_STATE, style({ height: '*' })), state(COLLAPSED_STATE, style({ height: 0, visibility: 'hidden' })), transition(`${EXPANDED_STATE} <=> ${COLLAPSED_STATE}`, animate('0.2s ease-in-out')), ]), ], host: { class: 'nav-group' }, template: "\n\n
\n \n \n
\n\n
\n \n
\n" }] }], ctorParameters: function () { return [{ type: IfExpandService }, { type: VerticalNavGroupRegistrationService }, { type: VerticalNavGroupService }, { type: VerticalNavService }, { type: ClrCommonStringsService }]; }, propDecorators: { expandedChange: [{ type: Output, args: ['clrVerticalNavGroupExpandedChange'] }], expanded: [{ type: HostBinding, args: ['class.is-expanded'] }], userExpandedInput: [{ type: Input, args: ['clrVerticalNavGroupExpanded'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrVerticalNavGroupChildren { } ClrVerticalNavGroupChildren.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavGroupChildren, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrVerticalNavGroupChildren.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrVerticalNavGroupChildren, selector: "clr-vertical-nav-group-children", ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavGroupChildren, decorators: [{ type: Component, args: [{ selector: 'clr-vertical-nav-group-children', template: ``, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrVerticalNavIcon { constructor(_verticalNavIconService) { this._verticalNavIconService = _verticalNavIconService; this._verticalNavIconService.registerIcon(); } ngOnDestroy() { this._verticalNavIconService.unregisterIcon(); } } ClrVerticalNavIcon.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavIcon, deps: [{ token: VerticalNavIconService }], target: i0.ɵɵFactoryTarget.Directive }); ClrVerticalNavIcon.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrVerticalNavIcon, selector: "[clrVerticalNavIcon]", host: { classAttribute: "nav-icon" }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavIcon, decorators: [{ type: Directive, args: [{ selector: '[clrVerticalNavIcon]', host: { class: 'nav-icon' }, }] }], ctorParameters: function () { return [{ type: VerticalNavIconService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrVerticalNavLink { constructor(host, ref, navGroupService) { this.destroy$ = new Subject(); // Note: since the `VerticalNavGroupService` is an optional provider, we'll setup the event // listener only when the `[clrVerticalLink]` is located within the `clr-vertical-nav-group`. navGroupService && fromEvent(host.nativeElement, 'click') .pipe(takeUntil(this.destroy$)) .subscribe(() => { navGroupService.expand(); ref.markForCheck(); }); } ngOnDestroy() { this.destroy$.next(); } } ClrVerticalNavLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavLink, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: VerticalNavGroupService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); ClrVerticalNavLink.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrVerticalNavLink, selector: "[clrVerticalNavLink]", host: { classAttribute: "nav-link" }, ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavLink, decorators: [{ type: Component, args: [{ selector: '[clrVerticalNavLink]', template: ` `, host: { class: 'nav-link', }, }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: VerticalNavGroupService, decorators: [{ type: Optional }, { type: Inject, args: [VerticalNavGroupService] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_VERTICAL_NAV_DIRECTIVES = [ ClrVerticalNav, ClrVerticalNavLink, ClrVerticalNavGroup, ClrVerticalNavGroupChildren, ClrVerticalNavIcon, ]; class ClrVerticalNavModule { constructor() { ClarityIcons.addIcons(angleIcon, angleDoubleIcon); } } ClrVerticalNavModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrVerticalNavModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavModule, declarations: [ClrVerticalNav, ClrVerticalNavLink, ClrVerticalNavGroup, ClrVerticalNavGroupChildren, ClrVerticalNavIcon], imports: [CommonModule, ClrIconModule, ClrConditionalModule, ClrFocusOnViewInitModule], exports: [ClrVerticalNav, ClrVerticalNavLink, ClrVerticalNavGroup, ClrVerticalNavGroupChildren, ClrVerticalNavIcon, ClrConditionalModule, ClrIconModule, ClrFocusOnViewInitModule] }); ClrVerticalNavModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavModule, imports: [CommonModule, ClrIconModule, ClrConditionalModule, ClrFocusOnViewInitModule, ClrConditionalModule, ClrIconModule, ClrFocusOnViewInitModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrVerticalNavModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrConditionalModule, ClrFocusOnViewInitModule], declarations: [CLR_VERTICAL_NAV_DIRECTIVES], exports: [CLR_VERTICAL_NAV_DIRECTIVES, ClrConditionalModule, ClrIconModule, ClrFocusOnViewInitModule], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrLayoutModule { } ClrLayoutModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLayoutModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrLayoutModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrLayoutModule, exports: [ClrMainContainerModule, ClrNavigationModule, ClrTabsModule, ClrVerticalNavModule] }); ClrLayoutModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLayoutModule, imports: [ClrMainContainerModule, ClrNavigationModule, ClrTabsModule, ClrVerticalNavModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrLayoutModule, decorators: [{ type: NgModule, args: [{ exports: [ClrMainContainerModule, ClrNavigationModule, ClrTabsModule, ClrVerticalNavModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ScrollingService { constructor(_document) { this._document = _document; } stopScrolling() { this._document.body.classList.add('no-scrolling'); } resumeScrolling() { if (this._document.body.classList.contains('no-scrolling')) { this._document.body.classList.remove('no-scrolling'); } } } ScrollingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ScrollingService, deps: [{ token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable }); ScrollingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ScrollingService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ScrollingService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrModal { constructor(_scrollingService, commonStrings, modalStackService) { this._scrollingService = _scrollingService; this.commonStrings = commonStrings; this.modalStackService = modalStackService; this.modalId = uniqueIdFactory(); this._open = false; this._openChanged = new EventEmitter(false); this.closable = true; this.closeButtonAriaLabel = this.commonStrings.keys.close; this.staticBackdrop = true; this.skipAnimation = 'false'; this.stopClose = false; this.altClose = new EventEmitter(false); this.labelledBy = this.modalId; // presently this is only used by inline wizards this.bypassScrollService = false; } // Detect when _open is set to true and set no-scrolling to true ngOnChanges(changes) { if (!this.bypassScrollService && changes && Object.prototype.hasOwnProperty.call(changes, '_open')) { if (changes._open.currentValue) { this._scrollingService.stopScrolling(); this.modalStackService.trackModalOpen(this); } else { this._scrollingService.resumeScrolling(); } } } ngOnDestroy() { this._scrollingService.resumeScrolling(); } open() { if (this._open) { return; } this._open = true; this._openChanged.emit(true); this.modalStackService.trackModalOpen(this); } close() { if (this.stopClose) { this.altClose.emit(false); return; } if (!this.closable || !this._open) { return; } this._open = false; } fadeDone(e) { if (e.toState === 'void') { // TODO: Investigate if we can decouple from animation events this._openChanged.emit(false); this.modalStackService.trackModalClose(this); } } } ClrModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModal, deps: [{ token: ScrollingService }, { token: ClrCommonStringsService }, { token: ModalStackService }], target: i0.ɵɵFactoryTarget.Component }); ClrModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrModal, selector: "clr-modal", inputs: { _open: ["clrModalOpen", "_open"], closable: ["clrModalClosable", "closable"], closeButtonAriaLabel: ["clrModalCloseButtonAriaLabel", "closeButtonAriaLabel"], size: ["clrModalSize", "size"], staticBackdrop: ["clrModalStaticBackdrop", "staticBackdrop"], skipAnimation: ["clrModalSkipAnimation", "skipAnimation"], stopClose: ["clrModalPreventClose", "stopClose"], labelledBy: ["clrModalLabelledById", "labelledBy"], bypassScrollService: ["clrModalOverrideScrollService", "bypassScrollService"] }, outputs: { _openChanged: "clrModalOpenChange", altClose: "clrModalAlternateClose" }, host: { properties: { "class.open": "this._open" } }, usesOnChanges: true, ngImport: i0, template: "\n\n
\n \n \n
{{commonStrings.keys.modalContentStart}}
\n
\n \n \n\n
\n
\n
\n \n
\n \n \n \n
\n
\n \n
\n \n
\n
\n
{{commonStrings.keys.modalContentEnd}}
\n
\n\n
\n\n", styles: [":host{display:none}:host.open{display:inline}\n"], dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdkTrapFocusModule_CdkTrapFocus, selector: "[cdkTrapFocus]" }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }], viewProviders: [ScrollingService], animations: [ trigger('fadeDown', [ transition('* => false', [style({ opacity: 0, transform: 'translate(0, -25%)' }), animate('0.2s ease-in-out')]), transition('false => *', [animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(0, -25%)' }))]), ]), trigger('fade', [ transition('void => *', [style({ opacity: 0 }), animate('0.2s ease-in-out', style({ opacity: 0.85 }))]), transition('* => void', [animate('0.2s ease-in-out', style({ opacity: 0 }))]), ]), ] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModal, decorators: [{ type: Component, args: [{ selector: 'clr-modal', viewProviders: [ScrollingService], animations: [ trigger('fadeDown', [ transition('* => false', [style({ opacity: 0, transform: 'translate(0, -25%)' }), animate('0.2s ease-in-out')]), transition('false => *', [animate('0.2s ease-in-out', style({ opacity: 0, transform: 'translate(0, -25%)' }))]), ]), trigger('fade', [ transition('void => *', [style({ opacity: 0 }), animate('0.2s ease-in-out', style({ opacity: 0.85 }))]), transition('* => void', [animate('0.2s ease-in-out', style({ opacity: 0 }))]), ]), ], template: "\n\n
\n \n \n
{{commonStrings.keys.modalContentStart}}
\n
\n \n \n\n
\n
\n
\n \n
\n \n \n \n
\n
\n \n
\n \n
\n
\n
{{commonStrings.keys.modalContentEnd}}
\n
\n\n
\n\n", styles: [":host{display:none}:host.open{display:inline}\n"] }] }], ctorParameters: function () { return [{ type: ScrollingService }, { type: ClrCommonStringsService }, { type: ModalStackService }]; }, propDecorators: { _open: [{ type: Input, args: ['clrModalOpen'] }, { type: HostBinding, args: ['class.open'] }], _openChanged: [{ type: Output, args: ['clrModalOpenChange'] }], closable: [{ type: Input, args: ['clrModalClosable'] }], closeButtonAriaLabel: [{ type: Input, args: ['clrModalCloseButtonAriaLabel'] }], size: [{ type: Input, args: ['clrModalSize'] }], staticBackdrop: [{ type: Input, args: ['clrModalStaticBackdrop'] }], skipAnimation: [{ type: Input, args: ['clrModalSkipAnimation'] }], stopClose: [{ type: Input, args: ['clrModalPreventClose'] }], altClose: [{ type: Output, args: ['clrModalAlternateClose'] }], labelledBy: [{ type: Input, args: ['clrModalLabelledById'] }], bypassScrollService: [{ type: Input, args: ['clrModalOverrideScrollService'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Allows modal overflow area to be scrollable via keyboard. * The modal body will focus with keyboard navigation only. * This allows inner focusable items to be focused without * the overflow scroll being focused. */ class ClrModalBody { constructor(renderer, host, ngZone) { this.renderer = renderer; this.host = host; this.tabindex = '0'; this.unlisteners = []; ngZone.runOutsideAngular(() => { this.observer = new ResizeObserver(() => this.addOrRemoveTabIndex()); this.observer.observe(this.host.nativeElement); this.unlisteners.push(this.renderer.listen(this.host.nativeElement, 'mouseup', () => { // set the tabindex binding back when click is completed with mouseup this.addOrRemoveTabIndex(); }), this.renderer.listen(this.host.nativeElement, 'mousedown', () => { // tabindex = 0 binding should be removed // so it won't be focused when click starts with mousedown this.removeTabIndex(); })); }); } ngOnDestroy() { while (this.unlisteners.length) { this.unlisteners.pop()(); } this.observer.disconnect(); this.observer = null; } addTabIndex() { this.renderer.setAttribute(this.host.nativeElement, 'tabindex', this.tabindex); } removeTabIndex() { this.renderer.removeAttribute(this.host.nativeElement, 'tabindex'); } addOrRemoveTabIndex() { const modalBody = this.host.nativeElement.parentElement; if (modalBody && modalBody.clientHeight < modalBody.scrollHeight) { this.addTabIndex(); } else { this.removeTabIndex(); } } } ClrModalBody.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModalBody, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); ClrModalBody.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrModalBody, selector: ".modal-body", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModalBody, decorators: [{ type: Directive, args: [{ selector: '.modal-body', }] }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i0.NgZone }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_MODAL_DIRECTIVES = [ClrModal, ClrModalBody]; class ClrModalModule { constructor() { ClarityIcons.addIcons(windowCloseIcon); } } ClrModalModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrModalModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrModalModule, declarations: [ClrModal, ClrModalBody], imports: [CommonModule, CdkTrapFocusModule, ClrIconModule], exports: [ClrModal, ClrModalBody, ClrIconModule] }); ClrModalModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModalModule, imports: [CommonModule, CdkTrapFocusModule, ClrIconModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrModalModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, CdkTrapFocusModule, ClrIconModule], declarations: [CLR_MODAL_DIRECTIVES], exports: [CLR_MODAL_DIRECTIVES, ClrIconModule], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const SIGNPOST_POSITIONS = { 'top-left': { anchorPoint: Point.TOP_CENTER, popoverPoint: Point.BOTTOM_RIGHT, offsetY: -10, offsetX: 0 }, 'top-middle': { anchorPoint: Point.TOP_CENTER, popoverPoint: Point.BOTTOM_CENTER, offsetY: -10, offsetX: 0 }, 'top-right': { anchorPoint: Point.TOP_CENTER, popoverPoint: Point.BOTTOM_LEFT, offsetY: -10, offsetX: 0 }, 'right-top': { anchorPoint: Point.RIGHT_CENTER, popoverPoint: Point.LEFT_BOTTOM, offsetY: 2, offsetX: 14 }, 'right-middle': { anchorPoint: Point.RIGHT_CENTER, popoverPoint: Point.LEFT_CENTER, offsetY: 6, offsetX: 14 }, 'right-bottom': { anchorPoint: Point.RIGHT_CENTER, popoverPoint: Point.LEFT_TOP, offsetY: -1, offsetX: 14 }, 'bottom-right': { anchorPoint: Point.BOTTOM_CENTER, popoverPoint: Point.TOP_LEFT, offsetY: 9, offsetX: -1 }, 'bottom-middle': { anchorPoint: Point.BOTTOM_CENTER, popoverPoint: Point.TOP_CENTER, offsetY: 9, offsetX: 12 }, 'bottom-left': { anchorPoint: Point.BOTTOM_CENTER, popoverPoint: Point.TOP_RIGHT, offsetY: 9, offsetX: 0 }, 'left-bottom': { anchorPoint: Point.LEFT_CENTER, popoverPoint: Point.RIGHT_TOP, offsetY: 0, offsetX: -14 }, 'left-middle': { anchorPoint: Point.LEFT_CENTER, popoverPoint: Point.RIGHT_CENTER, offsetY: 4, offsetX: -14 }, 'left-top': { anchorPoint: Point.LEFT_CENTER, popoverPoint: Point.RIGHT_BOTTOM, offsetY: 0, offsetX: -14 }, default: { anchorPoint: Point.RIGHT_CENTER, popoverPoint: Point.LEFT_CENTER, offsetY: 6, offsetX: 14 }, }; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ // aka where the arrow / pointer is at in relation to the anchor const POSITIONS$1 = [ 'top-left', 'top-middle', 'top-right', 'right-top', 'right-middle', 'right-bottom', 'bottom-right', 'bottom-middle', 'bottom-left', 'left-bottom', 'left-middle', 'left-top', ]; class ClrSignpostContent extends AbstractPopover { constructor(injector, parentHost, commonStrings, signpostIdService, signpostFocusManager, platformId, document) { super(injector, parentHost); this.commonStrings = commonStrings; this.signpostIdService = signpostIdService; this.signpostFocusManager = signpostFocusManager; this.platformId = platformId; this.signpostContentId = uniqueIdFactory(); if (!parentHost) { throw new Error('clr-signpost-content should only be used inside of a clr-signpost'); } // Defaults this.position = 'right-middle'; this.closeOnOutsideClick = true; this.signpostIdService.setId(this.signpostContentId); this.document = document; } /********* * * @description * A setter for the position of the ClrSignpostContent popover. This is a combination of the following: * - anchorPoint - where on the trigger to anchor the ClrSignpostContent * - popoverPoint - where on the ClrSignpostContent container to align with the anchorPoint * - offsetY - where on the Y axis to align the ClrSignpostContent so it meets specs * - offsetX - where on the X axis to align the ClrSignpostContent so it meets specs * There are 12 possible positions to place a ClrSignpostContent container: * - top-left * - top-middle * - top-right * - right-top * - right-middle * - right-bottom * - bottom-right * - bottom-middle * - bottom-left * - left-bottom * - left-middle * - left-top * * I think of it as follows for 'top-left' -> CONTAINER_SIDE-SIDE_POSITION. In this case CONTAINER_SIDE is 'top' * meaning the top of the trigger icon (above the icon that hides/shows) the ClrSignpostContent. And, SIDE_POSITION * is 'left' meaning two things: 1) the ClrSignpostContent container extends to the left and 2) the 'arrow/pointer' * linking the SingpostContent to the trigger points down at the horizontal center of the trigger icon. * * @param newPosition */ get position() { return this._position; } set position(position) { // Ugh this.renderer.removeClass(this.el.nativeElement, this.position); if (position && POSITIONS$1.indexOf(position) > -1) { this._position = position; } else { this._position = 'right-middle'; } // Ugh this.renderer.addClass(this.el.nativeElement, this.position); const setPosition = SIGNPOST_POSITIONS[this.position]; this.anchorPoint = setPosition.anchorPoint; this.popoverPoint = setPosition.popoverPoint; this.popoverOptions.offsetY = setPosition.offsetY; this.popoverOptions.offsetX = setPosition.offsetX; } /********** * * @description * Close function that uses the signpost instance to toggle the state of the content popover. * */ close() { this.toggleService.open = false; } ngOnDestroy() { super.ngOnDestroy(); if (isPlatformBrowser(this.platformId) && this.el.nativeElement.contains(this.document.activeElement)) { this.signpostFocusManager.focusTrigger(); } } } ClrSignpostContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostContent, deps: [{ token: i0.Injector }, { token: POPOVER_HOST_ANCHOR, optional: true }, { token: ClrCommonStringsService }, { token: SignpostIdService }, { token: SignpostFocusManager }, { token: PLATFORM_ID }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Component }); ClrSignpostContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrSignpostContent, selector: "clr-signpost-content", inputs: { position: ["clrPosition", "position"] }, host: { properties: { "class.signpost-content": "true", "id": "signpostContentId" } }, usesInheritance: true, ngImport: i0, template: `
`, isInline: true, dependencies: [{ kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostContent, decorators: [{ type: Component, args: [{ selector: 'clr-signpost-content', template: `
`, host: { '[class.signpost-content]': 'true', '[id]': 'signpostContentId' }, }] }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ElementRef, decorators: [{ type: Optional }, { type: Inject, args: [POPOVER_HOST_ANCHOR] }] }, { type: ClrCommonStringsService }, { type: SignpostIdService }, { type: SignpostFocusManager }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT] }] }]; }, propDecorators: { position: [{ type: Input, args: ['clrPosition'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_SIGNPOST_DIRECTIVES = [ClrSignpost, ClrSignpostContent, ClrSignpostTrigger]; class ClrSignpostModule { constructor() { ClarityIcons.addIcons(windowCloseIcon, infoCircleIcon); } } ClrSignpostModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrSignpostModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostModule, declarations: [ClrSignpost, ClrSignpostContent, ClrSignpostTrigger], imports: [CommonModule, ClrIconModule, ClrFocusOnViewInitModule], exports: [ClrSignpost, ClrSignpostContent, ClrSignpostTrigger, ClrConditionalModule] }); ClrSignpostModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostModule, imports: [CommonModule, ClrIconModule, ClrFocusOnViewInitModule, ClrConditionalModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrSignpostModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrFocusOnViewInitModule], declarations: [CLR_SIGNPOST_DIRECTIVES], exports: [CLR_SIGNPOST_DIRECTIVES, ClrConditionalModule], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TooltipIdService { constructor() { this._id = new Subject(); } get id() { return this._id.asObservable(); } updateId(id) { this._id.next(id); } } TooltipIdService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TooltipIdService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); TooltipIdService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TooltipIdService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TooltipIdService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TooltipMouseService { constructor(toggleService) { this.toggleService = toggleService; } onMouseEnterTrigger() { this.mouseOverTrigger = true; this.toggleService.open = true; } onMouseLeaveTrigger() { this.mouseOverTrigger = false; this.hideIfMouseOut(); } onMouseEnterContent() { this.mouseOverContent = true; } onMouseLeaveContent() { this.mouseOverContent = false; this.hideIfMouseOut(); } hideIfMouseOut() { // A zero timeout is used so that the code has a chance to update // the `mouseOverContent` property after the user moves the mouse from the trigger to the content. setTimeout(() => { if (!this.mouseOverTrigger && !this.mouseOverContent) { this.toggleService.open = false; } }, 0); } } TooltipMouseService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TooltipMouseService, deps: [{ token: ClrPopoverToggleService }], target: i0.ɵɵFactoryTarget.Injectable }); TooltipMouseService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TooltipMouseService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TooltipMouseService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: ClrPopoverToggleService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTooltip { } ClrTooltip.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltip, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrTooltip.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTooltip, selector: "clr-tooltip", host: { properties: { "class.tooltip": "true" } }, providers: [TooltipIdService, TooltipMouseService], hostDirectives: [{ directive: ClrPopoverHostDirective }], ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltip, decorators: [{ type: Component, args: [{ selector: 'clr-tooltip', template: ``, host: { '[class.tooltip]': 'true', }, providers: [TooltipIdService, TooltipMouseService], hostDirectives: [ClrPopoverHostDirective], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ function assertNever(value) { throw new Error(`Unhandled value: ${value}`); } /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const POSITIONS = ['bottom-left', 'bottom-right', 'top-left', 'top-right', 'right', 'left']; const SIZES = ['xs', 'sm', 'md', 'lg']; const defaultPosition = 'right'; const defaultSize = 'sm'; class ClrTooltipContent extends AbstractPopover { constructor(injector, parentHost, tooltipIdService, tooltipMouseService) { super(injector, parentHost); this.tooltipIdService = tooltipIdService; this.tooltipMouseService = tooltipMouseService; if (!parentHost) { throw new Error('clr-tooltip-content should only be used inside of a clr-tooltip'); } // Set the default id in case consumer does not supply a custom id. this.id = uniqueIdFactory(); } get id() { return this._id; } set id(value) { const id = value || ''; this._id = id; this.tooltipIdService.updateId(id); } get position() { return this._position; } set position(value) { const oldPosition = this._position; const newPosition = POSITIONS.includes(value) ? value : defaultPosition; this._position = newPosition; this.updateCssClass({ oldClass: `tooltip-${oldPosition}`, newClass: `tooltip-${newPosition}` }); // set the popover values based on direction switch (newPosition) { case 'top-right': this.anchorPoint = Point.TOP_CENTER; this.popoverPoint = Point.LEFT_BOTTOM; break; case 'top-left': this.anchorPoint = Point.TOP_CENTER; this.popoverPoint = Point.RIGHT_BOTTOM; break; case 'bottom-right': this.anchorPoint = Point.BOTTOM_CENTER; this.popoverPoint = Point.LEFT_TOP; break; case 'bottom-left': this.anchorPoint = Point.BOTTOM_CENTER; this.popoverPoint = Point.RIGHT_TOP; break; case 'right': this.anchorPoint = Point.RIGHT_CENTER; this.popoverPoint = Point.LEFT_TOP; break; case 'left': this.anchorPoint = Point.LEFT_CENTER; this.popoverPoint = Point.RIGHT_TOP; break; default: assertNever(newPosition); } } get size() { return this._size; } set size(value) { const oldSize = this._size; const newSize = SIZES.includes(value) ? value : defaultSize; this._size = newSize; this.updateCssClass({ oldClass: `tooltip-${oldSize}`, newClass: `tooltip-${newSize}` }); } ngOnInit() { this.size = this.size || defaultSize; this.position = this.position || defaultPosition; } onMouseEnter() { this.tooltipMouseService.onMouseEnterContent(); } onMouseLeave() { this.tooltipMouseService.onMouseLeaveContent(); } updateCssClass({ oldClass, newClass }) { this.renderer.removeClass(this.el.nativeElement, oldClass); this.renderer.addClass(this.el.nativeElement, newClass); } } ClrTooltipContent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipContent, deps: [{ token: i0.Injector }, { token: POPOVER_HOST_ANCHOR, optional: true }, { token: TooltipIdService }, { token: TooltipMouseService }], target: i0.ɵɵFactoryTarget.Component }); ClrTooltipContent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTooltipContent, selector: "clr-tooltip-content", inputs: { id: "id", position: ["clrPosition", "position"], size: ["clrSize", "size"] }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" }, properties: { "class.tooltip-content": "true", "style.opacity": "1", "attr.role": "\"tooltip\"", "id": "id" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipContent, decorators: [{ type: Component, args: [{ selector: 'clr-tooltip-content', template: ``, host: { '[class.tooltip-content]': 'true', '[style.opacity]': '1', '[attr.role]': '"tooltip"', '[id]': 'id', }, }] }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ElementRef, decorators: [{ type: Optional }, { type: Inject, args: [POPOVER_HOST_ANCHOR] }] }, { type: TooltipIdService }, { type: TooltipMouseService }]; }, propDecorators: { id: [{ type: Input }], position: [{ type: Input, args: ['clrPosition'] }], size: [{ type: Input, args: ['clrSize'] }], onMouseEnter: [{ type: HostListener, args: ['mouseenter'] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTooltipTrigger { constructor(toggleService, tooltipIdService, tooltipMouseService) { this.toggleService = toggleService; this.tooltipIdService = tooltipIdService; this.tooltipMouseService = tooltipMouseService; this.subs = []; // The aria-described by comes from the id of content. It this.subs.push(this.tooltipIdService.id.subscribe(tooltipId => (this.ariaDescribedBy = tooltipId))); } ngOnDestroy() { this.subs.forEach(sub => sub.unsubscribe()); } showTooltip() { this.toggleService.open = true; } hideTooltip() { this.toggleService.open = false; } onMouseEnter() { this.tooltipMouseService.onMouseEnterTrigger(); } onMouseLeave() { this.tooltipMouseService.onMouseLeaveTrigger(); } } ClrTooltipTrigger.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipTrigger, deps: [{ token: ClrPopoverToggleService }, { token: TooltipIdService }, { token: TooltipMouseService }], target: i0.ɵɵFactoryTarget.Directive }); ClrTooltipTrigger.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrTooltipTrigger, selector: "[clrTooltipTrigger]", host: { attributes: { "tabindex": "0" }, listeners: { "focus": "showTooltip()", "blur": "hideTooltip()", "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" }, properties: { "class.tooltip-trigger": "true", "attr.aria-describedby": "ariaDescribedBy", "attr.role": "\"button\"" } }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipTrigger, decorators: [{ type: Directive, args: [{ selector: '[clrTooltipTrigger]', host: { tabindex: '0', '[class.tooltip-trigger]': 'true', '[attr.aria-describedby]': 'ariaDescribedBy', '[attr.role]': '"button"', }, }] }], ctorParameters: function () { return [{ type: ClrPopoverToggleService }, { type: TooltipIdService }, { type: TooltipMouseService }]; }, propDecorators: { showTooltip: [{ type: HostListener, args: ['focus'] }], hideTooltip: [{ type: HostListener, args: ['blur'] }], onMouseEnter: [{ type: HostListener, args: ['mouseenter'] }], onMouseLeave: [{ type: HostListener, args: ['mouseleave'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_TOOLTIP_DIRECTIVES = [ClrTooltip, ClrTooltipTrigger, ClrTooltipContent]; class ClrTooltipModule { } ClrTooltipModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrTooltipModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipModule, declarations: [ClrTooltip, ClrTooltipTrigger, ClrTooltipContent], imports: [CommonModule], exports: [ClrTooltip, ClrTooltipTrigger, ClrTooltipContent, ClrConditionalModule, ClrIconModule] }); ClrTooltipModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipModule, imports: [CommonModule, ClrConditionalModule, ClrIconModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTooltipModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_TOOLTIP_DIRECTIVES], exports: [CLR_TOOLTIP_DIRECTIVES, ClrConditionalModule, ClrIconModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrPopoverModule { } ClrPopoverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrPopoverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModule, exports: [ClrDropdownModule, ClrSignpostModule, ClrTooltipModule] }); ClrPopoverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModule, imports: [ClrDropdownModule, ClrSignpostModule, ClrTooltipModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrPopoverModule, decorators: [{ type: NgModule, args: [{ exports: [ClrDropdownModule, ClrSignpostModule, ClrTooltipModule], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrProgressBar { constructor() { this.max = 100; /* * No need to convert to `number` cause we could have * floating point and parseInt will round the numbers * * working with string won't have any side-effects, * we don't do any math so string will do the job. */ this.value = 0; this.externalId = ''; } get id() { return this._ID; } set id(value) { this._ID = value; this.externalId = null; } get progressClass() { return true; } set clrLabeled(value) { this._labeled = isBooleanAttributeSet(value); } get labeledClass() { return this._labeled; } set clrFade(value) { this._fade = isBooleanAttributeSet(value); } get fadeClass() { return this._fade; } set clrLoop(value) { this._loop = isBooleanAttributeSet(value); } get loopClass() { return this._loop; } /** @deprecated since 2.0, remove in 4.0 */ set clrSuccess(value) { this._success = isBooleanAttributeSet(value); } get successClass() { return this._success; } /** @deprecated since 2.0, remove in 4.0 */ set clrDanger(value) { this._danger = isBooleanAttributeSet(value); } get dangerClass() { return this._danger; } set clrFlash(value) { this._flash = isBooleanAttributeSet(value); } get flashClass() { return this._flash; } /** @deprecated since 2.0, remove in 4.0 */ set clrFlashDanger(value) { this._flashDanger = isBooleanAttributeSet(value); } get flashDangerClass() { return this._flashDanger; } /** * Make sure that we always will have something that is readable * for the screen reader */ get displayValue() { if (this.displayval) { return this.displayval; } return `${this.value || 0}%`; } /** * Display optional text only when labeled is eneabled */ displayStringValue() { return this._labeled; } } ClrProgressBar.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrProgressBar, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrProgressBar.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrProgressBar, selector: "clr-progress-bar", inputs: { max: ["clrMax", "max"], displayval: ["clrDisplayval", "displayval"], value: ["clrValue", "value"], id: "id", clrLabeled: "clrLabeled", clrFade: "clrFade", clrLoop: "clrLoop", clrSuccess: "clrSuccess", clrDanger: "clrDanger", clrFlash: "clrFlash", clrFlashDanger: "clrFlashDanger" }, host: { properties: { "attr.id": "this.externalId", "class.progress": "this.progressClass", "class.labeled": "this.labeledClass", "class.progress-fade": "this.fadeClass", "class.loop": "this.loopClass", "class.success": "this.successClass", "class.danger": "this.dangerClass", "class.flash": "this.flashClass", "class.flash-danger": "this.flashDangerClass" } }, ngImport: i0, template: ` {{ displayValue }} `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrProgressBar, decorators: [{ type: Component, args: [{ selector: 'clr-progress-bar', template: ` {{ displayValue }} `, }] }], propDecorators: { max: [{ type: Input, args: ['clrMax'] }], displayval: [{ type: Input, args: ['clrDisplayval'] }], value: [{ type: Input, args: ['clrValue'] }], externalId: [{ type: HostBinding, args: ['attr.id'] }], id: [{ type: Input }], progressClass: [{ type: HostBinding, args: ['class.progress'] }], clrLabeled: [{ type: Input, args: ['clrLabeled'] }], labeledClass: [{ type: HostBinding, args: ['class.labeled'] }], clrFade: [{ type: Input, args: ['clrFade'] }], fadeClass: [{ type: HostBinding, args: ['class.progress-fade'] }], clrLoop: [{ type: Input, args: ['clrLoop'] }], loopClass: [{ type: HostBinding, args: ['class.loop'] }], clrSuccess: [{ type: Input, args: ['clrSuccess'] }], successClass: [{ type: HostBinding, args: ['class.success'] }], clrDanger: [{ type: Input, args: ['clrDanger'] }], dangerClass: [{ type: HostBinding, args: ['class.danger'] }], clrFlash: [{ type: Input, args: ['clrFlash'] }], flashClass: [{ type: HostBinding, args: ['class.flash'] }], clrFlashDanger: [{ type: Input, args: ['clrFlashDanger'] }], flashDangerClass: [{ type: HostBinding, args: ['class.flash-danger'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_PROGRESS_BAR_DIRECTIVES = [ClrProgressBar]; class ClrProgressBarModule { } ClrProgressBarModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrProgressBarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrProgressBarModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrProgressBarModule, declarations: [ClrProgressBar], imports: [CommonModule], exports: [ClrProgressBar] }); ClrProgressBarModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrProgressBarModule, imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrProgressBarModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], declarations: [CLR_PROGRESS_BAR_DIRECTIVES], exports: [CLR_PROGRESS_BAR_DIRECTIVES], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrTimelineLayout; (function (ClrTimelineLayout) { ClrTimelineLayout["HORIZONTAL"] = "horizontal"; ClrTimelineLayout["VERTICAL"] = "vertical"; })(ClrTimelineLayout || (ClrTimelineLayout = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ var ClrTimelineStepState; (function (ClrTimelineStepState) { ClrTimelineStepState["NOT_STARTED"] = "not-started"; ClrTimelineStepState["CURRENT"] = "current"; ClrTimelineStepState["PROCESSING"] = "processing"; ClrTimelineStepState["SUCCESS"] = "success"; ClrTimelineStepState["ERROR"] = "error"; })(ClrTimelineStepState || (ClrTimelineStepState = {})); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class TimelineIconAttributeService { constructor(commonStrings) { this.attributeMap = new Map(); this.attributeMap.set(ClrTimelineStepState.NOT_STARTED, { iconShape: 'circle', iconStatus: null, ariaLabel: commonStrings.keys.timelineStepNotStarted, }); this.attributeMap.set(ClrTimelineStepState.CURRENT, { iconShape: 'dot-circle', iconStatus: 'info', ariaLabel: commonStrings.keys.timelineStepCurrent, }); this.attributeMap.set(ClrTimelineStepState.PROCESSING, { iconShape: undefined, iconStatus: null, ariaLabel: commonStrings.keys.timelineStepProcessing, }); this.attributeMap.set(ClrTimelineStepState.SUCCESS, { iconShape: 'success-standard', iconStatus: 'success', ariaLabel: commonStrings.keys.timelineStepSuccess, }); this.attributeMap.set(ClrTimelineStepState.ERROR, { iconShape: 'error-standard', iconStatus: 'danger', ariaLabel: commonStrings.keys.timelineStepError, }); } getAriaLabel(step) { return this.attributeMap.get(step).ariaLabel; } getIconShape(step) { return this.attributeMap.get(step).iconShape; } getIconStatus(step) { return this.attributeMap.get(step).iconStatus; } } TimelineIconAttributeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TimelineIconAttributeService, deps: [{ token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Injectable }); TimelineIconAttributeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TimelineIconAttributeService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: TimelineIconAttributeService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: ClrCommonStringsService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTimeline { constructor() { this.layout = ClrTimelineLayout.HORIZONTAL; } get isVertical() { return this.layout === ClrTimelineLayout.VERTICAL; } } ClrTimeline.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimeline, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrTimeline.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTimeline, selector: "clr-timeline", inputs: { layout: ["clrLayout", "layout"] }, host: { properties: { "class.clr-timeline": "true", "class.clr-timeline-vertical": "this.isVertical" } }, providers: [TimelineIconAttributeService], ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimeline, decorators: [{ type: Component, args: [{ selector: 'clr-timeline', template: ``, host: { '[class.clr-timeline]': 'true' }, providers: [TimelineIconAttributeService], }] }], propDecorators: { layout: [{ type: Input, args: ['clrLayout'] }], isVertical: [{ type: HostBinding, args: ['class.clr-timeline-vertical'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Note: Why does this component have aria-hidden attribute? * * tl;dr: we want screen readers to ignore this element when its reading out to blind users. * * In order to make a timeline step accessible to screen readers we need the title read out before the * icon. In order to do this, ClrTimeLine step has a ContentChild that queries for the ClrTimelineStepTitle and * then adds the projected text into a .clr-sr-only element that is a sibling element to the icon. See the * ClrTimlineStep template for the DOM structure. */ class ClrTimelineStepTitle { } ClrTimelineStepTitle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStepTitle, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrTimelineStepTitle.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTimelineStepTitle, selector: "clr-timeline-step-title", host: { properties: { "class.clr-timeline-step-title": "true", "attr.aria-hidden": "true" } }, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStepTitle, decorators: [{ type: Component, args: [{ selector: 'clr-timeline-step-title', template: ``, host: { '[class.clr-timeline-step-title]': 'true', '[attr.aria-hidden]': 'true' }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTimelineStep { constructor(iconAttributeService, platformId) { this.iconAttributeService = iconAttributeService; this.platformId = platformId; this.state = ClrTimelineStepState.NOT_STARTED; } get iconAriaLabel() { return this.iconAttributeService.getAriaLabel(this.state); } get iconShape() { return this.iconAttributeService.getIconShape(this.state); } get iconStatus() { return this.iconAttributeService.getIconStatus(this.state); } get isProcessing() { return this.state === ClrTimelineStepState.PROCESSING; } ngAfterContentInit() { if (this.stepTitle && isPlatformBrowser(this.platformId)) { this.stepTitleText = this.stepTitle.nativeElement.innerText; } } } ClrTimelineStep.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStep, deps: [{ token: TimelineIconAttributeService }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); ClrTimelineStep.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTimelineStep, selector: "clr-timeline-step", inputs: { state: ["clrState", "state"] }, host: { properties: { "class.clr-timeline-step": "true" } }, queries: [{ propertyName: "stepTitle", first: true, predicate: ClrTimelineStepTitle, descendants: true, read: ElementRef }], ngImport: i0, template: ` {{ stepTitleText }}
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }, { kind: "component", type: ClrSpinner, selector: "clr-spinner", inputs: ["clrInline", "clrInverse", "clrSmall", "clrMedium"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStep, decorators: [{ type: Component, args: [{ selector: 'clr-timeline-step', template: ` {{ stepTitleText }}
`, host: { '[class.clr-timeline-step]': 'true' }, }] }], ctorParameters: function () { return [{ type: TimelineIconAttributeService }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }]; }, propDecorators: { state: [{ type: Input, args: ['clrState'] }], stepTitle: [{ type: ContentChild, args: [ClrTimelineStepTitle, { read: ElementRef }] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTimelineStepDescription { } ClrTimelineStepDescription.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStepDescription, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrTimelineStepDescription.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTimelineStepDescription, selector: "clr-timeline-step-description", host: { properties: { "class.clr-timeline-step-description": "true" } }, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStepDescription, decorators: [{ type: Component, args: [{ selector: 'clr-timeline-step-description', template: ``, host: { '[class.clr-timeline-step-description]': 'true' }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrTimelineStepHeader { } ClrTimelineStepHeader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStepHeader, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrTimelineStepHeader.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrTimelineStepHeader, selector: "clr-timeline-step-header", host: { properties: { "class.clr-timeline-step-header": "true" } }, ngImport: i0, template: ``, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineStepHeader, decorators: [{ type: Component, args: [{ selector: 'clr-timeline-step-header', template: ``, host: { '[class.clr-timeline-step-header]': 'true' }, }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_TIMELINE_DIRECTIVES = [ ClrTimeline, ClrTimelineStep, ClrTimelineStepDescription, ClrTimelineStepHeader, ClrTimelineStepTitle, ]; class ClrTimelineModule { constructor() { ClarityIcons.addIcons(circleIcon, dotCircleIcon, errorStandardIcon, successStandardIcon); } } ClrTimelineModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrTimelineModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineModule, declarations: [ClrTimeline, ClrTimelineStep, ClrTimelineStepDescription, ClrTimelineStepHeader, ClrTimelineStepTitle], imports: [CommonModule, ClrIconModule, ClrSpinnerModule], exports: [ClrTimeline, ClrTimelineStep, ClrTimelineStepDescription, ClrTimelineStepHeader, ClrTimelineStepTitle, ClrIconModule, ClrSpinnerModule] }); ClrTimelineModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineModule, imports: [CommonModule, ClrIconModule, ClrSpinnerModule, ClrIconModule, ClrSpinnerModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrTimelineModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrIconModule, ClrSpinnerModule], exports: [...CLR_TIMELINE_DIRECTIVES, ClrIconModule, ClrSpinnerModule], declarations: [CLR_TIMELINE_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ButtonHubService { constructor() { this.buttonsReady = false; this._previousBtnClicked = new Subject(); this._nextBtnClicked = new Subject(); this._dangerBtnClicked = new Subject(); this._cancelBtnClicked = new Subject(); this._finishBtnClicked = new Subject(); this._customBtnClicked = new Subject(); } get previousBtnClicked() { return this._previousBtnClicked.asObservable(); } get nextBtnClicked() { return this._nextBtnClicked.asObservable(); } get dangerBtnClicked() { return this._dangerBtnClicked.asObservable(); } get cancelBtnClicked() { return this._cancelBtnClicked.asObservable(); } get finishBtnClicked() { return this._finishBtnClicked.asObservable(); } get customBtnClicked() { return this._customBtnClicked.asObservable(); } buttonClicked(buttonType) { if ('previous' === buttonType) { this._previousBtnClicked.next(); } else if ('next' === buttonType) { this._nextBtnClicked.next(); } else if ('finish' === buttonType) { this._finishBtnClicked.next(); } else if ('danger' === buttonType) { this._dangerBtnClicked.next(); } else if ('cancel' === buttonType) { this._cancelBtnClicked.next(); } else { this._customBtnClicked.next(buttonType); } } } ButtonHubService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonHubService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); ButtonHubService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonHubService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ButtonHubService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * PageCollectionService manages the collection of pages assigned to the wizard and offers * a number of functions useful across the wizards providers and subcomponents -- all related * to essentially lookups on the collection of pages. * * The easiest way to access PageCollectionService is via the wizard. The * following example would allow you to access your instance of the wizard from your host * component and thereby access the page collection via YourHostComponent.wizard.pageCollection. * * @example * * * @example * export class YourHostComponent { * @ViewChild("wizard") wizard: Wizard; * ... * } * * The heart of the page collection is the query list of pages, which it is assigned as a * reference to the Wizard.pages QueryList when the wizard is created. * */ class PageCollectionService { constructor() { /** * * @memberof PageCollectionService */ this._pagesReset = new Subject(); } /** * Converts the PageCollectionService.pages QueryList to an array and returns it. * * Useful for many instances when you would prefer a QueryList to act like an array. * * @memberof PageCollectionService */ get pagesAsArray() { return this.pages ? this.pages.toArray() : []; } /** * Returns the length of the pages query list. * * @memberof PageCollectionService */ get pagesCount() { return this.pages ? this.pages.length : 0; } /** * Returns the next-to-last page in the query list of pages. Operates as a getter * so that it isn't working with stale data. * * @memberof PageCollectionService */ get penultimatePage() { const pageCount = this.pagesCount; if (pageCount < 2) { return null; } return this.pagesAsArray[pageCount - 2]; } /** * Returns the last page in the query list of pages. Operates as a getter * so that it isn't working with stale data. * * @memberof PageCollectionService */ get lastPage() { const pageCount = this.pagesCount; if (pageCount < 1) { return null; } return this.pagesAsArray[pageCount - 1]; } /** * Returns the first page in the query list of pages. Operates as a getter * so that it isn't working with stale data. * * @memberof PageCollectionService */ get firstPage() { if (!this.pagesCount) { return null; } return this.pagesAsArray[0]; } /** * An observable that the navigation service listens to in order to know when * the page collection completed states have been reset to false so that way it * can also reset the navigation to make the first page in the page collection * current/active. * * @memberof PageCollectionService */ get pagesReset() { return this._pagesReset.asObservable(); } /** * Used mostly internally, but accepts a string ID and returns a ClrWizardPage * object that matches the ID passed. Note that IDs here should include the prefix * "clr-wizard-page-". * * Returns the next-to-last page in the query list of pages. Operates as a getter * so that it isn't working with stale data. * * @memberof PageCollectionService */ getPageById(id) { const foundPages = this.pages.filter((page) => id === page.id); return this.checkResults(foundPages, id); } /** * Accepts s number as a parameter and treats that number as the index of the page * you're looking for in the collection of pages. Returns a wizard page object. * * @memberof PageCollectionService */ getPageByIndex(index) { const pageCount = this.pagesCount; const pagesLastIndex = pageCount > 1 ? pageCount - 1 : 0; if (index < 0) { throw new Error('Cannot retrieve page with index of ' + index); } if (index > pagesLastIndex) { throw new Error('Page index is greater than length of pages array.'); } return this.pagesAsArray[index]; } /** * Takes a wizard page object as a parameter and returns its index in the * collection of pages. * * @memberof PageCollectionService */ getPageIndex(page) { const index = this.pagesAsArray.indexOf(page); if (index < 0) { throw new Error('Requested page cannot be found in collection of pages.'); } return index; } /** * Accepts two numeric indexes and returns an array of wizard page objects that include * all wizard pages in the page collection from the first index to the second. * * @memberof PageCollectionService */ pageRange(start, end) { let pages = []; if (start < 0 || end < 0) { return []; } if (start === null || typeof start === 'undefined' || isNaN(start)) { return []; } if (end === null || typeof end === 'undefined' || isNaN(end)) { return []; } if (end > this.pagesCount) { end = this.pagesCount; } pages = this.pagesAsArray; if (end - start === 0) { // just return the one page they want return [this.getPageByIndex(start)]; } // slice end does not include item referenced by end index, which is weird for users // incrementing end index here to correct that so users and other methods // don't have to think about it end = end + 1; // slice does not return the last one in the range but it does include the first one // does not modify original array return pages.slice(start, end); } /** * Accepts two wizard page objects and returns those page objects with all other page * objects between them in the page collection. It doesn't care which page is ahead of the * other in the parameters. It will be smart enough to figure that out on its own. * * @memberof PageCollectionService */ getPageRangeFromPages(page, otherPage) { const pageIndex = this.getPageIndex(page); const otherPageIndex = this.getPageIndex(otherPage); let startIndex; let endIndex; if (pageIndex <= otherPageIndex) { startIndex = pageIndex; endIndex = otherPageIndex; } else { startIndex = otherPageIndex; endIndex = pageIndex; } return this.pageRange(startIndex, endIndex); } /** * Takes a wizard page object as a parameter and returns the wizard page object of * the page immediately before it in the page collection. Returns null if there is * no page before the page it is passed. * * @memberof PageCollectionService */ getPreviousPage(page) { const myPageIndex = this.getPageIndex(page); const previousPageIndex = myPageIndex - 1; if (previousPageIndex < 0) { return null; } return this.getPageByIndex(previousPageIndex); } /** * Accepts a wizard page object as a parameter and returns a Boolean that says if * the page you sent it is complete. * * @memberof PageCollectionService */ previousPageIsCompleted(page) { if (!page) { return false; } const previousPage = this.getPreviousPage(page); if (null === previousPage) { // page is the first page. no previous page. return true; } return previousPage.completed; } /** * Takes a wizard page object as a parameter and returns the wizard page object of * the page immediately after it in the page collection. Returns null if there is * no page after the page it is passed. * * @memberof PageCollectionService */ getNextPage(page) { const myPageIndex = this.getPageIndex(page); const nextPageIndex = myPageIndex + 1; if (nextPageIndex >= this.pagesAsArray.length) { return null; } return this.getPageByIndex(nextPageIndex); } /** * Takes a wizard page object as a parameter and generates a step item id from the * page ID. Returns the generated step item ID as a string. * * @memberof PageCollectionService */ getStepItemIdForPage(page) { const pageId = page.id; const pageIdParts = pageId.split('-').reverse(); pageIdParts[1] = 'step'; return pageIdParts.reverse().join('-'); } /** * Generally only used internally to mark that a specific page has been "committed". * This involves marking the page complete and firing the ClrWizardPage.onCommit * (clrWizardPageOnCommit) output. Takes the wizard page object that you intend to * mark completed as a parameter. * * @memberof PageCollectionService */ commitPage(page) { const pageHasOverrides = page.stopNext || page.preventDefault; page.completed = true; if (!pageHasOverrides) { // prevent loop of event emission; alternate flows work off // of event emitters this is how they break that cycle. page.onCommit.emit(page.id); } } /** * Sets all completed states of the pages in the page collection to false and * notifies the navigation service to likewise reset the navigation. * * @memberof PageCollectionService */ reset() { this.pagesAsArray.forEach((page) => { page.completed = false; }); this._pagesReset.next(true); } /** * Rolls through all the pages in the page collection to make sure there are no * incomplete pages sandwiched between completed pages in the workflow. Identifies * the first incomplete page index and sets all pages behind it to a completed * state of false. * * @memberof PageCollectionService */ updateCompletedStates() { const firstIncompleteIndex = this.findFirstIncompletePageIndex(); if (firstIncompleteIndex === this.pagesAsArray.length - 1) { // all complete no need to do anything return; } this.pagesAsArray.forEach((page, index) => { if (index > firstIncompleteIndex) { page.completed = false; } }); } /** * Retrieves the index of the first incomplete page in the page collection. * * @memberof PageCollectionService */ findFirstIncompletePageIndex() { let returnIndex = null; this.pagesAsArray.forEach((page, index) => { if (null === returnIndex && false === page.completed) { returnIndex = index; } }); // fallthrough, all completed, return last page if (null === returnIndex) { returnIndex = this.pagesCount - 1; } return returnIndex; } findFirstIncompletePage() { const myIncompleteIndex = this.findFirstIncompletePageIndex(); return this.pagesAsArray[myIncompleteIndex]; } /** * Consolidates guard logic that prevents a couple of unfortunate edge cases with * look ups on the collection of pages. * * @memberof PageCollectionService */ checkResults(results, requestedPageId) { const foundPagesCount = results.length || 0; if (foundPagesCount > 1) { throw new Error('More than one page has the requested id ' + requestedPageId + '.'); } else if (foundPagesCount < 1) { throw new Error('No page can be found with the id ' + requestedPageId + '.'); } else { return results[0]; } } } PageCollectionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: PageCollectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); PageCollectionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: PageCollectionService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: PageCollectionService, decorators: [{ type: Injectable }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Performs navigation functions for a wizard and manages the current page. Presented as a * separate service to encapsulate the behavior of navigating and completing the wizard so * that it can be shared across the wizard and its sub-components. * * The easiest way to access the navigation service is there a reference on your wizard. The * Following example would allow you to access your instance of the wizard from your host * component and thereby access the navigation service via YourHostComponent.wizard.navService. * * @example * * * @example * export class YourHostComponent { * @ViewChild("wizard") wizard: Wizard; * ... * } * */ class WizardNavigationService { /** * Creates an instance of WizardNavigationService. Also sets up subscriptions * that listen to the button service to determine when a button has been clicked * in the wizard. Is also responsible for taking action when the page collection * requests that navigation be reset to its pristine state. * * @memberof WizardNavigationService */ constructor(pageCollection, buttonService) { this.pageCollection = pageCollection; this.buttonService = buttonService; /** * A Boolean flag used by the ClrWizardPage to avoid a race condition when pages are * loading and there is no current page defined. * * @memberof WizardNavigationService */ this.navServiceLoaded = false; /** * A boolean flag shared across the Wizard subcomponents that follows the value * of the Wizard.forceForward (clrWizardForceForwardNavigation) input. When true, * navigating backwards in the stepnav menu will reset any skipped pages' completed * state to false. * * This is useful when a wizard executes validation on a page-by-page basis when * the next button is clicked. * * @memberof WizardNavigationService */ this.forceForwardNavigation = false; /** * A boolean flag shared across the Wizard subcomponents that follows the value * of the Wizard.stopCancel (clrWizardPreventDefaultCancel) input. When true, the cancel * routine is subverted and must be reinstated in the host component calling Wizard.close() * at some point. * * @memberof WizardNavigationService */ this.wizardHasAltCancel = false; /** * A boolean flag shared across the Wizard subcomponents that follows the value * of the Wizard.stopNext (clrWizardPreventDefaultNext) input. When true, the next and finish * routines are subverted and must be reinstated in the host component calling Wizard.next(), * Wizard.forceNext(), Wizard.finish(), or Wizard.forceFinish(). * * @memberof WizardNavigationService */ this.wizardHasAltNext = false; /** * A boolean flag shared across the Wizard subcomponents that follows the value * of the Wizard.stopNavigation (clrWizardPreventNavigation) input. When true, all * navigational elements in the wizard are disabled. * * This is intended to freeze the wizard in place. Events are not fired so this is * not a way to implement alternate functionality for navigation. * * @memberof WizardNavigationService */ this.wizardStopNavigation = false; /** * A boolean flag shared with the stepnav items that prevents user clicks on * stepnav items from navigating the wizard. * * @memberof WizardNavigationService */ this.wizardDisableStepnav = false; /** * * @memberof WizardNavigationService */ this._currentChanged = new Subject(); /** * @memberof WizardNavigationService */ this._movedToNextPage = new Subject(); /** * @memberof WizardNavigationService */ this._wizardFinished = new Subject(); /** * @memberof WizardNavigationService */ this._movedToPreviousPage = new Subject(); /** * @memberof WizardNavigationService */ this._cancelWizard = new Subject(); this.previousButtonSubscription = this.buttonService.previousBtnClicked.subscribe(() => { const currentPage = this.currentPage; if (this.currentPageIsFirst || currentPage.previousStepDisabled) { return; } currentPage.previousButtonClicked.emit(currentPage); if (!currentPage.preventDefault) { this.previous(); } }); this.nextButtonSubscription = this.buttonService.nextBtnClicked.subscribe(() => { this.checkAndCommitCurrentPage('next'); }); this.dangerButtonSubscription = this.buttonService.dangerBtnClicked.subscribe(() => { this.checkAndCommitCurrentPage('danger'); }); this.finishButtonSubscription = this.buttonService.finishBtnClicked.subscribe(() => { this.checkAndCommitCurrentPage('finish'); }); this.customButtonSubscription = this.buttonService.customBtnClicked.subscribe((type) => { if (!this.wizardStopNavigation) { this.currentPage.customButtonClicked.emit(type); } }); this.cancelButtonSubscription = this.buttonService.cancelBtnClicked.subscribe(() => { if (this.wizardStopNavigation) { return; } if (this.currentPage.preventDefault) { this.currentPage.pageOnCancel.emit(this.currentPage); } else { this.cancel(); } }); this.pagesResetSubscription = this.pageCollection.pagesReset.subscribe(() => { this.setFirstPageCurrent(); }); } /** * An Observable that is predominantly used amongst the subcomponents and services * of the wizard. It is recommended that users listen to the ClrWizardPage.onLoad * (clrWizardPageOnLoad) output instead of this Observable. * * @memberof WizardNavigationService */ get currentPageChanged() { // TODO: MAKE SURE EXTERNAL OUTPUTS SAY 'CHANGE' NOT 'CHANGED' // A BREAKING CHANGE SO AWAITING MINOR RELEASE return this._currentChanged.asObservable(); } /** * @memberof WizardNavigationService */ get currentPageTitle() { // when the querylist of pages is empty. this is the first place it fails... if (!this.currentPage) { return null; } return this.currentPage.title; } /** * Returns a Boolean that tells you whether or not the current page is the first * page in the Wizard. * * This is helpful for determining whether a page is navigable. * * @memberof WizardNavigationService */ get currentPageIsFirst() { return this.pageCollection.firstPage === this.currentPage; } /** * Returns a Boolean that tells you whether or not the current page is the * last page in the Wizard. * * This is used to determine which buttons should display in the wizard footer. * * @memberof WizardNavigationService */ get currentPageIsLast() { return this.pageCollection.lastPage === this.currentPage; } /** * Returns the ClrWizardPage object of the current page or null. * * @memberof WizardNavigationService */ get currentPage() { if (!this._currentPage) { return null; } return this._currentPage; } /** * Accepts a ClrWizardPage object, since that object to be the current/active * page in the wizard, and emits the ClrWizardPage.onLoad (clrWizardPageOnLoad) * event for that page. * * Note that all of this work is bypassed if the ClrWizardPage object is already * the current page. * * @memberof WizardNavigationService */ set currentPage(page) { if (this._currentPage !== page && !this.wizardStopNavigation) { this._currentPage = page; page.onLoad.emit(page.id); this._currentChanged.next(page); } } /** * An observable used internally to alert the wizard that forward navigation * has occurred. It is recommended that you use the Wizard.onMoveNext * (clrWizardOnNext) output instead of this one. * * @memberof WizardNavigationService */ get movedToNextPage() { return this._movedToNextPage.asObservable(); } /** * An observable used internally to alert the wizard that the nav service * has approved completion of the wizard. * * It is recommended that you use the Wizard.wizardFinished (clrWizardOnFinish) * output instead of this one. * * @memberof WizardNavigationService */ get wizardFinished() { return this._wizardFinished.asObservable(); } /** * Notifies the wizard when backwards navigation has occurred via the * previous button. * * @memberof WizardNavigationService */ get movedToPreviousPage() { return this._movedToPreviousPage.asObservable(); } /** * Notifies the wizard that a user is trying to cancel it. * * @memberof WizardNavigationService */ get notifyWizardCancel() { return this._cancelWizard.asObservable(); } /** * * @memberof WizardNavigationService */ ngOnDestroy() { this.previousButtonSubscription.unsubscribe(); this.nextButtonSubscription.unsubscribe(); this.dangerButtonSubscription.unsubscribe(); this.finishButtonSubscription.unsubscribe(); this.customButtonSubscription.unsubscribe(); this.cancelButtonSubscription.unsubscribe(); this.pagesResetSubscription.unsubscribe(); } /** * This is a public function that can be used to programmatically advance * the user to the next page. * * When invoked, this method will move the wizard to the next page after * successful validation. Note that this method goes through all checks * and event emissions as if Wizard.next(false) had been called. * * In most cases, it makes more sense to use Wizard.next(false). * * @memberof WizardNavigationService */ next() { if (this.currentPageIsLast) { this.checkAndCommitCurrentPage('finish'); } else { this.checkAndCommitCurrentPage('next'); } } /** * Bypasses checks and most event emissions to force a page to navigate forward. * * Comparable to calling Wizard.next() or Wizard.forceNext(). * * @memberof WizardNavigationService */ forceNext() { const currentPage = this.currentPage; const nextPage = this.pageCollection.getNextPage(currentPage); // catch errant null or undefineds that creep in if (!nextPage) { throw new Error('The wizard has no next page to go to.'); } if (this.wizardStopNavigation) { return; } if (!currentPage.completed) { // this is a state that alt next flows can get themselves in... this.pageCollection.commitPage(currentPage); } this.currentPage = nextPage; } /** * Accepts a button/action type as a parameter. Encapsulates all logic for * event emissions, state of the current page, and wizard and page level overrides. * * Avoid calling this function directly unless you really know what you're doing. * * @memberof WizardNavigationService */ checkAndCommitCurrentPage(buttonType) { const currentPage = this.currentPage; if (!currentPage.readyToComplete || this.wizardStopNavigation) { return; } const iAmTheLastPage = this.currentPageIsLast; const isNext = buttonType === 'next'; const isDanger = buttonType === 'danger'; const isDangerNext = isDanger && !iAmTheLastPage; const isDangerFinish = isDanger && iAmTheLastPage; const isFinish = buttonType === 'finish' || isDangerFinish; if (isFinish && !iAmTheLastPage) { return; } currentPage.primaryButtonClicked.emit(buttonType); if (isFinish) { currentPage.finishButtonClicked.emit(currentPage); } else if (isDanger) { currentPage.dangerButtonClicked.emit(); } else if (isNext) { currentPage.nextButtonClicked.emit(); } if (currentPage.stopNext || currentPage.preventDefault) { currentPage.onCommit.emit(currentPage.id); return; } // order is very important with these emitters! if (isFinish) { // mark page as complete if (!this.wizardHasAltNext) { this.pageCollection.commitPage(currentPage); } this._wizardFinished.next(); } if (this.wizardHasAltNext) { this.pageCollection.commitPage(currentPage); if (isNext || isDangerNext) { this._movedToNextPage.next(true); } // jump out here, no matter what type we're looking at return; } if (isNext || isDangerNext) { this.forceNext(); } if (!this.wizardHasAltNext && !this.wizardStopNavigation) { this._movedToNextPage.next(true); } } /** * This is a public function that can be used to programmatically conclude * the wizard. * * When invoked, this method will initiate the work involved with finalizing * and finishing the wizard workflow. Note that this method goes through all * checks and event emissions as if Wizard.finish(false) had been called. * * In most cases, it makes more sense to use Wizard.finish(false). * * @memberof WizardNavigationService */ finish() { this.checkAndCommitCurrentPage('finish'); } /** * Programmatically moves the wizard to the page before the current page. * * In most instances, it makes more sense to call Wizard.previous() * which does the same thing. * * @memberof WizardNavigationService */ previous() { if (this.currentPageIsFirst || this.wizardStopNavigation) { return; } const previousPage = this.pageCollection.getPreviousPage(this.currentPage); if (!previousPage) { return; } this._movedToPreviousPage.next(true); if (this.forceForwardNavigation) { this.currentPage.completed = false; } this.currentPage = previousPage; } /** * Allows a hook into the cancel workflow of the wizard from the nav service. Note that * this route goes through all checks and event emissions as if a cancel button had * been clicked. * * In most cases, users looking for a hook into the cancel routine are actually looking * for a way to close the wizard from their host component because they have prevented * the default cancel action. * * In this instance, it is recommended that you use Wizard.close() to avoid any event * emission loop resulting from an event handler calling back into routine that will * again evoke the events it handles. * * @memberof WizardNavigationService */ cancel() { this._cancelWizard.next(); } /** * Performs all required checks to determine if a user can navigate to a page. Checking at each * point if a page is navigable -- completed where the page immediately after the last completed * page. * * Takes two parameters. The first one must be either the ClrWizardPage object or the ID of the * ClrWizardPage object that you want to make the current page. * * The second parameter is optional and is a Boolean flag for "lazy completion". What this means * is the Wizard will mark all pages between the current page and the page you want to navigate * to as completed. This is useful for informational wizards that do not require user action, * allowing an easy means for users to jump ahead. * * To avoid checks on navigation, use ClrWizardPage.makeCurrent() instead. * * @memberof WizardNavigationService */ goTo(pageToGoToOrId, lazyComplete = false) { const myPages = this.pageCollection; const pageToGoTo = typeof pageToGoToOrId === 'string' ? myPages.getPageById(pageToGoToOrId) : pageToGoToOrId; const currentPage = this.currentPage; // no point in going to the current page. you're there already! // also hard block on any navigation when stopNavigation is true if (pageToGoTo === currentPage || this.wizardStopNavigation) { return; } const currentPageIndex = myPages.getPageIndex(currentPage); const goToPageIndex = myPages.getPageIndex(pageToGoTo); const goingForward = goToPageIndex > currentPageIndex; const pagesToCheck = myPages.getPageRangeFromPages(this.currentPage, pageToGoTo); const okayToMove = lazyComplete || this.canGoTo(pagesToCheck); if (!okayToMove) { return; } if (goingForward && lazyComplete) { pagesToCheck.forEach((page) => { if (page !== pageToGoTo) { page.completed = true; } }); } else if (!goingForward && this.forceForwardNavigation) { pagesToCheck.forEach((page) => { page.completed = false; }); } this.currentPage = pageToGoTo; } /** * Accepts a range of ClrWizardPage objects as a parameter. Performs the work of checking * those objects to determine if navigation can be accomplished. * * @memberof WizardNavigationService */ canGoTo(pagesToCheck) { let okayToMove = true; const myPages = this.pageCollection; // previous page can be important when moving because if it's completed it // allows us to move to the page even if it's incomplete... let previousPagePasses; if (!pagesToCheck || pagesToCheck.length < 1) { return false; } pagesToCheck.forEach((page) => { if (!okayToMove) { return; } if (page.completed) { // default is true. just jump out instead of complicating it. return; } // so we know our page is not completed... const previousPage = myPages.getPageIndex(page) > 0 ? myPages.getPreviousPage(page) : null; previousPagePasses = previousPage === null || previousPage.completed === true; // we are false if not the current page AND previous page is not completed // (but must have a previous page) if (!page.current && !previousPagePasses) { okayToMove = false; } // falls through to true as default }); return okayToMove; } /** * Looks through the collection of pages to find the first one that is incomplete * and makes that page the current/active page. * * @memberof WizardNavigationService */ setLastEnabledPageCurrent() { const allPages = this.pageCollection.pagesAsArray; let lastCompletedPageIndex = null; allPages.forEach((page, index) => { if (page.completed) { lastCompletedPageIndex = index; } }); if (lastCompletedPageIndex === null) { // always is at least the first item... lastCompletedPageIndex = 0; } else if (lastCompletedPageIndex + 1 < allPages.length) { lastCompletedPageIndex = lastCompletedPageIndex + 1; } this.currentPage = allPages[lastCompletedPageIndex]; } /** * Finds the first page in the collection of pages and makes that page the * current/active page. * * @memberof WizardNavigationService */ setFirstPageCurrent() { this.currentPage = this.pageCollection.pagesAsArray[0]; } /** * Updates the stepnav on the left side of the wizard when pages are dynamically * added or removed from the collection of pages. * * @memberof WizardNavigationService */ updateNavigation() { let toSetCurrent; this.pageCollection.updateCompletedStates(); const currentPageRemoved = this.pageCollection.pagesAsArray.indexOf(this.currentPage) < 0; if (currentPageRemoved) { toSetCurrent = this.pageCollection.findFirstIncompletePage(); this.currentPage = toSetCurrent; } } } WizardNavigationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WizardNavigationService, deps: [{ token: PageCollectionService }, { token: ButtonHubService }], target: i0.ɵɵFactoryTarget.Injectable }); WizardNavigationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WizardNavigationService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: WizardNavigationService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: PageCollectionService }, { type: ButtonHubService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class HeaderActionService { constructor(navService) { this.navService = navService; } get wizardHasHeaderActions() { const wizardHdrActions = this.wizardHeaderActions; if (!wizardHdrActions) { return false; } return wizardHdrActions.toArray().length > 0; } get currentPageHasHeaderActions() { return this.navService.currentPage ? this.navService.currentPage.hasHeaderActions : false; } get showWizardHeaderActions() { return !this.currentPageHasHeaderActions && this.wizardHasHeaderActions; } get displayHeaderActionsWrapper() { return this.currentPageHasHeaderActions || this.wizardHasHeaderActions; } } HeaderActionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: HeaderActionService, deps: [{ token: WizardNavigationService }], target: i0.ɵɵFactoryTarget.Injectable }); HeaderActionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: HeaderActionService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: HeaderActionService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: WizardNavigationService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let wizardHeaderActionIndex = 0; class ClrWizardHeaderAction { constructor() { // title is explanatory text added to the header action this.title = ''; // If our host has an ID attribute, we use this instead of our index. this._id = (wizardHeaderActionIndex++).toString(); this.disabled = false; this.headerActionClicked = new EventEmitter(false); } get id() { return `clr-wizard-header-action-${this._id}`; } click() { if (this.disabled) { return; } // passing the header action id allows users to have one method that // routes to many different actions based on the type of header action // clicked. this is further aided by users being able to specify ids // for their header actions. this.headerActionClicked.emit(this._id); } } ClrWizardHeaderAction.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardHeaderAction, deps: [], target: i0.ɵɵFactoryTarget.Component }); ClrWizardHeaderAction.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardHeaderAction, selector: "clr-wizard-header-action", inputs: { title: "title", _id: ["id", "_id"], disabled: ["clrWizardHeaderActionDisabled", "disabled"] }, outputs: { headerActionClicked: "actionClicked" }, host: { classAttribute: "clr-wizard-header-action-wrapper" }, ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardHeaderAction, decorators: [{ type: Component, args: [{ selector: 'clr-wizard-header-action', template: ` `, host: { class: 'clr-wizard-header-action-wrapper' }, }] }], propDecorators: { title: [{ type: Input, args: ['title'] }], _id: [{ type: Input, args: ['id'] }], disabled: [{ type: Input, args: ['clrWizardHeaderActionDisabled'] }], headerActionClicked: [{ type: Output, args: ['actionClicked'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardPageButtons { constructor(pageButtonsTemplateRef) { this.pageButtonsTemplateRef = pageButtonsTemplateRef; } } ClrWizardPageButtons.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageButtons, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrWizardPageButtons.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardPageButtons, selector: "[clrPageButtons]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageButtons, decorators: [{ type: Directive, args: [{ selector: '[clrPageButtons]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardPageHeaderActions { constructor(pageHeaderActionsTemplateRef) { this.pageHeaderActionsTemplateRef = pageHeaderActionsTemplateRef; } } ClrWizardPageHeaderActions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageHeaderActions, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrWizardPageHeaderActions.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardPageHeaderActions, selector: "[clrPageHeaderActions]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageHeaderActions, decorators: [{ type: Directive, args: [{ selector: '[clrPageHeaderActions]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardPageNavTitle { constructor(pageNavTitleTemplateRef) { this.pageNavTitleTemplateRef = pageNavTitleTemplateRef; } } ClrWizardPageNavTitle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageNavTitle, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrWizardPageNavTitle.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardPageNavTitle, selector: "[clrPageNavTitle]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageNavTitle, decorators: [{ type: Directive, args: [{ selector: '[clrPageNavTitle]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardPageTitle { constructor(pageTitleTemplateRef) { this.pageTitleTemplateRef = pageTitleTemplateRef; } } ClrWizardPageTitle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageTitle, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); ClrWizardPageTitle.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardPageTitle, selector: "[clrPageTitle]", inputs: { headingLevel: ["clrHeadingLevel", "headingLevel"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPageTitle, decorators: [{ type: Directive, args: [{ selector: '[clrPageTitle]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; }, propDecorators: { headingLevel: [{ type: Input, args: ['clrHeadingLevel'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ let wizardPageIndex = 0; /** * The ClrWizardPage component is responsible for displaying the content of each step * in the wizard workflow. * * ClrWizardPage component has hooks into the navigation service (ClrWizardPage.navService), * page collection (ClrWizardPage.pageCollection), and button service * (ClrWizardPage.buttonService). These three providers are shared across the components * within each instance of a Wizard. * */ class ClrWizardPage { /** * Creates an instance of ClrWizardPage. * * @memberof WizardPage */ constructor(navService, pageCollection, buttonService) { this.navService = navService; this.pageCollection = pageCollection; this.buttonService = buttonService; /** * An input value that is used internally to generate the ClrWizardPage ID as * well as the step nav item ID. * * Typed as any because it should be able to accept numbers as well as * strings. Passing an index for wizard whose pages are created with an * ngFor loop is a common use case. * * @memberof WizardPage * */ this._id = (wizardPageIndex++).toString(); /** * Overrides all actions from the page level, so you can use an alternate function for * validation or data-munging with a ClrWizardPage.onCommit (clrWizardPageOnCommit output), * ClrWizardPage.onCancel (clrWizardPageOnCancel output), or one * of the granular page-level button click event emitters. * * @memberof WizardPage * */ this.preventDefault = false; /** * Emits when the value of ClrWizardPage.nextStepDisabled changes. * Should emit the new value of nextStepDisabled. * * @memberof WizardPage * */ this.nextStepDisabledChange = new EventEmitter(); /** * Emits when the value of ClrWizardPage.previousStepDisabled changes. * Should emit the new value of previousStepDisabled. * * @memberof WizardPage * */ this.previousStepDisabledChange = new EventEmitter(); /** * * @memberof WizardPage * */ this.stopCancelChange = new EventEmitter(); /** * An event emitter carried over from a legacy version of ClrWizardPage. * Fires an event on ClrWizardPage whenever the next or finish buttons * are clicked and the page is the current page of the Wizard. * * Note that this does not automatically emit an event when a custom * button is used in place of a next or finish button. * * @memberof WizardPage * */ this.onCommit = new EventEmitter(false); /** * Emits an event when ClrWizardPage becomes the current page of the * Wizard. * * @memberof WizardPage * */ this.onLoad = new EventEmitter(); /** * Emits an event when the ClrWizardPage invokes the cancel routine for the wizard. * * Can be used in conjunction with the ClrWizardPage.stopCancel * (clrWizardPagePreventDefaultCancel) or ClrWizardPage.preventDefault * (clrWizardPagePagePreventDefault) inputs to implement custom cancel * functionality at the page level. This is useful if you would like to do * validation, save data, or warn users before cancelling the wizard. * * Note that this requires you to call Wizard.close() from the host component. * This constitues a full replacement of the cancel functionality. * * @memberof WizardPage * */ this.pageOnCancel = new EventEmitter(); /** * Emits an event when the finish button is clicked and the ClrWizardPage is * the wizard's current page. * * Can be used in conjunction with the ClrWizardPage.preventDefault * (clrWizardPagePagePreventDefault) input to implement custom finish * functionality at the page level. This is useful if you would like to do * validation, save data, or warn users before allowing them to complete * the wizard. * * Note that this requires you to call Wizard.finish() or Wizard.forceFinish() * from the host component. This combination creates a full replacement of * the finish functionality. * * @memberof WizardPage * */ this.finishButtonClicked = new EventEmitter(); /** * Emits an event when the previous button is clicked and the ClrWizardPage is * the wizard's current page. * * Can be used in conjunction with the ClrWizardPage.preventDefault * (clrWizardPagePagePreventDefault) input to implement custom backwards * navigation at the page level. This is useful if you would like to do * validation, save data, or warn users before allowing them to go * backwards in the wizard. * * Note that this requires you to call Wizard.previous() * from the host component. This combination creates a full replacement of * the backwards navigation functionality. * * @memberof WizardPage * */ this.previousButtonClicked = new EventEmitter(); /** * Emits an event when the next button is clicked and the ClrWizardPage is * the wizard's current page. * * Can be used in conjunction with the ClrWizardPage.preventDefault * (clrWizardPagePagePreventDefault) input to implement custom forwards * navigation at the page level. This is useful if you would like to do * validation, save data, or warn users before allowing them to go * to the next page in the wizard. * * Note that this requires you to call Wizard.forceNext() or Wizard.next() * from the host component. This combination creates a full replacement of * the forward navigation functionality. * * @memberof WizardPage * */ this.nextButtonClicked = new EventEmitter(); /** * Emits an event when a danger button is clicked and the ClrWizardPage is * the wizard's current page. By default, a danger button will act as * either a "next" or "finish" button depending on if the ClrWizardPage is the * last page or not. * * Can be used in conjunction with the ClrWizardPage.preventDefault * (clrWizardPagePagePreventDefault) input to implement custom forwards * or finish navigation at the page level when the danger button is clicked. * This is useful if you would like to do validation, save data, or warn * users before allowing them to go to the next page in the wizard or * finish the wizard. * * Note that this requires you to call Wizard.finish(), Wizard.forceFinish(), * Wizard.forceNext() or Wizard.next() from the host component. This * combination creates a full replacement of the forward navigation and * finish functionality. * * @memberof WizardPage * */ this.dangerButtonClicked = new EventEmitter(); /** * Emits an event when a next, finish, or danger button is clicked and the * ClrWizardPage is the wizard's current page. * * Can be used in conjunction with the ClrWizardPage.preventDefault * (clrWizardPagePagePreventDefault) input to implement custom forwards * or finish navigation at the page level, regardless of the type of * primary button. * * This is useful if you would like to do validation, save data, or warn * users before allowing them to go to the next page in the wizard or * finish the wizard. * * Note that this requires you to call Wizard.finish(), Wizard.forceFinish(), * Wizard.forceNext() or Wizard.next() from the host component. This * combination creates a full replacement of the forward navigation and * finish functionality. * * @memberof WizardPage * */ this.primaryButtonClicked = new EventEmitter(); this.customButtonClicked = new EventEmitter(); /** * * @memberof WizardPage * */ this._nextStepDisabled = false; /** * * @memberof WizardPage * */ this._previousStepDisabled = false; /** * * @memberof WizardPage * */ this._hasError = false; /** * * @memberof WizardPage * */ this._stopCancel = false; /** * * @memberof WizardPage * */ this._stopNext = false; /** * * @memberof WizardPage * */ this._complete = false; } /** * A property that tells whether or not the wizard should be allowed * to move to the next page. * * Useful for in-page validation because it prevents forward navigation * and visibly disables the next button. * * Does not require that you re-implement navigation routines like you * would if you were using ClrWizardPage.preventDefault or * Wizard.preventDefault. * * @memberof WizardPage * */ get nextStepDisabled() { return this._nextStepDisabled; } set nextStepDisabled(val) { const valBool = !!val; if (valBool !== this._nextStepDisabled) { this._nextStepDisabled = valBool; this.nextStepDisabledChange.emit(valBool); } } /** * A property that tells whether or not the wizard should be allowed * to move to the previous page. * * Useful for in-page validation because it prevents backward navigation * and visibly disables the previous button. * * Does not require that you re-implement navigation routines like you * would if you were using ClrWizardPage.preventDefault or * Wizard.preventDefault. * * @memberof WizardPage * */ get previousStepDisabled() { return this._previousStepDisabled; } set previousStepDisabled(val) { const valBool = !!val; if (valBool !== this._previousStepDisabled) { this._previousStepDisabled = valBool; this.previousStepDisabledChange.emit(valBool); } } /** * Whether the page has an error and also resolve the "falsy" value. The * current logic treat a "0" or an empty string as false and likewise will treat any * "truthy" value as true. * * @memberof WizardPage * */ get hasError() { return this._hasError; } set hasError(val) { const valBool = !!val; if (valBool !== this._hasError) { this._hasError = valBool; } } /** * Overrides the cancel action from the page level. Allows you to use an * alternate function for validation or data-munging before cancelling the * wizard when combined with the ClrWizardPage.onCancel * (the clrWizardPageOnCancel output). * * Requires that you manually close the wizard from your host component, * usually with a call to Wizard.forceNext() or wizard.next(); * * @memberof ClrWizardPage */ get stopCancel() { return this._stopCancel; } set stopCancel(val) { const valBool = !!val; if (valBool !== this._stopCancel) { this._stopCancel = valBool; this.stopCancelChange.emit(valBool); } } /** * Overrides forward navigation from the page level. Allows you to use an * alternate function for validation or data-munging before moving the * wizard to the next pagewhen combined with the ClrWizardPage.onCommit * (clrWizardPageOnCommit) or ClrWizardPage.nextButtonClicked * (clrWizardPageNext) outputs. * * Requires that you manually tell the wizard to navigate forward from * the hostComponent, usually with a call to Wizard.forceNext() or * wizard.next(); * * @memberof ClrWizardPage */ get stopNext() { return this._stopNext; } set stopNext(val) { const valBool = !!val; if (valBool !== this._stopNext) { this._stopNext = valBool; } } /** * A read-only getter that generates an ID string for the wizard page from * either the value passed to the ClrWizardPage "id" input or a wizard page * counter shared across all wizard pages in the application. * * Note that the value passed into the ID input Will be prefixed with * "clr-wizard-page-". * * @readonly * * @memberof ClrWizardPage */ get id() { // covers things like null, undefined, false, and empty string // while allowing zero to pass const idIsNonZeroFalsy = !this._id && this._id !== 0; // in addition to non-zero falsy we also want to make sure _id is not a negative // number. if (idIsNonZeroFalsy || this._id < 0) { // guard here in the event that input becomes undefined or null by accident this._id = (wizardPageIndex++).toString(); } return `clr-wizard-page-${this._id}`; } /** * A read-only getter that serves as a convenience for those who would rather * not think in the terms of !ClrWizardPage.nextStepDisabled. For some use cases, * ClrWizardPage.readyToComplete is more logical and declarative. * * @memberof WizardPage * */ get readyToComplete() { return !this.nextStepDisabled; } /** * A page is marked as completed if it is both readyToComplete and completed, * as in the next or finish action has been executed while this page was current. * * Note there is and open question about how to handle pages that are marked * complete but who are no longer readyToComplete. This might indicate an error * state for the ClrWizardPage. Currently, the wizard does not acknowledge this state * and only returns that the page is incomplete. * * @memberof WizardPage * */ get completed() { return this._complete && this.readyToComplete; // FOR V2: UNWIND COMPLETED, READYTOCOMPLETE, AND ERRORS // SUCH THAT ERRORS IS ITS OWN INPUT. IF A STEP IS // INCOMPLETE AND ERRORED, ERRORED WILL NOT SHOW. // FIRST QUESTION: AM I GREY OR COLORED? // SECOND QUESTION: AM I GREEN OR RED? } /** * A ClrWizardPage can be manually set to completed using this boolean setter. * It is recommended that users rely on the convenience functions in the wizard * and navigation service instead of manually setting pages’ completion state. * * @memberof ClrWizardPage */ set completed(value) { this._complete = value; } /** * Checks with the navigation service to see if it is the current page. * * @memberof WizardPage * */ get current() { return this.navService.currentPage === this; } get disabled() { return !this.enabled; } /** * A read-only getter that returns whether or not the page is navigable * in the wizard. A wizard page can be navigated to if it is completed * or the page before it is completed. * * This getter handles the logic for enabling or disabling the links in * the step nav on the left Side of the wizard. * * @memberof WizardPage * */ get enabled() { return this.current || this.completed || this.previousCompleted; } /** * A read-only getter that returns whether or not the page before this * ClrWizardPage is completed. This is useful for determining whether or not * a page is navigable if it is not current or already completed. * * @memberof WizardPage * */ get previousCompleted() { const previousPage = this.pageCollection.getPreviousPage(this); if (!previousPage) { return true; } return previousPage.completed; } /** * * @memberof WizardPage * */ get title() { return this.pageTitle.pageTitleTemplateRef; } /** * * @memberof WizardPage * */ get navTitle() { if (this.pageNavTitle) { return this.pageNavTitle.pageNavTitleTemplateRef; } return this.pageTitle.pageTitleTemplateRef; } /** * * @memberof WizardPage * */ get headerActions() { if (!this._headerActions) { return undefined; } return this._headerActions.pageHeaderActionsTemplateRef; } /** * * @memberof WizardPage * */ get hasHeaderActions() { return !!this._headerActions; } /** * * @memberof WizardPage * */ get buttons() { if (!this._buttons) { return undefined; } return this._buttons.pageButtonsTemplateRef; } /** * A read-only getter that returns a boolean that says whether or * not the ClrWizardPage includes buttons. Used to determine if the * Wizard should override the default button set defined as * its direct children. * * @memberof WizardPage * */ get hasButtons() { return !!this._buttons; } /** * A read-only getter that returns the id used by the step nav item associated with the page. * * ClrWizardPage needs this ID string for aria information. * * @memberof WizardPage * */ get stepItemId() { return this.pageCollection.getStepItemIdForPage(this); } /** * Links the nav service and establishes the current page if one is not defined. * * @memberof WizardPage * */ ngOnInit() { const navService = this.navService; if (!navService.currentPage && !navService.navServiceLoaded) { this.makeCurrent(); this.navService.navServiceLoaded = true; } } /** * Uses the nav service to make the ClrWizardPage the current page in the * wizard. Bypasses all checks but still emits the ClrWizardPage.onLoad * (clrWizardPageOnLoad) output. * * In most cases, it is better to use the default navigation functions * in Wizard. * * @memberof WizardPage * */ makeCurrent() { this.navService.currentPage = this; } } ClrWizardPage.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPage, deps: [{ token: WizardNavigationService }, { token: PageCollectionService }, { token: ButtonHubService }], target: i0.ɵɵFactoryTarget.Component }); ClrWizardPage.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardPage, selector: "clr-wizard-page", inputs: { _id: ["id", "_id"], preventDefault: ["clrWizardPagePreventDefault", "preventDefault"], nextStepDisabled: ["clrWizardPageNextDisabled", "nextStepDisabled"], previousStepDisabled: ["clrWizardPagePreviousDisabled", "previousStepDisabled"], hasError: ["clrWizardPageHasError", "hasError"], stopCancel: ["clrWizardPagePreventDefaultCancel", "stopCancel"], stopNext: ["clrWizardPagePreventDefaultNext", "stopNext"] }, outputs: { nextStepDisabledChange: "clrWizardPageNextDisabledChange", previousStepDisabledChange: "clrWizardPagePreviousDisabledChange", stopCancelChange: "clrWizardPagePreventDefaultCancelChange", onCommit: "clrWizardPageOnCommit", onLoad: "clrWizardPageOnLoad", pageOnCancel: "clrWizardPageOnCancel", finishButtonClicked: "clrWizardPageFinish", previousButtonClicked: "clrWizardPagePrevious", nextButtonClicked: "clrWizardPageNext", dangerButtonClicked: "clrWizardPageDanger", primaryButtonClicked: "clrWizardPagePrimary", customButtonClicked: "clrWizardPageCustomButton" }, host: { properties: { "id": "id", "attr.aria-hidden": "!current", "attr.aria-labelledby": "stepItemId", "class.active": "current", "class.clr-wizard-page": "true" } }, queries: [{ propertyName: "pageTitle", first: true, predicate: ClrWizardPageTitle, descendants: true, static: true }, { propertyName: "pageNavTitle", first: true, predicate: ClrWizardPageNavTitle, descendants: true, static: true }, { propertyName: "_buttons", first: true, predicate: ClrWizardPageButtons, descendants: true, static: true }, { propertyName: "_headerActions", first: true, predicate: ClrWizardPageHeaderActions, descendants: true, static: true }], ngImport: i0, template: '', isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardPage, decorators: [{ type: Component, args: [{ selector: 'clr-wizard-page', template: '', host: { '[id]': 'id', '[attr.aria-hidden]': '!current', '[attr.aria-labelledby]': 'stepItemId', '[class.active]': 'current', '[class.clr-wizard-page]': 'true', }, }] }], ctorParameters: function () { return [{ type: WizardNavigationService }, { type: PageCollectionService }, { type: ButtonHubService }]; }, propDecorators: { _id: [{ type: Input, args: ['id'] }], preventDefault: [{ type: Input, args: ['clrWizardPagePreventDefault'] }], nextStepDisabledChange: [{ type: Output, args: ['clrWizardPageNextDisabledChange'] }], previousStepDisabledChange: [{ type: Output, args: ['clrWizardPagePreviousDisabledChange'] }], stopCancelChange: [{ type: Output, args: ['clrWizardPagePreventDefaultCancelChange'] }], onCommit: [{ type: Output, args: ['clrWizardPageOnCommit'] }], onLoad: [{ type: Output, args: ['clrWizardPageOnLoad'] }], pageOnCancel: [{ type: Output, args: ['clrWizardPageOnCancel'] }], finishButtonClicked: [{ type: Output, args: ['clrWizardPageFinish'] }], previousButtonClicked: [{ type: Output, args: ['clrWizardPagePrevious'] }], nextButtonClicked: [{ type: Output, args: ['clrWizardPageNext'] }], dangerButtonClicked: [{ type: Output, args: ['clrWizardPageDanger'] }], primaryButtonClicked: [{ type: Output, args: ['clrWizardPagePrimary'] }], customButtonClicked: [{ type: Output, args: ['clrWizardPageCustomButton'] }], pageTitle: [{ type: ContentChild, args: [ClrWizardPageTitle, { static: true }] }], pageNavTitle: [{ type: ContentChild, args: [ClrWizardPageNavTitle, { static: true }] }], _buttons: [{ type: ContentChild, args: [ClrWizardPageButtons, { static: true }] }], _headerActions: [{ type: ContentChild, args: [ClrWizardPageHeaderActions, { static: true }] }], nextStepDisabled: [{ type: Input, args: ['clrWizardPageNextDisabled'] }], previousStepDisabled: [{ type: Input, args: ['clrWizardPagePreviousDisabled'] }], hasError: [{ type: Input, args: ['clrWizardPageHasError'] }], stopCancel: [{ type: Input, args: ['clrWizardPagePreventDefaultCancel'] }], stopNext: [{ type: Input, args: ['clrWizardPagePreventDefaultNext'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardTitle { } ClrWizardTitle.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardTitle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); ClrWizardTitle.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardTitle, selector: "clr-wizard-title", inputs: { headingLevel: ["clrHeadingLevel", "headingLevel"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardTitle, decorators: [{ type: Directive, args: [{ selector: 'clr-wizard-title', }] }], propDecorators: { headingLevel: [{ type: Input, args: ['clrHeadingLevel'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardStepnavItem { constructor(navService, pageCollection, commonStrings) { this.navService = navService; this.pageCollection = pageCollection; this.commonStrings = commonStrings; } get id() { this.pageGuard(); return this.pageCollection.getStepItemIdForPage(this.page); } get stepAriaCurrent() { return this.isCurrent && 'step'; } get isDisabled() { this.pageGuard(); return this.page.disabled || this.navService.wizardStopNavigation || this.navService.wizardDisableStepnav; } get isCurrent() { this.pageGuard(); return this.page.current; } get isComplete() { this.pageGuard(); return this.page.completed; } get hasError() { this.pageGuard(); return this.page.hasError && this.isComplete; } get canNavigate() { this.pageGuard(); return this.pageCollection.previousPageIsCompleted(this.page); } click() { this.pageGuard(); // if we click on our own stepnav or a disabled stepnav, we don't want to do anything if (this.isDisabled || this.isCurrent) { return; } this.navService.goTo(this.page); } pageGuard() { if (!this.page) { throw new Error('Wizard stepnav item is not associated with a wizard page.'); } } } ClrWizardStepnavItem.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardStepnavItem, deps: [{ token: WizardNavigationService }, { token: PageCollectionService }, { token: ClrCommonStringsService }], target: i0.ɵɵFactoryTarget.Component }); ClrWizardStepnavItem.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardStepnavItem, selector: "[clr-wizard-stepnav-item]", inputs: { page: "page" }, host: { properties: { "id": "id", "attr.aria-current": "stepAriaCurrent", "attr.aria-controls": "page.id", "class.clr-nav-link": "true", "class.nav-item": "true", "class.active": "isCurrent", "class.disabled": "isDisabled", "class.no-click": "!canNavigate", "class.complete": "isComplete", "class.error": "hasError" } }, ngImport: i0, template: ` `, isInline: true, dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdsIconCustomTag, selector: "cds-icon" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardStepnavItem, decorators: [{ type: Component, args: [{ selector: '[clr-wizard-stepnav-item]', template: ` `, host: { '[id]': 'id', '[attr.aria-current]': 'stepAriaCurrent', '[attr.aria-controls]': 'page.id', '[class.clr-nav-link]': 'true', '[class.nav-item]': 'true', '[class.active]': 'isCurrent', '[class.disabled]': 'isDisabled', '[class.no-click]': '!canNavigate', '[class.complete]': 'isComplete', '[class.error]': 'hasError', }, }] }], ctorParameters: function () { return [{ type: WizardNavigationService }, { type: PageCollectionService }, { type: ClrCommonStringsService }]; }, propDecorators: { page: [{ type: Input, args: ['page'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizardStepnav { constructor(pageService) { this.pageService = pageService; } } ClrWizardStepnav.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardStepnav, deps: [{ token: PageCollectionService }], target: i0.ɵɵFactoryTarget.Component }); ClrWizardStepnav.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardStepnav, selector: "clr-wizard-stepnav", host: { classAttribute: "clr-wizard-stepnav" }, ngImport: i0, template: `
{{ i + 1 }}
`, isInline: true, dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ClrWizardStepnavItem, selector: "[clr-wizard-stepnav-item]", inputs: ["page"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardStepnav, decorators: [{ type: Component, args: [{ selector: 'clr-wizard-stepnav', template: `
{{ i + 1 }}
`, host: { class: 'clr-wizard-stepnav' }, }] }], ctorParameters: function () { return [{ type: PageCollectionService }]; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClrWizard { constructor(platformId, commonStrings, navService, pageCollection, buttonService, headerActionService, elementRef, differs) { this.platformId = platformId; this.commonStrings = commonStrings; this.navService = navService; this.pageCollection = pageCollection; this.buttonService = buttonService; this.headerActionService = headerActionService; this.elementRef = elementRef; /** * Set the aria-label for the stepnav section of the wizard. Set using `[clrWizardStepnavAriaLabel]` input. */ this.stepnavAriaLabel = this.commonStrings.keys.wizardStepnavAriaLabel; /** * Set the modal size of the wizard. Set using `[clrWizardSize]` input. */ this.size = 'xl'; /** * Tells the modal part of the wizard whether it should have a close "X" * in the top right corner. Set using `[clrWizardClosable]` input. */ this.closable = true; /** * Used to communicate to the underlying modal that animations are not * wanted. Primary use is for the display of static/inline wizards. * Set using `[clrWizardPreventModalAnimation]` input. */ this._stopModalAnimations = false; /** * Emits when the wizard is opened or closed. * Listen via `(clrWizardOpenChange)` event. */ this._openChanged = new EventEmitter(false); /** * Emits when the wizard is canceled. Listen via `(clrWizardOnCancel)` event. * Can be combined with the `[clrWizardPreventDefaultCancel]` input to create * wizard-level custom cancel routines. */ this.onCancel = new EventEmitter(false); /** * Emits when the wizard is completed. Listen via `(clrWizardOnFinish)` event. * Can be combined with the `[clrWizardPreventDefaultNext]` input to create * wizard-level custom completion routines. */ this.wizardFinished = new EventEmitter(false); /** * Emits when the wizard is reset. Listen via `(clrWizardOnReset)` event. */ this.onReset = new EventEmitter(false); /** * Emits when the current page has changed. Listen via `(clrWizardCurrentPageChanged)` event. * output. Useful for non-blocking validation. */ this.currentPageChanged = new EventEmitter(false); /** * Emits when the wizard moves to the next page. Listen via `(clrWizardOnNext)` event. * Can be combined with the `[clrWizardPreventDefaultNext]` input to create * wizard-level custom navigation routines, which are useful for validation. */ this.onMoveNext = new EventEmitter(false); /** * Emits when the wizard moves to the previous page. Can be useful for validation. * Listen via `(clrWizardOnPrevious)` event. */ this.onMovePrevious = new EventEmitter(false); this._open = false; this.wizardId = uniqueIdFactory(); this._forceForward = false; this._stopNext = false; this._stopCancel = false; this._stopNavigation = false; this._disableStepnav = false; this.subscriptions = []; this.subscriptions.push(this.listenForNextPageChanges(), this.listenForPreviousPageChanges(), this.listenForCancelChanges(), this.listenForFinishedChanges(), this.listenForPageChanges()); this.differ = differs.find([]).create(null); } /** * Resets page completed states when navigating backwards. * Set using `[clrWizardForceForwardNavigation]` input. */ get forceForward() { return this._forceForward; } set forceForward(value) { this._forceForward = !!value; this.navService.forceForwardNavigation = value; } /** * Toggles open/close of the wizard component. * Set using the `[clrWizardOpen]` input. */ set clrWizardOpen(open) { if (open) { this.buttonService.buttonsReady = true; } this._open = open; } /** * Prevents ClrWizard from moving to the next page or closing itself on finishing. * Set using the `[clrWizardPreventDefaultNext]` input. Note that using stopNext * will require you to create your own calls to .next() and .finish() in your * host component to make the ClrWizard work as expected. */ get stopNext() { return this._stopNext; } set stopNext(value) { this._stopNext = !!value; this.navService.wizardHasAltNext = value; } /** * Prevents ClrWizard from closing when the cancel button or close "X" is clicked. * Set using the `[clrWizardPreventDefaultCancel]` input. * * Note that using stopCancel will require you to create your own calls to `close()` in your host compone`nt * to make the ClrWizard work as expected. Useful for doing checks or prompts * before closing a ClrWizard. */ get stopCancel() { return this._stopCancel; } set stopCancel(value) { this._stopCancel = !!value; this.navService.wizardHasAltCancel = value; } /** * Prevents ClrWizard from performing any form of navigation away from the current * page. Set using the `[clrWizardPreventNavigation]` input. * Note that stopNavigation is meant to freeze the wizard in place, typically * during a long validation or background action where you want the wizard to * display loading content but not allow the user to execute navigation in * the stepnav, close X, or the back, finish, or next buttons. */ get stopNavigation() { return this._stopNavigation; } set stopNavigation(value) { this._stopNavigation = !!value; this.navService.wizardStopNavigation = value; } /** * Prevents clicks on the links in the stepnav from working. * Set using `[clrWizardDisableStepnav]` input. * A more granular bypassing of navigation which can be useful when your * ClrWizard is in a state of completion and you don't want users to be * able to jump backwards and change things. */ get disableStepnav() { return this._disableStepnav; } set disableStepnav(value) { this._disableStepnav = !!value; this.navService.wizardDisableStepnav = value; } get currentPage() { return this.navService.currentPage; } set currentPage(page) { this.navService.goTo(page, true); } get isLast() { return this.navService.currentPageIsLast; } get isFirst() { return this.navService.currentPageIsFirst; } get isInline() { return this.elementRef.nativeElement.classList.contains('clr-wizard--inline'); } get stopModalAnimations() { return this._stopModalAnimations ? 'true' : 'false'; } ngAfterContentInit() { this.pageCollection.pages = this.pages; this.headerActionService.wizardHeaderActions = this.headerActions; this.initializeButtons(); } ngDoCheck() { this.updateNavOnPageChanges(); } ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } /** * Marks Wizard as finished. By default it does not execute event * emissions or checks before completing and closing. This method is commonly * used as part of an alternative navigation with `[clrWizardPreventDefaultNext]`. * * If `skipChecksAndEmits` is true, the wizard will complete and close * regardless of the state of its current page. This is useful for alternative * navigation where event emissions have already been done and firing them again * may cause an event loop. */ finish(skipChecksAndEmits = true) { if (skipChecksAndEmits) { this.forceFinish(); } else { this.navService.finish(); } } /** * Marks the wizard as finished but does run checks and emissions. * Good for a last step in an alternate workflow. Does the same thing as * calling `ClrWizard.finish(true)` or `ClrWizard.finish()` without a parameter. */ forceFinish() { if (this.stopNavigation) { return; } this.close(); } /** * Opens the wizard. If there is no current page defined, sets the first page in the wizard to be current. */ open() { this._open = true; if (!this.currentPage) { this.navService.setFirstPageCurrent(); } // Only render buttons when wizard is opened, to avoid chocolate errors this.buttonService.buttonsReady = true; this._openChanged.emit(true); } /** * Closes the wizard. Call this directly instead of `cancel()` to implement alternative cancel functionality. */ close() { if (this.stopNavigation) { return; } this._open = false; this._openChanged.emit(false); } /** * Used to open and close the wizard. By default the wizard will * close if invoked with no parameter. If parameter is true wizard will open * else if false will close. */ toggle(open) { if (open) { this.open(); } else { this.close(); } } /** * Moves the wizard to the previous page. */ previous() { this.navService.previous(); } /** * By default, `next()` does not execute event emissions. * This method is commonly called as part of an alternative navigation * with `[clrWizardPreventDefaultNext]`. The wizard will move to the next page * regardless of the state of its current page. This is useful for alternative * navigation where event emissions have already been done and firing them again * may cause an event loop. * * If `skipChecksAndEmits` is false, the wizard will execute default checks * and emit events as normal. This is useful for custom buttons or programmatic * workflows that are not executing the wizards default checks and emissions. * It is another way to navigate without having to rewrite the wizard’s default * functionality from scratch. */ next(skipChecksAndEmits = true) { if (skipChecksAndEmits) { this.forceNext(); } else { this.navService.next(); } } /** * Moves the wizard to the next page without the checks and emissions. * Good for a last step in an alternate workflow. * Alias for `ClrWizard.next(true)` or `ClrWizard.next()` */ forceNext() { this.navService.forceNext(); } /** * Cancels and closes the wizard. Do not use this for an override of the cancel * the functionality with `[clrWizardPreventDefaultCancel]`, `[clrWizardPreventPageDefaultCancel]`, * or `[clrWizardPagePreventDefault]` because it will initiate the same checks * and event emissions that invoked your event handler. Use `ClrWizard.close()` instead. */ cancel() { this.navService.cancel(); } /** * Overrides behavior of the underlying modal to avoid collisions with * alternative cancel functionality. In most cases, use `ClrWizard.cancel()` instead. */ modalCancel() { if (this.closable) { this.checkAndCancel(); } } /** * Checks for alternative cancel flows defined at the current page or * wizard level. Performs a canceled if not. Emits events that initiate * the alternative cancel outputs `(clrWizardPageOnCancel)` and `(clrWizardOnCancel)`. */ checkAndCancel() { const currentPage = this.currentPage; const currentPageHasOverrides = currentPage.stopCancel || currentPage.preventDefault; if (this.stopNavigation) { return; } currentPage.pageOnCancel.emit(); if (!currentPageHasOverrides) { this.onCancel.emit(); } if (!this.stopCancel && !currentPageHasOverrides) { this.close(); } } /** * Navigates to a given page in the Wizard. Navigation will invoke the wizard’s default * checks and event emissions. * * The format of the expected ID parameter can be found in the return of the * ClrWizardPage.id getter, usually prefixed with `clr-wizard-page-` and then either a * numeric ID or the ID specified for the `ClrWizardPage` component’s `id` input. */ goTo(pageId) { if (!pageId) { return; } this.navService.goTo(pageId); } /** * Reset sets all WizardPages to incomplete and sets the first page in the `ClrWizard` to * be the current page, resetting the wizard navigation. * Use `(clrWizardOnReset)` event to reset the data or model of your wizard. */ reset() { this.pageCollection.reset(); this.onReset.next(); } listenForNextPageChanges() { return this.navService.movedToNextPage.pipe(filter(() => isPlatformBrowser(this.platformId))).subscribe(() => { this.onMoveNext.emit(); this.pageTitle?.nativeElement.focus(); }); } listenForPreviousPageChanges() { return this.navService.movedToPreviousPage.pipe(filter(() => isPlatformBrowser(this.platformId))).subscribe(() => { this.onMovePrevious.emit(); this.pageTitle?.nativeElement.focus(); }); } listenForCancelChanges() { return this.navService.notifyWizardCancel.subscribe(() => this.checkAndCancel()); } listenForFinishedChanges() { return this.navService.wizardFinished.subscribe(() => this.emitWizardFinished()); } listenForPageChanges() { return this.navService.currentPageChanged.subscribe(() => { // Added to address VPAT-749: // When clicking on a wizard tab, focus should move to that // tabs content to make the wizard more accessible. this.pageTitle?.nativeElement.focus(); this.currentPageChanged.emit(); }); } updateNavOnPageChanges() { const changes = this.differ.diff(this.pages); if (changes) { changes.forEachAddedItem(() => this.navService.updateNavigation()); changes.forEachRemovedItem(() => this.navService.updateNavigation()); } } initializeButtons() { // Only trigger buttons ready if default is open (inlined) if (this._open) { this.buttonService.buttonsReady = true; } } emitWizardFinished() { if (!this.stopNext) { this.forceFinish(); } this.wizardFinished.emit(); } } ClrWizard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizard, deps: [{ token: PLATFORM_ID }, { token: ClrCommonStringsService }, { token: WizardNavigationService }, { token: PageCollectionService }, { token: ButtonHubService }, { token: HeaderActionService }, { token: i0.ElementRef }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component }); ClrWizard.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizard, selector: "clr-wizard", inputs: { stepnavAriaLabel: ["clrWizardStepnavAriaLabel", "stepnavAriaLabel"], size: ["clrWizardSize", "size"], closable: ["clrWizardClosable", "closable"], _stopModalAnimations: ["clrWizardPreventModalAnimation", "_stopModalAnimations"], forceForward: ["clrWizardForceForwardNavigation", "forceForward"], clrWizardOpen: "clrWizardOpen", stopNext: ["clrWizardPreventDefaultNext", "stopNext"], stopCancel: ["clrWizardPreventDefaultCancel", "stopCancel"], stopNavigation: ["clrWizardPreventNavigation", "stopNavigation"], disableStepnav: ["clrWizardDisableStepnav", "disableStepnav"] }, outputs: { _openChanged: "clrWizardOpenChange", onCancel: "clrWizardOnCancel", wizardFinished: "clrWizardOnFinish", onReset: "clrWizardOnReset", currentPageChanged: "clrWizardCurrentPageChanged", onMoveNext: "clrWizardOnNext", onMovePrevious: "clrWizardOnPrevious" }, host: { properties: { "class.clr-wizard": "true", "class.wizard-md": "size == 'md'", "class.wizard-lg": "size == 'lg'", "class.wizard-xl": "size == 'xl'", "class.lastPage": "navService.currentPageIsLast" } }, providers: [WizardNavigationService, PageCollectionService, ButtonHubService, HeaderActionService], queries: [{ propertyName: "wizardTitle", first: true, predicate: ClrWizardTitle, descendants: true }, { propertyName: "pages", predicate: ClrWizardPage, descendants: true }, { propertyName: "headerActions", predicate: ClrWizardHeaderAction }], viewQueries: [{ propertyName: "pageTitle", first: true, predicate: ["pageTitle"], descendants: true }], ngImport: i0, template: "\n\n\n
\n
\n \n
\n \n
\n\n
\n \n \n \n\n
\n
\n \n
\n
\n \n
\n
\n
\n\n
\n
\n \n
\n
\n \n \n \n\n", dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ClrModal, selector: "clr-modal", inputs: ["clrModalOpen", "clrModalClosable", "clrModalCloseButtonAriaLabel", "clrModalSize", "clrModalStaticBackdrop", "clrModalSkipAnimation", "clrModalPreventClose", "clrModalLabelledById", "clrModalOverrideScrollService"], outputs: ["clrModalOpenChange", "clrModalAlternateClose"] }, { kind: "directive", type: ClrModalBody, selector: ".modal-body" }, { kind: "component", type: ClrWizardStepnav, selector: "clr-wizard-stepnav" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizard, decorators: [{ type: Component, args: [{ selector: 'clr-wizard', providers: [WizardNavigationService, PageCollectionService, ButtonHubService, HeaderActionService], host: { '[class.clr-wizard]': 'true', '[class.wizard-md]': "size == 'md'", '[class.wizard-lg]': "size == 'lg'", '[class.wizard-xl]': "size == 'xl'", '[class.lastPage]': 'navService.currentPageIsLast', }, template: "\n\n\n
\n
\n \n
\n \n
\n\n
\n \n \n \n\n
\n
\n \n
\n
\n \n
\n
\n
\n\n
\n
\n \n
\n
\n \n \n \n\n" }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }, { type: ClrCommonStringsService }, { type: WizardNavigationService }, { type: PageCollectionService }, { type: ButtonHubService }, { type: HeaderActionService }, { type: i0.ElementRef }, { type: i0.IterableDiffers }]; }, propDecorators: { stepnavAriaLabel: [{ type: Input, args: ['clrWizardStepnavAriaLabel'] }], size: [{ type: Input, args: ['clrWizardSize'] }], closable: [{ type: Input, args: ['clrWizardClosable'] }], _stopModalAnimations: [{ type: Input, args: ['clrWizardPreventModalAnimation'] }], _openChanged: [{ type: Output, args: ['clrWizardOpenChange'] }], onCancel: [{ type: Output, args: ['clrWizardOnCancel'] }], wizardFinished: [{ type: Output, args: ['clrWizardOnFinish'] }], onReset: [{ type: Output, args: ['clrWizardOnReset'] }], currentPageChanged: [{ type: Output, args: ['clrWizardCurrentPageChanged'] }], onMoveNext: [{ type: Output, args: ['clrWizardOnNext'] }], onMovePrevious: [{ type: Output, args: ['clrWizardOnPrevious'] }], pageTitle: [{ type: ViewChild, args: ['pageTitle'] }], pages: [{ type: ContentChildren, args: [ClrWizardPage, { descendants: true }] }], headerActions: [{ type: ContentChildren, args: [ClrWizardHeaderAction] }], wizardTitle: [{ type: ContentChild, args: [ClrWizardTitle] }], forceForward: [{ type: Input, args: ['clrWizardForceForwardNavigation'] }], clrWizardOpen: [{ type: Input, args: ['clrWizardOpen'] }], stopNext: [{ type: Input, args: ['clrWizardPreventDefaultNext'] }], stopCancel: [{ type: Input, args: ['clrWizardPreventDefaultCancel'] }], stopNavigation: [{ type: Input, args: ['clrWizardPreventNavigation'] }], disableStepnav: [{ type: Input, args: ['clrWizardDisableStepnav'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const DEFAULT_BUTTON_TYPES = { cancel: 'cancel', previous: 'previous', next: 'next', finish: 'finish', danger: 'danger', }; const CUSTOM_BUTTON_TYPES = { cancel: 'custom-cancel', previous: 'custom-previous', next: 'custom-next', finish: 'custom-finish', danger: 'custom-danger', }; class ClrWizardButton { constructor(navService, buttonService) { this.navService = navService; this.buttonService = buttonService; this.type = ''; this.disabled = false; this.hidden = false; // EventEmitter which is emitted when a button is clicked. this.wasClicked = new EventEmitter(false); } get isCancel() { return this.checkDefaultAndCustomType(this.type, 'cancel'); } get isNext() { return this.checkDefaultAndCustomType(this.type, 'next'); } get isPrevious() { return this.checkDefaultAndCustomType(this.type, 'previous'); } get isFinish() { return this.checkDefaultAndCustomType(this.type, 'finish'); } get isDanger() { return this.checkDefaultAndCustomType(this.type, 'danger'); } get isPrimaryAction() { return this.isNext || this.isDanger || this.isFinish; } get _disabledAttribute() { if (this.isDisabled) { return ''; } return null; } get isDisabled() { // dealing with negatives here. cognitively easier to think of it like this... const disabled = true; const nav = this.navService; const page = this.navService.currentPage; // Ensure we don't change the response until buttons are ready to avoid chocolate if (!this.buttonService.buttonsReady) { return !disabled; } if (this.disabled || nav.wizardStopNavigation || !page) { return true; } if (this.isCancel) { return !disabled; } if (this.isPrevious && (nav.currentPageIsFirst || page.previousStepDisabled)) { return disabled; } if (this.isDanger && !page.readyToComplete) { return disabled; } if (this.isNext && (nav.currentPageIsLast || !page.readyToComplete)) { return disabled; } if (this.isFinish && (!nav.currentPageIsLast || !page.readyToComplete)) { return disabled; } return !disabled; } get isHidden() { // dealing with negatives here. cognitively easier to think of it like this... const hidden = true; const nav = this.navService; // Ensure we don't change the response until buttons are ready to avoid chocolate if (!this.buttonService.buttonsReady) { return !hidden; } if (this.hidden) { return true; } if (this.isCancel) { return !hidden; } if (this.isPrevious && nav.currentPageIsFirst) { return hidden; } if (this.isNext && nav.currentPageIsLast) { return hidden; } if (this.isFinish && !nav.currentPageIsLast) { return hidden; } return !hidden; } click() { if (this.isDisabled) { return; } this.wasClicked.emit(this.type); this.buttonService.buttonClicked(this.type); } checkDefaultAndCustomType(valueToCheck = '', typeToLookUp) { if (DEFAULT_BUTTON_TYPES[typeToLookUp] === valueToCheck) { return true; } if (CUSTOM_BUTTON_TYPES[typeToLookUp] === valueToCheck) { return true; } return false; } } ClrWizardButton.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardButton, deps: [{ token: WizardNavigationService }, { token: ButtonHubService }], target: i0.ɵɵFactoryTarget.Component }); ClrWizardButton.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ClrWizardButton, selector: "clr-wizard-button", inputs: { type: "type", disabled: ["clrWizardButtonDisabled", "disabled"], hidden: ["clrWizardButtonHidden", "hidden"] }, outputs: { wasClicked: "clrWizardButtonClicked" }, host: { properties: { "attr.aria-hidden": "isHidden" }, classAttribute: "clr-wizard-btn-wrapper" }, ngImport: i0, template: ` `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardButton, decorators: [{ type: Component, args: [{ selector: 'clr-wizard-button', template: ` `, host: { class: 'clr-wizard-btn-wrapper', '[attr.aria-hidden]': 'isHidden' }, }] }], ctorParameters: function () { return [{ type: WizardNavigationService }, { type: ButtonHubService }]; }, propDecorators: { type: [{ type: Input, args: ['type'] }], disabled: [{ type: Input, args: ['clrWizardButtonDisabled'] }], hidden: [{ type: Input, args: ['clrWizardButtonHidden'] }], wasClicked: [{ type: Output, args: ['clrWizardButtonClicked'] }] } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_WIZARD_DIRECTIVES = [ ClrWizard, ClrWizardPage, ClrWizardStepnav, ClrWizardStepnavItem, ClrWizardButton, ClrWizardHeaderAction, ClrWizardTitle, ClrWizardPageTitle, ClrWizardPageNavTitle, ClrWizardPageButtons, ClrWizardPageHeaderActions, ]; class ClrWizardModule { constructor() { ClarityIcons.addIcons(errorStandardIcon); } } ClrWizardModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClrWizardModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardModule, declarations: [ClrWizard, ClrWizardPage, ClrWizardStepnav, ClrWizardStepnavItem, ClrWizardButton, ClrWizardHeaderAction, ClrWizardTitle, ClrWizardPageTitle, ClrWizardPageNavTitle, ClrWizardPageButtons, ClrWizardPageHeaderActions], imports: [CommonModule, ClrModalModule, ClrAlertModule], exports: [ClrWizard, ClrWizardPage, ClrWizardStepnav, ClrWizardStepnavItem, ClrWizardButton, ClrWizardHeaderAction, ClrWizardTitle, ClrWizardPageTitle, ClrWizardPageNavTitle, ClrWizardPageButtons, ClrWizardPageHeaderActions] }); ClrWizardModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardModule, imports: [CommonModule, ClrModalModule, ClrAlertModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClrWizardModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule, ClrModalModule, ClrAlertModule], declarations: [CLR_WIZARD_DIRECTIVES], exports: [CLR_WIZARD_DIRECTIVES], }] }], ctorParameters: function () { return []; } }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ class ClarityModule { } ClarityModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClarityModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); ClarityModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ClarityModule, exports: [ClrEmphasisModule, ClrDataModule, ClrIconModule, ClrModalModule, ClrLoadingModule, ClrConditionalModule, ClrFocusOnViewInitModule, ClrButtonModule, ClrFormsModule, ClrLayoutModule, ClrPopoverModule, ClrWizardModule, ClrStepperModule, ClrSpinnerModule, ClrProgressBarModule, ClrPopoverModuleNext, ClrTimelineModule] }); ClarityModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClarityModule, imports: [ClrEmphasisModule, ClrDataModule, ClrIconModule, ClrModalModule, ClrLoadingModule, ClrConditionalModule, ClrFocusOnViewInitModule, ClrButtonModule, ClrFormsModule, ClrLayoutModule, ClrPopoverModule, ClrWizardModule, ClrStepperModule, ClrSpinnerModule, ClrProgressBarModule, ClrPopoverModuleNext, ClrTimelineModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ClarityModule, decorators: [{ type: NgModule, args: [{ exports: [ ClrEmphasisModule, ClrDataModule, ClrIconModule, ClrModalModule, ClrLoadingModule, ClrConditionalModule, ClrFocusOnViewInitModule, ClrButtonModule, ClrFormsModule, ClrLayoutModule, ClrPopoverModule, ClrWizardModule, ClrStepperModule, ClrSpinnerModule, ClrProgressBarModule, ClrPopoverModuleNext, ClrTimelineModule, ], }] }] }); /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ const CLR_MENU_POSITIONS = [ 'bottom-left', 'bottom-right', 'top-left', 'top-right', 'left-bottom', 'left-top', 'right-bottom', 'right-top', ]; /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /* * Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. * This software is released under MIT license. * The full license information can be found in LICENSE in the root directory of this project. */ /** * Generated bundle index. Do not edit. */ export { CHANGE_KEYS, CLR_ALERT_DIRECTIVES, CLR_BUTTON_GROUP_DIRECTIVES, CLR_DATAGRID_DIRECTIVES, CLR_DATEPICKER_DIRECTIVES, CLR_DROPDOWN_DIRECTIVES, CLR_ICON_DIRECTIVES, CLR_LAYOUT_DIRECTIVES, CLR_LOADING_BUTTON_DIRECTIVES, CLR_LOADING_DIRECTIVES, CLR_MENU_POSITIONS, CLR_MODAL_DIRECTIVES, CLR_NAVIGATION_DIRECTIVES, CLR_PROGRESS_BAR_DIRECTIVES, CLR_SIGNPOST_DIRECTIVES, CLR_SPINNER_DIRECTIVES, CLR_STACK_VIEW_DIRECTIVES, CLR_TABS_DIRECTIVES, CLR_TOOLTIP_DIRECTIVES, CLR_TREE_VIEW_DIRECTIVES, CLR_VERTICAL_NAV_DIRECTIVES, CLR_WIZARD_DIRECTIVES, CONDITIONAL_DIRECTIVES, CUSTOM_BUTTON_TYPES, CdsIconCustomTag, ClarityModule, ClrAbstractContainer, ClrAccordion, ClrAccordionContent, ClrAccordionDescription, ClrAccordionModule, ClrAccordionPanel, ClrAccordionTitle, ClrAlert, ClrAlertItem, ClrAlertModule, ClrAlertText, ClrAlerts, ClrAlertsPager, ClrAlignment, ClrAriaCurrentLink, ClrAxis, ClrButton, ClrButtonGroup, ClrButtonGroupModule, ClrButtonModule, ClrCalendar, ClrCheckbox, ClrCheckboxContainer, ClrCheckboxModule, ClrCheckboxWrapper, ClrCombobox, ClrComboboxContainer, ClrComboboxModule, ClrCommonFormsModule, ClrCommonStringsService, ClrConditionalModule, ClrControl, ClrControlContainer, ClrControlError, ClrControlHelper, ClrControlSuccess, ClrDataModule, ClrDatagrid, ClrDatagridActionBar, ClrDatagridActionOverflow, ClrDatagridCell, ClrDatagridColumn, ClrDatagridColumnSeparator, ClrDatagridColumnToggle, ClrDatagridColumnToggleButton, ClrDatagridDetail, ClrDatagridDetailBody, ClrDatagridDetailHeader, ClrDatagridFilter, ClrDatagridFooter, ClrDatagridHideableColumn, ClrDatagridItems, ClrDatagridItemsTrackBy, ClrDatagridModule, ClrDatagridPageSize, ClrDatagridPagination, ClrDatagridPlaceholder, ClrDatagridRow, ClrDatagridRowDetail, ClrDatagridSortOrder, ClrDatalist, ClrDatalistContainer, ClrDatalistInput, ClrDatalistModule, ClrDateContainer, ClrDateInput, ClrDateInputValidator, ClrDatepickerModule, ClrDatepickerViewManager, ClrDay, ClrDaypicker, ClrDestroyService, ClrDropdown, ClrDropdownItem, ClrDropdownMenu, ClrDropdownModule, ClrDropdownTrigger, ClrEmphasisModule, ClrExpandableAnimation, ClrFocusOnViewInit, ClrFocusOnViewInitModule, ClrForm, ClrFormLayout, ClrFormsModule, ClrHeader, ClrIconCustomTag, ClrIconModule, ClrIfActive, ClrIfDetail, ClrIfError, ClrIfExpanded, ClrIfOpen, ClrIfSuccess, ClrInput, ClrInputContainer, ClrInputModule, ClrLabel, ClrLayout, ClrLayoutModule, ClrLoading, ClrLoadingButton, ClrLoadingButtonModule, ClrLoadingModule, ClrLoadingState, ClrMainContainer, ClrMainContainerModule, ClrModal, ClrModalBody, ClrModalModule, ClrMonthpicker, ClrNavLevel, ClrNavigationModule, ClrOption, ClrOptionItems, ClrOptionSelected, ClrOptions, ClrPassword, ClrPasswordContainer, ClrPasswordModule, ClrPopoverAnchor, ClrPopoverContent, ClrPopoverEventsService, ClrPopoverHostDirective, ClrPopoverModule, ClrPopoverPositionService, ClrPopoverToggleService, ClrProgressBar, ClrProgressBarModule, ClrRadio, ClrRadioContainer, ClrRadioModule, ClrRadioWrapper, ClrRange, ClrRangeContainer, ClrRangeModule, ClrRecursiveForOf, ClrSelect, ClrSelectContainer, ClrSelectModule, ClrSelectedState, ClrSide, ClrSignpost, ClrSignpostContent, ClrSignpostModule, ClrSignpostTrigger, ClrSpinner, ClrSpinnerModule, ClrStackBlock, ClrStackContentInput, ClrStackHeader, ClrStackView, ClrStackViewCustomTags, ClrStackViewLabel, ClrStackViewModule, ClrStandaloneCdkTrapFocus, ClrStepButton, ClrStepButtonType, ClrStepper, ClrStepperModule, ClrStepperPanel, ClrStopEscapePropagationDirective, ClrTab, ClrTabContent, ClrTabLink, ClrTabOverflowContent, ClrTabs, ClrTabsModule, ClrTextarea, ClrTextareaContainer, ClrTextareaModule, ClrTimeline, ClrTimelineLayout, ClrTimelineModule, ClrTimelineStep, ClrTimelineStepDescription, ClrTimelineStepHeader, ClrTimelineStepState, ClrTimelineStepTitle, ClrTooltip, ClrTooltipContent, ClrTooltipModule, ClrTooltipTrigger, ClrTree, ClrTreeNode, ClrTreeNodeLink, ClrTreeViewModule, ClrVerticalNav, ClrVerticalNavGroup, ClrVerticalNavGroupChildren, ClrVerticalNavIcon, ClrVerticalNavLink, ClrVerticalNavModule, ClrWizard, ClrWizardButton, ClrWizardHeaderAction, ClrWizardModule, ClrWizardPage, ClrWizardPageButtons, ClrWizardPageHeaderActions, ClrWizardPageNavTitle, ClrWizardPageTitle, ClrWizardStepnav, ClrWizardStepnavItem, ClrWizardTitle, ClrYearpicker, DEFAULT_BUTTON_TYPES, DatagridNumericFilter, DatagridPropertyComparator, DatagridPropertyNumericFilter, DatagridPropertyStringFilter, DatagridStringFilter, EXPANDABLE_ANIMATION_DIRECTIVES, FOCUS_ON_VIEW_INIT, FOCUS_ON_VIEW_INIT_DIRECTIVES, IS_TOGGLE, IS_TOGGLE_PROVIDER, LoadingListener, MainContainerWillyWonka, NavDetectionOompaLoompa, TOGGLE_SERVICE, TOGGLE_SERVICE_PROVIDER, ToggleServiceFactory, WrappedFormControl, collapse, commonStringsDefault, fade, fadeSlide, isToggleFactory, slide, AccordionOompaLoompa as ÇlrAccordionOompaLoompa, AccordionWillyWonka as ÇlrAccordionWillyWonka, ActionableOompaLoompa as ÇlrActionableOompaLoompa, ActiveOompaLoompa as ÇlrActiveOompaLoompa, ClrPopoverCloseButton as ÇlrClrPopoverCloseButton, ClrPopoverModuleNext as ÇlrClrPopoverModuleNext, ClrPopoverOpenCloseButton as ÇlrClrPopoverOpenCloseButton, DatagridCellRenderer as ÇlrDatagridCellRenderer, DatagridDetailRegisterer as ÇlrDatagridDetailRegisterer, DatagridHeaderRenderer as ÇlrDatagridHeaderRenderer, DatagridMainRenderer as ÇlrDatagridMainRenderer, DatagridRowRenderer as ÇlrDatagridRowRenderer, ClrDatagridSelectionCellDirective as ÇlrDatagridSelectionCellDirective, DatagridWillyWonka as ÇlrDatagridWillyWonka, ExpandableOompaLoompa as ÇlrExpandableOompaLoompa, StepperOompaLoompa as ÇlrStepperOompaLoompa, StepperWillyWonka as ÇlrStepperWillyWonka, TabsWillyWonka as ÇlrTabsWillyWonka, WrappedCell as ÇlrWrappedCell, WrappedColumn as ÇlrWrappedColumn, WrappedRow as ÇlrWrappedRow }; //# sourceMappingURL=clr-angular.mjs.map