html-combobox-element 0.0.6 → 0.0.8

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.
package/README.md CHANGED
@@ -45,6 +45,7 @@ This registers the `<combo-box>`, `<box-option>` and `<box-tag>` custom elements
45
45
 
46
46
  ### Differences from `<select>`
47
47
  - In `multiple` mode, the `combobox.value` lists every selected value, where `select.value` gives only the first;
48
+ - In `multiple` mode, the selected values are displayed as chips;
48
49
  - In `single`mode, the `<combo-box>` without a selected option stays empty, where a `<select>` selects its first option.
49
50
 
50
51
  ### Events – type: when
@@ -55,23 +56,24 @@ This registers the `<combo-box>`, `<box-option>` and `<box-tag>` custom elements
55
56
  - `reset`: The form was reset
56
57
 
57
58
  Read from event:
58
- - `event.target.changed`: tells whether the value differs from when it opened
59
- - `event.target.query`: tells the search field current text
60
- - `event.target.query`: the combobox selection
59
+ - `event.target.changed`: tells whether the value differs from when it opened;
60
+ - `event.target.query`: tells the search field current text;
61
+ - `event.target.value`: the combobox selection;
62
+ - `event.target.valueAsArray`: the combobox selection as an array of strings.
61
63
 
62
- Like native form controls, changes made by script dispatch no `change`.
63
- Framework bindings that assume `input` means "the value changed" need the `change` event instead.
64
+ Like native form controls, changes made by script dispatch no `change`. Framework bindings that assume `input` means "the value changed" need the `change` event instead.
64
65
 
65
66
  ### Attributes
66
67
  All `<select>`'s attributes are supported, and few extra:
67
- - `filterable`: Displays search field in picker; options are automatically filtered against input value
68
- - `searchable`: Displays search field in picker; you listen for input events and implement own filter. Usefully for fuzzy search, etc.
69
- - `placeholder`: The combobox own placeholder, shown when there is no selection
70
- - `query`: The search field input value
68
+ - `filterable`: Displays search field in picker; options are automatically filtered against input value;
69
+ - `searchable`: Displays search field in picker; you listen for input events and implement own filter. Usefully for fuzzy search, etc.;
70
+ - `placeholder`: The combobox own placeholder, shown when there is no selection;
71
+ - `query`: The search field input value.
71
72
 
72
73
  ## Options API
73
74
  Like `select.options`, `combobox.options` is a live collection too, but a fully compatible polyfill – `HTMLComboboxOptionsCollection`, because `HTMLOptionsCollection` can't be constructed or subclassed.
74
75
  The only difference between `select.options` and `combobox.options`, is that `combobox.options` will false on `instanceof HTMLOptionsCollection` check.
76
+ The `<box-option>` itself has the same API as native `<option>`. It exists, because the `<option>` can't be styled at all.
75
77
 
76
78
  ## Accessibility
77
79
  - Roles and states are set through `ElementInternals`, and mirrored as `role` and `aria`attributes, so tools that read the DOM can see it too.
@@ -144,95 +146,52 @@ That teaches it the `<select>` API of `<combo-box>` through the DOM only. Your p
144
146
  Playwright names a custom element from `<label for>` only for native controls,
145
147
  so query `getByRole('combobox', { name })` with `aria-label` or `aria-labelledby` on the `<combo-box>`, or without a name.
146
148
 
147
- ## TypeScript and JSX
148
- JSX/template type-checking only picks up custom element typings from a file in your own project - not from a package's shipped `.d.ts`.
149
- Due to this TypeScript limitation that affects any library adding custom elements to `JSX.IntrinsicElements` under the modern automatic JSX runtime – using `<combo-box>` in JSX or a Vue template needs one extra step.
150
-
151
- So, in addition to `import 'html-combobox-element'`, create and include one small file in tsconfig.json, with the snippet for your framework:
152
-
153
- <details>
154
- <summary><strong>React</strong> (<code>jsx: "react-jsx"</code>)</summary>
155
-
156
- ```ts
157
- // combo-box.d.ts
158
- declare module 'react/jsx-runtime' {
159
- namespace JSX {
160
- interface IntrinsicElements {
161
- 'combo-box': ComboboxElementAttributes;
162
- 'box-option': ComboboxOptionElementAttributes;
163
- 'box-tag': ComboboxTagElementAttributes;
164
- }
165
- }
166
- }
167
- declare module 'react/jsx-dev-runtime' {
168
- namespace JSX {
169
- interface IntrinsicElements {
170
- 'combo-box': ComboboxElementAttributes;
171
- 'box-option': ComboboxOptionElementAttributes;
172
- 'box-tag': ComboboxTagElementAttributes;
173
- }
174
- }
175
- }
176
- ```
177
-
178
- </details>
179
-
180
- <details>
181
- <summary><strong>Preact</strong> (<code>jsx: "react-jsx"</code>, <code>jsxImportSource: "preact"</code>)</summary>
182
-
183
- ```ts
184
- // combo-box.d.ts
185
- declare module 'preact/jsx-runtime' {
186
- namespace JSX {
187
- interface IntrinsicElements {
188
- 'combo-box': ComboboxElementAttributes;
189
- 'box-option': ComboboxOptionElementAttributes;
190
- 'box-tag': ComboboxTagElementAttributes;
191
- }
192
- }
193
- }
194
- ```
195
-
196
- </details>
197
-
198
- <details>
199
- <summary><strong>Solid</strong> (<code>jsx: "preserve"</code>, <code>jsxImportSource: "solid-js"</code>)</summary>
200
-
149
+ ## TypeScript and JSX frameworks
150
+ `import 'html-combobox-element'` also brings the typings for:
151
+ - `document.createElement('combo-box')`;
152
+ - `querySelector`;
153
+ - `addEventListener` with a typed `event.target`.
154
+
155
+ ### Event listeners attached through the props
156
+ The props are the same everywhere, but which handlers get called, and with what, depends on the framework:
157
+
158
+ | Handler prop | React 19 | React 18 | Vue/Preact/SolidJS |
159
+ |--------------|---|---|--------------------|
160
+ | `onInput` | SyntheticEvent | SyntheticEvent | DOM event |
161
+ | `onChange` | SyntheticEvent | never called | DOM event |
162
+ | `onsearch` | DOM event | never called | DOM event |
163
+ | `oninvalid` | DOM event | never called | DOM event |
164
+ | `onreset` | DOM event | never called | DOM event |
165
+ | `onclose` | DOM event | never called | DOM event |
166
+ | `onClose` | never called | never called | DOM event |
167
+ | `onSearch` | never called | never called | DOM event |
168
+ | `onReset` | never called | never called | DOM event |
169
+ | `onInvalid` | never called | never called | DOM event |
170
+
171
+ The `combobox.addEventListener(type, cb)` works seamlessly in all frameworks.
172
+
173
+ ### Boolean props
174
+ The `multiple`, `clearable`, `disabled`, ... behave like native ones in every framework, except that the string `'false'` is also `false`, i.e. turns the feature off.
175
+
176
+ ### React
177
+ Package ships types, for `jsx: "react-jsx"`, `"react-jsxdev"` and classic `"react"`.
178
+ Handlers are typed accordingly: `onChange`, `onInput`, `onFocus`, `onClick`, ... receive a SyntheticEvent: `event.target` is the `<combo-box>`, `event.nativeEvent` is the DOM event.
179
+
180
+ - In React 19, events it doesn't know ("close", "search") are attached as native listeners under the exact, case-sensitive name, so use `onclose` and `onsearch`.
181
+ - In React 18, listen to `change`, `close` and `search` on the element itself through the ref.
182
+ - In a project written in React, but aliased to _Preact_ at build time – types may confuse. Rely on runtime behaviour, rather than on Typescript errors.
183
+
184
+ ### Preact and SolidJS
185
+ Nothing to do, everything just work.
186
+
187
+ ### Vue
188
+ Vue template compiler treats unknown tags as Vue components by default. You must tell it to treat `<combo-box>`, `<box-option>` and `<box-tag>` tags as custom elements.
189
+
190
+ ### Monorepos and microservices
191
+ The typings are part of a TypeScript program only if the program includes this package.
192
+ A workspace package that renders `<combo-box>` but leaves the import to the app shell type-checks inside the app,
193
+ but not on its own (its CI, editor, project references).
194
+ Add a type-only import there - it's removed from the JS output, nothing is registered twice:
201
195
  ```ts
202
- // combo-box.d.ts
203
- declare module 'solid-js/jsx-runtime' {
204
- namespace JSX {
205
- interface IntrinsicElements {
206
- 'combo-box': ComboboxElementAttributes;
207
- 'box-option': ComboboxOptionElementAttributes;
208
- 'box-tag': ComboboxTagElementAttributes;
209
- }
210
- }
211
- }
196
+ import type {} from 'html-combobox-element';
212
197
  ```
213
-
214
- </details>
215
-
216
- <details>
217
- <summary><strong>Vue</strong> (SFC <code>&lt;template&gt;</code>, checked via <code>vue-tsc</code>)</summary>
218
-
219
- Vue templates aren't JSX, so they're type-checked through `GlobalComponents` instead:
220
-
221
- ```ts
222
- // combo-box.d.ts
223
- declare module 'vue' {
224
- export interface GlobalComponents {
225
- 'combo-box': new () => { $props: ComboboxElementAttributes };
226
- 'box-option': new () => { $props: ComboboxOptionElementAttributes };
227
- }
228
- }
229
-
230
- ```
231
-
232
- This checks required props and value types for props you pass; like any native custom
233
- element, Vue still allows extra/unrecognized attributes through (that's expected Vue
234
- behavior for custom elements, not a gap in this typing). The trailing `export {};` may be
235
- required here (without it the file is treated as a script, not a module, and the
236
- augmentation breaks Vue's own types).
237
-
238
- </details>
package/README.md.rej ADDED
@@ -0,0 +1,34 @@
1
+ diff a/README.md b/README.md (rejected hunks)
2
+ @@ -152,7 +152,7 @@ Nothing to add: `<combo-box>`, `<box-option>` and `<box-tag>` are typed with Rea
3
+
4
+ React wraps events in its own SyntheticEvents, so handlers are typed accordingly:
5
+ - `onChange`, `onInput`, `onFocus`, `onClick`, ... receive a SyntheticEvent: `event.target` is the `<combo-box>` (`event.target.value`, `event.target.query`), `event.nativeEvent` is the DOM event.
6
+ -- Events React doesn't know are attached by React 19 as native listeners under the exact, case-sensitive name: use `onclose` and `onsearch` (lowercase). `onClose`/`onSearch` never fire, and are type errors.
7
+ +- Events React doesn't handle for custom elements are attached by React 19 as native listeners under the exact, case-sensitive name: use `onclose`, `onsearch`, `onreset` and `oninvalid` (lowercase). `onClose`/`onSearch`/`onReset`/`onInvalid` never fire, and are type errors. (`reset` and `invalid` don't bubble, and React handles them only for its own form elements.)
8
+
9
+ ```tsx
10
+ <combo-box
11
+ @@ -170,14 +170,16 @@ With `@types/react` 18 the framework-agnostic typings are used, as in previous v
12
+ ### What each runtime does
13
+ The props are the same everywhere, but which handlers get called, and with what, depends on the framework (verified in `tests/frameworks.spec.ts`):
14
+
15
+ -| Handler prop | React 19 | React 18 | Preact (also as `preact/compat`) | Vue |
16
+ -|---|---|---|---|---|
17
+ -| `onChange` | SyntheticEvent | **never called** | DOM event | DOM event |
18
+ -| `onInput` | SyntheticEvent | SyntheticEvent | DOM event | DOM event |
19
+ -| `onClose` / `onSearch` | never called | never called | DOM event | DOM event |
20
+ -| `onclose` / `onsearch` | DOM event | never called | DOM event | DOM event |
21
+ +| Handler prop | React 19 | React 18 | Preact (also as `preact/compat`) | Solid | Vue |
22
+ +|---|---|---|---|---|---|
23
+ +| `onChange` | SyntheticEvent | **never called** | DOM event | DOM event | DOM event |
24
+ +| `onInput` | SyntheticEvent | SyntheticEvent | DOM event | DOM event | DOM event |
25
+ +| `onClose` / `onSearch` / `onReset` / `onInvalid` | never called | never called | DOM event | DOM event | DOM event |
26
+ +| `onclose` / `onsearch` / `onreset` / `oninvalid` | DOM event | never called | DOM event | DOM event | DOM event |
27
+
28
+ -With React 18, listen to `change`, `close` and `search` on the element itself:
29
+ +In Solid, `on:close` (its explicit native-listener syntax) works too.
30
+ +
31
+ +With React 18, listen to `change`, `close`, `search`, `reset` and `invalid` on the element itself:
32
+ ```tsx
33
+ function useComboboxEvent<K extends keyof ComboboxEventMap>(
34
+ ref: React.RefObject<HTMLElementTagNameMap['combo-box'] | null>,
@@ -1,2 +1,15 @@
1
- /** Transform invalid (nullish or stringed) values to correct boolean value */
1
+ /**
2
+ * An ATTRIBUTE value as a boolean: present means true (`multiple=""`, `multiple="multiple"`),
3
+ * absent (`null`) means false. The string "false" also means false, so `multiple="false"` from a
4
+ * template or a framework that stringifies values doesn't turn the feature on.
5
+ */
2
6
  export declare function toBoolean(value: any): boolean;
7
+ /**
8
+ * A PROPERTY value as a boolean, like native boolean properties (`select.multiple = ''` is false):
9
+ * JavaScript truthiness, except the string "false", which stays false as with attributes.
10
+ *
11
+ * Frameworks that set properties rely on this: Preact clears a removed or `undefined` prop with
12
+ * `element.multiple = ''`, which must turn the feature off. Attribute values (`setAttribute`,
13
+ * the initial attributes) go through `toBoolean` instead.
14
+ */
15
+ export declare function propertyToBoolean(value: unknown): boolean;
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toBoolean = toBoolean;
4
- /** Transform invalid (nullish or stringed) values to correct boolean value */
4
+ exports.propertyToBoolean = propertyToBoolean;
5
+ /**
6
+ * An ATTRIBUTE value as a boolean: present means true (`multiple=""`, `multiple="multiple"`),
7
+ * absent (`null`) means false. The string "false" also means false, so `multiple="false"` from a
8
+ * template or a framework that stringifies values doesn't turn the feature on.
9
+ */
5
10
  function toBoolean(value) {
6
11
  if (value == null || value === 'false' || value === false)
7
12
  value = false;
@@ -9,3 +14,14 @@ function toBoolean(value) {
9
14
  value = true;
10
15
  return Boolean(value);
11
16
  }
17
+ /**
18
+ * A PROPERTY value as a boolean, like native boolean properties (`select.multiple = ''` is false):
19
+ * JavaScript truthiness, except the string "false", which stays false as with attributes.
20
+ *
21
+ * Frameworks that set properties rely on this: Preact clears a removed or `undefined` prop with
22
+ * `element.multiple = ''`, which must turn the feature off. Attribute values (`setAttribute`,
23
+ * the initial attributes) go through `toBoolean` instead.
24
+ */
25
+ function propertyToBoolean(value) {
26
+ return value !== 'false' && Boolean(value);
27
+ }
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- var _a;
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.HTMLComboboxElement = void 0;
5
4
  const Combobox_markup_js_1 = require("./Combobox.markup.js");
@@ -11,7 +10,7 @@ class HTMLComboboxElement extends HTMLElement {
11
10
  // Setters (and the setAttribute/removeAttribute overrides routed to them) only normalize and write
12
11
  // the attribute; attributeChangedCallback applies the side effects, whatever changed the attribute
13
12
  // (setters, native Element.prototype methods, DevTools, other JavaScript worlds).
14
- static observedAttributes = [..._a.OWN_IDL];
13
+ static observedAttributes = [...HTMLComboboxElement.OWN_IDL];
15
14
  static #BOOLEAN_ATTRIBUTES = new Set(['required', 'disabled', 'clearable', 'multiple', 'filterable', 'searchable']);
16
15
  static observerOptions = { childList: true };
17
16
  static styleSheet = [new CSSStyleSheet];
@@ -40,7 +39,7 @@ class HTMLComboboxElement extends HTMLElement {
40
39
  this.shadowRoot = this.attachShadow({ mode: 'open' });
41
40
  this.#markup = new Combobox_markup_js_1.ComboboxMarkup(this.shadowRoot, this.#internals);
42
41
  this.shadowRoot.appendChild(Combobox_markup_js_1.ComboboxMarkup.markup.content.cloneNode(true));
43
- this.shadowRoot.adoptedStyleSheets = _a.styleSheet;
42
+ this.shadowRoot.adoptedStyleSheets = HTMLComboboxElement.styleSheet;
44
43
  this.#observer = new MutationObserver(this.#onOptionsChanges);
45
44
  this.#markup.connect();
46
45
  this.#syncPopupSemantics();
@@ -57,7 +56,7 @@ class HTMLComboboxElement extends HTMLElement {
57
56
  this.shadowRoot.addEventListener('tagcleared', this.#onClearTag);
58
57
  this.shadowRoot.addEventListener('click', this.#onOptionClick, true);
59
58
  for (const child of Array.from(this.children)) {
60
- if (_a.#isOptionLike(child)) {
59
+ if (HTMLComboboxElement.#isOptionLike(child)) {
61
60
  this.#markup.optionsContainer?.appendChild(child);
62
61
  }
63
62
  }
@@ -70,7 +69,7 @@ class HTMLComboboxElement extends HTMLElement {
70
69
  if (!this.hasAttribute('role'))
71
70
  super.setAttribute('role', 'combobox');
72
71
  this.#initialAttributesSynchronization();
73
- this.#observer.observe(this.#markup.optionsContainer, _a.observerOptions);
72
+ this.#observer.observe(this.#markup.optionsContainer, HTMLComboboxElement.observerOptions);
74
73
  this.addEventListener('keydown', this.#onKeyDown);
75
74
  this.addEventListener('click', this.#onHostClick);
76
75
  this.#markup.clearAllButton.addEventListener('click', this.#onClearAll);
@@ -104,7 +103,7 @@ class HTMLComboboxElement extends HTMLElement {
104
103
  // - Solid mostly bypasses all of them for static subtrees (see connectedCallback above),
105
104
  // but dynamic option lists still go through insert()/insertBefore().
106
105
  insertBefore = (node, referenceNode) => {
107
- if (_a.#isOptionLike(node)) {
106
+ if (HTMLComboboxElement.#isOptionLike(node)) {
108
107
  this.#markup.optionsContainer?.insertBefore(node, referenceNode);
109
108
  }
110
109
  else {
@@ -113,7 +112,7 @@ class HTMLComboboxElement extends HTMLElement {
113
112
  return node;
114
113
  };
115
114
  appendChild = (node) => {
116
- if (_a.#isOptionLike(node)) {
115
+ if (HTMLComboboxElement.#isOptionLike(node)) {
117
116
  this.#markup.optionsContainer?.appendChild(node);
118
117
  }
119
118
  else {
@@ -127,7 +126,7 @@ class HTMLComboboxElement extends HTMLElement {
127
126
  prepend = (...nodes) => {
128
127
  [...nodes].reverse().forEach(node => {
129
128
  const n = typeof node === 'string' ? new Text(node) : node;
130
- if (_a.#isOptionLike(n)) {
129
+ if (HTMLComboboxElement.#isOptionLike(n)) {
131
130
  this.#markup.optionsContainer?.insertBefore(n, this.#markup.optionsContainer.firstChild);
132
131
  }
133
132
  else {
@@ -179,7 +178,7 @@ class HTMLComboboxElement extends HTMLElement {
179
178
  // A path that skipped the setters can leave e.g. multiple="false": fix it once. The removal
180
179
  // calls back again with a valid value, which applies the change; that one isn't fixed again,
181
180
  // so this can't loop. The side effects below are safe to repeat.
182
- if (_a.#BOOLEAN_ATTRIBUTES.has(name) && newValue !== null && !(0, Boolean_attribute_value_normalizer_js_1.toBoolean)(newValue)) {
181
+ if (HTMLComboboxElement.#BOOLEAN_ATTRIBUTES.has(name) && newValue !== null && !(0, Boolean_attribute_value_normalizer_js_1.toBoolean)(newValue)) {
183
182
  super.removeAttribute(name);
184
183
  return;
185
184
  }
@@ -253,26 +252,26 @@ class HTMLComboboxElement extends HTMLElement {
253
252
  return this.hasAttribute('clearable');
254
253
  }
255
254
  set clearable(value) {
256
- super.toggleAttribute('clearable', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
255
+ super.toggleAttribute('clearable', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
257
256
  }
258
257
  get filterable() {
259
258
  return this.hasAttribute('filterable');
260
259
  }
261
260
  set filterable(value) {
262
- super.toggleAttribute('filterable', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
261
+ super.toggleAttribute('filterable', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
263
262
  }
264
263
  get searchable() {
265
264
  return this.hasAttribute('searchable');
266
265
  }
267
266
  set searchable(value) {
268
- super.toggleAttribute('searchable', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
267
+ super.toggleAttribute('searchable', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
269
268
  }
270
269
  // <select> specific properties (implements HTMLSelectElement)
271
270
  get disabled() {
272
271
  return this.hasAttribute('disabled');
273
272
  }
274
273
  set disabled(value) {
275
- super.toggleAttribute('disabled', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
274
+ super.toggleAttribute('disabled', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
276
275
  }
277
276
  get form() {
278
277
  return this.#internals.form;
@@ -291,7 +290,7 @@ class HTMLComboboxElement extends HTMLElement {
291
290
  return this.hasAttribute('multiple');
292
291
  }
293
292
  set multiple(value) {
294
- super.toggleAttribute('multiple', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
293
+ super.toggleAttribute('multiple', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
295
294
  }
296
295
  /** The options, as a live `HTMLOptionsCollection`-like list (like `select.options`) */
297
296
  get options() {
@@ -305,7 +304,7 @@ class HTMLComboboxElement extends HTMLElement {
305
304
  return this.hasAttribute('required');
306
305
  }
307
306
  set required(value) {
308
- super.toggleAttribute('required', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
307
+ super.toggleAttribute('required', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
309
308
  }
310
309
  /** Index of the first selected option, or -1. Setting it selects only that option. */
311
310
  get selectedIndex() {
@@ -396,15 +395,16 @@ class HTMLComboboxElement extends HTMLElement {
396
395
  }
397
396
  // Overwritten methods
398
397
  setAttribute(name, value) {
399
- if (_a.OWN_IDL.has(name)) {
400
- Reflect.set(this, name, value);
398
+ if (HTMLComboboxElement.OWN_IDL.has(name)) {
399
+ // through the setter, with attribute semantics: setAttribute('multiple', '') turns it on
400
+ Reflect.set(this, name, HTMLComboboxElement.#BOOLEAN_ATTRIBUTES.has(name) ? (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value) : value);
401
401
  }
402
402
  else {
403
403
  super.setAttribute(name, value);
404
404
  }
405
405
  }
406
406
  removeAttribute(name) {
407
- if (_a.#BOOLEAN_ATTRIBUTES.has(name)) {
407
+ if (HTMLComboboxElement.#BOOLEAN_ATTRIBUTES.has(name)) {
408
408
  Reflect.set(this, name, false);
409
409
  }
410
410
  else if (name === 'placeholder' || name === 'query') {
@@ -833,12 +833,13 @@ class HTMLComboboxElement extends HTMLElement {
833
833
  }
834
834
  }
835
835
  #initialAttributesSynchronization() {
836
- for (const key of _a.OWN_IDL) {
836
+ for (const key of HTMLComboboxElement.OWN_IDL) {
837
837
  // Without a value attribute, the selection comes from the options' `selected` attributes:
838
838
  // `value = null` would clear it
839
839
  if (key === 'value' && !this.hasAttribute('value'))
840
840
  continue;
841
- this[key] = this.getAttribute(key);
841
+ const attribute = this.getAttribute(key);
842
+ Reflect.set(this, key, HTMLComboboxElement.#BOOLEAN_ATTRIBUTES.has(key) ? (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(attribute) : attribute);
842
843
  }
843
844
  }
844
845
  static loadCssFromUrls(urls) {
@@ -846,17 +847,17 @@ class HTMLComboboxElement extends HTMLElement {
846
847
  }
847
848
  static loadCssFromDocumentStyleSheets() {
848
849
  if (document.readyState === 'complete') {
849
- _a.#loadDocumentStyleSheets();
850
+ HTMLComboboxElement.#loadDocumentStyleSheets();
850
851
  }
851
852
  if (document.readyState === 'loading') {
852
- document.addEventListener('DOMContentLoaded', _a.#loadDocumentStyleSheets);
853
+ document.addEventListener('DOMContentLoaded', HTMLComboboxElement.#loadDocumentStyleSheets);
853
854
  }
854
855
  if (document.readyState === 'interactive') {
855
- queueMicrotask(_a.#loadDocumentStyleSheets);
856
+ queueMicrotask(HTMLComboboxElement.#loadDocumentStyleSheets);
856
857
  }
857
858
  }
858
859
  static #loadDocumentStyleSheets() {
859
- const [innerSheet] = _a.styleSheet;
860
+ const [innerSheet] = HTMLComboboxElement.styleSheet;
860
861
  for (const outerSheet of document.styleSheets) {
861
862
  for (const rule of outerSheet.cssRules) {
862
863
  innerSheet.insertRule(rule.cssText, innerSheet.cssRules.length);
@@ -865,7 +866,6 @@ class HTMLComboboxElement extends HTMLElement {
865
866
  }
866
867
  }
867
868
  exports.HTMLComboboxElement = HTMLComboboxElement;
868
- _a = HTMLComboboxElement;
869
869
  if (!window.customElements.get('combo-box')) {
870
870
  window.customElements.define('combo-box', HTMLComboboxElement);
871
871
  }
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- var _a;
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.HTMLComboboxOptionElement = void 0;
5
4
  const Boolean_attribute_value_normalizer_js_1 = require("./Boolean.attribute.value.normalizer.js");
@@ -22,6 +21,7 @@ const Boolean_attribute_value_normalizer_js_1 = require("./Boolean.attribute.val
22
21
  */
23
22
  class HTMLComboboxOptionElement extends HTMLElement {
24
23
  static OWN_IDL = new Set(['value', 'label', 'selected', 'disabled']);
24
+ static #BOOLEAN_ATTRIBUTES = new Set(['selected', 'disabled']);
25
25
  static observedAttributes = ['selected', 'disabled'];
26
26
  static EventInit = { bubbles: true, cancelable: true, composed: true };
27
27
  #internals;
@@ -47,7 +47,7 @@ class HTMLComboboxOptionElement extends HTMLElement {
47
47
  // (<box-option label="Plum"></box-option> displays its label through CSS, see the markup styles.)
48
48
  if (!this.textContent)
49
49
  this.textContent = this.getAttribute('value') ?? '';
50
- this.dispatchEvent(new Event('optionselectedstatechange', _a.EventInit));
50
+ this.dispatchEvent(new Event('optionselectedstatechange', HTMLComboboxOptionElement.EventInit));
51
51
  }
52
52
  /** Like <option>: the value attribute, or the text when there is none */
53
53
  get value() {
@@ -79,13 +79,13 @@ class HTMLComboboxOptionElement extends HTMLElement {
79
79
  }
80
80
  // Normalization only: the side effects run in attributeChangedCallback
81
81
  set selected(value) {
82
- super.toggleAttribute('selected', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
82
+ super.toggleAttribute('selected', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
83
83
  }
84
84
  get disabled() {
85
85
  return this.hasAttribute('disabled');
86
86
  }
87
87
  set disabled(value) {
88
- super.toggleAttribute('disabled', (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value));
88
+ super.toggleAttribute('disabled', (0, Boolean_attribute_value_normalizer_js_1.propertyToBoolean)(value));
89
89
  }
90
90
  attributeChangedCallback(name, _oldValue, newValue) {
91
91
  // A path that skipped the setters can leave a value they'd never write, e.g. selected="false".
@@ -103,7 +103,7 @@ class HTMLComboboxOptionElement extends HTMLElement {
103
103
  if (name === 'selected') {
104
104
  this.#syncSelected(now);
105
105
  if (this.isConnected) {
106
- this.dispatchEvent(new Event('optionselectedstatechange', _a.EventInit));
106
+ this.dispatchEvent(new Event('optionselectedstatechange', HTMLComboboxOptionElement.EventInit));
107
107
  }
108
108
  }
109
109
  else {
@@ -139,13 +139,15 @@ class HTMLComboboxOptionElement extends HTMLElement {
139
139
  super.setAttribute('aria-selected', ariaSelected);
140
140
  }
141
141
  #initialAttributesSynchronization() {
142
- for (const key of _a.OWN_IDL) {
143
- this[key] = this.getAttribute(key);
142
+ for (const key of HTMLComboboxOptionElement.OWN_IDL) {
143
+ const attribute = this.getAttribute(key);
144
+ Reflect.set(this, key, HTMLComboboxOptionElement.#BOOLEAN_ATTRIBUTES.has(key) ? (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(attribute) : attribute);
144
145
  }
145
146
  }
146
147
  setAttribute(name, value) {
147
- if (_a.OWN_IDL.has(name)) {
148
- this[name] = value;
148
+ if (HTMLComboboxOptionElement.OWN_IDL.has(name)) {
149
+ // through the setter, with attribute semantics: setAttribute('selected', '') selects
150
+ Reflect.set(this, name, HTMLComboboxOptionElement.#BOOLEAN_ATTRIBUTES.has(name) ? (0, Boolean_attribute_value_normalizer_js_1.toBoolean)(value) : value);
149
151
  }
150
152
  else {
151
153
  super.setAttribute(name, value);
@@ -162,7 +164,6 @@ class HTMLComboboxOptionElement extends HTMLElement {
162
164
  }
163
165
  }
164
166
  exports.HTMLComboboxOptionElement = HTMLComboboxOptionElement;
165
- _a = HTMLComboboxOptionElement;
166
167
  if (!window.customElements.get('box-option')) {
167
168
  window.customElements.define('box-option', HTMLComboboxOptionElement);
168
169
  }
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- var _a;
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.HTMLComboboxOptionsCollection = void 0;
5
4
  const HTML_combobox_option_element_js_1 = require("./HTML.combobox.option.element.js");
@@ -86,7 +85,7 @@ class HTMLComboboxOptionsCollection {
86
85
  const length = Number(value) >>> 0;
87
86
  const options = Array.from(source(this).options());
88
87
  if (length > options.length) {
89
- source(this).container().append(..._a.#blankOptions(length - options.length));
88
+ source(this).container().append(...HTMLComboboxOptionsCollection.#blankOptions(length - options.length));
90
89
  }
91
90
  else {
92
91
  options.slice(length).forEach((option) => option.remove());
@@ -161,7 +160,7 @@ class HTMLComboboxOptionsCollection {
161
160
  }
162
161
  const length = this.length;
163
162
  if (index >= length) {
164
- source(this).container().append(..._a.#blankOptions(index - length), value);
163
+ source(this).container().append(...HTMLComboboxOptionsCollection.#blankOptions(index - length), value);
165
164
  return;
166
165
  }
167
166
  const current = this.item(index);
@@ -173,4 +172,3 @@ class HTMLComboboxOptionsCollection {
173
172
  }
174
173
  }
175
174
  exports.HTMLComboboxOptionsCollection = HTMLComboboxOptionsCollection;
176
- _a = HTMLComboboxOptionsCollection;