UNPKG

novo-elements

Version:

1 lines 63 kB
{"version":3,"file":"novo-elements-elements-select.mjs","sources":["../../../projects/novo-elements/src/elements/select/Select.ts","../../../projects/novo-elements/src/elements/select/Select.extupdatefix.directive.ts","../../../projects/novo-elements/src/elements/select/Select.module.ts","../../../projects/novo-elements/src/elements/select/novo-elements-elements-select.ts"],"sourcesContent":["// NG\nimport { ActiveDescendantKeyManager, FocusMonitor } from '@angular/cdk/a11y';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { SelectionModel } from '@angular/cdk/collections';\nimport { hasModifierKey } from '@angular/cdk/keycodes';\nimport {\n AfterViewInit,\n booleanAttribute,\n ChangeDetectorRef,\n Component,\n computed,\n ContentChildren,\n ElementRef,\n EventEmitter,\n HostListener,\n Inject,\n Injector,\n input,\n Input,\n NgZone,\n OnChanges,\n OnDestroy,\n OnInit,\n Optional,\n Output,\n QueryList,\n Self,\n signal,\n SimpleChanges,\n ViewChild,\n ViewChildren,\n} from '@angular/core';\nimport { ControlValueAccessor, FormGroupDirective, NgControl, NgForm } from '@angular/forms';\n// Vendor\nimport { merge, Observable, of, Subject, Subscription } from 'rxjs';\nimport { filter, map, startWith, take, takeUntil } from 'rxjs/operators';\n// App\nimport { NovoLabelService } from 'novo-elements/services';\nimport { Helpers, Key } from 'novo-elements/utils';\nimport {\n CanDisableCtor,\n CanRequireCtor,\n CanUpdateErrorStateCtor,\n ErrorStateMatcher,\n HasOverlayCtor,\n HasTabIndexCtor,\n mixinDisabled,\n mixinErrorState,\n mixinOverlay,\n mixinRequired,\n mixinTabIndex,\n NovoOptgroup,\n NovoOption,\n NovoOptionSelectionChange,\n NOVO_OPTION_PARENT_COMPONENT,\n _countGroupLabelsBeforeOption,\n _getOptionScrollPosition,\n NovoOverlayTemplateComponent,\n} from 'novo-elements/elements/common';\nimport { NOVO_FORM_FIELD, NovoFieldControl, NovoFieldElement } from 'novo-elements/elements/field';\n\n/** Change event object that is emitted when the select value has changed. */\nexport class NovoSelectChange {\n constructor(\n /** Reference to the select that emitted the change event. */\n public source: NovoSelectElement,\n /** Current value of the select that emitted the event. */\n public value: any,\n ) {}\n}\n\n// Create Base Class from Mixins\n// Boilerplate for applying mixins\nclass NovoSelectBase {\n constructor(\n public _defaultErrorStateMatcher: ErrorStateMatcher,\n public _parentForm: NgForm,\n public _parentFormGroup: FormGroupDirective,\n public ngControl: NgControl,\n ) {}\n}\nconst NovoSelectMixins: HasOverlayCtor &\n CanRequireCtor &\n CanDisableCtor &\n HasTabIndexCtor &\n CanUpdateErrorStateCtor &\n typeof NovoSelectBase = mixinOverlay(mixinTabIndex(mixinRequired(mixinDisabled(mixinErrorState(NovoSelectBase)))));\n\nlet nextId = 0;\n\n@Component({\n selector: 'novo-select',\n inputs: ['disabled', 'required', 'tabIndex'],\n providers: [\n { provide: NovoFieldControl, useExisting: NovoSelectElement },\n { provide: NOVO_OPTION_PARENT_COMPONENT, useExisting: NovoSelectElement },\n ],\n template: `\n <div class=\"novo-select-trigger\">\n <span class=\"novo-select-placeholder\" *ngIf=\"empty\">{{ placeholder }}</span>\n <span class=\"text-ellipsis\" *ngIf=\"!empty\"><novo-icon size=\"sm\" style=\"margin: 0 0 .25rem .1rem\" *ngIf=\"displayIcon\">{{ displayIcon }}</novo-icon> {{ displayValue }}</span>\n <i class=\"bhi-collapse\"></i>\n </div>\n <novo-overlay-template\n [parent]=\"elementRef\"\n [position]=\"position\"\n [width]=\"overlayWidth\"\n [height]=\"overlayHeight\"\n (closing)=\"elementRef.nativeElement.focus()\"\n >\n <div #panel class=\"novo-select-list\" tabIndex=\"-1\" [class.has-header]=\"headerConfig\" [class.active]=\"panelOpen\">\n <novo-option *ngIf=\"headerConfig\" class=\"select-header\" [class.open]=\"header.open\">\n <novo-button *ngIf=\"!header.open\" icon=\"add-thin\" (click)=\"toggleHeader($event); (false)\" tabIndex=\"-1\" class=\"header\">\n {{ headerConfig.label }}\n </novo-button>\n <div *ngIf=\"header.open\" [ngClass]=\"{ active: header.open }\">\n <input\n autofocus\n type=\"text\"\n [placeholder]=\"headerConfig.placeholder\"\n [attr.id]=\"name\"\n autocomplete=\"off\"\n [value]=\"header.value\"\n [ngClass]=\"{ invalid: !header.valid }\"\n />\n <footer>\n <novo-button (click)=\"toggleHeader($event, false)\">{{ labels.cancel }}</novo-button>\n <novo-button (click)=\"saveHeader()\" class=\"primary\">{{ labels.save }}</novo-button>\n </footer>\n </div>\n </novo-option>\n <!-- Declarative Content Goes Here -->\n <ng-content></ng-content>\n <!-- Data Driven Content Goes Here -->\n <ng-container *ngFor=\"let option of filteredOptions; let i = index\">\n <novo-option\n *ngIf=\"!option.divider; else divider\"\n class=\"select-item\"\n [disabled]=\"option.disabled\"\n [class.active]=\"option.active\"\n [attr.data-automation-value]=\"option.label\"\n [value]=\"option.value\"\n [tooltip]=\"option.tooltip\"\n [tooltipPosition]=\"option.tooltipPosition || 'right'\"\n >\n <span [innerHtml]=\"option.label | highlight:filterTerm\"></span> <i *ngIf=\"option.active\" class=\"bhi-check\"></i>\n </novo-option>\n <ng-template #divider>\n <novo-divider class=\"select-item-divider\" [class.with-label]=\"option.label\" [class.without-label]=\"!option.label\">\n {{ option?.label }}\n </novo-divider>\n </ng-template>\n </ng-container>\n </div>\n </novo-overlay-template>\n `,\n styleUrls: ['./Select.scss'],\n host: {\n class: 'novo-select',\n role: 'combobox',\n 'aria-autocomplete': 'none',\n 'aria-haspopup': 'true',\n '[attr.id]': 'id',\n '[attr.aria-controls]': 'panelOpen ? id + \"-panel\" : null',\n '[attr.aria-expanded]': 'panelOpen',\n '[attr.aria-required]': 'required.toString()',\n '[attr.aria-disabled]': 'disabled.toString()',\n '[attr.aria-invalid]': 'errorState',\n '[attr.aria-labelledby]': '_ariaLabelledBy || null',\n '[attr.aria-describedby]': '_ariaDescribedby || null',\n '[attr.aria-activedescendant]': '_getAriaActiveDescendant()',\n '[class.novo-select-disabled]': 'disabled',\n '[class.novo-select-invalid]': 'errorState',\n '[class.novo-select-required]': 'required',\n '[class.novo-select-empty]': 'empty',\n '[class.novo-select-multiple]': 'multiple',\n '[tabindex]': 'disabled ? -1 : 0',\n },\n standalone: false,\n})\nexport class NovoSelectElement\n extends NovoSelectMixins\n implements OnInit, AfterViewInit, OnChanges, OnDestroy, ControlValueAccessor, NovoFieldControl<any>\n{\n private _uniqueId: string = `novo-select-${++nextId}`;\n private _stateChanges = Subscription.EMPTY;\n private _activeOptionChanges = Subscription.EMPTY;\n private _selectedOptionChanges = Subscription.EMPTY;\n protected readonly _destroy = new Subject<void>();\n\n readonly controlType: string = 'select';\n\n /** @docs-private Implemented as part of NovoFieldControl. */\n lastKeyValue: string = null;\n /** @docs-private Implemented as part of NovoFieldControl.*/\n lastCaretPosition: number | null;\n\n _selectionModel: SelectionModel<NovoOption>;\n\n /** The aria-labelledby attribute */\n _ariaLabelledBy: string;\n /** The aria-describedby attribute on the chip list for improved a11y. */\n _ariaDescribedby: string;\n /** User defined tab index. */\n _userTabIndex: number | null = null;\n /** The FocusKeyManager which handles focus. */\n _keyManager: ActiveDescendantKeyManager<NovoOption>;\n /**\n * The display string for the current value, kept from when the associated <novo-option> has stopped rendering\n * due to filtration\n */\n private _lingeringDisplayValue: string = null;\n private _legacyOption: any;\n\n @Input()\n id: string = this._uniqueId;\n @Input()\n name: string = this._uniqueId;\n @Input()\n placeholder: string = 'Select...';\n @Input({ transform: booleanAttribute })\n readonly: boolean;\n @Input()\n headerConfig: any;\n @Input()\n position: string = 'above-below';\n @Input()\n overlayWidth: number;\n @Input()\n overlayHeight: number;\n @Input()\n displayIcon: string = null;\n @Output()\n onSelect: EventEmitter<any> = new EventEmitter();\n /** Event emitted when the selected value has been changed by the user. */\n @Output() readonly selectionChange: EventEmitter<NovoSelectChange> = new EventEmitter<NovoSelectChange>();\n /** Event that emits whenever the raw value of the select changes.*/\n @Output() readonly valueChange: EventEmitter<any> = new EventEmitter<any>();\n\n /** Event emitted when the select panel has been toggled. */\n @Output() readonly openedChange: EventEmitter<boolean> = new EventEmitter<boolean>();\n /** Event emitted when the select has been opened. */\n @Output('opened') readonly _openedStream: Observable<void> = this.openedChange.pipe(\n filter((o) => o),\n map(() => {}),\n );\n /** Event emitted when the select has been closed. */\n @Output('closed') readonly _closedStream: Observable<void> = this.openedChange.pipe(\n filter((o) => !o),\n map(() => {}),\n );\n\n /** Function that maps an option's control value to its display value in the trigger. */\n @Input() displayWith: ((value: any) => string) | null = null;\n /** * Function to compare the option values with the selected values. */\n @Input() compareWith: (o1: any, o2: any) => boolean = (o1: any, o2: any) =>\n o1 === o2 || o1 === o2.id || (!Helpers.isEmpty(o1.id) && !Helpers.isEmpty(o2.id) && o1.id === o2.id);\n\n header: any = {\n open: false,\n valid: true,\n value: '',\n };\n createdItem: any;\n model: any;\n onModelChange: Function = () => {};\n onModelTouched: Function = () => {};\n filterTerm: string = '';\n filterTermTimeout;\n filteredOptions: any = [];\n disabled: boolean = false;\n\n /** Element for the panel containing the autocomplete options. */\n @ViewChild(NovoOverlayTemplateComponent, { static: true })\n overlay: NovoOverlayTemplateComponent;\n\n @ContentChildren(NovoOptgroup, { descendants: true })\n optionGroups: QueryList<NovoOptgroup>;\n @ContentChildren(NovoOption, { descendants: true })\n contentOptions: QueryList<NovoOption>;\n @ViewChildren(NovoOption)\n viewOptions: QueryList<NovoOption>;\n\n viewOptionsSignal = signal<NovoOption[]>(null);\n contentOptionsSignal = signal<NovoOption[]>(null);\n\n // This signal may be set programmatically by a SelectSearchComponent.\n hideLegacyOptionsForSearch = signal(false);\n\n hideLegacyOptions = input(false, { transform: booleanAttribute });\n\n private displayLegacyOptions = computed(() => {\n return !(this.hideLegacyOptionsForSearch() || this.hideLegacyOptions());\n })\n\n @ViewChild('panel')\n panel: ElementRef;\n\n /**\n * Implemented as part of NovoFieldControl.\n * @docs-private\n */\n @Input()\n get value(): any {\n return this._value;\n }\n set value(newValue: any) {\n // Always re-assign an array, because it might have been mutated.\n if (newValue !== this._value || (this._multiple && Array.isArray(newValue))) {\n if (this.options) {\n this._setSelectionByValue(newValue);\n }\n this._value = newValue;\n this._lingeringDisplayValue = null;\n }\n }\n private _value: any = null;\n\n /** Whether the user should be allowed to select multiple options. */\n @Input()\n get multiple(): boolean {\n return this._multiple;\n }\n set multiple(value: boolean) {\n this._multiple = coerceBooleanProperty(value);\n this.position = 'above-below';\n }\n private _multiple: boolean = false;\n\n /** Array of options to display in the select dropdown */\n @Input()\n set options(options: Array<any>) {\n this._options = options;\n this._initLegacyOptions();\n }\n get options(): Array<any> {\n return this._options;\n }\n private _options: Array<any>;\n\n /** Whether the select is focused. */\n get focused(): boolean {\n return this._focused || this.panelOpen;\n }\n private _focused = false;\n\n /** Implemented as part of NovoFieldControl. */\n get empty(): boolean {\n return Helpers.isEmpty(this._value);\n }\n\n /** The currently selected option. */\n get selected(): NovoOption | NovoOption[] {\n return this.multiple ? this._selectionModel.selected : this._selectionModel.selected[0];\n }\n\n /** The value displayed in the trigger. */\n get displayValue(): string {\n if (this.empty) {\n return '';\n }\n if (this._multiple) {\n const selectedOptions = this._selectionModel.selected.map((option) => this._getDisplayValue(option));\n return selectedOptions.join(', ');\n }\n return this._getDisplayValue(this._selectionModel.selected[0]);\n }\n\n constructor(\n public elementRef: ElementRef,\n public labels: NovoLabelService,\n public ref: ChangeDetectorRef,\n private focusMonitor: FocusMonitor,\n private ngZone: NgZone,\n private injector: Injector,\n defaultErrorStateMatcher: ErrorStateMatcher,\n @Optional() @Self() ngControl: NgControl,\n @Optional() _parentForm: NgForm,\n @Optional() _parentFormGroup: FormGroupDirective,\n @Optional() @Inject(NOVO_FORM_FIELD) private _fieldElement: NovoFieldElement,\n ) {\n super(defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl);\n if (ngControl) {\n ngControl.valueAccessor = this;\n }\n this._selectionModel = new SelectionModel<NovoOption>(this.multiple);\n // Initialize KeyManager to manage keyboard events\n this._initKeyManager();\n }\n\n ngOnInit() {\n this.stateChanges.next();\n this._initLegacyOptions();\n this.focusMonitor.monitor(this.elementRef.nativeElement).subscribe((origin) =>\n this.ngZone.run(() => {\n this._focused = !!origin;\n this.stateChanges.next();\n }),\n );\n }\n\n ngOnChanges(changes: SimpleChanges) {\n // Updating the disabled state is handled by `mixinDisabled`, but we need to additionally let\n // the parent form field know to run change detection when the disabled state changes.\n if (changes?.disabled) {\n this.stateChanges.next();\n }\n if (changes?.multiple) {\n // TODO: copy selection over??\n this._selectionModel = new SelectionModel<NovoOption>(this.multiple);\n }\n this._initLegacyOptions();\n }\n\n ngAfterViewInit() {\n // Subscribe to NovoOption selections\n this._watchSelectionEvents();\n // Set initial value\n this._initializeSelection();\n // Listen to selection changes to select and deselect options\n this._selectionModel.changed.pipe(takeUntil(this._destroy)).subscribe((event) => {\n event.added.forEach((option) => {\n if (option.select) {\n option.select();\n }\n });\n event.removed.forEach((option) => {\n if (option.deselect) {\n option.deselect();\n }\n });\n });\n // Listen to QueryList changes\n merge(this.contentOptions.changes, this.viewOptions.changes)\n .pipe(takeUntil(this._destroy))\n .subscribe(() => {\n this._watchSelectionEvents();\n this._initializeSelection();\n });\n\n this.contentOptions.changes.pipe(takeUntil(this._destroy), startWith(this.contentOptions))\n .subscribe(contentOptions => {\n this.contentOptionsSignal.set(contentOptions.toArray());\n });\n\n this.viewOptions.changes.pipe(takeUntil(this._destroy), startWith(this.viewOptions))\n .subscribe(viewOptions => {\n this.viewOptionsSignal.set(viewOptions.toArray());\n });\n\n merge(this.overlay.opening, this.overlay.closing)\n .pipe(takeUntil(this._destroy))\n .subscribe(() => {\n this.openedChange.emit(this.panelOpen);\n });\n setTimeout(() => {\n if (this._fieldElement?._labelElement) {\n this._ariaLabelledBy = this._fieldElement._labelElement.id;\n }\n });\n }\n\n ngOnDestroy() {\n this._destroy.next();\n this._destroy.complete();\n this._stateChanges.unsubscribe();\n this._activeOptionChanges.unsubscribe();\n this._selectedOptionChanges.unsubscribe();\n this.focusMonitor.stopMonitoring(this.elementRef.nativeElement);\n }\n\n @HostListener('click')\n onClick() {\n this.togglePanel();\n return false;\n }\n\n openPanel() {\n super.openPanel();\n this._highlightCorrectOption();\n }\n\n private _initializeSelection(): void {\n // Defer setting the value in order to avoid the \"Expression\n // has changed after it was checked\" errors from Angular.\n Promise.resolve().then(() => {\n this._setSelectionByValue(this.ngControl ? this.ngControl.value : this._value);\n this.stateChanges.next();\n });\n }\n\n /**\n * Sets the selected option based on a value. If no option can be\n * found with the designated value, the select trigger is cleared.\n */\n private _setSelectionByValue(value: any | any[]): void {\n this._selectionModel.selected.forEach((option) => {\n if (option.setInactiveStyles) {\n option.setInactiveStyles();\n }\n });\n this._selectionModel.clear();\n if (this.multiple && value) {\n value.forEach((currentValue: any) => this._selectValue(currentValue));\n this._sortValues();\n } else if (this._keyManager) {\n const correspondingOption = this._selectValue(value);\n // Shift focus to the active item. Note that we shouldn't do this in multiple\n // mode, because we don't know what option the user interacted with last.\n if (correspondingOption) {\n this._keyManager.updateActiveItem(correspondingOption);\n } else if (!this.panelOpen) {\n // Otherwise reset the highlighted option. Note that we only want to do this while\n // closed, because doing it while open can shift the user's focus unnecessarily.\n this._keyManager.updateActiveItem(-1);\n }\n }\n this.ref.markForCheck();\n }\n\n /**\n * Finds and selects and option based on its value.\n * @returns Option that has the corresponding value.\n */\n private _selectValue(value: any): NovoOption | undefined {\n const allOptions = this._getOptions();\n const correspondingOption = allOptions.find((option: NovoOption) => {\n // Skip options that are already in the model. This allows us to handle cases\n // where the same primitive value is selected multiple times.\n if (this._selectionModel.isSelected(option)) {\n return false;\n }\n return !Helpers.isEmpty(value) && !Helpers.isEmpty(option.value) && this.compareWith(option.value, value);\n });\n if (correspondingOption) {\n this._selectionModel.select(correspondingOption);\n } else if (value && !correspondingOption && this.displayLegacyOptions()) {\n // If searchComponent is present, we are using a text input filter; so if there is an\n // option not in the list, it is just filtered out\n // Double Check option not already added.\n const legacyOption = this.filteredOptions.find((it) => it.value === value);\n if (!legacyOption) {\n // Add a disabled option to the list and select it\n this._legacyOption = {\n disabled: true,\n tooltip: 'Value is not provided in list of valid options.',\n label: value?.label || value,\n value,\n }\n this.filteredOptions.push(this._legacyOption);\n this.ref.detectChanges();\n }\n }\n\n return correspondingOption;\n }\n\n public select(option, i, fireEvents: boolean = true) {\n console.warn('select() method is deprecated');\n }\n public clear() {\n console.warn('clear() method is deprecated');\n }\n\n /**\n * If the item is not disabled, this method closes the panel, and if a value is specified,\n * also sets the associated control to that value. It will also mark the control as dirty\n * if this interaction stemmed from the user.\n */\n handleSelection(option: NovoOption, isUserInput: boolean = false): void {\n const wasSelected = this._selectionModel.isSelected(option);\n if (option.value == null && !this._multiple) {\n option.deselect();\n this._selectionModel.clear();\n if (this.value != null) {\n this._propagateChanges(option.value);\n }\n } else {\n if (wasSelected !== option.selected) {\n option.selected ? this._selectionModel.select(option) : this._selectionModel.deselect(option);\n }\n if (isUserInput) {\n this._keyManager.setActiveItem(option);\n }\n if (this.multiple) {\n this._sortValues();\n if (isUserInput) {\n this.focus();\n }\n }\n }\n const legacyOptionIndex = this.filteredOptions.lastIndexOf(this._legacyOption);\n if (legacyOptionIndex !== -1) {\n this.filteredOptions.splice(legacyOptionIndex, 1);\n }\n\n if (wasSelected !== this._selectionModel.isSelected(option)) {\n this._propagateChanges();\n }\n this.stateChanges.next();\n this._watchSelectionEvents();\n }\n\n private _getDisplayValue(option: NovoOption & { value?: any; label?: string }): string {\n if (!option) {\n return this._lingeringDisplayValue ?? '';\n }\n let toDisplay = option.viewValue;\n if (this.displayWith) {\n toDisplay = this.displayWith(option.value);\n }\n // Simply falling back to an empty string if the display value is falsy does not work properly.\n // The display value can also be the number zero and shouldn't fall back to an empty string.\n let displayValue = toDisplay != null ? toDisplay : '';\n // eslint-disable-next-line eqeqeq\n if (displayValue != '') {\n this._lingeringDisplayValue = displayValue;\n } else if (this._lingeringDisplayValue) {\n displayValue = this._lingeringDisplayValue;\n }\n return displayValue;\n }\n\n /**\n * Clear any previous selected option and emit a selection change event for this option\n */\n private _clearPreviousSelectedOption(skip: NovoOption) {\n this._getOptions().forEach((option) => {\n if (option !== skip && option.selected) {\n option.deselect();\n }\n });\n }\n\n private _watchSelectionEvents() {\n const options = this._getOptions();\n const selectionEvents = options ? merge(...options.map((option) => option.onSelectionChange)) : of();\n this._selectedOptionChanges.unsubscribe();\n this._selectedOptionChanges = selectionEvents.pipe(take(1)).subscribe((event: NovoOptionSelectionChange) => {\n this.onModelTouched();\n this.handleSelection(event.source, event.isUserInput);\n if (event.isUserInput && !this.multiple && this.panelOpen) {\n this.closePanel();\n this.focus();\n }\n });\n }\n\n /** Handles all keydown events on the select. */\n @HostListener('keydown', ['$event'])\n _handleKeydown(event: KeyboardEvent): void {\n if (!this.disabled) {\n this.panelOpen ? this._handleOpenKeydown(event) : this._handleClosedKeydown(event);\n }\n }\n\n /** Handles keyboard events while the select is closed. */\n private _handleClosedKeydown(event: KeyboardEvent): void {\n const key = event.key;\n const isArrowKey = key === Key.ArrowDown || key === Key.ArrowUp || key === Key.ArrowLeft || key === Key.ArrowRight;\n const isOpenKey = key === Key.Enter || key === Key.Space;\n const manager = this._keyManager;\n // Open the select on ALT + arrow key to match the native <select>\n if ((!manager.isTyping() && isOpenKey && !hasModifierKey(event)) || ((this.multiple || event.altKey) && isArrowKey)) {\n event.preventDefault(); // prevents the page from scrolling down when pressing space\n this.openPanel();\n }\n }\n\n /** Handles keyboard events when the selected is open. */\n private _handleOpenKeydown(event: KeyboardEvent): void {\n const manager = this._keyManager;\n const key = event.key;\n const isArrowKey = key === Key.ArrowDown || key === Key.ArrowUp;\n const isTyping = manager.isTyping();\n\n if (isArrowKey && event.altKey) {\n // Close the select on ALT + arrow key to match the native <select>\n event.preventDefault();\n this.closePanel();\n // Don't do anything in this case if the user is typing,\n // because the typing sequence can include the space key.\n } else if (!isTyping && (key === Key.Enter || key === Key.Space) && manager.activeItem && !hasModifierKey(event)) {\n event.preventDefault();\n manager.activeItem._selectViaInteraction();\n } else if (!isTyping && this._multiple && ['a', 'A'].includes(key) && event.ctrlKey) {\n event.preventDefault();\n const hasDeselectedOptions = this.options.some((opt) => !opt.disabled && !opt.selected);\n this.options.forEach((option) => {\n if (!option.disabled) {\n hasDeselectedOptions ? option.select() : option.deselect();\n }\n });\n } else if (Key.Escape === key) {\n this.closePanel();\n } else {\n const previouslyFocusedIndex = manager.activeItemIndex;\n manager.onKeydown(event);\n if (this._multiple && isArrowKey && event.shiftKey && manager.activeItem && manager.activeItemIndex !== previouslyFocusedIndex) {\n manager.activeItem._selectViaInteraction();\n }\n }\n }\n\n writeValue(value: any): void {\n this.value = value;\n }\n\n registerOnChange(fn: Function): void {\n this.onModelChange = fn;\n }\n\n registerOnTouched(fn: Function): void {\n this.onModelTouched = fn;\n }\n\n setDisabledState(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** Implemented as part of NovoFieldControl. */\n setDescribedByIds(ids: string[]) {\n this._ariaDescribedby = ids.join(' ');\n }\n\n /** Implemented as part of NovoFieldControl. */\n onContainerClick(event: MouseEvent) {\n this.focus();\n }\n\n /**\n * Focuses the first non-disabled chip in this chip list, or the associated input when there\n * are no eligible chips.\n */\n focus(options?: FocusOptions): void {\n if (!this.disabled) {\n this.elementRef.nativeElement.focus(options);\n }\n }\n\n protected _getOptions() {\n return [...(this.viewOptions || []), ...(this.contentOptions || [])];\n }\n\n protected _optionsComputed = computed(() => {\n return [...(this.viewOptionsSignal() || []), ...(this.contentOptionsSignal() || [])]\n });\n\n /** Sorts the selected values in the selected based on their order in the panel. */\n private _sortValues() {\n if (this.multiple) {\n // TODO.\n }\n }\n\n /** Emits change event to set the model value. */\n private _propagateChanges(fallbackValue?: any): void {\n let valueToEmit: any = null;\n if (this.multiple) {\n valueToEmit = (this.selected as NovoOption[]).map((option) => option.value);\n } else {\n valueToEmit = this.selected ? (this.selected as NovoOption).value : fallbackValue;\n }\n\n this._value = valueToEmit;\n this.valueChange.emit(valueToEmit);\n this.onModelChange(valueToEmit);\n this.onSelect.emit({ selected: valueToEmit });\n this.selectionChange.emit(this._makeChangeEvent(valueToEmit));\n this.ref.markForCheck();\n }\n\n protected _makeChangeEvent(value: any) {\n return new NovoSelectChange(this, value);\n }\n\n /** Scrolls the active option into view. */\n protected _scrollOptionIntoView(index: number): void {\n const options = new QueryList<NovoOption>();\n options.reset(this._getOptions());\n const labelCount = _countGroupLabelsBeforeOption(index, options, this.optionGroups);\n const itemHeight = this._getItemHeight();\n this.panel.nativeElement.scrollTop = _getOptionScrollPosition(\n (index + labelCount) * itemHeight,\n itemHeight,\n this.panel.nativeElement.scrollTop,\n this.panel.nativeElement.offsetHeight,\n );\n }\n\n /** Sets up a key manager to listen to keyboard events on the overlay panel. */\n private _initKeyManager() {\n this._keyManager = new ActiveDescendantKeyManager<NovoOption>(this._optionsComputed, this.injector).withTypeAhead(250).withHomeAndEnd();\n\n this._keyManager.tabOut.pipe(takeUntil(this._destroy)).subscribe(() => {\n if (this.panelOpen) {\n // Select the active item when tabbing away. This is consistent with how the native\n // select behaves. Note that we only want to do this in single selection mode.\n if (!this.multiple && this._keyManager.activeItem) {\n this._keyManager.activeItem._selectViaInteraction();\n }\n // Restore focus to the trigger before closing. Ensures that the focus\n // position won't be lost if the user got focus into the overlay.\n this.focus();\n this.closePanel();\n }\n });\n\n this._keyManager.change.pipe(takeUntil(this._destroy)).subscribe(() => {\n if (this.panelOpen && this.overlay) {\n this._scrollOptionIntoView(this._keyManager.activeItemIndex || 0);\n } else if (!this.panelOpen && !this.multiple && this._keyManager.activeItem) {\n this._keyManager.activeItem._selectViaInteraction();\n }\n });\n }\n\n /**\n * Highlights the selected item. If no option is selected, it will highlight\n * the first item instead.\n */\n private _highlightCorrectOption(): void {\n if (this._keyManager) {\n if (this.empty) {\n this._keyManager.setFirstItemActive();\n } else {\n const options = this._getOptions();\n // eslint-disable-next-line eqeqeq\n const index = options.findIndex(option => option.value == this._value)\n this._keyManager.setActiveItem(index);\n }\n }\n }\n\n /** Calculates the height of the select's options. */\n private _getItemHeight(): number {\n const [first] = this._getOptions();\n if (first) {\n return first._getHostElement().offsetHeight;\n }\n return 0;\n }\n\n // TODO: Deprecate this\n private _initLegacyOptions() {\n if (this.options && this.options.length && typeof this.options[0] === 'string') {\n this.filteredOptions = this.options.map((item) => {\n return { value: item, label: item };\n });\n } else {\n this.filteredOptions = (this.options || [])\n .map((item) => {\n return {\n ...item,\n disabled: Boolean(item.readOnly || item.disabled),\n };\n })\n .map((item) => {\n return {\n ...item,\n active: false,\n };\n });\n }\n }\n\n /**\n * TODO: Deprecate all header methods\n */\n toggleHeader(event, forceValue: boolean = false) {\n if (event) {\n event.stopPropagation();\n event.preventDefault();\n }\n // Reverse the active property (if forceValue, use that)\n this.header = {\n open: forceValue !== undefined ? forceValue : !this.header.open,\n value: '',\n valid: true,\n };\n }\n\n /**\n * @deprecated use highlight pipe\n */\n highlight(match, query) {\n // Replaces the capture string with a the same string inside of a \"strong\" tag\n return query ? match.replace(new RegExp(this.escapeRegexp(query), 'gi'), '<strong>$&</strong>') : match;\n }\n\n escapeRegexp(queryToEscape) {\n // Ex: if the capture is \"a\" the result will be \\a\n return queryToEscape.replace(/([.?*+^$[\\]\\\\(){}|-])/g, '\\\\$1');\n }\n\n saveHeader() {\n if (this.header.value) {\n this.headerConfig.onSave(this.header.value);\n this.createdItem = this.header.value;\n this.closePanel();\n } else {\n this.header.valid = false;\n }\n }\n\n /** Determines the `aria-activedescendant` to be set on the host. */\n _getAriaActiveDescendant(): string | null {\n if (this.panelOpen && this._keyManager && this._keyManager.activeItem) {\n return this._keyManager.activeItem.id;\n }\n\n return null;\n }\n}\n","import { Directive, OnInit, inject } from '@angular/core';\nimport { FormControl, NgControl } from '@angular/forms';\nimport { NovoSelectElement } from './Select';\n\n/**\n * Fixes a <novo-select> element so that if its value is updated externally, the checkboxes in the dropdown selector\n * update accordingly. Because this is a functionality change to a core control, this fix is provided as a directive\n * to only be used if needed.\n */\n@Directive({\n selector: 'novo-select[extupdatefix]',\n standalone: false,\n})\nexport class NovoSelectExtUpdateFix implements OnInit {\n control = inject(NgControl);\n selectElement = inject(NovoSelectElement);\n\n ngOnInit() {\n if (this.control?.control && 'registerOnChange' in this.control.control) {\n (this.control.control as FormControl).registerOnChange((rawValue, viewToModelUpdate) => {\n if (this.selectElement.multiple === Array.isArray(rawValue)) {\n this.afterExternalUpdate(rawValue);\n }\n });\n }\n }\n\n afterExternalUpdate(rawValue: any) {\n this.selectElement['_setSelectionByValue'](rawValue);\n }\n}\n","// NG\nimport { A11yModule } from '@angular/cdk/a11y';\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n// App\nimport { NovoPipesModule } from 'novo-elements/pipes';\nimport { NovoButtonModule } from 'novo-elements/elements/button';\nimport { NovoOptionModule, NovoOverlayModule } from 'novo-elements/elements/common';\nimport { NovoDividerModule } from 'novo-elements/elements/divider';\nimport { NovoTooltipModule } from 'novo-elements/elements/tooltip';\nimport { NovoSelectElement } from './Select';\nimport { NovoSelectExtUpdateFix } from './Select.extupdatefix.directive';\nimport { NovoIconModule } from 'novo-elements/elements/icon';\n\n@NgModule({\n imports: [\n A11yModule,\n CommonModule,\n FormsModule,\n NovoButtonModule,\n NovoDividerModule,\n NovoOptionModule,\n NovoOverlayModule,\n NovoPipesModule,\n NovoTooltipModule,\n NovoIconModule,\n ],\n declarations: [NovoSelectElement, NovoSelectExtUpdateFix],\n exports: [NovoSelectElement, NovoSelectExtUpdateFix],\n})\nexport class NovoSelectModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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