@substrate-system/select 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,87 @@
1
+ import { WebComponent } from '@substrate-system/web-component';
2
+ declare global {
3
+ interface HTMLElementTagNameMap {
4
+ 'substrate-select': SubstrateSelect;
5
+ }
6
+ }
7
+ /**
8
+ * ARIA attributes the component observes, so a change after upgrade is
9
+ * moved to the inner select too. `attributeChangedCallback` only sees
10
+ * attributes named in `observedAttributes`. Copied from
11
+ * `@substrate-system/input` (`src/util.ts`). At first render every
12
+ * `aria-*` attribute moves, listed here or not.
13
+ */
14
+ export declare const ARIA_ATTRIBUTES: string[];
15
+ export interface SubstrateSelectChangeDetail {
16
+ value: string;
17
+ }
18
+ declare const SubstrateSelect_base: typeof WebComponent & {
19
+ new (...args: any[]): WebComponent;
20
+ TAG: string;
21
+ define: typeof WebComponent.define;
22
+ event: typeof WebComponent.event;
23
+ };
24
+ /**
25
+ * Use the `create` factory rather than `class X extends WebComponent`
26
+ * with `static TAG`. The base class declares `TAG` as an *instance*
27
+ * field defaulting to `''`, and `emit`/`on` namespace from that instance
28
+ * field while `static event()` reads the static one. Setting only
29
+ * `static TAG` therefore emits `':change'` while listeners built from
30
+ * `SubstrateSelect.event('change')` expect `'substrate-select:change'`,
31
+ * and nothing fires. `create` sets both.
32
+ */
33
+ export declare class SubstrateSelect extends SubstrateSelect_base {
34
+ #private;
35
+ /**
36
+ * The base class generates the accessors for these and derives
37
+ * `observedAttributes` from them.
38
+ *
39
+ * @see docs/adr/ADR-004-attributes-as-state.md
40
+ */
41
+ static reflectedStringAttributes: string[];
42
+ static reflectedBooleanAttributes: string[];
43
+ static get observedAttributes(): string[];
44
+ /**
45
+ * Installed at runtime by `define()`. `declare` types them without
46
+ * emitting a field that would shadow the generated accessor.
47
+ */
48
+ label: string | null;
49
+ name: string | null;
50
+ disabled: boolean;
51
+ required: boolean;
52
+ /**
53
+ * The inner select's value. Before the first render this holds the
54
+ * value and `render` applies it once the options are in.
55
+ */
56
+ get value(): string;
57
+ set value(value: string);
58
+ /**
59
+ * The inner select, or `null` before the first render. An escape
60
+ * hatch, for example to remove options.
61
+ */
62
+ get select(): HTMLSelectElement | null;
63
+ connectedCallback(): void;
64
+ disconnectedCallback(): void;
65
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
66
+ handleChange_label(_oldValue: string | null, newValue: string | null): void;
67
+ handleChange_name(_oldValue: string | null, newValue: string | null): void;
68
+ handleChange_disabled(_oldValue: string | null, newValue: string | null): void;
69
+ handleChange_required(_oldValue: string | null, newValue: string | null): void;
70
+ handleChange_autocomplete(_oldValue: string | null, newValue: string | null): void;
71
+ handleChange_form(_oldValue: string | null, newValue: string | null): void;
72
+ /**
73
+ * After the first render, `id` and `aria-*` live on the inner select,
74
+ * so removing one from the host removes it from the select. This is
75
+ * how frameworks clear an attribute (Preact calls `removeAttribute`
76
+ * for `undefined`). A removed `id` falls back to the generated one,
77
+ * so the label stays connected.
78
+ *
79
+ * Internal code calls `super.removeAttribute` to strip the host
80
+ * without touching the select. `toggleAttribute(name, false)` and
81
+ * `removeAttributeNode` on the host are not covered.
82
+ */
83
+ removeAttribute(qualifiedName: string): void;
84
+ render(): void;
85
+ }
86
+ export {};
87
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AAK9D,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,kBAAkB,EAAC,eAAe,CAAA;KACrC;CACJ;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,UAsD3B,CAAA;AAkCD,MAAM,WAAW,2BAA2B;IACxC,KAAK,EAAC,MAAM,CAAC;CAChB;;;;;;;AAED;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,oBAAuC;;IACxE;;;;;OAKG;IACH,MAAM,CAAC,yBAAyB,WAAoB;IACpD,MAAM,CAAC,0BAA0B,WAA2B;IAE5D,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAQxC;IAED;;;OAGG;IACK,KAAK,EAAC,MAAM,GAAC,IAAI,CAAA;IACjB,IAAI,EAAC,MAAM,GAAC,IAAI,CAAA;IAChB,QAAQ,EAAC,OAAO,CAAA;IAChB,QAAQ,EAAC,OAAO,CAAA;IAExB;;;OAGG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IAED,IAAI,KAAK,CAAE,KAAK,EAAC,MAAM,EAYtB;IAED;;;OAGG;IACH,IAAI,MAAM,IAAI,iBAAiB,GAAC,IAAI,CAEnC;IASD,iBAAiB;IA4BjB,oBAAoB;IAQpB,wBAAwB,CACpB,IAAI,EAAC,MAAM,EACX,QAAQ,EAAC,MAAM,GAAC,IAAI,EACpB,QAAQ,EAAC,MAAM,GAAC,IAAI;IAgBxB,kBAAkB,CAAE,SAAS,EAAC,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAC,MAAM,GAAC,IAAI;IAkB/D,iBAAiB,CAAE,SAAS,EAAC,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAC,MAAM,GAAC,IAAI;IAI9D,qBAAqB,CAAE,SAAS,EAAC,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAC,MAAM,GAAC,IAAI;IAIlE,qBAAqB,CAAE,SAAS,EAAC,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAC,MAAM,GAAC,IAAI;IAIlE,yBAAyB,CACrB,SAAS,EAAC,MAAM,GAAC,IAAI,EACrB,QAAQ,EAAC,MAAM,GAAC,IAAI;IAKxB,iBAAiB,CAAE,SAAS,EAAC,MAAM,GAAC,IAAI,EAAE,QAAQ,EAAC,MAAM,GAAC,IAAI;IAiD9D;;;;;;;;;;OAUG;IACH,eAAe,CAAE,aAAa,EAAC,MAAM;IAoFrC,MAAM;CA+ET"}
package/dist/index.js ADDED
@@ -0,0 +1,376 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { WebComponent } from "@substrate-system/web-component";
4
+ import Debug from "@substrate-system/debug";
5
+ const debug = Debug("substrate-select");
6
+ const ARIA_ATTRIBUTES = [
7
+ "aria-activedescendant",
8
+ "aria-atomic",
9
+ "aria-autocomplete",
10
+ "aria-braillelabel",
11
+ "aria-brailleroledescription",
12
+ "aria-busy",
13
+ "aria-checked",
14
+ "aria-colcount",
15
+ "aria-colindex",
16
+ "aria-colindextext",
17
+ "aria-colspan",
18
+ "aria-controls",
19
+ "aria-current",
20
+ "aria-describedby",
21
+ "aria-description",
22
+ "aria-details",
23
+ "aria-disabled",
24
+ "aria-dropeffect",
25
+ "aria-errormessage",
26
+ "aria-expanded",
27
+ "aria-flowto",
28
+ "aria-grabbed",
29
+ "aria-haspopup",
30
+ "aria-hidden",
31
+ "aria-invalid",
32
+ "aria-keyshortcuts",
33
+ "aria-label",
34
+ "aria-labelledby",
35
+ "aria-level",
36
+ "aria-live",
37
+ "aria-modal",
38
+ "aria-multiline",
39
+ "aria-multiselectable",
40
+ "aria-orientation",
41
+ "aria-owns",
42
+ "aria-placeholder",
43
+ "aria-posinset",
44
+ "aria-pressed",
45
+ "aria-readonly",
46
+ "aria-relevant",
47
+ "aria-required",
48
+ "aria-roledescription",
49
+ "aria-rowcount",
50
+ "aria-rowindex",
51
+ "aria-rowindextext",
52
+ "aria-rowspan",
53
+ "aria-selected",
54
+ "aria-setsize",
55
+ "aria-sort",
56
+ "aria-valuemax",
57
+ "aria-valuemin",
58
+ "aria-valuenow",
59
+ "aria-valuetext"
60
+ ];
61
+ const FORWARDED_ATTRIBUTES = [
62
+ "name",
63
+ "disabled",
64
+ "required",
65
+ "autocomplete",
66
+ "form"
67
+ ];
68
+ const UPGRADED_PROPERTIES = [
69
+ "value",
70
+ "label",
71
+ "name",
72
+ "disabled",
73
+ "required"
74
+ ];
75
+ function isOptionNode(node) {
76
+ return node instanceof HTMLOptionElement || node instanceof HTMLOptGroupElement;
77
+ }
78
+ __name(isOptionNode, "isOptionNode");
79
+ class SubstrateSelect extends WebComponent.create("substrate-select") {
80
+ static {
81
+ __name(this, "SubstrateSelect");
82
+ }
83
+ /**
84
+ * The base class generates the accessors for these and derives
85
+ * `observedAttributes` from them.
86
+ *
87
+ * @see docs/adr/ADR-004-attributes-as-state.md
88
+ */
89
+ static reflectedStringAttributes = ["label", "name"];
90
+ static reflectedBooleanAttributes = ["disabled", "required"];
91
+ static get observedAttributes() {
92
+ return [
93
+ ...super.observedAttributes,
94
+ "id",
95
+ "autocomplete",
96
+ "form",
97
+ ...ARIA_ATTRIBUTES
98
+ ];
99
+ }
100
+ /**
101
+ * The inner select's value. Before the first render this holds the
102
+ * value and `render` applies it once the options are in.
103
+ */
104
+ get value() {
105
+ if (this.#select) return this.#select.value;
106
+ return this.#pendingValue ?? "";
107
+ }
108
+ set value(value) {
109
+ const normalized = String(value ?? "");
110
+ if (this.#select) {
111
+ this.#adopt(Array.from(this.childNodes));
112
+ this.#pendingValue = null;
113
+ this.#select.value = normalized;
114
+ return;
115
+ }
116
+ this.#pendingValue = normalized;
117
+ }
118
+ /**
119
+ * The inner select, or `null` before the first render. An escape
120
+ * hatch, for example to remove options.
121
+ */
122
+ get select() {
123
+ return this.#select;
124
+ }
125
+ #select = null;
126
+ #label = null;
127
+ #pendingValue = null;
128
+ #observer = null;
129
+ #generatedId = "substrate-select-" + Math.random().toString(36).slice(2, 10);
130
+ connectedCallback() {
131
+ debug("connected");
132
+ for (const prop of UPGRADED_PROPERTIES) {
133
+ this.#upgradeProperty(prop);
134
+ }
135
+ this.render();
136
+ this.#adopt(Array.from(this.childNodes));
137
+ this.#observer ??= new MutationObserver((records) => {
138
+ this.#handleRecords(records);
139
+ });
140
+ this.#observer.observe(this, { childList: true });
141
+ if (this.#select) {
142
+ this.#observer.observe(this.#select, {
143
+ childList: true,
144
+ subtree: true
145
+ });
146
+ }
147
+ }
148
+ disconnectedCallback() {
149
+ debug("disconnected");
150
+ if (!this.#observer) return;
151
+ this.#handleRecords(this.#observer.takeRecords());
152
+ this.#observer.disconnect();
153
+ }
154
+ attributeChangedCallback(name, oldValue, newValue) {
155
+ if (name === "id" || name.startsWith("aria-")) {
156
+ this.#moveToSelect(name, newValue);
157
+ return;
158
+ }
159
+ super.attributeChangedCallback(
160
+ name,
161
+ oldValue,
162
+ newValue
163
+ );
164
+ }
165
+ handleChange_label(_oldValue, newValue) {
166
+ const select = this.#select;
167
+ if (!select) return;
168
+ if (!newValue) {
169
+ this.#label?.remove();
170
+ this.#label = null;
171
+ return;
172
+ }
173
+ if (!this.#label) {
174
+ this.#label = this.#createLabel(select.id);
175
+ this.insertBefore(this.#label, select);
176
+ }
177
+ this.#label.textContent = newValue;
178
+ }
179
+ handleChange_name(_oldValue, newValue) {
180
+ this.#forward("name", newValue);
181
+ }
182
+ handleChange_disabled(_oldValue, newValue) {
183
+ this.#forward("disabled", newValue);
184
+ }
185
+ handleChange_required(_oldValue, newValue) {
186
+ this.#forward("required", newValue);
187
+ }
188
+ handleChange_autocomplete(_oldValue, newValue) {
189
+ this.#forward("autocomplete", newValue);
190
+ }
191
+ handleChange_form(_oldValue, newValue) {
192
+ this.#forward("form", newValue);
193
+ }
194
+ /**
195
+ * Copy a forwarded attribute to the select. Before the first render
196
+ * there is no select, and `render` copies the host's attributes.
197
+ */
198
+ #forward(name, value) {
199
+ const select = this.#select;
200
+ if (!select) return;
201
+ if (value === null) {
202
+ select.removeAttribute(name);
203
+ } else {
204
+ select.setAttribute(name, value);
205
+ }
206
+ }
207
+ /**
208
+ * Move `id` or an `aria-*` attribute from the host to the select.
209
+ *
210
+ * A `null` value is ignored. The host never keeps these attributes
211
+ * after the first render, so a removal callback is always the one
212
+ * this method or `render` just caused. A consumer's removal goes
213
+ * through the `removeAttribute` override instead, because the host
214
+ * no longer has the attribute and no callback would fire.
215
+ *
216
+ * Before the first render there is no select; `render` reads the
217
+ * host attributes itself.
218
+ */
219
+ #moveToSelect(name, value) {
220
+ const select = this.#select;
221
+ if (value === null || !select) return;
222
+ if (name === "id") {
223
+ this.#setSelectId(value || this.#generatedId);
224
+ } else {
225
+ select.setAttribute(name, value);
226
+ }
227
+ super.removeAttribute(name);
228
+ }
229
+ #setSelectId(id) {
230
+ if (!this.#select) return;
231
+ this.#select.id = id;
232
+ if (this.#label) this.#label.htmlFor = id;
233
+ }
234
+ /**
235
+ * After the first render, `id` and `aria-*` live on the inner select,
236
+ * so removing one from the host removes it from the select. This is
237
+ * how frameworks clear an attribute (Preact calls `removeAttribute`
238
+ * for `undefined`). A removed `id` falls back to the generated one,
239
+ * so the label stays connected.
240
+ *
241
+ * Internal code calls `super.removeAttribute` to strip the host
242
+ * without touching the select. `toggleAttribute(name, false)` and
243
+ * `removeAttributeNode` on the host are not covered.
244
+ */
245
+ removeAttribute(qualifiedName) {
246
+ const name = qualifiedName.toLowerCase();
247
+ const select = this.#select;
248
+ if (select && name === "id") {
249
+ this.#setSelectId(this.#generatedId);
250
+ } else if (select && name.startsWith("aria-")) {
251
+ select.removeAttribute(name);
252
+ }
253
+ super.removeAttribute(qualifiedName);
254
+ }
255
+ /**
256
+ * Apply a value that was set before the first render. It stays
257
+ * pending until an option with that value exists, so a value set
258
+ * before the options arrive (an empty first render, then appended
259
+ * options) still lands. A later `value` set or a user change clears
260
+ * it.
261
+ */
262
+ #applyPendingValue() {
263
+ const select = this.#select;
264
+ const pending = this.#pendingValue;
265
+ if (!select || pending === null) return;
266
+ const options = Array.from(select.options);
267
+ if (!options.some((option) => option.value === pending)) return;
268
+ select.value = pending;
269
+ this.#pendingValue = null;
270
+ }
271
+ /**
272
+ * A property set before the element was defined is an own data
273
+ * property that hides the class accessor. Remove it and set it
274
+ * again so the accessor sees it.
275
+ */
276
+ #upgradeProperty(prop) {
277
+ if (!Object.prototype.hasOwnProperty.call(this, prop)) return;
278
+ const value = Reflect.get(this, prop);
279
+ Reflect.deleteProperty(this, prop);
280
+ Reflect.set(this, prop, value);
281
+ }
282
+ /**
283
+ * Move options added to the host into the select, and retry a
284
+ * waiting value when nodes were added inside the select.
285
+ */
286
+ #handleRecords(records) {
287
+ const fromHost = records.filter((record) => record.target === this);
288
+ this.#adopt(
289
+ fromHost.flatMap((record) => Array.from(record.addedNodes))
290
+ );
291
+ const intoSelect = records.some((record) => {
292
+ return record.target !== this && record.addedNodes.length > 0;
293
+ });
294
+ if (intoSelect) this.#applyPendingValue();
295
+ }
296
+ /**
297
+ * Move `<option>` and `<optgroup>` children of the host to the end of
298
+ * the select. The component's own label and select, and anything
299
+ * that is not an option, stay where they are.
300
+ */
301
+ #adopt(nodes) {
302
+ const select = this.#select;
303
+ if (!select) return;
304
+ let moved = false;
305
+ for (const node of nodes) {
306
+ if (node.parentNode !== this) continue;
307
+ if (!isOptionNode(node)) continue;
308
+ select.append(node);
309
+ moved = true;
310
+ }
311
+ if (moved) this.#applyPendingValue();
312
+ }
313
+ #createLabel(selectId) {
314
+ const label = document.createElement("label");
315
+ label.htmlFor = selectId;
316
+ return label;
317
+ }
318
+ render() {
319
+ if (this.#select) return;
320
+ const authored = [];
321
+ const stray = [];
322
+ for (const node of Array.from(this.childNodes)) {
323
+ if (isOptionNode(node)) {
324
+ authored.push(node);
325
+ } else if (node.nodeType !== Node.TEXT_NODE || node.textContent?.trim()) {
326
+ stray.push(node);
327
+ }
328
+ }
329
+ if (stray.length) debug("dropping non-option children", stray);
330
+ const chosen = authored.flatMap((node) => {
331
+ return node instanceof HTMLOptionElement ? [node] : Array.from(node.querySelectorAll("option"));
332
+ }).filter((option) => option.selected).pop();
333
+ const select = document.createElement("select");
334
+ select.id = this.getAttribute("id") ?? this.#generatedId;
335
+ for (const attr of Array.from(this.attributes)) {
336
+ if (attr.name.startsWith("aria-")) {
337
+ select.setAttribute(attr.name, attr.value);
338
+ }
339
+ }
340
+ for (const name of FORWARDED_ATTRIBUTES) {
341
+ const value = this.getAttribute(name);
342
+ if (value !== null) select.setAttribute(name, value);
343
+ }
344
+ select.addEventListener("change", () => {
345
+ this.#pendingValue = null;
346
+ this.emit("change", {
347
+ detail: { value: select.value }
348
+ });
349
+ });
350
+ select.append(...authored);
351
+ if (chosen) chosen.selected = true;
352
+ this.#select = select;
353
+ this.#applyPendingValue();
354
+ if (this.#pendingValue !== null) select.selectedIndex = -1;
355
+ const labelText = this.getAttribute("label");
356
+ if (labelText) {
357
+ this.#label = this.#createLabel(select.id);
358
+ this.#label.textContent = labelText;
359
+ this.replaceChildren(this.#label, select);
360
+ } else {
361
+ this.replaceChildren(select);
362
+ }
363
+ super.removeAttribute("id");
364
+ for (const attr of Array.from(this.attributes)) {
365
+ if (attr.name.startsWith("aria-")) {
366
+ super.removeAttribute(attr.name);
367
+ }
368
+ }
369
+ }
370
+ }
371
+ SubstrateSelect.define();
372
+ export {
373
+ ARIA_ATTRIBUTES,
374
+ SubstrateSelect
375
+ };
376
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["// pattern: Imperative Shell\nimport { WebComponent } from '@substrate-system/web-component'\nimport Debug from '@substrate-system/debug'\nconst debug = Debug('substrate-select')\n\n// for document.querySelector\ndeclare global {\n interface HTMLElementTagNameMap {\n 'substrate-select':SubstrateSelect\n }\n}\n\n/**\n * ARIA attributes the component observes, so a change after upgrade is\n * moved to the inner select too. `attributeChangedCallback` only sees\n * attributes named in `observedAttributes`. Copied from\n * `@substrate-system/input` (`src/util.ts`). At first render every\n * `aria-*` attribute moves, listed here or not.\n */\nexport const ARIA_ATTRIBUTES = [\n 'aria-activedescendant',\n 'aria-atomic',\n 'aria-autocomplete',\n 'aria-braillelabel',\n 'aria-brailleroledescription',\n 'aria-busy',\n 'aria-checked',\n 'aria-colcount',\n 'aria-colindex',\n 'aria-colindextext',\n 'aria-colspan',\n 'aria-controls',\n 'aria-current',\n 'aria-describedby',\n 'aria-description',\n 'aria-details',\n 'aria-disabled',\n 'aria-dropeffect',\n 'aria-errormessage',\n 'aria-expanded',\n 'aria-flowto',\n 'aria-grabbed',\n 'aria-haspopup',\n 'aria-hidden',\n 'aria-invalid',\n 'aria-keyshortcuts',\n 'aria-label',\n 'aria-labelledby',\n 'aria-level',\n 'aria-live',\n 'aria-modal',\n 'aria-multiline',\n 'aria-multiselectable',\n 'aria-orientation',\n 'aria-owns',\n 'aria-placeholder',\n 'aria-posinset',\n 'aria-pressed',\n 'aria-readonly',\n 'aria-relevant',\n 'aria-required',\n 'aria-roledescription',\n 'aria-rowcount',\n 'aria-rowindex',\n 'aria-rowindextext',\n 'aria-rowspan',\n 'aria-selected',\n 'aria-setsize',\n 'aria-sort',\n 'aria-valuemax',\n 'aria-valuemin',\n 'aria-valuenow',\n 'aria-valuetext'\n]\n\n/**\n * Attributes copied to the inner select and also left on the host.\n */\nconst FORWARDED_ATTRIBUTES = [\n 'name',\n 'disabled',\n 'required',\n 'autocomplete',\n 'form'\n]\n\n/**\n * Properties a framework may set before this module defines the\n * element. See `#upgradeProperty`.\n */\nconst UPGRADED_PROPERTIES = [\n 'value',\n 'label',\n 'name',\n 'disabled',\n 'required'\n]\n\nfunction isOptionNode (\n node:Node\n):node is HTMLOptionElement|HTMLOptGroupElement {\n return (\n node instanceof HTMLOptionElement ||\n node instanceof HTMLOptGroupElement\n )\n}\n\nexport interface SubstrateSelectChangeDetail {\n value:string;\n}\n\n/**\n * Use the `create` factory rather than `class X extends WebComponent`\n * with `static TAG`. The base class declares `TAG` as an *instance*\n * field defaulting to `''`, and `emit`/`on` namespace from that instance\n * field while `static event()` reads the static one. Setting only\n * `static TAG` therefore emits `':change'` while listeners built from\n * `SubstrateSelect.event('change')` expect `'substrate-select:change'`,\n * and nothing fires. `create` sets both.\n */\nexport class SubstrateSelect extends WebComponent.create('substrate-select') {\n /**\n * The base class generates the accessors for these and derives\n * `observedAttributes` from them.\n *\n * @see docs/adr/ADR-004-attributes-as-state.md\n */\n static reflectedStringAttributes = ['label', 'name']\n static reflectedBooleanAttributes = ['disabled', 'required']\n\n static get observedAttributes ():string[] {\n return [\n ...super.observedAttributes,\n 'id',\n 'autocomplete',\n 'form',\n ...ARIA_ATTRIBUTES\n ]\n }\n\n /**\n * Installed at runtime by `define()`. `declare` types them without\n * emitting a field that would shadow the generated accessor.\n */\n declare label:string|null\n declare name:string|null\n declare disabled:boolean\n declare required:boolean\n\n /**\n * The inner select's value. Before the first render this holds the\n * value and `render` applies it once the options are in.\n */\n get value ():string {\n if (this.#select) return this.#select.value\n return this.#pendingValue ?? ''\n }\n\n set value (value:string) {\n const normalized = String(value ?? '')\n if (this.#select) {\n // Options appended this tick are still in the host, waiting\n // for the observer. Move them now so the value can match.\n this.#adopt(Array.from(this.childNodes))\n // A later set replaces any value still waiting for its option\n this.#pendingValue = null\n this.#select.value = normalized\n return\n }\n this.#pendingValue = normalized\n }\n\n /**\n * The inner select, or `null` before the first render. An escape\n * hatch, for example to remove options.\n */\n get select ():HTMLSelectElement|null {\n return this.#select\n }\n\n #select:HTMLSelectElement|null = null\n #label:HTMLLabelElement|null = null\n #pendingValue:string|null = null\n #observer:MutationObserver|null = null\n #generatedId = 'substrate-select-' +\n Math.random().toString(36).slice(2, 10)\n\n connectedCallback () {\n debug('connected')\n for (const prop of UPGRADED_PROPERTIES) {\n this.#upgradeProperty(prop)\n }\n\n // Not `super.connectedCallback()`: that renders on every\n // connect. `render` is idempotent, so a reconnect keeps the\n // existing select, its options, and the user's selection.\n this.render()\n\n // Options appended while disconnected\n this.#adopt(Array.from(this.childNodes))\n\n this.#observer ??= new MutationObserver(records => {\n this.#handleRecords(records)\n })\n this.#observer.observe(this, { childList: true })\n // Options added through `el.select` may be what a waiting value\n // is waiting for. `subtree` covers options inside an optgroup.\n if (this.#select) {\n this.#observer.observe(this.#select, {\n childList: true,\n subtree: true\n })\n }\n }\n\n disconnectedCallback () {\n debug('disconnected')\n if (!this.#observer) return\n // Deliver additions the observer has queued but not reported\n this.#handleRecords(this.#observer.takeRecords())\n this.#observer.disconnect()\n }\n\n attributeChangedCallback (\n name:string,\n oldValue:string|null,\n newValue:string|null\n ) {\n if (name === 'id' || name.startsWith('aria-')) {\n this.#moveToSelect(name, newValue)\n return\n }\n\n // The base class types these as `string`; the DOM passes `null`\n // for an absent attribute, and the handlers here accept it.\n super.attributeChangedCallback(\n name,\n oldValue as string,\n newValue as string\n )\n }\n\n handleChange_label (_oldValue:string|null, newValue:string|null) {\n const select = this.#select\n if (!select) return // render reads the attribute\n\n if (!newValue) {\n this.#label?.remove()\n this.#label = null\n return\n }\n\n if (!this.#label) {\n this.#label = this.#createLabel(select.id)\n this.insertBefore(this.#label, select)\n }\n\n this.#label.textContent = newValue\n }\n\n handleChange_name (_oldValue:string|null, newValue:string|null) {\n this.#forward('name', newValue)\n }\n\n handleChange_disabled (_oldValue:string|null, newValue:string|null) {\n this.#forward('disabled', newValue)\n }\n\n handleChange_required (_oldValue:string|null, newValue:string|null) {\n this.#forward('required', newValue)\n }\n\n handleChange_autocomplete (\n _oldValue:string|null,\n newValue:string|null\n ) {\n this.#forward('autocomplete', newValue)\n }\n\n handleChange_form (_oldValue:string|null, newValue:string|null) {\n this.#forward('form', newValue)\n }\n\n /**\n * Copy a forwarded attribute to the select. Before the first render\n * there is no select, and `render` copies the host's attributes.\n */\n #forward (name:string, value:string|null) {\n const select = this.#select\n if (!select) return\n\n if (value === null) {\n select.removeAttribute(name)\n } else {\n select.setAttribute(name, value)\n }\n }\n\n /**\n * Move `id` or an `aria-*` attribute from the host to the select.\n *\n * A `null` value is ignored. The host never keeps these attributes\n * after the first render, so a removal callback is always the one\n * this method or `render` just caused. A consumer's removal goes\n * through the `removeAttribute` override instead, because the host\n * no longer has the attribute and no callback would fire.\n *\n * Before the first render there is no select; `render` reads the\n * host attributes itself.\n */\n #moveToSelect (name:string, value:string|null) {\n const select = this.#select\n if (value === null || !select) return\n\n if (name === 'id') {\n this.#setSelectId(value || this.#generatedId)\n } else {\n select.setAttribute(name, value)\n }\n super.removeAttribute(name)\n }\n\n #setSelectId (id:string) {\n if (!this.#select) return\n this.#select.id = id\n if (this.#label) this.#label.htmlFor = id\n }\n\n /**\n * After the first render, `id` and `aria-*` live on the inner select,\n * so removing one from the host removes it from the select. This is\n * how frameworks clear an attribute (Preact calls `removeAttribute`\n * for `undefined`). A removed `id` falls back to the generated one,\n * so the label stays connected.\n *\n * Internal code calls `super.removeAttribute` to strip the host\n * without touching the select. `toggleAttribute(name, false)` and\n * `removeAttributeNode` on the host are not covered.\n */\n removeAttribute (qualifiedName:string) {\n const name = qualifiedName.toLowerCase()\n const select = this.#select\n if (select && name === 'id') {\n this.#setSelectId(this.#generatedId)\n } else if (select && name.startsWith('aria-')) {\n select.removeAttribute(name)\n }\n super.removeAttribute(qualifiedName)\n }\n\n /**\n * Apply a value that was set before the first render. It stays\n * pending until an option with that value exists, so a value set\n * before the options arrive (an empty first render, then appended\n * options) still lands. A later `value` set or a user change clears\n * it.\n */\n #applyPendingValue () {\n const select = this.#select\n const pending = this.#pendingValue\n if (!select || pending === null) return\n // Write only on a match. A write with no match would clear\n // whatever is selected now, including a pick made through\n // `el.select`, with no event.\n const options = Array.from(select.options)\n if (!options.some(option => option.value === pending)) return\n select.value = pending\n this.#pendingValue = null\n }\n\n /**\n * A property set before the element was defined is an own data\n * property that hides the class accessor. Remove it and set it\n * again so the accessor sees it.\n */\n #upgradeProperty (prop:string) {\n if (!Object.prototype.hasOwnProperty.call(this, prop)) return\n const value = Reflect.get(this, prop)\n Reflect.deleteProperty(this, prop)\n Reflect.set(this, prop, value)\n }\n\n /**\n * Move options added to the host into the select, and retry a\n * waiting value when nodes were added inside the select.\n */\n #handleRecords (records:MutationRecord[]) {\n const fromHost = records.filter(record => record.target === this)\n this.#adopt(\n fromHost.flatMap(record => Array.from(record.addedNodes))\n )\n const intoSelect = records.some(record => {\n return record.target !== this && record.addedNodes.length > 0\n })\n if (intoSelect) this.#applyPendingValue()\n }\n\n /**\n * Move `<option>` and `<optgroup>` children of the host to the end of\n * the select. The component's own label and select, and anything\n * that is not an option, stay where they are.\n */\n #adopt (nodes:Node[]) {\n const select = this.#select\n if (!select) return\n let moved = false\n for (const node of nodes) {\n // already moved, or removed again before delivery\n if (node.parentNode !== this) continue\n if (!isOptionNode(node)) continue\n select.append(node)\n moved = true\n }\n // a value set before connect may be waiting for these options\n if (moved) this.#applyPendingValue()\n }\n\n #createLabel (selectId:string):HTMLLabelElement {\n const label = document.createElement('label')\n label.htmlFor = selectId\n return label\n }\n\n render () {\n if (this.#select) return\n\n const authored:(HTMLOptionElement|HTMLOptGroupElement)[] = []\n const stray:Node[] = []\n for (const node of Array.from(this.childNodes)) {\n if (isOptionNode(node)) {\n authored.push(node)\n } else if (\n node.nodeType !== Node.TEXT_NODE ||\n node.textContent?.trim()\n ) {\n stray.push(node)\n }\n }\n if (stray.length) debug('dropping non-option children', stray)\n\n // The option the parser marked selected. Reapplied after the\n // move instead of relying on insertion to keep it.\n const chosen = authored\n .flatMap(node => {\n return node instanceof HTMLOptionElement ?\n [node] :\n Array.from(node.querySelectorAll('option'))\n })\n .filter(option => option.selected)\n .pop()\n\n // DOM APIs only, so attribute values are never parsed as HTML\n const select = document.createElement('select')\n select.id = this.getAttribute('id') ?? this.#generatedId\n for (const attr of Array.from(this.attributes)) {\n if (attr.name.startsWith('aria-')) {\n select.setAttribute(attr.name, attr.value)\n }\n }\n for (const name of FORWARDED_ATTRIBUTES) {\n const value = this.getAttribute(name)\n if (value !== null) select.setAttribute(name, value)\n }\n\n // Native `change` and `input` bubble out of the host as they\n // are. Also emit the namespaced event (ADR-005).\n select.addEventListener('change', () => {\n // the user's pick replaces a value still waiting for its\n // option\n this.#pendingValue = null\n this.emit<SubstrateSelectChangeDetail>('change', {\n detail: { value: select.value }\n })\n })\n\n select.append(...authored)\n if (chosen) chosen.selected = true\n this.#select = select\n this.#applyPendingValue()\n // A value set from code wins over an authored `selected`, as on\n // a native select, so while it waits nothing is selected\n if (this.#pendingValue !== null) select.selectedIndex = -1\n\n const labelText = this.getAttribute('label')\n if (labelText) {\n this.#label = this.#createLabel(select.id)\n this.#label.textContent = labelText\n this.replaceChildren(this.#label, select)\n } else {\n this.replaceChildren(select)\n }\n\n // `super`, not `this`: strip the host only; the select keeps\n // the values. The removal callbacks this causes carry `null`,\n // which `#moveToSelect` ignores.\n super.removeAttribute('id')\n for (const attr of Array.from(this.attributes)) {\n if (attr.name.startsWith('aria-')) {\n super.removeAttribute(attr.name)\n }\n }\n }\n}\n\nSubstrateSelect.define()\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ substrate-select{--substrate-select-text:var(--substrate-text,black);--substrate-select-surface:var(--substrate-surface,white);--substrate-select-border:var(--substrate-border,#9b9b9b);--substrate-select-accent:var(--substrate-accent,#2563eb);--substrate-select-focus:var(--substrate-focus,#2563eb);--substrate-select-focus-width:var(--substrate-focus-width,2px);--substrate-select-focus-offset:var(--substrate-focus-offset,2px);--substrate-select-radius:var(--substrate-radius,0);--substrate-select-option-hover:#f3f4f6;--substrate-select-checked:#1d4ed8;--substrate-select-shadow:0 4px 12px #21212114;gap:.25rem;display:grid;& select{appearance:none;box-sizing:border-box;max-width:100%;font:inherit;color:var(--substrate-select-text);background-color:var(--substrate-select-surface);border:1px solid var(--substrate-select-border);border-radius:var(--substrate-select-radius);outline:var(--substrate-select-focus-width) solid transparent;outline-offset:var(--substrate-select-focus-offset);cursor:pointer;background-image:linear-gradient(45deg,#0000 calc(50% - .07rem),currentColor calc(50% - .07rem) calc(50% + .07rem),#0000 calc(50% + .07rem)),linear-gradient(-45deg,#0000 calc(50% - .07rem),currentColor calc(50% - .07rem) calc(50% + .07rem),#0000 calc(50% + .07rem));background-position:calc(100% - 1.4rem) calc(50% + .1rem),calc(100% - 1rem) calc(50% + .1rem);background-repeat:no-repeat;background-size:.4rem .4rem;padding:1rem 2.75rem .8rem 1rem;transition:border-color .2s,outline-color .2s;&:hover:not(:disabled){border-color:var(--substrate-select-accent)}&:focus-visible{outline-color:var(--substrate-select-focus)}&:disabled{cursor:not-allowed;opacity:.6}}@supports (appearance:base-select){& select,& select::picker(select){appearance:base-select}& select{background-image:none;align-items:center;gap:.75rem;min-block-size:calc(1lh + 1.8rem + 2px);padding-inline-end:1rem;display:flex;&::picker-icon{content:"";box-sizing:border-box;border-bottom:.125rem solid;border-right:.125rem solid;width:.5rem;height:.5rem;margin-inline-start:auto;transition:transform .2s;transform:translateY(-.125rem)rotate(45deg)}&:open::picker-icon{transform:translateY(.125rem)rotate(225deg)}& option{cursor:pointer;gap:.5rem;padding:.5rem .75rem;&:hover,&:focus-visible{background-color:var(--substrate-select-option-hover)}&:checked{color:var(--substrate-select-checked)}&::checkmark{content:"✓";color:var(--substrate-select-accent)}}}& select::picker(select){color:var(--substrate-select-text);background-color:var(--substrate-select-surface);border:1px solid var(--substrate-select-border);border-radius:var(--substrate-select-radius);box-shadow:var(--substrate-select-shadow);opacity:0;transition:opacity .15s, translate .15s, display .15s allow-discrete, overlay .15s allow-discrete;margin-block:.25rem;padding-block:.25rem;translate:0 -.5rem}& select:open::picker(select){opacity:1;translate:0}@starting-style{& select:open::picker(select){opacity:0;translate:0 -.5rem}}@media (prefers-reduced-motion:reduce){& select::picker-icon,& select::picker(select){transition:none}& select::picker(select){translate:0}}}@media (prefers-reduced-motion:reduce){& select{transition:none}}}substrate-select:not(:defined){display:none}
@@ -0,0 +1,2 @@
1
+ var te=Object.defineProperty;var o=(t,e)=>te(t,"name",{value:e,configurable:!0});var re=Object.defineProperty,ne=o((t,e)=>re(t,"name",{value:e,configurable:!0}),"__name");function H(t){return Object.keys(t).reduce((e,r)=>{let n=t[r];return n?typeof n=="boolean"?n?(e+` ${r}`).trim():e:Array.isArray(n)?e+` ${r}="${n.join(" ")}"`:(e+` ${r}="${n}"`).trim():e},"")}o(H,"toAttributes");ne(H,"toAttributes");var ie=Object.defineProperty,w=o((t,e)=>ie(t,"name",{value:e,configurable:!0}),"__name");function j(t){return document.createElement(t).constructor!==window.HTMLElement}o(j,"isRegistered");w(j,"isRegistered");function se(t,e){window&&"customElements"in window&&(j(t)||window.customElements.define(t,e))}o(se,"define");w(se,"define");var we=document.querySelector.bind(document),_e=document.querySelectorAll.bind(document);function _(t,e){return t.matches||(t=t.parentElement),t.matches(e)?t:t.closest(e)}o(_,"match");w(_,"match");var oe=Object.defineProperty,d=o((t,e)=>oe(t,"name",{value:e,configurable:!0}),"__name"),y=class t extends window.HTMLElement{static{o(this,"WebComponent")}static{d(this,"WebComponent")}static TAG="";TAG="";static reflectedBooleanAttributes=[];static reflectedStringAttributes=[];static get observedAttributes(){return[...new Set([...this.reflectedBooleanAttributes,...this.reflectedStringAttributes])]}static match(e){return _(e,this.TAG)}static create(e){let r=class extends t{static{o(this,"CreatedClass")}static{d(this,"CreatedClass")}static TAG=e;TAG=e;render(){throw new Error("`render` should be implemented by children")}};return r.define=function(){return t.define.call(this)},r.event=function(n){return t.event.call(this,n)},r}static define(){B(this.TAG,this)}attributeChangedCallback(e,r,n){let i=this[G(e)];i&&i.call(this,r,n)}connectedCallback(){this.render()}qs(e){return this.querySelector(e)}qsa(e){return this.querySelectorAll(e)}static event(e){return $(this.TAG,e)}emit(e,r={}){if(e==="*")throw new Error('Do not emit the literal "*"');let{bubbles:n=!0,cancelable:i=!0,detail:l}=r,s=`${this.TAG}:${e}`,a=new CustomEvent(s,{bubbles:n,cancelable:i,detail:l});return this.dispatchEvent(a)}dispatch(e,r={}){let n=new CustomEvent(e,{bubbles:r.bubbles===void 0?!0:r.bubbles,cancelable:r.cancelable===void 0?!0:r.cancelable,detail:r.detail});return this.dispatchEvent(n)}on(e,r,n){let i=t.event.call(this,e);this.addEventListener(i,r,n)}off(e,r,n){let i=t.event.call(this,e);this.removeEventListener(i,r,n)}};function $(t,e){return`${t}:${e}`}o($,"eventName");d($,"eventName");var q=Object.create(null);function G(t){return q[t]||(q[t]=`handleChange_${t}`)}o(G,"handlerKey");d(G,"handlerKey");function k(t){return document.createElement(t).constructor!==window.HTMLElement}o(k,"isRegistered");d(k,"isRegistered");function B(t,e){if(typeof window>"u"||!("customElements"in window)||k(t))return;let r=e,n=r.reflectedBooleanAttributes??[],i=r.reflectedStringAttributes??[],l=e.prototype;for(let s of n)s in HTMLElement.prototype||Object.getOwnPropertyDescriptor(l,s)||Object.defineProperty(l,s,{get(){return this.hasAttribute(s)},set(a){this.toggleAttribute(s,!!a)},configurable:!0,enumerable:!0});for(let s of i){if(n.includes(s)){console.warn(`[web-component] "${s}" appears in both reflectedBooleanAttributes and reflectedStringAttributes on <${t}>. Boolean wins.`);continue}s in HTMLElement.prototype||Object.getOwnPropertyDescriptor(l,s)||Object.defineProperty(l,s,{get(){return this.getAttribute(s)},set(a){a==null?this.removeAttribute(s):this.setAttribute(s,String(a))},configurable:!0,enumerable:!0})}window.customElements.define(t,e)}o(B,"define");d(B,"define");var ae=Object.defineProperty,p=o((t,e)=>ae(t,"name",{value:e,configurable:!0}),"__name"),f=1e3,h=f*60,m=h*60,u=m*24,le=u*7,ce=u*365.25;function x(t,e={}){e=e||{};let r=typeof t;if(r==="string"&&t.length>0)return V(t);if(r==="number"&&isFinite(t))return e.long?I(t):F(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}o(x,"ms_default");p(x,"default");function V(t){if(t=String(t),t.length>100)return;let e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(t);if(!e)return;let r=parseFloat(e[1]);switch((e[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return r*ce;case"weeks":case"week":case"w":return r*le;case"days":case"day":case"d":return r*u;case"hours":case"hour":case"hrs":case"hr":case"h":return r*m;case"minutes":case"minute":case"mins":case"min":case"m":return r*h;case"seconds":case"second":case"secs":case"sec":case"s":return r*f;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}o(V,"parse");p(V,"parse");function F(t){let e=Math.abs(t);return e>=u?Math.round(t/u)+"d":e>=m?Math.round(t/m)+"h":e>=h?Math.round(t/h)+"m":e>=f?Math.round(t/f)+"s":t+"ms"}o(F,"fmtShort");p(F,"fmtShort");function I(t){let e=Math.abs(t);return e>=u?g(t,e,u,"day"):e>=m?g(t,e,m,"hour"):e>=h?g(t,e,h,"minute"):e>=f?g(t,e,f,"second"):t+" ms"}o(I,"fmtLong");p(I,"fmtLong");function g(t,e,r,n){let i=e>=r*1.5;return Math.round(t/r)+" "+n+(i?"s":"")}o(g,"plural");p(g,"plural");var ue=Object.defineProperty,A=o((t,e)=>ue(t,"name",{value:e,configurable:!0}),"__name");function C(t){return t instanceof Error?t.stack||t.message:String(t)}o(C,"coerce");A(C,"coerce");function O(t,e){let r=0;for(let n=0;n<t.length;n++)r=(r<<5)-r+t.charCodeAt(n),r|=0;return e[Math.abs(r)%e.length]}o(O,"selectColor");A(O,"selectColor");function S(t){return t.split(/[\s,]+/).filter(Boolean).map(n=>n.replace(/\*/g,".*?")).map(n=>new RegExp("^"+n+"$"))}o(S,"createRegexFromEnvVar");A(S,"createRegexFromEnvVar");function T(t=6){return Math.random().toString(20).substring(2,t)}o(T,"generateRandomString");A(T,"generateRandomString");var de=Object.defineProperty,U=o((t,e)=>de(t,"name",{value:e,configurable:!0}),"__name"),b=U(function(t){},"noop");b.extend=function(t){return b};b.error=function(...t){};function fe(t){return b}o(fe,"createDebug");U(fe,"createDebug");var W=["#cc0000","#004de6","#008a00","#9900db","#dd7700","#cc0088","#61a200","#873600","#bc007d"],z="#940000";var he=Object.defineProperty,c=o((t,e)=>he(t,"name",{value:e,configurable:!0}),"__name"),me=console.log||(()=>{}),J=M;function R(t,e){if(e===!0)return!0;let r=localStorage?.getItem("DEBUG");return r==="*"?!0:t==="DEV"?!r:r?S(r).some(i=>i.test(t)):!1}o(R,"isEnabled");c(R,"isEnabled");function K(){return{j:c(function(t){try{return JSON.stringify(t)}catch(e){return"[UnexpectedJSONParseError]: "+String(e)}},"j")}}o(K,"createFormatters");c(K,"createFormatters");function L(t,e,{prevTime:r,color:n}){e=e||[];let i=Number(new Date),l=i-(r||i);r=i,e[0]=C(e[0]);let s=K();typeof e[0]!="string"&&e.unshift("%O");let a=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,(E,Y)=>{if(E==="%%")return"%";a++;let D=s[Y];if(typeof D=="function"){let ee=e[a];E=D.call(self,ee),e.splice(a,1),a--}return E});let v=X({diff:l,color:n,useColors:Z(),namespace:t},e);me(...v)}o(L,"logger");c(L,"logger");function Z(){return typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)?!1:!!(typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.webkitAppearance||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}o(Z,"shouldUseColors");c(Z,"shouldUseColors");function X({diff:t,color:e,namespace:r,useColors:n},i){if(i[0]=(n?"%c":"")+r+(n?" %c":" ")+i[0]+(n?"%c ":" ")+"+"+x(t,{}),!n)return;let l="color: "+e;i.splice(1,0,l,"color: inherit");let s=0,a=0;return i[0].replace(/%[a-zA-Z%]/g,v=>{v!=="%%"&&(s++,v==="%c"&&(a=s))}),i.splice(a,0,l),i}o(X,"formatArgs");c(X,"formatArgs");function M(t){if(t===!1)return b;let e=Number(new Date),r=O(typeof t=="string"?t:T(10),W),n=t===!0,i=typeof t=="string"?t:"DEV",l=c(function(...s){if(R(i,n))return L(i,s,{prevTime:e,color:r})},"debug");return l.extend=function(s){let a=i+":"+s;return M(a)},l.error=function(...s){if(R(i,n))return L("ERROR",s,{prevTime:e,color:z})},l}o(M,"createDebug");c(M,"createDebug");var P=J("substrate-select"),be=["aria-activedescendant","aria-atomic","aria-autocomplete","aria-braillelabel","aria-brailleroledescription","aria-busy","aria-checked","aria-colcount","aria-colindex","aria-colindextext","aria-colspan","aria-controls","aria-current","aria-describedby","aria-description","aria-details","aria-disabled","aria-dropeffect","aria-errormessage","aria-expanded","aria-flowto","aria-grabbed","aria-haspopup","aria-hidden","aria-invalid","aria-keyshortcuts","aria-label","aria-labelledby","aria-level","aria-live","aria-modal","aria-multiline","aria-multiselectable","aria-orientation","aria-owns","aria-placeholder","aria-posinset","aria-pressed","aria-readonly","aria-relevant","aria-required","aria-roledescription","aria-rowcount","aria-rowindex","aria-rowindextext","aria-rowspan","aria-selected","aria-setsize","aria-sort","aria-valuemax","aria-valuemin","aria-valuenow","aria-valuetext"],ge=["name","disabled","required","autocomplete","form"],pe=["value","label","name","disabled","required"];function Q(t){return t instanceof HTMLOptionElement||t instanceof HTMLOptGroupElement}o(Q,"isOptionNode");var N=class extends y.create("substrate-select"){static{o(this,"SubstrateSelect")}static reflectedStringAttributes=["label","name"];static reflectedBooleanAttributes=["disabled","required"];static get observedAttributes(){return[...super.observedAttributes,"id","autocomplete","form",...be]}get value(){return this.#e?this.#e.value:this.#r??""}set value(e){let r=String(e??"");if(this.#e){this.#a(Array.from(this.childNodes)),this.#r=null,this.#e.value=r;return}this.#r=r}get select(){return this.#e}#e=null;#t=null;#r=null;#n=null;#s="substrate-select-"+Math.random().toString(36).slice(2,10);connectedCallback(){P("connected");for(let e of pe)this.#f(e);this.render(),this.#a(Array.from(this.childNodes)),this.#n??=new MutationObserver(e=>{this.#c(e)}),this.#n.observe(this,{childList:!0}),this.#e&&this.#n.observe(this.#e,{childList:!0,subtree:!0})}disconnectedCallback(){P("disconnected"),this.#n&&(this.#c(this.#n.takeRecords()),this.#n.disconnect())}attributeChangedCallback(e,r,n){if(e==="id"||e.startsWith("aria-")){this.#d(e,n);return}super.attributeChangedCallback(e,r,n)}handleChange_label(e,r){let n=this.#e;if(n){if(!r){this.#t?.remove(),this.#t=null;return}this.#t||(this.#t=this.#u(n.id),this.insertBefore(this.#t,n)),this.#t.textContent=r}}handleChange_name(e,r){this.#i("name",r)}handleChange_disabled(e,r){this.#i("disabled",r)}handleChange_required(e,r){this.#i("required",r)}handleChange_autocomplete(e,r){this.#i("autocomplete",r)}handleChange_form(e,r){this.#i("form",r)}#i(e,r){let n=this.#e;n&&(r===null?n.removeAttribute(e):n.setAttribute(e,r))}#d(e,r){let n=this.#e;r===null||!n||(e==="id"?this.#l(r||this.#s):n.setAttribute(e,r),super.removeAttribute(e))}#l(e){this.#e&&(this.#e.id=e,this.#t&&(this.#t.htmlFor=e))}removeAttribute(e){let r=e.toLowerCase(),n=this.#e;n&&r==="id"?this.#l(this.#s):n&&r.startsWith("aria-")&&n.removeAttribute(r),super.removeAttribute(e)}#o(){let e=this.#e,r=this.#r;!e||r===null||!Array.from(e.options).some(i=>i.value===r)||(e.value=r,this.#r=null)}#f(e){if(!Object.prototype.hasOwnProperty.call(this,e))return;let r=Reflect.get(this,e);Reflect.deleteProperty(this,e),Reflect.set(this,e,r)}#c(e){let r=e.filter(i=>i.target===this);this.#a(r.flatMap(i=>Array.from(i.addedNodes))),e.some(i=>i.target!==this&&i.addedNodes.length>0)&&this.#o()}#a(e){let r=this.#e;if(!r)return;let n=!1;for(let i of e)i.parentNode===this&&Q(i)&&(r.append(i),n=!0);n&&this.#o()}#u(e){let r=document.createElement("label");return r.htmlFor=e,r}render(){if(this.#e)return;let e=[],r=[];for(let s of Array.from(this.childNodes))Q(s)?e.push(s):(s.nodeType!==Node.TEXT_NODE||s.textContent?.trim())&&r.push(s);r.length&&P("dropping non-option children",r);let n=e.flatMap(s=>s instanceof HTMLOptionElement?[s]:Array.from(s.querySelectorAll("option"))).filter(s=>s.selected).pop(),i=document.createElement("select");i.id=this.getAttribute("id")??this.#s;for(let s of Array.from(this.attributes))s.name.startsWith("aria-")&&i.setAttribute(s.name,s.value);for(let s of ge){let a=this.getAttribute(s);a!==null&&i.setAttribute(s,a)}i.addEventListener("change",()=>{this.#r=null,this.emit("change",{detail:{value:i.value}})}),i.append(...e),n&&(n.selected=!0),this.#e=i,this.#o(),this.#r!==null&&(i.selectedIndex=-1);let l=this.getAttribute("label");l?(this.#t=this.#u(i.id),this.#t.textContent=l,this.replaceChildren(this.#t,i)):this.replaceChildren(i),super.removeAttribute("id");for(let s of Array.from(this.attributes))s.name.startsWith("aria-")&&super.removeAttribute(s.name)}};N.define();export{be as ARIA_ATTRIBUTES,N as SubstrateSelect};
2
+ //# sourceMappingURL=index.min.js.map