@scania/tegel
Version:
Tegel Design System
1,206 lines (1,205 loc) • 56.1 kB
JavaScript
import { Host, h, } from "@stencil/core";
import findNextFocusableElement from "../../utils/findNextFocusableElement";
import findPreviousFocusableElement from "../../utils/findPreviousFocusableElement";
import appendHiddenInput from "../../utils/appendHiddenInput";
import { convertToString, convertArrayToStrings } from "../../utils/convertToString";
import generateUniqueId from "../../utils/generateUniqueId";
function hasValueChanged(newValue, currentValue) {
if (newValue.length !== currentValue.length)
return true;
return newValue.some((val) => !currentValue.includes(val));
}
function getTypedQuery(rawValue, displayValue) {
if (rawValue.length <= displayValue.length + 1) {
return rawValue;
}
if (rawValue.startsWith(displayValue)) {
return rawValue.slice(displayValue.length);
}
if (rawValue.endsWith(displayValue)) {
return rawValue.slice(0, rawValue.length - displayValue.length);
}
return rawValue;
}
/**
* @slot <default> - <b>Unnamed slot.</b> For dropdown option elements.
*/
export class TdsDropdown {
constructor() {
/** Sets the Dropdown in a disabled state */
this.disabled = false;
/** Mode variant of the component, based on current mode. */
this.modeVariant = null;
/** The direction the Dropdown should open, auto if not specified. */
this.openDirection = 'auto';
/** The size of the Dropdown. */
this.size = 'lg';
this.animation = 'slide';
/** Sets the Dropdown in an error state */
this.error = false;
/** Enables multiselect in the Dropdown. */
this.multiselect = false;
/** Enables filtration in the Dropdown. */
this.filter = false;
/** Normalizes input text for fuzzier search */
this.normalizeText = true;
/** Text that is displayed if filter is used and there are no options that matches the search.
* Setting it to an empty string disables message from showing up. */
this.noResultText = 'No result';
/** Value of the dropdown. For multiselect, provide array of strings/numbers. For single select, provide a string/number. */
this.value = null;
this.open = false;
this.internalValue = '';
this.filterResult = null;
this.filterFocus = false;
this.internalDefaultValue = '';
this.selectedOptions = [];
this.filterQuery = '';
this.hasFocus = false;
this.uuid = generateUniqueId();
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) => { var _a; return (_a = element.textContent) === null || _a === void 0 ? void 0 : _a.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 = () => {
var _a;
if (!this.disabled) {
this.open = !this.open;
if (this.open) {
if (this.filter) {
this.focusInputElement();
}
else {
const button = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('button');
if (button) {
button.focus();
}
}
}
}
};
this.focusInputElement = () => {
if (this.inputElement)
this.inputElement.focus();
};
this.handleFilter = (event) => {
const input = event.currentTarget;
if (this.multiselect &&
this.filterQuery.length === 0 &&
this.selectedOptions.length > 0 &&
this.inputElement) {
const displayValue = this.getValue();
const rawValue = input.value;
const typed = getTypedQuery(rawValue, displayValue);
if (typed !== rawValue) {
this.inputElement.value = typed;
}
}
this.tdsInput.emit(event);
const query = this.inputElement
? this.inputElement.value.toLowerCase()
: input.value.toLowerCase();
this.filterQuery = query;
/** 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) => {
var _a;
if (!this.normalizeString((_a = element === null || element === void 0 ? void 0 : element.textContent) !== null && _a !== void 0 ? _a : '')
.toLowerCase()
.includes(this.normalizeString(query).toLowerCase())) {
element.setAttribute('hidden', '');
}
else {
element.removeAttribute('hidden');
}
return !element.hasAttribute('hidden');
}).length;
}
};
this.handleFilterReset = () => {
if (this.multiselect) {
/** Multiselect + filter: two-step clear */
if (this.filterQuery.length > 0) {
const clearedValue = this.filterQuery;
this.filterQuery = '';
this.resetFilterVisibility();
if (this.inputElement) {
this.inputElement.value = this.getValue();
this.inputElement.focus();
}
this.tdsClear.emit({ clearedValue });
}
else if (this.selectedOptions.length > 0) {
const clearedValue = this.selectedOptions.join(',');
this.updateDropdownStateFromUser([]);
if (this.inputElement) {
this.inputElement.value = '';
this.inputElement.focus();
}
this.tdsClear.emit({ clearedValue });
}
}
else {
/** Single select + filter: clear everything immediately */
const clearedParts = [];
if (this.filterQuery.length > 0) {
clearedParts.push(this.filterQuery);
this.filterQuery = '';
this.resetFilterVisibility();
}
if (this.selectedOptions.length > 0) {
clearedParts.push(this.selectedOptions.join(','));
this.updateDropdownStateFromUser([]);
}
if (this.inputElement) {
this.inputElement.value = '';
this.inputElement.focus();
}
if (clearedParts.length > 0) {
this.tdsClear.emit({ clearedValue: clearedParts.join(',') });
}
}
};
this.resetFilterVisibility = () => {
this.filterQuery = '';
const children = this.getChildren();
children.forEach((element) => {
element.removeAttribute('hidden');
});
this.filterResult = null;
};
this.handleMultiselectClear = () => {
const clearedValue = this.selectedOptions.join(',');
this.updateDropdownStateFromUser([]);
this.tdsClear.emit({ clearedValue });
};
this.handleFocus = () => {
this.open = true;
this.filterFocus = true;
if (this.multiselect && this.filter) {
/** For multiselect+filter, show selected labels on focus.
* Clearing happens on click via handleInputClick. */
if (this.inputElement) {
this.inputElement.value = this.getValue();
}
}
else if (this.inputElement) {
this.inputElement.value = '';
}
if (this.filter) {
this.resetFilterVisibility();
}
};
this.handleBlur = () => {
this.filterFocus = false;
this.filterQuery = '';
if (this.inputElement) {
this.inputElement.value = this.getValue();
}
/** Reset filter to show all options for next open */
if (this.filter) {
this.resetFilterVisibility();
}
};
this.handleInputClick = () => {
if (this.multiselect && this.filter) {
this.filterQuery = '';
if (this.inputElement) {
this.inputElement.value = '';
}
this.resetFilterVisibility();
}
};
this.resetInput = () => {
const inputEl = this.host.querySelector('input');
if (inputEl) {
this.reset();
}
};
}
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) => {
var _a;
return ({
value: element.value,
label: (_a = element.textContent) === null || _a === void 0 ? void 0 : _a.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() {
var _a;
if (this.filter) {
/** For filter mode, focus the input element */
this.focusInputElement();
}
else {
/** For non-filter mode, focus the button element */
const button = (_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.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) {
/** Emit clear event if there's a filter query when clicking outside */
if (this.filter && this.filterQuery) {
this.tdsClear.emit({ clearedValue: this.filterQuery });
}
this.open = false;
}
}
}
onFocusIn(event) {
/** Check if the focus is within this dropdown component */
if (this.host.contains(event.target)) {
if (!this.hasFocus) {
this.hasFocus = true;
this.tdsFocus.emit(event);
}
}
}
onFocusOut(event) {
/** Only emit blur if focus is actually leaving the entire dropdown component */
const relatedTarget = event.relatedTarget;
/** If relatedTarget is null (focus going to body/window) or outside the component, emit blur */
if (this.hasFocus && (!relatedTarget || !this.host.contains(relatedTarget))) {
this.hasFocus = false;
this.handleBlur();
this.tdsBlur.emit(event);
}
}
async onKeyDown(event) {
var _a, _b;
/** 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;
if (children.length > 0) {
const elementIndex = findNextFocusableElement(children, startingIndex);
const target = typeof elementIndex === 'number' ? children[elementIndex] : children[0];
target === null || target === void 0 ? void 0 : target.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;
if (children.length > 0) {
const elementIndex = findPreviousFocusableElement(children, startingIndex);
const target = typeof elementIndex === 'number' ? children[elementIndex] : children[children.length - 1];
target === null || target === void 0 ? void 0 : target.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 = (_b = this.host.shadowRoot) === null || _b === void 0 ? void 0 : _b.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) {
if (!this.open) {
this.filterQuery = '';
this.resetFilterVisibility();
if (this.inputElement) {
this.inputElement.value = this.selectedOptions.length ? this.getValue() : '';
}
}
}
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) {
/** Clear filter query when an option is selected */
if (this.filter && this.filterQuery.length > 0) {
this.filterQuery = '';
/** Reset filter to show all options */
this.resetFilterVisibility();
}
if (this.multiselect) {
this.updateDropdownStateFromUser([...this.selectedOptions, value]);
}
else {
this.updateDropdownStateFromUser([value]);
}
/** After selection, show all selected labels in the input */
if (this.filter && this.multiselect && this.inputElement) {
this.inputElement.value = this.getValue();
}
}
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);
}
}
updateDropdownListInertState() {
if (this.dropdownList) {
if (this.open) {
this.dropdownList.removeAttribute('inert');
}
else {
this.dropdownList.setAttribute('inert', '');
}
}
}
render() {
var _a, _b, _c, _d;
appendHiddenInput(this.host, this.name, this.selectedOptions.join(','), this.disabled);
/** Generate unique IDs for associating labels and helpers with the input/button */
const baseId = this.name || this.uuid;
const inputId = `dropdown-input-${baseId}`;
const labelId = this.label ? `dropdown-label-${baseId}` : undefined;
const helperId = this.helper ? `dropdown-helper-${baseId}` : undefined;
const hasSelection = this.selectedOptions.length > 0;
const hasTyped = this.filterQuery.length > 0;
const isFloated = this.filterFocus || hasSelection || hasTyped;
const isFloatedButton = this.open || hasSelection;
const showPlaceholderInside = this.filterFocus && !hasTyped && !hasSelection;
const showPlaceholderButton = this.labelPosition !== 'inside' || isFloatedButton;
const fallbackAriaLabel = this.label ? undefined : 'Dropdown';
const ariaLabel = (_a = this.tdsAriaLabel) !== null && _a !== void 0 ? _a : fallbackAriaLabel;
let derivedPlaceholder = (_b = this.placeholder) !== null && _b !== void 0 ? _b : '';
if (this.labelPosition === 'inside') {
derivedPlaceholder = showPlaceholderInside ? (_c = this.placeholder) !== null && _c !== void 0 ? _c : '' : '';
}
let buttonText = '';
if (this.selectedOptions.length > 0) {
buttonText = this.getValue();
}
else if (showPlaceholderButton) {
buttonText = (_d = this.placeholder) !== null && _d !== void 0 ? _d : '';
}
return (h(Host, { key: 'e7c3ade8e5b56a41f78016c44fb75efcaaf666c1', class: {
[`tds-mode-variant-${this.modeVariant}`]: Boolean(this.modeVariant),
} }, this.label && this.labelPosition === 'outside' && (h("div", { key: '26dd2d4137fea024b4b436fca739cfecaea13491', id: labelId, class: `label-outside ${this.disabled ? 'disabled' : ''}` }, this.label)), h("div", { key: 'ce88e29fa87c4c9e54ea68bef9bde26b6300bae9', 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' && (h("label", { id: labelId, htmlFor: inputId, class: {
'label-inside': true,
[this.size]: true,
'floated': isFloated,
} }, this.label)), h("input", { "aria-label": ariaLabel, "aria-labelledby": labelId, "aria-describedby": helperId, "aria-disabled": this.disabled, ref: (inputEl) => {
this.inputElement = inputEl;
if (this.inputElement && !this.filterFocus) {
this.inputElement.value = this.getValue();
}
}, class: {
placeholder: this.labelPosition === 'inside',
}, id: inputId, type: "text", placeholder: derivedPlaceholder, disabled: this.disabled, onInput: (event) => this.handleFilter(event), onFocus: () => this.handleFocus(), onClick: () => this.handleInputClick(), onKeyDown: (event) => {
if (event.key === 'Escape') {
this.open = false;
}
} })), h("tds-icon", { tabIndex: 0, role: "button", "aria-label": this.filterQuery.length > 0 ? 'Clear filter' : 'Clear selection', svgTitle: this.filterQuery.length > 0 ? 'Clear filter' : 'Clear selection', onClick: this.handleFilterReset, onKeyDown: (event) => {
if (event.key === 'Enter') {
this.handleFilterReset();
}
}, class: {
'clear-icon': true,
'hide': !(this.filterQuery.length > 0 || this.selectedOptions.length > 0),
}, 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' && (h("div", { id: labelId, class: {
'label-inside': true,
[this.size]: true,
'floated': isFloatedButton,
} }, this.label)), h("div", { "aria-label": this.tdsAriaLabel ? `Selected options for ${this.tdsAriaLabel}` : undefined, class: `placeholder ${this.size}` }, buttonText)), h("tds-icon", { tabIndex: 0, role: "button", "aria-label": "Clear selection", svgTitle: "Clear selection", onClick: (event) => {
event.stopPropagation();
this.handleMultiselectClear();
}, onKeyDown: (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.stopPropagation();
event.preventDefault();
this.handleMultiselectClear();
}
}, class: {
'clear-icon': true,
'hide': !(this.multiselect && this.selectedOptions.length > 0),
}, name: "cross", size: "16px" }), 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: '0d76e422a2f0887595f60d57e03ec3980d4b9774', role: "listbox", "aria-label": this.tdsAriaLabel, inert: !this.open, "aria-orientation": "vertical", "aria-multiselectable": this.multiselect, ref: (element) => {
if (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: 'f971e4e9e24fe8d9092066d72bb05b76547f05a7', onSlotchange: () => this.handleSlotChange() }), this.filterResult === 0 && this.noResultText !== '' && (h("div", { key: '0d8f90a543bf7b8dc3b3185d27f05d0517b4e0e6', class: `no-result ${this.size}` }, this.noResultText))), this.helper && (h("div", { key: '4f17cfead0616b262e91e0e5b82cf59ce1309d73', id: helperId, class: {
helper: true,
error: this.error,
disabled: this.disabled,
} }, this.error && h("tds-icon", { key: '032599d86280e2a204c22fb97409f097841259b5', name: "error", size: "16px" }), this.helper))));
}
static get is() { return "tds-dropdown"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() {
return {
"$": ["dropdown.scss"]
};
}
static get styleUrls() {
return {
"$": ["dropdown.css"]
};
}
static get properties() {
return {
"name": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Name for the Dropdowns input element."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "name"
},
"disabled": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Sets the Dropdown in a disabled state"
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "disabled",
"defaultValue": "false"
},
"helper": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Helper text for the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "helper"
},
"label": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Label text for the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "label"
},
"labelPosition": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'inside' | 'outside'",
"resolved": "\"inside\" | \"outside\" | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Label text position"
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "label-position"
},
"modeVariant": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'primary' | 'secondary' | null",
"resolved": "\"primary\" | \"secondary\" | null",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Mode variant of the component, based on current mode."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "mode-variant",
"defaultValue": "null"
},
"openDirection": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'up' | 'down' | 'auto'",
"resolved": "\"auto\" | \"down\" | \"up\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The direction the Dropdown should open, auto if not specified."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "open-direction",
"defaultValue": "'auto'"
},
"placeholder": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Placeholder text for the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "placeholder"
},
"size": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'xs' | 'sm' | 'md' | 'lg'",
"resolved": "\"lg\" | \"md\" | \"sm\" | \"xs\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "The size of the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "size",
"defaultValue": "'lg'"
},
"animation": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'none' | 'slide'",
"resolved": "\"none\" | \"slide\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "animation",
"defaultValue": "'slide'"
},
"error": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Sets the Dropdown in an error state"
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "error",
"defaultValue": "false"
},
"multiselect": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Enables multiselect in the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "multiselect",
"defaultValue": "false"
},
"filter": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Enables filtration in the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "filter",
"defaultValue": "false"
},
"normalizeText": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Normalizes input text for fuzzier search"
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "normalize-text",
"defaultValue": "true"
},
"noResultText": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Text that is displayed if filter is used and there are no options that matches the search.\nSetting it to an empty string disables message from showing up."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "no-result-text",
"defaultValue": "'No result'"
},
"defaultValue": {
"type": "any",
"mutable": false,
"complexType": {
"original": "string | number",
"resolved": "number | string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Default value selected in the Dropdown."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "default-value"
},
"value": {
"type": "any",
"mutable": true,
"complexType": {
"original": "string | number | (string | number)[] | null",
"resolved": "(string | number)[] | null | number | string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Value of the dropdown. For multiselect, provide array of strings/numbers. For single select, provide a string/number."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "value",
"defaultValue": "null"
},
"tdsAriaLabel": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Defines aria-label attribute for input"
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "tds-aria-label"
}
};
}
static get states() {
return {
"open": {},
"internalValue": {},
"filterResult": {},
"filterFocus": {},
"internalDefaultValue": {},
"selectedOptions": {},
"filterQuery": {}
};
}
static get events() {
return [{
"method": "tdsChange",
"name": "tdsChange",
"bubbles": true,
"cancelable": false,
"composed": true,
"docs": {
"tags": [],
"text": "Change event for the Dropdown."
},
"complexType": {
"original": "{\n name: string | undefined;\n value: string | null;\n }",
"resolved": "{ name: string | undefined; value: string | null; }",
"references": {}
}
}, {
"method": "tdsFocus",
"name": "tdsFocus",
"bubbles": true,
"cancelable": false,
"composed": true,
"docs": {
"tags": [],
"text": "Focus event for the Dropdown."
},
"complexType": {
"original": "FocusEvent",
"resolved": "FocusEvent",
"references": {
"FocusEvent": {
"location": "global",
"id": "global::FocusEvent"
}
}
}
}, {
"method": "tdsBlur",
"name": "tdsBlur",
"bubbles": true,
"cancelable": false,
"composed": true,
"docs": {
"tags": [],
"text": "Blur event for the Dropdown."
},
"complexType": {
"original": "FocusEvent",
"resolved": "FocusEvent",
"references": {
"FocusEvent": {
"location": "global",
"id": "global::FocusEvent"
}
}
}
}, {
"method": "tdsInput",
"name": "tdsInput",
"bubbles": true,
"cancelable": false,
"composed": true,
"docs": {
"tags": [],
"text": "Input event for the Dropdown."
},
"complexType": {
"original": "InputEvent",
"resolved": "InputEvent",
"references": {
"InputEvent": {
"location": "global",
"id": "global::InputEvent"
}
}
}
}, {
"method": "tdsClear",
"name": "tdsClear",
"bubbles": true,
"cancelable": false,
"composed": true,
"docs": {
"tags": [],
"text": "Clear event for the Dropdown."
},
"complexType": {
"original": "{ clearedValue: string }",
"resolved": "{ clearedValue: string; }",
"references": {}
}
}];
}
static get methods() {
return {
"setValue": {
"complexType": {
"signature": "(value: string | number | string[] | number[], label?: string) => Promise<{ value: string | number | undefined; label: string | undefined; }[]>",
"parameters": [{
"name": "value",
"type": "string | number | string[] | number[]",
"docs": ""
}, {
"name": "label",
"type": "string | undefined",
"docs": ""
}],
"references": {
"Promise": {
"location": "global",
"id": "global::Promise"
},