diff --git a/src/scss/components/select/multi-select.ts b/src/scss/components/select/multi-select.ts index d3096ad..8725bf9 100644 --- a/src/scss/components/select/multi-select.ts +++ b/src/scss/components/select/multi-select.ts @@ -1,13 +1,14 @@ import { LitElement, html } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { map } from "lit/directives/map.js"; +import "./select-option.ts"; @customElement("multi-select") export class MultiSelect extends LitElement { @property({ type: String }) label: string = "Select options"; - @property({ type: String }) + @property({ type: String, attribute: "field-name" }) name: string = ""; @property({ type: Array }) @@ -27,20 +28,35 @@ export class MultiSelect extends LitElement { connectedCallback() { super.connectedCallback(); - if (this.options.length === 0) { - this._readOptionsFromSlot(); - } else { - this.optionsMap = new Map(this.options.map((opt) => [opt, opt])); - } - this._hideSlottedOptions(); - this._createHiddenInputsContainer(); + Promise.resolve().then(() => { + if (this.options.length === 0) { + this._readOptionsFromSlot(); + } else { + this.optionsMap = new Map(this.options.map((opt) => [opt, opt])); + } + this._hideSlottedOptions(); + this._createHiddenInputsContainer(); + }); + + this.addEventListener("select-option-connected", this._onOptionConnected); } disconnectedCallback() { super.disconnectedCallback(); + this.removeEventListener( + "select-option-connected", + this._onOptionConnected, + ); this._removeHiddenInputsContainer(); } + private _onOptionConnected = () => { + if (this.options.length === 0) { + this._readOptionsFromSlot(); + this._hideSlottedOptions(); + } + }; + _createHiddenInputsContainer() { if (!this.hiddenInputsContainer) { this.hiddenInputsContainer = document.createElement("div"); @@ -50,7 +66,7 @@ export class MultiSelect extends LitElement { } _removeHiddenInputsContainer() { - if (this.hiddenInputsContainer && this.hiddenInputsContainer.parentNode) { + if (this.hiddenInputsContainer?.parentNode) { this.hiddenInputsContainer.parentNode.removeChild( this.hiddenInputsContainer, ); @@ -79,23 +95,22 @@ export class MultiSelect extends LitElement { } _hideSlottedOptions() { - const optionElements = this.querySelectorAll("option"); - optionElements.forEach((opt) => { - opt.style.display = "none"; + this.querySelectorAll("select-option").forEach((el) => { + el.style.display = "none"; }); } _readOptionsFromSlot() { - const optionElements = this.querySelectorAll("option"); + const optionElements = this.querySelectorAll("select-option"); this.optionsMap = new Map(); const preselected: string[] = []; optionElements.forEach((opt) => { - const value = opt.value || opt.textContent || ""; - const text = opt.textContent || ""; + const value = opt.getAttribute("value") || opt.textContent?.trim() || ""; + const text = opt.textContent?.trim() || ""; if (value) { this.optionsMap.set(value, text); - if (opt.hasAttribute("selected") || opt.selected) { + if (opt.hasAttribute("selected")) { preselected.push(value); } } diff --git a/src/scss/components/select/select-option.ts b/src/scss/components/select/select-option.ts new file mode 100644 index 0000000..0eeeb16 --- /dev/null +++ b/src/scss/components/select/select-option.ts @@ -0,0 +1,28 @@ +import { LitElement } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +@customElement("select-option") +export class SelectOption extends LitElement { + @property({ type: String }) value: string = ""; + @property({ type: Boolean }) selected: boolean = false; + + createRenderRoot() { + return this; + } + + connectedCallback() { + super.connectedCallback(); + this.dispatchEvent( + new CustomEvent("select-option-connected", { + bubbles: true, + composed: true, + }), + ); + } +} + +declare global { + interface HTMLElementTagNameMap { + "select-option": SelectOption; + } +} diff --git a/src/scss/components/select/select.stories.ts b/src/scss/components/select/select.stories.ts index 39c6d0c..966c9eb 100644 --- a/src/scss/components/select/select.stories.ts +++ b/src/scss/components/select/select.stories.ts @@ -6,9 +6,7 @@ import "./multi-select.ts"; const meta: Meta = { title: "Components/Select", parameters: { - backgrounds: { - default: "light", - }, + backgrounds: { default: "light" }, }, argTypes: { label: { control: "text" }, @@ -58,8 +56,8 @@ export const MultiSelectSlot: Story = { name: "Multi Select (HTML Slot)", render: () => html` - - + English + French `, }; @@ -68,8 +66,8 @@ export const MultiSelectWithValues: Story = { name: "Multi Select (HTML Slot With Custom Values)", render: () => html` - - + English + French `, }; @@ -85,11 +83,13 @@ export const MultiSelectInForm: Story = { alert("Selected values: " + JSON.stringify(selected)); }} > - - - + + English + French - + `, };