UNPKG

@scania/tegel

Version:
732 lines (722 loc) 43.2 kB
import { r as registerInstance, c as createEvent, h, H as Host, g as getElement } from './index-51d04e39.js'; import { g as generateUniqueId } from './generateUniqueId-7934d315.js'; /** * Find the next focusable element index in a list of focusable elements. * @param items List of focusable elements, element with a attribute of disabled that is true will be skipped over. * @param nextItemIndex The index in the list to start the search on. */ const findNextFocusableElement = (items, nextItemIndex) => { if (items[nextItemIndex] === undefined) { return 0; } for (let index = nextItemIndex; index < items.length; index++) { if (!items[index].disabled) { return index; } } }; /** * Find the previous focusable element index in a list of focusable elements. * * @param items List of focusable elements, element with a attribute of disabled that is true will be skipped over. * @param nextItemIndex The index in the list to start the search on. */ const findPreviousFocusableElement = (items, previousItemIndex) => { if (items[previousItemIndex] === undefined) { return items.length - 1; } for (let index = previousItemIndex; index >= 0; index--) { if (!items[index].disabled) { return index; } } }; /** reference: https://github.com/ionic-team/ionic-framework/blob/main/core/src/utils/helpers.ts#L346 * * Appends a hidden input element to allow the component * work within and get picked up by a <form>. * @param element The element on which the input with be appended. * @param name Name of the input. * @param value The value of the input. * @param disabled Disables the input if true. * @param additionalAttributes Additional attributes that should be passed to the input. */ const appendHiddenInput = (element, name, value, disabled, additionalAttributes) => { let input = element.querySelector('input'); if (!element.querySelector('input')) { input = element.ownerDocument.createElement('input'); input.type = 'hidden'; if (additionalAttributes) { additionalAttributes.forEach((attr) => input.setAttribute(attr.key, attr.value)); } element.appendChild(input); } input.disabled = disabled; input.name = name; input.value = value || ''; }; /** * Converts a value (string or number) to string * @param value - The value to convert * @returns The string representation of the value, or empty string if null/undefined */ const convertToString = (value) => { if (value === null || value === undefined) return ''; return value.toString(); }; // Optional: If we need array conversion often const convertArrayToStrings = (values) => { return values.map((value) => convertToString(value)); }; const dropdownCss = "@charset \"UTF-8\";:host button{all:unset;height:100%;width:100%;background-color:var(--tds-dropdown-bg);border-bottom:1px solid var(--tds-dropdown-border-bottom);border-radius:var(--tds-dropdown-border-radius)}:host button:hover{border-bottom:1px solid var(--tds-dropdown-border-bottom-hover)}:host button .value-wrapper{padding:0 16px;display:flex;align-items:center;justify-content:space-between}:host button.placeholder{color:var(--tds-dropdown-placeholder-color);line-height:1.3}:host button.value{color:var(--tds-dropdown-value-color);font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls);line-height:1.3}:host button:focus{border-bottom:0}:host button.error{border-bottom:1px solid var(--tds-dropdown-error)}:host button.error:focus{border-bottom-color:transparent}:host button.error:focus::before{content:\"\";position:absolute;bottom:0;left:0;width:100%;height:1px;background:var(--tds-dropdown-error)}:host button:disabled{color:var(--tds-dropdown-disabled-color);border-bottom:1px solid transparent}:host button .menu-icon{margin-right:0}:host .dropdown-select:focus-within{outline:2px solid var(--tds-focus-outline-color);box-shadow:0 0 0 1px var(--tds-white);outline-offset:1px;z-index:1}:host .filter{display:flex;align-items:center;justify-content:space-between;height:100%;background-color:var(--tds-dropdown-bg);border-bottom:1px solid var(--tds-dropdown-border-bottom);padding-left:16px;border-radius:4px 4px 0 0}:host .filter:hover{border-bottom:1px solid var(--tds-dropdown-border-bottom-hover)}:host .filter.disabled{color:var(--tds-dropdown-disabled-color);border-bottom:1px solid transparent}:host .filter.disabled .value-wrapper input{color:var(--tds-dropdown-disabled-color)}:host .filter .value-wrapper{display:flex;width:100%;height:100%}:host .filter .value-wrapper input{color:var(--tds-dropdown-filter-input-color)}:host .filter .label-inside-as-placeholder{position:absolute;font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls);line-height:1.3;color:var(--tds-dropdown-placeholder-color)}:host .filter .label-inside-as-placeholder.lg{top:20px}:host .filter .label-inside-as-placeholder.md{top:16px}:host .filter .label-inside-as-placeholder.sm{display:none}:host .filter .label-inside-as-placeholder.selected{font:var(--tds-detail-07);letter-spacing:var(--tds-detail-07-ls);transition:all 0.2s ease-in-out}:host .filter .label-inside-as-placeholder.selected.lg{top:12px}:host .filter .label-inside-as-placeholder.selected.md{top:8px}:host .filter .label-inside-as-placeholder.selected.sm{display:none}:host .filter .label-inside-as-placeholder.selected+.placeholder:not(.sm){margin-top:8px}:host .filter.focus{border-bottom:0}:host .filter.focus:hover{border-bottom:0}:host .filter.error{border-bottom:1px solid var(--tds-dropdown-error)}:host .filter.error.focus{border-bottom-color:transparent}:host .filter.error.focus::before{content:\"\";position:absolute;bottom:0;left:0;width:100%;height:1px;background:var(--tds-dropdown-error)}:host .filter input{flex:1;all:unset;width:100%}:host .filter input::placeholder{color:var(--tds-dropdown-placeholder-color)}:host .filter input:disabled::placeholder{color:var(--tds-dropdown-disabled-color)}:host .filter tds-icon{cursor:pointer}:host .filter .menu-icon{margin-right:16px}:host .filter .clear-icon{margin:0 8px;color:var(--tds-dropdown-clear-icon-color);padding-right:8px;border-right:1px solid var(--tds-dropdown-clear-icon-color)}:host .filter .clear-icon:hover{color:var(--tds-dropdown-clear-icon-hover-color)}:host .filter .clear-icon.hide{display:none;visibility:hidden}:host{--tds-scrollbar-width-standard:thin;--tds-scrollbar-width:10px;--tds-scrollbar-height:10px;--tds-scrollbar-thumb-border-width:3px;--tds-scrollbar-thumb-border-hover-width:2px}body{scrollbar-width:thin}:host{display:block;position:relative;font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls)}:host .label-outside{font:var(--tds-detail-05);letter-spacing:var(--tds-detail-05-ls);color:var(--tds-dropdown-label-color);margin-bottom:8px}:host .label-outside.disabled{color:var(--tds-dropdown-disabled-color)}:host .dropdown-select{position:relative}:host .dropdown-select button:focus{outline:2px solid var(--tds-focus-outline-color);box-shadow:0 0 0 1px var(--tds-white);outline-offset:1px;z-index:1;border-radius:0}:host .dropdown-select button{transition:border-bottom-color var(--tds-motion-duration-fast-02) var(--tds-motion-easing-scania)}:host .dropdown-select button:hover{border-bottom-color:var(--tds-dropdown-border-bottom-hover)}:host .dropdown-select button{border-bottom-color:var(--tds-dropdown-border-bottom)}:host .dropdown-select button.error{border-bottom-color:var(--tds-dropdown-error)}:host .dropdown-select button.error:focus{border-bottom-color:transparent}:host .dropdown-select.disabled .label-inside,:host .dropdown-select.disabled .placeholder,:host .dropdown-select.disabled .label-inside-as-placeholder,:host .dropdown-select.disabled .value-wrapper{color:var(--tds-dropdown-disabled-color)}:host .dropdown-select.disabled button{border:none}:host .dropdown-select .label-inside{position:absolute;font:var(--tds-detail-07);letter-spacing:var(--tds-detail-07-ls);color:var(--tds-dropdown-label-inside-color)}:host .dropdown-select .label-inside.lg{top:12px;left:16px}:host .dropdown-select .label-inside.md{top:8px;left:16px}:host .dropdown-select .label-inside.sm{display:none}:host .dropdown-select .label-inside.xs{display:none}:host .dropdown-select .label-inside+.placeholder:not(.sm){margin-top:8px}:host .dropdown-select .placeholder{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:var(--tds-placeholder-margin);}:host .dropdown-select .placeholder.xs{line-height:1}:host .dropdown-select .label-inside-as-placeholder{color:var(--tds-dropdown-placeholder-color)}:host .dropdown-select .label-inside-as-placeholder.selected{position:absolute;font:var(--tds-detail-07);letter-spacing:var(--tds-detail-07-ls);transition:all 0.2s ease-in-out}:host .dropdown-select .label-inside-as-placeholder.selected.lg{top:12px}:host .dropdown-select .label-inside-as-placeholder.selected.md{top:8px}:host .dropdown-select .label-inside-as-placeholder.selected.sm{display:none}:host .dropdown-select .label-inside-as-placeholder.selected+.placeholder:not(.sm){margin-top:8px}:host .dropdown-select.lg{height:55px}:host .dropdown-select.md{height:47px}:host .dropdown-select.sm{height:39px}:host .dropdown-select.xs{height:29px}:host .helper{margin-top:4px;color:var(--tds-dropdown-helper-color);font:var(--tds-detail-05);letter-spacing:var(--tds-detail-05-ls);display:flex;align-items:center;gap:8px}:host .helper.error{color:var(--tds-dropdown-error)}:host .helper.disabled{color:var(--tds-dropdown-disabled-color)}:host .dropdown-list{z-index:100;position:absolute;width:100%;transform-origin:top;box-shadow:0 2px 3px 0 rgba(0, 0, 0, 0.1);border-radius:var(--tds-dropdown-list-border-radius-down);overflow-y:auto;transform:scaleY(0);pointer-events:none}:host .dropdown-list:hover::-webkit-scrollbar-thumb{border:var(--tds-scrollbar-thumb-border-hover-width) solid transparent;background:var(--tds-scrollbar-hover-thumb-color);background-clip:padding-box}:host .dropdown-list::-webkit-scrollbar{width:var(--tds-scrollbar-width)}:host .dropdown-list::-webkit-scrollbar-track{background:var(--tds-scrollbar-track-color)}:host .dropdown-list::-webkit-scrollbar-thumb{border-radius:40px;background:var(--tds-scrollbar-thumb-color);border:var(--tds-scrollbar-thumb-border-width) solid transparent;background-clip:padding-box}:host .dropdown-list::-webkit-scrollbar-button{height:0;width:0}@supports not selector(::-webkit-scrollbar){:host .dropdown-list{scrollbar-color:var(--tds-scrollbar-thumb-color) var(--tds-scrollbar-track-color);scrollbar-width:var(--tds-scrollbar-width-standard)}}:host .dropdown-list.lg{max-height:312px}:host .dropdown-list.md{max-height:312px}:host .dropdown-list.sm{max-height:260px}:host .dropdown-list.xs{max-height:260px}:host .dropdown-list.up{bottom:100%;margin-top:0;margin-bottom:1px;transform-origin:bottom;display:flex;flex-direction:column-reverse;border-radius:var(--tds-dropdown-list-border-radius-up)}:host .dropdown-list.up.label-outside{bottom:calc(100% - 24px)}:host .dropdown-list.closed{transform:scaleY(0);pointer-events:none}:host .dropdown-list.open{transform:scaleY(1);visibility:visible;opacity:1;pointer-events:auto}:host .dropdown-list.animation-enter-slide{transition:transform var(--tds-motion-duration-moderate-01) var(--tds-motion-easing-enter)}:host .dropdown-list.animation-exit-slide{transition:transform var(--tds-motion-duration-moderate-01) var(--tds-motion-easing-exit)}:host .dropdown-list .no-result{font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls);display:flex;align-items:center;padding:0 16px;background-color:var(--tds-dropdown-bg)}:host .dropdown-list .no-result.lg{height:56px}:host .dropdown-list .no-result.md{height:48px}:host .dropdown-list .no-result.sm{height:40px}:host .dropdown-list .no-result.xs{height:40px}:host .menu-icon{color:var(--tds-dropdown-menu-icon-color)}:host tds-icon{transition:transform var(--tds-motion-duration-fast-02) var(--tds-motion-easing-scania)}:host tds-icon.open{transform:rotateZ(180deg)}"; const TdsDropdownStyle0 = dropdownCss; function hasValueChanged(newValue, currentValue) { if (newValue.length !== currentValue.length) return true; return newValue.some((val) => !currentValue.includes(val)); } const TdsDropdown = class { constructor(hostRef) { registerInstance(this, hostRef); this.tdsChange = createEvent(this, "tdsChange", 6); this.tdsFocus = createEvent(this, "tdsFocus", 6); this.tdsBlur = createEvent(this, "tdsBlur", 6); this.tdsInput = createEvent(this, "tdsInput", 6); this.setDefaultOption = () => { if (this.internalDefaultValue) { // Convert the internal default value to an array if it's not already const defaultValues = this.multiselect ? this.internalDefaultValue.split(',') : [this.internalDefaultValue]; this.updateDropdownStateInternal(defaultValues); } }; this.getChildren = () => { const tdsDropdownOptions = Array.from(this.host.children).filter((element) => element.tagName === 'TDS-DROPDOWN-OPTION'); if (tdsDropdownOptions.length === 0) { console.warn('TDS DROPDOWN: No options found. Disregard if loading data asynchronously.'); } return tdsDropdownOptions; }; this.getSelectedChildren = () => { if (this.selectedOptions.length === 0) return []; return this.selectedOptions .map((stringValue) => { var _a; const matchingElement = (_a = this.getChildren()) === null || _a === void 0 ? void 0 : _a.find((element) => convertToString(element.value) === convertToString(stringValue)); return matchingElement; }) .filter(Boolean); }; this.getSelectedChildrenLabels = () => { var _a; return (_a = this.getSelectedChildren()) === null || _a === void 0 ? void 0 : _a.map((element) => element.textContent.trim()); }; this.getValue = () => { const labels = this.getSelectedChildrenLabels(); if (!labels) { return ''; } return labels === null || labels === void 0 ? void 0 : labels.join(', '); }; this.setValueAttribute = () => { if (this.selectedOptions.length === 0) { this.host.removeAttribute('value'); } else { this.host.setAttribute('value', this.selectedOptions.join(',')); } }; this.getOpenDirection = () => { var _a, _b, _c, _d, _e; if (this.openDirection === 'auto' || !this.openDirection) { const dropdownMenuHeight = (_b = (_a = this.dropdownList) === null || _a === void 0 ? void 0 : _a.offsetHeight) !== null && _b !== void 0 ? _b : 0; const distanceToBottom = (_e = (_d = (_c = this.host).getBoundingClientRect) === null || _d === void 0 ? void 0 : _d.call(_c).top) !== null && _e !== void 0 ? _e : 0; const viewportHeight = window.innerHeight; if (distanceToBottom + dropdownMenuHeight + 57 > viewportHeight) { return 'up'; } return 'down'; } return this.openDirection; }; this.handleToggleOpen = () => { if (!this.disabled) { this.open = !this.open; if (this.open) { if (this.filter) { this.focusInputElement(); } else { const button = this.host.shadowRoot.querySelector('button'); if (button) { button.focus(); } } } } }; this.focusInputElement = () => { if (this.inputElement) this.inputElement.focus(); }; this.handleFilter = (event) => { this.tdsInput.emit(event); const query = event.target.value.toLowerCase(); /* Check if the query is empty, and if so, show all options */ const children = this.getChildren(); if (query === '') { children.forEach((element) => { element.removeAttribute('hidden'); return element; }); this.filterResult = null; /* Hide the options that do not match the query */ } else { this.filterResult = children.filter((element) => { if (!this.normalizeString(element.textContent) .toLowerCase() .includes(this.normalizeString(query).toLowerCase())) { element.setAttribute('hidden', ''); } else { element.removeAttribute('hidden'); } return !element.hasAttribute('hidden'); }).length; } }; this.handleFilterReset = () => { this.reset(); this.inputElement.value = ''; this.handleFilter({ target: { value: '' } }); this.inputElement.focus(); // Add this line to ensure internal value is cleared this.internalValue = ''; }; this.handleFocus = (event) => { this.open = true; this.filterFocus = true; if (this.multiselect && this.inputElement) { this.inputElement.value = ''; } this.tdsFocus.emit(event); if (this.filter) { this.handleFilter({ target: { value: '' } }); } }; this.handleBlur = (event) => { this.tdsBlur.emit(event); }; this.resetInput = () => { const inputEl = this.host.querySelector('input'); if (inputEl) { this.reset(); } }; this.name = undefined; this.disabled = false; this.helper = undefined; this.label = undefined; this.labelPosition = undefined; this.modeVariant = null; this.openDirection = 'auto'; this.placeholder = undefined; this.size = 'lg'; this.animation = 'slide'; this.error = false; this.multiselect = false; this.filter = false; this.normalizeText = true; this.noResultText = 'No result'; this.defaultValue = undefined; this.value = null; this.tdsAriaLabel = undefined; this.open = false; this.internalValue = undefined; this.filterResult = undefined; this.filterFocus = undefined; this.internalDefaultValue = undefined; this.selectedOptions = []; } handleValueChange(newValue) { // Normalize to array const normalizedValue = this.normalizeValue(newValue); // Only update if actually changed if (hasValueChanged(normalizedValue, this.selectedOptions)) { this.updateDropdownStateFromUser(normalizedValue); } } normalizeValue(value) { if (value === null || value === undefined || value === '') return []; // For single select, ensure we handle both string and array inputs if (!this.multiselect) { // If array is passed to single select, take first value if (Array.isArray(value)) { return [convertToString(value[0])]; } return [convertToString(value)]; } // For multiselect if (Array.isArray(value)) { return convertArrayToStrings(value); } // Handle comma-separated string for multiselect return value .toString() .split(',') .filter((v) => v !== ''); } updateDropdownStateInternal(values) { this.updateDropdownState(values, false); } updateDropdownStateFromUser(values) { this.updateDropdownState(values, true); } updateDropdownState(values, emitChange = true) { // Validate the values first const validValues = this.validateValues(values); // Update internal state this.selectedOptions = [...validValues]; // Update the value prop this.value = this.multiselect ? this.selectedOptions : this.selectedOptions[0] || null; // Update internal value for display this.internalValue = this.getValue(); // Update DOM this.updateOptionElements(); // Update display value this.updateDisplayValue(); // Emit change event only if value has changed by user if (emitChange) this.emitChange(); // Update value attribute this.setValueAttribute(); } validateValues(values) { // Make sure we have children before validation const children = this.getChildren(); if (!children || children.length === 0) { console.warn('No dropdown options found'); return values; // Return original values if no children yet } return values.filter((val) => { const isValid = children.some((element) => convertToString(element.value) === convertToString(val)); if (!isValid) { console.warn(`Option with value "${val}" does not exist`); } return isValid; }); } updateOptionElements() { var _a; (_a = this.getChildren()) === null || _a === void 0 ? void 0 : _a.forEach((element) => { // Convert element.value to string for comparison element.setSelected(this.selectedOptions.includes(convertToString(element.value))); }); } updateDisplayValue() { this.internalValue = this.getSelectedChildrenLabels().join(', '); if (this.filter && this.inputElement) { this.inputElement.value = this.internalValue; } } emitChange() { const value = this.multiselect ? this.selectedOptions.join(',') : this.selectedOptions[0] || null; this.tdsChange.emit({ name: this.name, value: value !== null && value !== void 0 ? value : null, }); } /** Method for setting the selected value of the Dropdown. * * Single selection example: * * <code> * dropdown.setValue('option-1', 'Option 1'); * </code> * * Multiselect example: * * <code> * dropdown.setValue(['option-1', 'option-2']); * </code> */ // @ts-expect-error for label: the label is optional here ONLY to not break the API. Should be removed for 2.0. // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars async setValue(value, label) { let normalizedValue; if (Array.isArray(value)) { normalizedValue = convertArrayToStrings(value); } else { normalizedValue = [convertToString(value)]; } this.updateDropdownStateFromUser(normalizedValue); return this.getSelectedChildren().map((element) => ({ value: element.value, label: element.textContent.trim(), })); } async reset() { this.updateDropdownStateFromUser([]); } async removeValue(oldValue) { const newValues = this.selectedOptions.filter((v) => v !== oldValue); this.updateDropdownStateFromUser(newValues); } /** Method that forces focus on the input element. */ async focusElement() { if (this.filter) { // For filter mode, focus the input element this.focusInputElement(); } else { // For non-filter mode, focus the button element const button = this.host.shadowRoot.querySelector('button'); if (button) { button.focus(); } } // Always trigger the focus event to open the dropdown this.handleFocus({}); } /** Method for closing the Dropdown. */ async close() { this.open = false; } /** Method to force update the dropdown display value. * Use this method when you programmatically change the text content of dropdown options * to ensure the selected value display updates immediately. */ async updateDisplay() { this.updateDisplayValue(); } onAnyClick(event) { if (this.open) { // Source: https://lamplightdev.com/blog/2021/04/10/how-to-detect-clicks-outside-of-a-web-component/ const isClickOutside = !event.composedPath().includes(this.host); if (isClickOutside) { this.open = false; } } } async onKeyDown(event) { var _a; // Get the active element const { activeElement } = document; if (!activeElement) { return; } const children = this.getChildren(); if (event.key === 'ArrowDown') { /* Get the index of the current focus index, if there is no nextElementSibling return the index for the first child in our Dropdown. */ const startingIndex = activeElement.nextElementSibling ? children.findIndex((element) => element === activeElement.nextElementSibling) : 0; const elementIndex = findNextFocusableElement(children, startingIndex); children[elementIndex].focus(); } else if (event.key === 'ArrowUp') { /* Get the index of the current focus index, if there is no previousElementSibling return the index for the first last in our Dropdown. */ const startingIndex = activeElement.nextElementSibling ? this.getChildren().findIndex((element) => element === activeElement.previousElementSibling) : 0; const elementIndex = findPreviousFocusableElement(children, startingIndex); children[elementIndex].focus(); } else if (event.key === 'Escape') { this.open = false; // Return focus to input/button when Escape key is used if (this.filter) { (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.focus(); } else { const button = this.host.shadowRoot.querySelector('button'); button === null || button === void 0 ? void 0 : button.focus(); } } } // If the Dropdown gets closed, // this sets the value of the dropdown to the current selection labels or null if no selection is made. handleOpenState() { if (this.filter && this.multiselect) { if (!this.open) { this.inputElement.value = this.selectedOptions.length ? this.getValue() : ''; } } // Update the inert state of dropdown list when open state changes this.updateDropdownListInertState(); } handleDefaultValueChange(newValue) { if (newValue !== undefined && newValue !== null) { this.internalDefaultValue = convertToString(newValue); this.setDefaultOption(); } } componentWillLoad() { // First handle the value prop if it exists if (this.value !== null && this.value !== undefined) { const normalizedValue = this.normalizeValue(this.value); this.updateDropdownStateInternal(normalizedValue); return; // Exit early if we handled the value prop } // Only use defaultValue if no value prop was provided if (this.defaultValue !== null && this.defaultValue !== undefined) { const defaultValueStr = convertToString(this.defaultValue); const initialValue = this.multiselect ? defaultValueStr.split(',').map(convertToString) : [defaultValueStr]; this.updateDropdownStateInternal(initialValue); } } /** Method to handle slot changes */ handleSlotChange() { this.setDefaultOption(); } /** Method to check if we should normalize text */ normalizeString(text) { return this.normalizeText ? text.normalize('NFD').replace(/\p{Diacritic}/gu, '') : text; } /** * @internal */ async appendValue(value) { if (this.multiselect) { this.updateDropdownStateFromUser([...this.selectedOptions, value]); } else { this.updateDropdownStateFromUser([value]); } } componentDidRender() { const form = this.host.closest('form'); if (form) { form.addEventListener('reset', this.resetInput); } // Initialize inert state after rendering this.updateDropdownListInertState(); } disconnectedCallback() { const form = this.host.closest('form'); if (form) { form.removeEventListener('reset', this.resetInput); } } connectedCallback() { if (!this.tdsAriaLabel) { console.warn('Tegel Dropdown component: tdsAriaLabel prop is missing'); } } updateDropdownListInertState() { if (this.dropdownList) { if (this.open) { this.dropdownList.removeAttribute('inert'); } else { this.dropdownList.setAttribute('inert', ''); } } } render() { appendHiddenInput(this.host, this.name, this.selectedOptions.join(','), this.disabled); // Generate unique IDs for associating labels and helpers with the input/button const labelId = this.label ? `dropdown-label-${this.name || generateUniqueId()}` : undefined; const helperId = this.helper ? `dropdown-helper-${this.name || generateUniqueId()}` : undefined; return (h(Host, { key: '676f9d61c5fd8488cedbc949757e992be13e49eb', class: { [`tds-mode-variant-${this.modeVariant}`]: Boolean(this.modeVariant), } }, this.label && this.labelPosition === 'outside' && (h("div", { key: 'ac4f3c9ca2719acc72f06ae977bf032d05913c6d', id: labelId, class: `label-outside ${this.disabled ? 'disabled' : ''}` }, this.label)), h("div", { key: 'c9d4142f63e315c73daef5038f266a32b05559a1', class: { 'dropdown-select': true, [this.size]: true, 'disabled': this.disabled, } }, this.filter ? (h("div", { class: { filter: true, focus: this.filterFocus, disabled: this.disabled, error: this.error, } }, h("div", { class: "value-wrapper" }, this.label && this.labelPosition === 'inside' && this.placeholder && (h("div", { id: labelId, class: `label-inside ${this.size}` }, this.label)), this.label && this.labelPosition === 'inside' && !this.placeholder && (h("div", { id: labelId, class: ` label-inside-as-placeholder ${this.size} ${this.selectedOptions.length ? 'selected' : ''} ` }, this.label)), h("input", { "aria-label": this.tdsAriaLabel, "aria-labelledby": labelId, "aria-describedby": helperId, "aria-disabled": this.disabled, // eslint-disable-next-line no-return-assign ref: (inputEl) => (this.inputElement = inputEl), class: { placeholder: this.labelPosition === 'inside', }, type: "text", placeholder: this.filterFocus ? '' : this.placeholder, value: this.multiselect && this.filterFocus ? '' : this.getValue(), disabled: this.disabled, onInput: (event) => this.handleFilter(event), onBlur: (event) => { this.filterFocus = false; if (this.multiselect) { this.inputElement.value = this.getValue(); } this.handleBlur(event); }, onFocus: (event) => this.handleFocus(event), onKeyDown: (event) => { if (event.key === 'Escape') { this.open = false; } } })), h("tds-icon", { tabIndex: 0, role: "button", "aria-label": "Clear filter", svgTitle: "Clear filter", onClick: this.handleFilterReset, onKeyDown: (event) => { if (event.key === 'Enter') { this.handleFilterReset(); } }, class: { 'clear-icon': true, 'hide': !(this.open && this.inputElement.value !== ''), }, name: "cross", size: "16px" }), h("tds-icon", { tdsAriaHidden: true, role: "button", "aria-label": "Open/Close dropdown", svgTitle: "Open/Close dropdown", onClick: this.handleToggleOpen, onKeyDown: (event) => { if (event.key === 'Enter') { this.handleToggleOpen(); } }, class: `menu-icon ${this.open ? 'open' : 'closed'}`, name: "chevron_down", size: "16px" }))) : (h("button", { "aria-label": this.tdsAriaLabel, "aria-labelledby": labelId, "aria-describedby": helperId, "aria-disabled": this.disabled, onClick: () => this.handleToggleOpen(), onKeyDown: (event) => { if (event.key === 'Escape') { this.open = false; } }, class: ` ${this.selectedOptions.length ? 'value' : 'placeholder'} ${this.open ? 'open' : 'closed'} ${this.error ? 'error' : ''} `, disabled: this.disabled }, h("div", { class: `value-wrapper ${this.size}` }, this.label && this.labelPosition === 'inside' && this.placeholder && (h("div", { id: labelId, class: `label-inside ${this.size}` }, this.label)), this.label && this.labelPosition === 'inside' && !this.placeholder && (h("div", { id: labelId, class: ` label-inside-as-placeholder ${this.size} ${this.selectedOptions.length ? 'selected' : ''} ` }, this.label)), h("div", { class: `placeholder ${this.size}` }, this.selectedOptions.length ? this.getValue() : this.placeholder), h("tds-icon", { "aria-label": "Open/Close dropdown", svgTitle: "Open/Close dropdown", class: `menu-icon ${this.open ? 'open' : 'closed'}`, name: "chevron_down", size: "16px" }))))), h("div", { key: '6de931198040eec79815f83e2617d2646507b6a1', role: "listbox", "aria-label": this.tdsAriaLabel, inert: !this.open, "aria-orientation": "vertical", "aria-multiselectable": this.multiselect, ref: (element) => { this.dropdownList = element; }, class: { 'dropdown-list': true, [this.size]: true, [this.getOpenDirection()]: true, 'label-outside': this.label && this.labelPosition === 'outside', 'open': this.open, 'closed': !this.open, [`animation-enter-${this.animation}`]: this.animation !== 'none' && this.open, [`animation-exit-${this.animation}`]: this.animation !== 'none' && !this.open, } }, h("slot", { key: '61ab9737181371073b25b95c34dad3311c2995c0', onSlotchange: () => this.handleSlotChange() }), this.filterResult === 0 && this.noResultText !== '' && (h("div", { key: 'aca39f881a57a6a23de03da78b5062e5dff55af7', class: `no-result ${this.size}` }, this.noResultText))), this.helper && (h("div", { key: '1e4221e58bc16608bfb0f780b7bc8040935eab37', id: helperId, class: { helper: true, error: this.error, disabled: this.disabled, } }, this.error && h("tds-icon", { key: 'ec946e77add75e7eaf194e2b38e5dd1c548ab32f', name: "error", size: "16px" }), this.helper)))); } get host() { return getElement(this); } static get watchers() { return { "value": ["handleValueChange"], "open": ["handleOpenState"], "defaultValue": ["handleDefaultValueChange"] }; } }; TdsDropdown.style = TdsDropdownStyle0; const dropdownOptionCss = ":host{box-sizing:border-box;display:block;background-color:var(--tds-dropdown-option-background)}:host *{box-sizing:border-box}:host .dropdown-option{color:var(--tds-dropdown-option-color);border-bottom:1px solid var(--tds-dropdown-option-border);font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls);overflow-wrap:anywhere;transition:background-color var(--tds-motion-duration-fast-02) var(--tds-motion-easing-scania)}:host .dropdown-option.selected{background-color:var(--tds-dropdown-option-background-selected)}:host .dropdown-option.disabled{color:var(--tds-dropdown-option-color-disabled)}:host .dropdown-option button:focus{outline:2px solid var(--tds-dropdown-option-focus);box-shadow:inset 0 0 0 3px var(--tds-white);outline-offset:-2px}:host .dropdown-option button{all:unset;width:100%}:host .dropdown-option button.lg{padding:19px 0 20px}:host .dropdown-option button.md{padding:15px 0 16px}:host .dropdown-option button.sm{padding:11px 0 12px}:host .dropdown-option button.xs{padding:7px 0 8px}:host .dropdown-option button .single-select{display:flex;align-items:center;justify-content:space-between;padding:0 16px}:host .dropdown-option .multiselect{width:100%;height:100%}:host .dropdown-option .multiselect tds-checkbox{display:flex;height:100%;width:100%}:host .dropdown-option .multiselect tds-checkbox.lg{padding:15px 16px 16px}:host .dropdown-option .multiselect tds-checkbox.md{padding:11px 16px 12px}:host .dropdown-option .multiselect tds-checkbox.sm{padding:7px 16px 8px}:host .dropdown-option .multiselect tds-checkbox.xs{padding:7px 16px 8px}:host .dropdown-option:hover{border-bottom-color:var(--tds-dropdown-option-border-hover);cursor:pointer}:host .dropdown-option:hover.disabled{border-bottom-color:var(--tds-dropdown-option-border-hover);cursor:not-allowed}:host([hidden]){display:none}"; const TdsDropdownOptionStyle0 = dropdownOptionCss; const TdsDropdownOption = class { constructor(hostRef) { registerInstance(this, hostRef); this.tdsSelect = createEvent(this, "tdsSelect", 6); this.tdsFocus = createEvent(this, "tdsFocus", 6); this.tdsBlur = createEvent(this, "tdsBlur", 6); this.parentElement = null; // @ts-expect-error - label property is used internally for text content tracking // eslint-disable-next-line no-unused-vars, this.label = ''; this.componentWillRender = () => { var _a, _b, _c; if (!this.host.parentElement) { return; } this.parentElement = ((_a = this.host.parentElement) === null || _a === void 0 ? void 0 : _a.tagName) === 'TDS-DROPDOWN' ? this.host.parentElement : this.host.getRootNode().host; if (this.parentElement) { this.multiselect = (_b = this.parentElement.multiselect) !== null && _b !== void 0 ? _b : false; this.size = this.parentElement.size || 'lg'; } this.label = ((_c = this.host.textContent) === null || _c === void 0 ? void 0 : _c.trim()) || ''; }; this.handleSingleSelect = () => { if (!this.disabled) { this.selected = true; this.parentElement.appendValue(this.internalValue); this.parentElement.close(); this.tdsSelect.emit({ value: this.internalValue, selected: this.selected, }); } }; this.handleMultiselect = (event) => { if (!this.disabled) { if (event.detail.checked) { this.parentElement.appendValue(this.internalValue); this.selected = true; this.tdsSelect.emit({ value: this.internalValue, selected: this.selected, }); } else { this.parentElement.removeValue(this.internalValue); this.selected = false; this.tdsSelect.emit({ value: this.internalValue, selected: this.selected, }); } event.stopPropagation(); } }; this.handleFocus = (event) => { this.tdsFocus.emit(event); }; this.handleBlur = (event) => { this.tdsBlur.emit(event); }; this.value = undefined; this.internalValue = undefined; this.disabled = false; this.tdsAriaLabel = undefined; this.selected = false; this.multiselect = false; this.size = 'lg'; } /** Method to select/deselect an option. */ async setSelected(selected) { this.selected = selected; } valueWatcher(newValue) { this.internalValue = convertToString(newValue); } componentWillLoad() { this.internalValue = convertToString(this.value); } connectedCallback() { if (!this.tdsAriaLabel && !this.multiselect) { console.warn('Tegel Dropdown option component: tdsAriaLabel prop is missing'); } } render() { return (h(Host, { key: '52827112a3060a8858978c3e65c284358f923539' }, h("div", { key: 'edf5262e5dbbfadf34ff6faa164e58b7fec1e561', class: `dropdown-option ${this.size} ${this.selected ? 'selected' : ''} ${this.disabled ? 'disabled' : ''} ` }, this.multiselect ? (h("div", { class: "multiselect", onKeyDown: (event) => { if (event.key === 'Escape') { this.parentElement.close(); } } }, h("tds-checkbox", { onTdsChange: (event) => { this.handleMultiselect(event); }, disabled: this.disabled, checked: this.selected, tdsAriaLabel: this.tdsAriaLabel, class: { [this.size]: true, } }, h("div", { slot: "label" }, h("slot", null))))) : (h("button", { role: "option", "aria-disabled": this.disabled, "aria-selected": this.selected, "aria-label": this.tdsAriaLabel, onClick: () => { this.handleSingleSelect(); }, onFocus: (event) => this.handleFocus(event), onBlur: (event) => this.handleBlur(event), disabled: this.disabled, class: this.size }, h("div", { class: "single-select" }, h("slot", null), this.selected && h("tds-icon", { name: "tick", size: "16px" }))))))); } static get delegatesFocus() { return true; } get host() { return getElement(this); } static get watchers() { return { "value": ["valueWatcher"] }; } }; TdsDropdownOption.style = TdsDropdownOptionStyle0; export { TdsDropdown as tds_dropdown, TdsDropdownOption as tds_dropdown_option };