UNPKG

igniteui-webcomponents

Version:

Ignite UI for Web Components is a complete library of UI components, giving you the ability to build modern web applications using encapsulation and the concept of reusable components in a dependency-free approach.

457 lines (455 loc) 16.4 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var IgcSelectComponent_1; import { html } from 'lit'; import { property, query, queryAssignedElements, state, } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { themes } from '../../theming/theming-decorator.js'; import { addKeybindings, altKey, arrowDown, arrowLeft, arrowRight, arrowUp, endKey, enterKey, escapeKey, homeKey, spaceBar, tabKey, } from '../common/controllers/key-bindings.js'; import { addRootScrollHandler } from '../common/controllers/root-scroll.js'; import { blazorAdditionalDependencies } from '../common/decorators/blazorAdditionalDependencies.js'; import { watch } from '../common/decorators/watch.js'; import { registerComponent } from '../common/definitions/register.js'; import { IgcBaseComboBoxLikeComponent, getActiveItems, getItems, getNextActiveItem, getPreviousActiveItem, setInitialSelectionState, } from '../common/mixins/combo-box.js'; import { EventEmitterMixin } from '../common/mixins/event-emitter.js'; import { FormAssociatedRequiredMixin } from '../common/mixins/forms/associated-required.js'; import { createFormValueState, } from '../common/mixins/forms/form-value.js'; import { findElementFromEventPath, isEmpty, isString, partNameMap, } from '../common/util.js'; import IgcIconComponent from '../icon/icon.js'; import IgcInputComponent from '../input/input.js'; import IgcPopoverComponent from '../popover/popover.js'; import IgcValidationContainerComponent from '../validation-container/validation-container.js'; import IgcSelectGroupComponent from './select-group.js'; import IgcSelectHeaderComponent from './select-header.js'; import IgcSelectItemComponent from './select-item.js'; import { styles } from './themes/select.base.css.js'; import { styles as shared } from './themes/shared/select.common.css.js'; import { all } from './themes/themes.js'; import { selectValidators } from './validators.js'; let IgcSelectComponent = IgcSelectComponent_1 = class IgcSelectComponent extends FormAssociatedRequiredMixin(EventEmitterMixin(IgcBaseComboBoxLikeComponent)) { static register() { registerComponent(IgcSelectComponent_1, IgcIconComponent, IgcInputComponent, IgcPopoverComponent, IgcSelectGroupComponent, IgcSelectHeaderComponent, IgcSelectItemComponent); } get _activeItems() { return Array.from(getActiveItems(this, IgcSelectItemComponent.tagName)); } get __validators() { return selectValidators; } set value(value) { this._updateValue(value); const item = this.getItem(this._formValue.value); item ? this.setSelectedItem(item) : this.clearSelectedItem(); } get value() { return this._formValue.value; } get items() { return Array.from(getItems(this, IgcSelectItemComponent.tagName)); } get groups() { return Array.from(getItems(this, IgcSelectGroupComponent.tagName)); } get selectedItem() { return this._selectedItem; } scrollStrategyChanged() { this._rootScrollController.update({ resetListeners: true }); } openChange() { this._rootClickController.update(); this._rootScrollController.update(); } constructor() { super(); this._searchTerm = ''; this._lastKeyTime = 0; this._rootScrollController = addRootScrollHandler(this, { hideCallback: this.handleClosing, }); this._selectedItem = null; this.outlined = false; this.distance = 0; this.placement = 'bottom-start'; this.scrollStrategy = 'scroll'; this._formValue = createFormValueState(this, { initialValue: undefined, transformers: { setValue: (value) => value || undefined, setDefaultValue: (value) => value || undefined, }, }); this._rootClickController.update({ hideCallback: this.handleClosing }); addKeybindings(this, { skip: () => this.disabled, bindingDefaults: { preventDefault: true, triggers: ['keydownRepeat'] }, }) .set([altKey, arrowDown], this.altArrowDown) .set([altKey, arrowUp], this.altArrowUp) .set(arrowDown, this.onArrowDown) .set(arrowUp, this.onArrowUp) .set(arrowLeft, this.onArrowUp) .set(arrowRight, this.onArrowDown) .set(tabKey, this.onTabKey, { preventDefault: false }) .set(escapeKey, this.onEscapeKey) .set(homeKey, this.onHomeKey) .set(endKey, this.onEndKey) .set(spaceBar, this.onSpaceBarKey) .set(enterKey, this.onEnterKey); this.addEventListener('keydown', this.handleSearch); this.addEventListener('focusin', this.handleFocusIn); this.addEventListener('focusout', this.handleFocusOut); } createRenderRoot() { const root = super.createRenderRoot(); root.addEventListener('slotchange', () => this.requestUpdate()); return root; } async firstUpdated() { await this.updateComplete; const selected = setInitialSelectionState(this.items); if (this.value && !selected) { this._selectItem(this.getItem(this.value), false); } if (selected && selected.value !== this.value) { this.defaultValue = selected.value; this._selectItem(selected, false); } if (this.autofocus) { this.focus(); } this._updateValidity(); } handleFocusIn({ relatedTarget }) { this._dirty = true; if (this.contains(relatedTarget) || this.open) { return; } } handleFocusOut({ relatedTarget }) { if (this.contains(relatedTarget)) { return; } this.checkValidity(); } handleClick(event) { const item = findElementFromEventPath(IgcSelectItemComponent.tagName, event); if (item && this._activeItems.includes(item)) { this._selectItem(item); } } handleChange(item) { return this.emitEvent('igcChange', { detail: item }); } handleSearch(event) { if (!/^.$/u.test(event.key)) { return; } event.preventDefault(); const now = Date.now(); if (now - this._lastKeyTime > 500) { this._searchTerm = ''; } this._lastKeyTime = now; this._searchTerm += event.key.toLocaleLowerCase(); const item = this._activeItems.find((item) => item.textContent?.trim().toLocaleLowerCase().startsWith(this._searchTerm)); if (item) { this.open ? this.activateItem(item) : this._selectItem(item); this._activeItem.focus(); } } handleAnchorClick() { super.handleAnchorClick(); this.focusItemOnOpen(); } onEnterKey() { this.open && this._activeItem ? this._selectItem(this._activeItem) : this.handleAnchorClick(); } onSpaceBarKey() { if (!this.open) { this.handleAnchorClick(); } } onArrowDown() { const item = getNextActiveItem(this.items, this._activeItem); this.open ? this._navigateToActiveItem(item) : this._selectItem(item); } onArrowUp() { const item = getPreviousActiveItem(this.items, this._activeItem); this.open ? this._navigateToActiveItem(item) : this._selectItem(item); } altArrowDown() { if (!this.open) { this._show(true); this.focusItemOnOpen(); } } async altArrowUp() { if (this.open && (await this._hide(true))) { this._input.focus(); } } async onEscapeKey() { if (await this._hide(true)) { this._input.focus(); } } onTabKey(event) { if (this.open) { event.preventDefault(); this._selectItem(this._activeItem ?? this._selectedItem); this._hide(true); } } onHomeKey() { const item = this._activeItems.at(0); this.open ? this._navigateToActiveItem(item) : this._selectItem(item); } onEndKey() { const item = this._activeItems.at(-1); this.open ? this._navigateToActiveItem(item) : this._selectItem(item); } handleClosing() { this._hide(true); } activateItem(item) { if (this._activeItem) { this._activeItem.active = false; } this._activeItem = item; this._activeItem.active = true; } setSelectedItem(item) { if (this._selectedItem) { this._selectedItem.selected = false; } this._selectedItem = item; this._selectedItem.selected = true; return this._selectedItem; } _selectItem(item, emit = true) { if (!item) { this.clearSelectedItem(); this._updateValue(); return null; } const shouldFocus = emit && this.open; const shouldHide = emit && !this.keepOpenOnSelect; if (this._selectedItem === item) { if (shouldFocus) this._input.focus(); return this._selectedItem; } const newItem = this.setSelectedItem(item); this.activateItem(newItem); this._updateValue(newItem.value); if (emit) this.handleChange(newItem); if (shouldFocus) this._input.focus(); if (shouldHide) this._hide(true); return this._selectedItem; } _navigateToActiveItem(item) { if (item) { this.activateItem(item); this._activeItem.focus({ preventScroll: true }); item.scrollIntoView({ behavior: 'auto', block: 'nearest' }); } } _updateValue(value) { this._formValue.setValueAndFormState(value); this._validate(); } clearSelectedItem() { if (this._selectedItem) { this._selectedItem.selected = false; } this._selectedItem = null; } async focusItemOnOpen() { await this.updateComplete; (this._selectedItem || this._activeItem)?.focus(); } getItem(value) { return this.items.find((item) => item.value === value); } focus(options) { this._input.focus(options); } blur() { this._input.blur(); } reportValidity() { const valid = super.reportValidity(); if (!valid) this._input.focus(); return valid; } navigateTo(value) { const item = isString(value) ? this.getItem(value) : this.items[value]; if (item) { this._navigateToActiveItem(item); } return item ?? null; } select(value) { const item = isString(value) ? this.getItem(value) : this.items[value]; return item ? this._selectItem(item, false) : null; } clearSelection() { this._updateValue(); this.clearSelectedItem(); } renderInputSlots() { const prefixName = isEmpty(this._inputPrefix) ? '' : 'prefix'; const suffixName = isEmpty(this._inputSuffix) ? '' : 'suffix'; return html ` <span slot=${prefixName}> <slot name="prefix"></slot> </span> <span slot=${suffixName}> <slot name="suffix"></slot> </span> `; } renderToggleIcon() { const parts = partNameMap({ 'toggle-icon': true, filled: this.value }); const iconHidden = this.open && !isEmpty(this._expandedIconSlot); const iconExpandedHidden = !iconHidden; return html ` <span slot="suffix" part=${parts} aria-hidden="true"> <slot name="toggle-icon" ?hidden=${iconHidden}> <igc-icon name=${this.open ? 'input_collapse' : 'input_expand'} collection="default" ></igc-icon> </slot> <slot name="toggle-icon-expanded" ?hidden=${iconExpandedHidden}></slot> </span> `; } renderHelperText() { return IgcValidationContainerComponent.create(this, { id: 'select-helper-text', slot: 'anchor', hasHelperText: true, }); } renderInputAnchor() { const value = this.selectedItem?.textContent?.trim(); return html ` <igc-input id="input" slot="anchor" role="combobox" readonly aria-controls="dropdown" aria-describedby="select-helper-text" aria-expanded=${this.open ? 'true' : 'false'} exportparts="container: input, input: native-input, label, prefix, suffix" tabIndex=${this.disabled ? -1 : 0} value=${ifDefined(value)} placeholder=${ifDefined(this.placeholder)} label=${ifDefined(this.label)} .disabled=${this.disabled} .required=${this.required} .invalid=${this.invalid} .outlined=${this.outlined} @click=${this.handleAnchorClick} > ${this.renderInputSlots()} ${this.renderToggleIcon()} </igc-input> ${this.renderHelperText()} `; } renderDropdown() { return html `<div part="base" .inert=${!this.open}> <div id="dropdown" role="listbox" part="list" aria-labelledby="input" @click=${this.handleClick} > <slot name="header"></slot> <slot></slot> <slot name="footer"></slot> </div> </div>`; } render() { return html `<igc-popover ?open=${this.open} flip shift same-width .offset=${this.distance} .placement=${this.placement} >${this.renderInputAnchor()} ${this.renderDropdown()} </igc-popover>`; } }; IgcSelectComponent.tagName = 'igc-select'; IgcSelectComponent.styles = [styles, shared]; __decorate([ state() ], IgcSelectComponent.prototype, "_selectedItem", void 0); __decorate([ state() ], IgcSelectComponent.prototype, "_activeItem", void 0); __decorate([ query(IgcInputComponent.tagName, true) ], IgcSelectComponent.prototype, "_input", void 0); __decorate([ queryAssignedElements({ slot: 'suffix' }) ], IgcSelectComponent.prototype, "_inputSuffix", void 0); __decorate([ queryAssignedElements({ slot: 'prefix' }) ], IgcSelectComponent.prototype, "_inputPrefix", void 0); __decorate([ queryAssignedElements({ slot: 'toggle-icon-expanded' }) ], IgcSelectComponent.prototype, "_expandedIconSlot", void 0); __decorate([ property() ], IgcSelectComponent.prototype, "value", null); __decorate([ property({ reflect: true, type: Boolean }) ], IgcSelectComponent.prototype, "outlined", void 0); __decorate([ property({ type: Boolean }) ], IgcSelectComponent.prototype, "autofocus", void 0); __decorate([ property({ type: Number }) ], IgcSelectComponent.prototype, "distance", void 0); __decorate([ property() ], IgcSelectComponent.prototype, "label", void 0); __decorate([ property() ], IgcSelectComponent.prototype, "placeholder", void 0); __decorate([ property() ], IgcSelectComponent.prototype, "placement", void 0); __decorate([ property({ attribute: 'scroll-strategy' }) ], IgcSelectComponent.prototype, "scrollStrategy", void 0); __decorate([ watch('scrollStrategy', { waitUntilFirstUpdate: true }) ], IgcSelectComponent.prototype, "scrollStrategyChanged", null); __decorate([ watch('open', { waitUntilFirstUpdate: true }) ], IgcSelectComponent.prototype, "openChange", null); IgcSelectComponent = IgcSelectComponent_1 = __decorate([ themes(all), blazorAdditionalDependencies('IgcIconComponent, IgcInputComponent, IgcSelectGroupComponent, IgcSelectHeaderComponent, IgcSelectItemComponent') ], IgcSelectComponent); export default IgcSelectComponent; //# sourceMappingURL=select.js.map