@vonage/vivid 3.0.0-next.120 → 3.0.0-next.122

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.
Files changed (118) hide show
  1. package/custom-elements.json +119 -438
  2. package/header/index.js +4 -56
  3. package/index.js +40 -39
  4. package/layout/index.js +1 -1
  5. package/lib/accordion/definition.d.ts +0 -2
  6. package/lib/accordion-item/definition.d.ts +0 -2
  7. package/lib/action-group/definition.d.ts +0 -2
  8. package/lib/avatar/definition.d.ts +0 -2
  9. package/lib/badge/definition.d.ts +1 -1
  10. package/lib/banner/definition.d.ts +0 -2
  11. package/lib/breadcrumb/definition.d.ts +0 -2
  12. package/lib/breadcrumb-item/definition.d.ts +0 -2
  13. package/lib/button/definition.d.ts +0 -2
  14. package/lib/calendar/definition.d.ts +0 -2
  15. package/lib/calendar-event/definition.d.ts +0 -2
  16. package/lib/card/definition.d.ts +0 -2
  17. package/lib/checkbox/definition.d.ts +0 -2
  18. package/lib/components.d.ts +1 -0
  19. package/lib/dialog/definition.d.ts +0 -2
  20. package/lib/divider/definition.d.ts +0 -2
  21. package/lib/elevation/definition.d.ts +0 -2
  22. package/lib/fab/definition.d.ts +1 -1
  23. package/lib/focus/definition.d.ts +1 -1
  24. package/lib/header/definition.d.ts +1 -1
  25. package/lib/icon/definition.d.ts +1 -1
  26. package/lib/layout/definition.d.ts +1 -1
  27. package/lib/listbox/definition.d.ts +1 -1
  28. package/lib/menu/definition.d.ts +6 -2
  29. package/lib/menu-item/definition.d.ts +1 -1
  30. package/lib/nav/definition.d.ts +1 -1
  31. package/lib/nav-disclosure/definition.d.ts +1 -1
  32. package/lib/nav-item/definition.d.ts +1 -1
  33. package/lib/note/definition.d.ts +1 -1
  34. package/lib/number-field/definition.d.ts +2 -1
  35. package/lib/option/definition.d.ts +1 -1
  36. package/lib/popup/definition.d.ts +1 -2
  37. package/lib/progress/definition.d.ts +1 -1
  38. package/lib/progress-ring/definition.d.ts +1 -1
  39. package/lib/radio/definition.d.ts +1 -1
  40. package/lib/radio-group/definition.d.ts +6 -2
  41. package/lib/side-drawer/definition.d.ts +1 -1
  42. package/lib/slider/definition.d.ts +1 -1
  43. package/lib/switch/definition.d.ts +1 -1
  44. package/lib/text-anchor/definition.d.ts +1 -1
  45. package/lib/text-area/definition.d.ts +1 -1
  46. package/lib/text-field/definition.d.ts +1 -1
  47. package/lib/tooltip/definition.d.ts +1 -1
  48. package/listbox/index.js +2 -2
  49. package/menu/index.js +3 -3
  50. package/menu-item/index.js +1 -1
  51. package/nav/index.js +1 -1
  52. package/nav-disclosure/index.js +1 -1
  53. package/nav-item/index.js +1 -1
  54. package/note/index.js +1 -1
  55. package/number-field/index.js +8 -8
  56. package/option/index.js +1 -1
  57. package/package.json +3 -2
  58. package/popup/index.js +1 -1
  59. package/progress/index.js +1 -1
  60. package/progress-ring/index.js +1 -1
  61. package/radio/index.js +1 -1
  62. package/radio-group/index.js +1 -1
  63. package/shared/definition.js +7 -7
  64. package/shared/definition10.js +6 -6
  65. package/shared/definition11.js +9 -9
  66. package/shared/definition12.js +7 -7
  67. package/shared/definition13.js +7 -7
  68. package/shared/definition14.js +9 -9
  69. package/shared/definition15.js +6 -6
  70. package/shared/definition16.js +9 -9
  71. package/shared/definition17.js +10 -10
  72. package/shared/definition18.js +7 -7
  73. package/shared/definition19.js +9 -9
  74. package/shared/definition2.js +9 -9
  75. package/shared/definition20.js +48 -34
  76. package/shared/definition21.js +36 -1070
  77. package/shared/definition22.js +980 -163
  78. package/shared/definition23.js +212 -299
  79. package/shared/definition24.js +311 -1492
  80. package/shared/definition25.js +1493 -315
  81. package/shared/definition26.js +348 -15
  82. package/shared/definition27.js +13 -70
  83. package/shared/definition28.js +68 -24
  84. package/shared/definition29.js +22 -47
  85. package/shared/definition3.js +6 -6
  86. package/shared/definition30.js +41 -79
  87. package/shared/definition31.js +77 -60
  88. package/shared/definition32.js +68 -36
  89. package/shared/definition33.js +32 -422
  90. package/shared/definition34.js +419 -70
  91. package/shared/definition35.js +67 -573
  92. package/shared/definition36.js +528 -83
  93. package/shared/definition37.js +88 -220
  94. package/shared/definition38.js +247 -87
  95. package/shared/definition39.js +110 -68
  96. package/shared/definition4.js +7 -7
  97. package/shared/definition40.js +77 -0
  98. package/shared/definition5.js +7 -7
  99. package/shared/definition6.js +8 -8
  100. package/shared/definition7.js +8 -8
  101. package/shared/definition8.js +9 -9
  102. package/shared/definition9.js +9 -9
  103. package/shared/design-system/index.d.ts +2 -1
  104. package/shared/form-elements.js +1 -1
  105. package/shared/index.js +2 -2
  106. package/side-drawer/index.js +1 -1
  107. package/slider/index.js +1 -1
  108. package/styles/core/all.css +1 -1
  109. package/styles/core/theme.css +1 -1
  110. package/styles/core/typography.css +1 -1
  111. package/styles/tokens/theme-dark.css +4 -4
  112. package/styles/tokens/theme-light.css +4 -4
  113. package/switch/index.js +1 -1
  114. package/text-anchor/index.js +5 -5
  115. package/text-area/index.js +1 -1
  116. package/text-field/index.js +1 -1
  117. package/tooltip/index.js +2 -2
  118. package/vivid.api.json +545 -1162
@@ -1,261 +1,1078 @@
1
- import { F as FoundationElement, V as Observable, _ as __decorate, N as observable, a as attr, b as __metadata, h as html, r as registerFactorial } from './index.js';
2
- import { i as iconElements } from './definition3.js';
3
- import { f as focusElements } from './definition4.js';
4
- import { A as AffixIconWithTrailing, a as affixIconTemplateFactory } from './affix.js';
1
+ import { F as FoundationElement, V as Observable, _ as __decorate, a as attr, N as observable, U as DOM, Z as nullableNumberConverter, Q as __classPrivateFieldGet, b as __metadata, h as html, r as registerFactory } from './index.js';
2
+ import { f as focusRegistries } from './definition4.js';
3
+ import { i as isListboxOption, l as listboxOptionRegistries } from './definition23.js';
5
4
  import { A as ARIAGlobalStatesAndProperties } from './aria-global.js';
6
- import { S as StartEnd } from './start-end.js';
7
5
  import { a as applyMixins } from './apply-mixins.js';
8
- import { i as isHTMLElement } from './dom.js';
6
+ import { a as keySpace, b as keyEscape, k as keyEnter, c as keyTab, d as keyEnd, e as keyArrowUp, f as keyArrowDown, g as keyHome } from './key-codes.js';
7
+ import { i as inRange } from './numbers.js';
8
+ import './affix.js';
9
9
  import { f as focusTemplateFactory } from './focus2.js';
10
10
  import './icon.js';
11
- import { w as when } from './when.js';
11
+ import { s as slotted } from './slotted.js';
12
12
  import { c as classNames } from './class-names.js';
13
13
 
14
14
  /**
15
- * Determines if the element is a {@link (ListboxOption:class)}
15
+ * Returns the index of the last element in the array where predicate is true, and -1 otherwise.
16
16
  *
17
- * @param element - the element to test.
18
- * @public
17
+ * @param array - the array to test
18
+ * @param predicate - find calls predicate once for each element of the array, in descending order, until it finds one where predicate returns true. If such an element is found, findLastIndex immediately returns that element index. Otherwise, findIndex returns -1.
19
19
  */
20
- function isListboxOption(el) {
21
- return (isHTMLElement(el) &&
22
- (el.getAttribute("role") === "option" ||
23
- el instanceof HTMLOptionElement));
20
+ function findLastIndex(array, predicate) {
21
+ let k = array.length;
22
+ while (k--) {
23
+ if (predicate(array[k], k, array)) {
24
+ return k;
25
+ }
26
+ }
27
+ return -1;
24
28
  }
29
+
30
+ let uniqueIdCounter = 0;
25
31
  /**
26
- * An Option Custom HTML Element.
27
- * Implements {@link https://www.w3.org/TR/wai-aria-1.1/#option | ARIA option }.
32
+ * Generates a unique ID based on incrementing a counter.
33
+ */
34
+ function uniqueId(prefix = "") {
35
+ return `${prefix}${uniqueIdCounter++}`;
36
+ }
37
+
38
+ /**
39
+ * A Listbox Custom HTML Element.
40
+ * Implements the {@link https://www.w3.org/TR/wai-aria-1.1/#listbox | ARIA listbox }.
28
41
  *
29
- * @slot start - Content which can be provided before the listbox option content
30
- * @slot end - Content which can be provided after the listbox option content
31
- * @slot - The default slot for listbox option content
32
- * @csspart content - Wraps the listbox option content
42
+ * @slot - The default slot for the listbox options
33
43
  *
34
44
  * @public
35
45
  */
36
- class ListboxOption$1 extends FoundationElement {
37
- constructor(text, value, defaultSelected, selected) {
38
- super();
46
+ class Listbox$1 extends FoundationElement {
47
+ constructor() {
48
+ super(...arguments);
49
+ /**
50
+ * The internal unfiltered list of selectable options.
51
+ *
52
+ * @internal
53
+ */
54
+ this._options = [];
39
55
  /**
40
- * The defaultSelected state of the option.
56
+ * The index of the selected option.
57
+ *
41
58
  * @public
42
59
  */
43
- this.defaultSelected = false;
60
+ this.selectedIndex = -1;
44
61
  /**
45
- * Tracks whether the "selected" property has been changed.
62
+ * A collection of the selected options.
63
+ *
64
+ * @public
65
+ */
66
+ this.selectedOptions = [];
67
+ /**
68
+ * A standard `click` event creates a `focus` event before firing, so a
69
+ * `mousedown` event is used to skip that initial focus.
70
+ *
46
71
  * @internal
47
72
  */
48
- this.dirtySelected = false;
73
+ this.shouldSkipFocus = false;
49
74
  /**
50
- * The checked state of the control.
75
+ * The current typeahead buffer string.
51
76
  *
52
- * @public
77
+ * @internal
53
78
  */
54
- this.selected = this.defaultSelected;
79
+ this.typeaheadBuffer = "";
55
80
  /**
56
- * Track whether the value has been changed from the initial value
81
+ * Flag for the typeahead timeout expiration.
82
+ *
83
+ * @internal
57
84
  */
58
- this.dirtyValue = false;
59
- if (text) {
60
- this.textContent = text;
85
+ this.typeaheadExpired = true;
86
+ /**
87
+ * The timeout ID for the typeahead handler.
88
+ *
89
+ * @internal
90
+ */
91
+ this.typeaheadTimeout = -1;
92
+ }
93
+ /**
94
+ * The first selected option.
95
+ *
96
+ * @internal
97
+ */
98
+ get firstSelectedOption() {
99
+ var _a;
100
+ return (_a = this.selectedOptions[0]) !== null && _a !== void 0 ? _a : null;
101
+ }
102
+ /**
103
+ * Returns true if there is one or more selectable option.
104
+ *
105
+ * @internal
106
+ */
107
+ get hasSelectableOptions() {
108
+ return this.options.length > 0 && !this.options.every(o => o.disabled);
109
+ }
110
+ /**
111
+ * The number of options.
112
+ *
113
+ * @public
114
+ */
115
+ get length() {
116
+ var _a, _b;
117
+ return (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
118
+ }
119
+ /**
120
+ * The list of options.
121
+ *
122
+ * @public
123
+ */
124
+ get options() {
125
+ Observable.track(this, "options");
126
+ return this._options;
127
+ }
128
+ set options(value) {
129
+ this._options = value;
130
+ Observable.notify(this, "options");
131
+ }
132
+ /**
133
+ * Flag for the typeahead timeout expiration.
134
+ *
135
+ * @deprecated use `Listbox.typeaheadExpired`
136
+ * @internal
137
+ */
138
+ get typeAheadExpired() {
139
+ return this.typeaheadExpired;
140
+ }
141
+ set typeAheadExpired(value) {
142
+ this.typeaheadExpired = value;
143
+ }
144
+ /**
145
+ * Handle click events for listbox options.
146
+ *
147
+ * @internal
148
+ */
149
+ clickHandler(e) {
150
+ const captured = e.target.closest(`option,[role=option]`);
151
+ if (captured && !captured.disabled) {
152
+ this.selectedIndex = this.options.indexOf(captured);
153
+ return true;
154
+ }
155
+ }
156
+ /**
157
+ * Ensures that the provided option is focused and scrolled into view.
158
+ *
159
+ * @param optionToFocus - The option to focus
160
+ * @internal
161
+ */
162
+ focusAndScrollOptionIntoView(optionToFocus = this.firstSelectedOption) {
163
+ // To ensure that the browser handles both `focus()` and `scrollIntoView()`, the
164
+ // timing here needs to guarantee that they happen on different frames. Since this
165
+ // function is typically called from the `openChanged` observer, `DOM.queueUpdate`
166
+ // causes the calls to be grouped into the same frame. To prevent this,
167
+ // `requestAnimationFrame` is used instead of `DOM.queueUpdate`.
168
+ if (this.contains(document.activeElement) && optionToFocus !== null) {
169
+ optionToFocus.focus();
170
+ requestAnimationFrame(() => {
171
+ optionToFocus.scrollIntoView({ block: "nearest" });
172
+ });
61
173
  }
62
- if (value) {
63
- this.initialValue = value;
174
+ }
175
+ /**
176
+ * Handles `focusin` actions for the component. When the component receives focus,
177
+ * the list of selected options is refreshed and the first selected option is scrolled
178
+ * into view.
179
+ *
180
+ * @internal
181
+ */
182
+ focusinHandler(e) {
183
+ if (!this.shouldSkipFocus && e.target === e.currentTarget) {
184
+ this.setSelectedOptions();
185
+ this.focusAndScrollOptionIntoView();
64
186
  }
65
- if (defaultSelected) {
66
- this.defaultSelected = defaultSelected;
187
+ this.shouldSkipFocus = false;
188
+ }
189
+ /**
190
+ * Returns the options which match the current typeahead buffer.
191
+ *
192
+ * @internal
193
+ */
194
+ getTypeaheadMatches() {
195
+ const pattern = this.typeaheadBuffer.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
196
+ const re = new RegExp(`^${pattern}`, "gi");
197
+ return this.options.filter((o) => o.text.trim().match(re));
198
+ }
199
+ /**
200
+ * Determines the index of the next option which is selectable, if any.
201
+ *
202
+ * @param prev - the previous selected index
203
+ * @param next - the next index to select
204
+ *
205
+ * @internal
206
+ */
207
+ getSelectableIndex(prev = this.selectedIndex, next) {
208
+ const direction = prev > next ? -1 : prev < next ? 1 : 0;
209
+ const potentialDirection = prev + direction;
210
+ let nextSelectableOption = null;
211
+ switch (direction) {
212
+ case -1: {
213
+ nextSelectableOption = this.options.reduceRight((nextSelectableOption, thisOption, index) => !nextSelectableOption &&
214
+ !thisOption.disabled &&
215
+ index < potentialDirection
216
+ ? thisOption
217
+ : nextSelectableOption, nextSelectableOption);
218
+ break;
219
+ }
220
+ case 1: {
221
+ nextSelectableOption = this.options.reduce((nextSelectableOption, thisOption, index) => !nextSelectableOption &&
222
+ !thisOption.disabled &&
223
+ index > potentialDirection
224
+ ? thisOption
225
+ : nextSelectableOption, nextSelectableOption);
226
+ break;
227
+ }
67
228
  }
68
- if (selected) {
69
- this.selected = selected;
229
+ return this.options.indexOf(nextSelectableOption);
230
+ }
231
+ /**
232
+ * Handles external changes to child options.
233
+ *
234
+ * @param source - the source object
235
+ * @param propertyName - the property
236
+ *
237
+ * @internal
238
+ */
239
+ handleChange(source, propertyName) {
240
+ switch (propertyName) {
241
+ case "selected": {
242
+ if (Listbox$1.slottedOptionFilter(source)) {
243
+ this.selectedIndex = this.options.indexOf(source);
244
+ }
245
+ this.setSelectedOptions();
246
+ break;
247
+ }
70
248
  }
71
- this.proxy = new Option(`${this.textContent}`, this.initialValue, this.defaultSelected, this.selected);
72
- this.proxy.disabled = this.disabled;
73
249
  }
74
250
  /**
75
- * Updates the ariaChecked property when the checked property changes.
251
+ * Moves focus to an option whose label matches characters typed by the user.
252
+ * Consecutive keystrokes are batched into a buffer of search text used
253
+ * to match against the set of options. If `TYPE_AHEAD_TIMEOUT_MS` passes
254
+ * between consecutive keystrokes, the search restarts.
76
255
  *
77
- * @param prev - the previous checked value
78
- * @param next - the current checked value
256
+ * @param key - the key to be evaluated
79
257
  *
80
- * @public
258
+ * @internal
81
259
  */
82
- checkedChanged(prev, next) {
83
- if (typeof next === "boolean") {
84
- this.ariaChecked = next ? "true" : "false";
260
+ handleTypeAhead(key) {
261
+ if (this.typeaheadTimeout) {
262
+ window.clearTimeout(this.typeaheadTimeout);
263
+ }
264
+ this.typeaheadTimeout = window.setTimeout(() => (this.typeaheadExpired = true), Listbox$1.TYPE_AHEAD_TIMEOUT_MS);
265
+ if (key.length > 1) {
85
266
  return;
86
267
  }
87
- this.ariaChecked = null;
268
+ this.typeaheadBuffer = `${this.typeaheadExpired ? "" : this.typeaheadBuffer}${key}`;
88
269
  }
89
270
  /**
90
- * Updates the proxy's text content when the default slot changes.
91
- * @param prev - the previous content value
92
- * @param next - the current content value
271
+ * Handles `keydown` actions for listbox navigation and typeahead.
93
272
  *
94
273
  * @internal
95
274
  */
96
- contentChanged(prev, next) {
97
- if (this.proxy instanceof HTMLOptionElement) {
98
- this.proxy.textContent = this.textContent;
275
+ keydownHandler(e) {
276
+ if (this.disabled) {
277
+ return true;
99
278
  }
100
- this.$emit("contentchange", null, { bubbles: true });
101
- }
102
- defaultSelectedChanged() {
103
- if (!this.dirtySelected) {
104
- this.selected = this.defaultSelected;
105
- if (this.proxy instanceof HTMLOptionElement) {
106
- this.proxy.selected = this.defaultSelected;
279
+ this.shouldSkipFocus = false;
280
+ const key = e.key;
281
+ switch (key) {
282
+ // Select the first available option
283
+ case keyHome: {
284
+ if (!e.shiftKey) {
285
+ e.preventDefault();
286
+ this.selectFirstOption();
287
+ }
288
+ break;
289
+ }
290
+ // Select the next selectable option
291
+ case keyArrowDown: {
292
+ if (!e.shiftKey) {
293
+ e.preventDefault();
294
+ this.selectNextOption();
295
+ }
296
+ break;
297
+ }
298
+ // Select the previous selectable option
299
+ case keyArrowUp: {
300
+ if (!e.shiftKey) {
301
+ e.preventDefault();
302
+ this.selectPreviousOption();
303
+ }
304
+ break;
305
+ }
306
+ // Select the last available option
307
+ case keyEnd: {
308
+ e.preventDefault();
309
+ this.selectLastOption();
310
+ break;
311
+ }
312
+ case keyTab: {
313
+ this.focusAndScrollOptionIntoView();
314
+ return true;
315
+ }
316
+ case keyEnter:
317
+ case keyEscape: {
318
+ return true;
319
+ }
320
+ case keySpace: {
321
+ if (this.typeaheadExpired) {
322
+ return true;
323
+ }
324
+ }
325
+ // Send key to Typeahead handler
326
+ default: {
327
+ if (key.length === 1) {
328
+ this.handleTypeAhead(`${key}`);
329
+ }
330
+ return true;
107
331
  }
108
332
  }
109
333
  }
110
- disabledChanged(prev, next) {
111
- this.ariaDisabled = this.disabled ? "true" : "false";
112
- if (this.proxy instanceof HTMLOptionElement) {
113
- this.proxy.disabled = this.disabled;
114
- }
334
+ /**
335
+ * Prevents `focusin` events from firing before `click` events when the
336
+ * element is unfocused.
337
+ *
338
+ * @internal
339
+ */
340
+ mousedownHandler(e) {
341
+ this.shouldSkipFocus = !this.contains(document.activeElement);
342
+ return true;
115
343
  }
116
- selectedAttributeChanged() {
117
- this.defaultSelected = this.selectedAttribute;
118
- if (this.proxy instanceof HTMLOptionElement) {
119
- this.proxy.defaultSelected = this.defaultSelected;
344
+ /**
345
+ * Switches between single-selection and multi-selection mode.
346
+ *
347
+ * @param prev - the previous value of the `multiple` attribute
348
+ * @param next - the next value of the `multiple` attribute
349
+ *
350
+ * @internal
351
+ */
352
+ multipleChanged(prev, next) {
353
+ this.ariaMultiSelectable = next ? "true" : null;
354
+ }
355
+ /**
356
+ * Updates the list of selected options when the `selectedIndex` changes.
357
+ *
358
+ * @param prev - the previous selected index value
359
+ * @param next - the current selected index value
360
+ *
361
+ * @internal
362
+ */
363
+ selectedIndexChanged(prev, next) {
364
+ var _a;
365
+ if (!this.hasSelectableOptions) {
366
+ this.selectedIndex = -1;
367
+ return;
120
368
  }
369
+ if (((_a = this.options[this.selectedIndex]) === null || _a === void 0 ? void 0 : _a.disabled) && typeof prev === "number") {
370
+ const selectableIndex = this.getSelectableIndex(prev, next);
371
+ const newNext = selectableIndex > -1 ? selectableIndex : prev;
372
+ this.selectedIndex = newNext;
373
+ if (next === newNext) {
374
+ this.selectedIndexChanged(next, newNext);
375
+ }
376
+ return;
377
+ }
378
+ this.setSelectedOptions();
379
+ }
380
+ /**
381
+ * Updates the selectedness of each option when the list of selected options changes.
382
+ *
383
+ * @param prev - the previous list of selected options
384
+ * @param next - the current list of selected options
385
+ *
386
+ * @internal
387
+ */
388
+ selectedOptionsChanged(prev, next) {
389
+ var _a;
390
+ const filteredNext = next.filter(Listbox$1.slottedOptionFilter);
391
+ (_a = this.options) === null || _a === void 0 ? void 0 : _a.forEach(o => {
392
+ const notifier = Observable.getNotifier(o);
393
+ notifier.unsubscribe(this, "selected");
394
+ o.selected = filteredNext.includes(o);
395
+ notifier.subscribe(this, "selected");
396
+ });
121
397
  }
122
- selectedChanged() {
123
- this.ariaSelected = this.selected ? "true" : "false";
124
- if (!this.dirtySelected) {
125
- this.dirtySelected = true;
398
+ /**
399
+ * Moves focus to the first selectable option.
400
+ *
401
+ * @public
402
+ */
403
+ selectFirstOption() {
404
+ var _a, _b;
405
+ if (!this.disabled) {
406
+ this.selectedIndex = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.findIndex(o => !o.disabled)) !== null && _b !== void 0 ? _b : -1;
126
407
  }
127
- if (this.proxy instanceof HTMLOptionElement) {
128
- this.proxy.selected = this.selected;
408
+ }
409
+ /**
410
+ * Moves focus to the last selectable option.
411
+ *
412
+ * @internal
413
+ */
414
+ selectLastOption() {
415
+ if (!this.disabled) {
416
+ this.selectedIndex = findLastIndex(this.options, o => !o.disabled);
129
417
  }
130
418
  }
131
- initialValueChanged(previous, next) {
132
- // If the value is clean and the component is connected to the DOM
133
- // then set value equal to the attribute value.
134
- if (!this.dirtyValue) {
135
- this.value = this.initialValue;
136
- this.dirtyValue = false;
419
+ /**
420
+ * Moves focus to the next selectable option.
421
+ *
422
+ * @internal
423
+ */
424
+ selectNextOption() {
425
+ if (!this.disabled && this.selectedIndex < this.options.length - 1) {
426
+ this.selectedIndex += 1;
137
427
  }
138
428
  }
139
- get label() {
140
- var _a;
141
- return (_a = this.value) !== null && _a !== void 0 ? _a : this.text;
429
+ /**
430
+ * Moves focus to the previous selectable option.
431
+ *
432
+ * @internal
433
+ */
434
+ selectPreviousOption() {
435
+ if (!this.disabled && this.selectedIndex > 0) {
436
+ this.selectedIndex = this.selectedIndex - 1;
437
+ }
142
438
  }
143
- get text() {
439
+ /**
440
+ * Updates the selected index to match the first selected option.
441
+ *
442
+ * @internal
443
+ */
444
+ setDefaultSelectedOption() {
144
445
  var _a, _b;
145
- return (_b = (_a = this.textContent) === null || _a === void 0 ? void 0 : _a.replace(/\s+/g, " ").trim()) !== null && _b !== void 0 ? _b : "";
446
+ this.selectedIndex = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.findIndex(el => el.defaultSelected)) !== null && _b !== void 0 ? _b : -1;
146
447
  }
147
- set value(next) {
148
- const newValue = `${next !== null && next !== void 0 ? next : ""}`;
149
- this._value = newValue;
150
- this.dirtyValue = true;
151
- if (this.proxy instanceof HTMLOptionElement) {
152
- this.proxy.value = newValue;
448
+ /**
449
+ * Sets an option as selected and gives it focus.
450
+ *
451
+ * @public
452
+ */
453
+ setSelectedOptions() {
454
+ var _a, _b, _c;
455
+ if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.length) {
456
+ this.selectedOptions = [this.options[this.selectedIndex]];
457
+ this.ariaActiveDescendant = (_c = (_b = this.firstSelectedOption) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : "";
458
+ this.focusAndScrollOptionIntoView();
153
459
  }
154
- Observable.notify(this, "value");
155
460
  }
156
- get value() {
157
- var _a;
158
- Observable.track(this, "value");
159
- return (_a = this._value) !== null && _a !== void 0 ? _a : this.text;
461
+ /**
462
+ * Updates the list of options and resets the selected option when the slotted option content changes.
463
+ *
464
+ * @param prev - the previous list of slotted options
465
+ * @param next - the current list of slotted options
466
+ *
467
+ * @internal
468
+ */
469
+ slottedOptionsChanged(prev, next) {
470
+ this.options = next.reduce((options, item) => {
471
+ if (isListboxOption(item)) {
472
+ options.push(item);
473
+ }
474
+ return options;
475
+ }, []);
476
+ const setSize = `${this.options.length}`;
477
+ this.options.forEach((option, index) => {
478
+ if (!option.id) {
479
+ option.id = uniqueId("option-");
480
+ }
481
+ option.ariaPosInSet = `${index + 1}`;
482
+ option.ariaSetSize = setSize;
483
+ });
484
+ if (this.$fastController.isConnected) {
485
+ this.setSelectedOptions();
486
+ this.setDefaultSelectedOption();
487
+ }
160
488
  }
161
- get form() {
162
- return this.proxy ? this.proxy.form : null;
489
+ /**
490
+ * Updates the filtered list of options when the typeahead buffer changes.
491
+ *
492
+ * @param prev - the previous typeahead buffer value
493
+ * @param next - the current typeahead buffer value
494
+ *
495
+ * @internal
496
+ */
497
+ typeaheadBufferChanged(prev, next) {
498
+ if (this.$fastController.isConnected) {
499
+ const typeaheadMatches = this.getTypeaheadMatches();
500
+ if (typeaheadMatches.length) {
501
+ const selectedIndex = this.options.indexOf(typeaheadMatches[0]);
502
+ if (selectedIndex > -1) {
503
+ this.selectedIndex = selectedIndex;
504
+ }
505
+ }
506
+ this.typeaheadExpired = false;
507
+ }
163
508
  }
164
509
  }
510
+ /**
511
+ * A static filter to include only selectable options.
512
+ *
513
+ * @param n - element to filter
514
+ * @public
515
+ */
516
+ Listbox$1.slottedOptionFilter = (n) => isListboxOption(n) && !n.hidden;
517
+ /**
518
+ * Typeahead timeout in milliseconds.
519
+ *
520
+ * @internal
521
+ */
522
+ Listbox$1.TYPE_AHEAD_TIMEOUT_MS = 1000;
165
523
  __decorate([
166
- observable
167
- ], ListboxOption$1.prototype, "checked", void 0);
524
+ attr({ mode: "boolean" })
525
+ ], Listbox$1.prototype, "disabled", void 0);
168
526
  __decorate([
169
527
  observable
170
- ], ListboxOption$1.prototype, "content", void 0);
528
+ ], Listbox$1.prototype, "selectedIndex", void 0);
171
529
  __decorate([
172
530
  observable
173
- ], ListboxOption$1.prototype, "defaultSelected", void 0);
174
- __decorate([
175
- attr({ mode: "boolean" })
176
- ], ListboxOption$1.prototype, "disabled", void 0);
177
- __decorate([
178
- attr({ attribute: "selected", mode: "boolean" })
179
- ], ListboxOption$1.prototype, "selectedAttribute", void 0);
531
+ ], Listbox$1.prototype, "selectedOptions", void 0);
180
532
  __decorate([
181
533
  observable
182
- ], ListboxOption$1.prototype, "selected", void 0);
534
+ ], Listbox$1.prototype, "slottedOptions", void 0);
183
535
  __decorate([
184
- attr({ attribute: "value", mode: "fromView" })
185
- ], ListboxOption$1.prototype, "initialValue", void 0);
536
+ observable
537
+ ], Listbox$1.prototype, "typeaheadBuffer", void 0);
186
538
  /**
187
- * States and properties relating to the ARIA `option` role.
539
+ * Includes ARIA states and properties relating to the ARIA listbox role
188
540
  *
189
541
  * @public
190
542
  */
191
- class DelegatesARIAListboxOption {
543
+ class DelegatesARIAListbox {
192
544
  }
193
545
  __decorate([
194
546
  observable
195
- ], DelegatesARIAListboxOption.prototype, "ariaChecked", void 0);
547
+ ], DelegatesARIAListbox.prototype, "ariaActiveDescendant", void 0);
548
+ __decorate([
549
+ observable
550
+ ], DelegatesARIAListbox.prototype, "ariaDisabled", void 0);
196
551
  __decorate([
197
552
  observable
198
- ], DelegatesARIAListboxOption.prototype, "ariaPosInSet", void 0);
553
+ ], DelegatesARIAListbox.prototype, "ariaExpanded", void 0);
199
554
  __decorate([
200
555
  observable
201
- ], DelegatesARIAListboxOption.prototype, "ariaSelected", void 0);
556
+ ], DelegatesARIAListbox.prototype, "ariaMultiSelectable", void 0);
557
+ applyMixins(DelegatesARIAListbox, ARIAGlobalStatesAndProperties);
558
+ applyMixins(Listbox$1, DelegatesARIAListbox);
559
+
560
+ /**
561
+ * A Listbox Custom HTML Element.
562
+ * Implements the {@link https://w3c.github.io/aria/#listbox | ARIA listbox }.
563
+ *
564
+ * @public
565
+ */
566
+ class ListboxElement extends Listbox$1 {
567
+ constructor() {
568
+ super(...arguments);
569
+ /**
570
+ * The index of the most recently checked option.
571
+ *
572
+ * @internal
573
+ * @remarks
574
+ * Multiple-selection mode only.
575
+ */
576
+ this.activeIndex = -1;
577
+ /**
578
+ * The start index when checking a range of options.
579
+ *
580
+ * @internal
581
+ */
582
+ this.rangeStartIndex = -1;
583
+ }
584
+ /**
585
+ * Returns the last checked option.
586
+ *
587
+ * @internal
588
+ */
589
+ get activeOption() {
590
+ return this.options[this.activeIndex];
591
+ }
592
+ /**
593
+ * Returns the list of checked options.
594
+ *
595
+ * @internal
596
+ */
597
+ get checkedOptions() {
598
+ var _a;
599
+ return (_a = this.options) === null || _a === void 0 ? void 0 : _a.filter(o => o.checked);
600
+ }
601
+ /**
602
+ * Returns the index of the first selected option.
603
+ *
604
+ * @internal
605
+ */
606
+ get firstSelectedOptionIndex() {
607
+ return this.options.indexOf(this.firstSelectedOption);
608
+ }
609
+ /**
610
+ * Updates the `ariaActiveDescendant` property when the active index changes.
611
+ *
612
+ * @param prev - the previous active index
613
+ * @param next - the next active index
614
+ *
615
+ * @internal
616
+ */
617
+ activeIndexChanged(prev, next) {
618
+ var _a, _b;
619
+ this.ariaActiveDescendant = (_b = (_a = this.options[next]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : "";
620
+ this.focusAndScrollOptionIntoView();
621
+ }
622
+ /**
623
+ * Toggles the checked state for the currently active option.
624
+ *
625
+ * @remarks
626
+ * Multiple-selection mode only.
627
+ *
628
+ * @internal
629
+ */
630
+ checkActiveIndex() {
631
+ if (!this.multiple) {
632
+ return;
633
+ }
634
+ const activeItem = this.activeOption;
635
+ if (activeItem) {
636
+ activeItem.checked = true;
637
+ }
638
+ }
639
+ /**
640
+ * Sets the active index to the first option and marks it as checked.
641
+ *
642
+ * @remarks
643
+ * Multi-selection mode only.
644
+ *
645
+ * @param preserveChecked - mark all options unchecked before changing the active index
646
+ *
647
+ * @internal
648
+ */
649
+ checkFirstOption(preserveChecked = false) {
650
+ if (preserveChecked) {
651
+ if (this.rangeStartIndex === -1) {
652
+ this.rangeStartIndex = this.activeIndex + 1;
653
+ }
654
+ this.options.forEach((o, i) => {
655
+ o.checked = inRange(i, this.rangeStartIndex);
656
+ });
657
+ }
658
+ else {
659
+ this.uncheckAllOptions();
660
+ }
661
+ this.activeIndex = 0;
662
+ this.checkActiveIndex();
663
+ }
664
+ /**
665
+ * Decrements the active index and sets the matching option as checked.
666
+ *
667
+ * @remarks
668
+ * Multi-selection mode only.
669
+ *
670
+ * @param preserveChecked - mark all options unchecked before changing the active index
671
+ *
672
+ * @internal
673
+ */
674
+ checkLastOption(preserveChecked = false) {
675
+ if (preserveChecked) {
676
+ if (this.rangeStartIndex === -1) {
677
+ this.rangeStartIndex = this.activeIndex;
678
+ }
679
+ this.options.forEach((o, i) => {
680
+ o.checked = inRange(i, this.rangeStartIndex, this.options.length);
681
+ });
682
+ }
683
+ else {
684
+ this.uncheckAllOptions();
685
+ }
686
+ this.activeIndex = this.options.length - 1;
687
+ this.checkActiveIndex();
688
+ }
689
+ /**
690
+ * @override
691
+ * @internal
692
+ */
693
+ connectedCallback() {
694
+ super.connectedCallback();
695
+ this.addEventListener("focusout", this.focusoutHandler);
696
+ }
697
+ /**
698
+ * @override
699
+ * @internal
700
+ */
701
+ disconnectedCallback() {
702
+ this.removeEventListener("focusout", this.focusoutHandler);
703
+ super.disconnectedCallback();
704
+ }
705
+ /**
706
+ * Increments the active index and marks the matching option as checked.
707
+ *
708
+ * @remarks
709
+ * Multiple-selection mode only.
710
+ *
711
+ * @param preserveChecked - mark all options unchecked before changing the active index
712
+ *
713
+ * @internal
714
+ */
715
+ checkNextOption(preserveChecked = false) {
716
+ if (preserveChecked) {
717
+ if (this.rangeStartIndex === -1) {
718
+ this.rangeStartIndex = this.activeIndex;
719
+ }
720
+ this.options.forEach((o, i) => {
721
+ o.checked = inRange(i, this.rangeStartIndex, this.activeIndex + 1);
722
+ });
723
+ }
724
+ else {
725
+ this.uncheckAllOptions();
726
+ }
727
+ this.activeIndex += this.activeIndex < this.options.length - 1 ? 1 : 0;
728
+ this.checkActiveIndex();
729
+ }
730
+ /**
731
+ * Decrements the active index and marks the matching option as checked.
732
+ *
733
+ * @remarks
734
+ * Multiple-selection mode only.
735
+ *
736
+ * @param preserveChecked - mark all options unchecked before changing the active index
737
+ *
738
+ * @internal
739
+ */
740
+ checkPreviousOption(preserveChecked = false) {
741
+ if (preserveChecked) {
742
+ if (this.rangeStartIndex === -1) {
743
+ this.rangeStartIndex = this.activeIndex;
744
+ }
745
+ if (this.checkedOptions.length === 1) {
746
+ this.rangeStartIndex += 1;
747
+ }
748
+ this.options.forEach((o, i) => {
749
+ o.checked = inRange(i, this.activeIndex, this.rangeStartIndex);
750
+ });
751
+ }
752
+ else {
753
+ this.uncheckAllOptions();
754
+ }
755
+ this.activeIndex -= this.activeIndex > 0 ? 1 : 0;
756
+ this.checkActiveIndex();
757
+ }
758
+ /**
759
+ * Handles click events for listbox options.
760
+ *
761
+ * @param e - the event object
762
+ *
763
+ * @override
764
+ * @internal
765
+ */
766
+ clickHandler(e) {
767
+ var _a;
768
+ if (!this.multiple) {
769
+ return super.clickHandler(e);
770
+ }
771
+ const captured = (_a = e.target) === null || _a === void 0 ? void 0 : _a.closest(`[role=option]`);
772
+ if (!captured || captured.disabled) {
773
+ return;
774
+ }
775
+ this.uncheckAllOptions();
776
+ this.activeIndex = this.options.indexOf(captured);
777
+ this.checkActiveIndex();
778
+ this.toggleSelectedForAllCheckedOptions();
779
+ return true;
780
+ }
781
+ /**
782
+ * @override
783
+ * @internal
784
+ */
785
+ focusAndScrollOptionIntoView() {
786
+ super.focusAndScrollOptionIntoView(this.activeOption);
787
+ }
788
+ /**
789
+ * In multiple-selection mode:
790
+ * If any options are selected, the first selected option is checked when
791
+ * the listbox receives focus. If no options are selected, the first
792
+ * selectable option is checked.
793
+ *
794
+ * @override
795
+ * @internal
796
+ */
797
+ focusinHandler(e) {
798
+ if (!this.multiple) {
799
+ return super.focusinHandler(e);
800
+ }
801
+ if (!this.shouldSkipFocus && e.target === e.currentTarget) {
802
+ this.uncheckAllOptions();
803
+ if (this.activeIndex === -1) {
804
+ this.activeIndex =
805
+ this.firstSelectedOptionIndex !== -1
806
+ ? this.firstSelectedOptionIndex
807
+ : 0;
808
+ }
809
+ this.checkActiveIndex();
810
+ this.setSelectedOptions();
811
+ this.focusAndScrollOptionIntoView();
812
+ }
813
+ this.shouldSkipFocus = false;
814
+ }
815
+ /**
816
+ * Unchecks all options when the listbox loses focus.
817
+ *
818
+ * @internal
819
+ */
820
+ focusoutHandler(e) {
821
+ if (this.multiple) {
822
+ this.uncheckAllOptions();
823
+ }
824
+ }
825
+ /**
826
+ * Handles keydown actions for listbox navigation and typeahead
827
+ *
828
+ * @override
829
+ * @internal
830
+ */
831
+ keydownHandler(e) {
832
+ if (!this.multiple) {
833
+ return super.keydownHandler(e);
834
+ }
835
+ if (this.disabled) {
836
+ return true;
837
+ }
838
+ const { key, shiftKey } = e;
839
+ this.shouldSkipFocus = false;
840
+ switch (key) {
841
+ // Select the first available option
842
+ case keyHome: {
843
+ this.checkFirstOption(shiftKey);
844
+ return;
845
+ }
846
+ // Select the next selectable option
847
+ case keyArrowDown: {
848
+ this.checkNextOption(shiftKey);
849
+ return;
850
+ }
851
+ // Select the previous selectable option
852
+ case keyArrowUp: {
853
+ this.checkPreviousOption(shiftKey);
854
+ return;
855
+ }
856
+ // Select the last available option
857
+ case keyEnd: {
858
+ this.checkLastOption(shiftKey);
859
+ return;
860
+ }
861
+ case keyTab: {
862
+ this.focusAndScrollOptionIntoView();
863
+ return true;
864
+ }
865
+ case keyEscape: {
866
+ this.uncheckAllOptions();
867
+ this.checkActiveIndex();
868
+ return true;
869
+ }
870
+ case keySpace: {
871
+ e.preventDefault();
872
+ if (this.typeAheadExpired) {
873
+ this.toggleSelectedForAllCheckedOptions();
874
+ return;
875
+ }
876
+ }
877
+ // Send key to Typeahead handler
878
+ default: {
879
+ if (key.length === 1) {
880
+ this.handleTypeAhead(`${key}`);
881
+ }
882
+ return true;
883
+ }
884
+ }
885
+ }
886
+ /**
887
+ * Prevents `focusin` events from firing before `click` events when the
888
+ * element is unfocused.
889
+ *
890
+ * @override
891
+ * @internal
892
+ */
893
+ mousedownHandler(e) {
894
+ if (e.offsetX >= 0 && e.offsetX <= this.scrollWidth) {
895
+ return super.mousedownHandler(e);
896
+ }
897
+ }
898
+ /**
899
+ * Switches between single-selection and multi-selection mode.
900
+ *
901
+ * @internal
902
+ */
903
+ multipleChanged(prev, next) {
904
+ var _a;
905
+ this.ariaMultiSelectable = next ? "true" : null;
906
+ (_a = this.options) === null || _a === void 0 ? void 0 : _a.forEach(o => {
907
+ o.checked = next ? false : undefined;
908
+ });
909
+ this.setSelectedOptions();
910
+ }
911
+ /**
912
+ * Sets an option as selected and gives it focus.
913
+ *
914
+ * @override
915
+ * @public
916
+ */
917
+ setSelectedOptions() {
918
+ if (!this.multiple) {
919
+ super.setSelectedOptions();
920
+ return;
921
+ }
922
+ if (this.$fastController.isConnected && this.options) {
923
+ this.selectedOptions = this.options.filter(o => o.selected);
924
+ this.focusAndScrollOptionIntoView();
925
+ }
926
+ }
927
+ /**
928
+ * Ensures the size is a positive integer when the property is updated.
929
+ *
930
+ * @param prev - the previous size value
931
+ * @param next - the current size value
932
+ *
933
+ * @internal
934
+ */
935
+ sizeChanged(prev, next) {
936
+ var _a;
937
+ const size = Math.max(0, parseInt((_a = next === null || next === void 0 ? void 0 : next.toFixed()) !== null && _a !== void 0 ? _a : "", 10));
938
+ if (size !== next) {
939
+ DOM.queueUpdate(() => {
940
+ this.size = size;
941
+ });
942
+ }
943
+ }
944
+ /**
945
+ * Toggles the selected state of the provided options. If any provided items
946
+ * are in an unselected state, all items are set to selected. If every
947
+ * provided item is selected, they are all unselected.
948
+ *
949
+ * @internal
950
+ */
951
+ toggleSelectedForAllCheckedOptions() {
952
+ const enabledCheckedOptions = this.checkedOptions.filter(o => !o.disabled);
953
+ const force = !enabledCheckedOptions.every(o => o.selected);
954
+ enabledCheckedOptions.forEach(o => (o.selected = force));
955
+ this.selectedIndex = this.options.indexOf(enabledCheckedOptions[enabledCheckedOptions.length - 1]);
956
+ this.setSelectedOptions();
957
+ }
958
+ /**
959
+ * @override
960
+ * @internal
961
+ */
962
+ typeaheadBufferChanged(prev, next) {
963
+ if (!this.multiple) {
964
+ super.typeaheadBufferChanged(prev, next);
965
+ return;
966
+ }
967
+ if (this.$fastController.isConnected) {
968
+ const typeaheadMatches = this.getTypeaheadMatches();
969
+ const activeIndex = this.options.indexOf(typeaheadMatches[0]);
970
+ if (activeIndex > -1) {
971
+ this.activeIndex = activeIndex;
972
+ this.uncheckAllOptions();
973
+ this.checkActiveIndex();
974
+ }
975
+ this.typeAheadExpired = false;
976
+ }
977
+ }
978
+ /**
979
+ * Unchecks all options.
980
+ *
981
+ * @remarks
982
+ * Multiple-selection mode only.
983
+ *
984
+ * @param preserveChecked - reset the rangeStartIndex
985
+ *
986
+ * @internal
987
+ */
988
+ uncheckAllOptions(preserveChecked = false) {
989
+ this.options.forEach(o => (o.checked = this.multiple ? false : undefined));
990
+ if (!preserveChecked) {
991
+ this.rangeStartIndex = -1;
992
+ }
993
+ }
994
+ }
202
995
  __decorate([
203
996
  observable
204
- ], DelegatesARIAListboxOption.prototype, "ariaSetSize", void 0);
205
- applyMixins(DelegatesARIAListboxOption, ARIAGlobalStatesAndProperties);
206
- applyMixins(ListboxOption$1, StartEnd, DelegatesARIAListboxOption);
997
+ ], ListboxElement.prototype, "activeIndex", void 0);
998
+ __decorate([
999
+ attr({ mode: "boolean" })
1000
+ ], ListboxElement.prototype, "multiple", void 0);
1001
+ __decorate([
1002
+ attr({ converter: nullableNumberConverter })
1003
+ ], ListboxElement.prototype, "size", void 0);
207
1004
 
208
- class ListboxOption extends ListboxOption$1 {
209
- set text(value) {
210
- this._text = value;
1005
+ var _Listbox_instances, _Listbox_disableSlottedChildren;
1006
+ class Listbox extends ListboxElement {
1007
+ constructor() {
1008
+ super(...arguments);
1009
+ _Listbox_instances.add(this);
1010
+ }
1011
+ slottedOptionsChanged(prev, next) {
1012
+ super.slottedOptionsChanged(prev, next);
1013
+ __classPrivateFieldGet(this, _Listbox_instances, "m", _Listbox_disableSlottedChildren).call(this);
211
1014
  }
212
- get text() {
213
- var _a;
214
- return (_a = this._text) !== null && _a !== void 0 ? _a : '';
1015
+ attributeChangedCallback(name, oldValue, newValue) {
1016
+ super.attributeChangedCallback(name, oldValue, newValue);
1017
+ if (name === 'disabled') {
1018
+ __classPrivateFieldGet(this, _Listbox_instances, "m", _Listbox_disableSlottedChildren).call(this);
1019
+ }
215
1020
  }
216
1021
  }
217
- __decorate([attr({
218
- attribute: 'text'
219
- }), __metadata("design:type", String)], ListboxOption.prototype, "_text", void 0);
220
- applyMixins(ListboxOption, AffixIconWithTrailing);
1022
+ _Listbox_instances = new WeakSet(), _Listbox_disableSlottedChildren = function _Listbox_disableSlottedChildren() {
1023
+ this.options.forEach(optionElement => {
1024
+ if (!optionElement.disabled) {
1025
+ optionElement.disabled = this.disabled;
1026
+ }
1027
+ });
1028
+ };
1029
+ __decorate([attr, __metadata("design:type", String)], Listbox.prototype, "appearance", void 0);
221
1030
 
222
1031
  let _ = t => t,
223
- _t,
224
- _t2;
1032
+ _t;
225
1033
  const getClasses = ({
226
- icon,
227
- disabled,
228
- selected,
229
- checked
230
- }) => classNames('base', ['disabled', disabled], ['selected', Boolean(selected)], ['active', Boolean(checked)], ['icon', Boolean(icon)]);
231
- const ListboxOptionTemplate = context => {
232
- const affixIconTemplate = affixIconTemplateFactory(context);
1034
+ appearance,
1035
+ disabled
1036
+ }) => classNames('base', ['disabled', disabled], [`appearance-${appearance}`, Boolean(appearance)]);
1037
+ const ListboxTemplate = context => {
233
1038
  const focusTemplate = focusTemplateFactory(context);
234
1039
  return html(_t || (_t = _`
235
- <template
236
- aria-checked="${0}"
237
- aria-disabled="${0}"
238
- aria-posinset="${0}"
239
- aria-selected="${0}"
240
- aria-setsize="${0}"
241
- role="option">
242
- <div class="${0}">
243
- ${0}
244
- ${0}
1040
+ <template
1041
+ aria-activedescendant="${0}"
1042
+ aria-multiselectable="${0}"
1043
+ aria-label="listbox"
1044
+ role="listbox"
1045
+ @click="${0}"
1046
+ @focusin="${0}"
1047
+ @keydown="${0}"
1048
+ @mousedown="${0}"
1049
+ tabindex="${0}"
1050
+ >
1051
+ <div
1052
+ class="${0}"
1053
+ >
1054
+ ${0}
1055
+
1056
+ <slot
245
1057
  ${0}
246
- </div>
247
- </template>
248
- `), x => x.ariaChecked, x => x.ariaDisabled, x => x.ariaPosInSet, x => x.ariaSelected, x => x.ariaSetSize, getClasses, () => focusTemplate, x => affixIconTemplate(x.icon), when(x => x.text, html(_t2 || (_t2 = _`<div class="text">${0}</div>`), x => x.text)));
1058
+ ></slot>
1059
+ </div>
1060
+ </template>
1061
+ `), x => x.ariaActiveDescendant, x => x.ariaMultiSelectable, (x, c) => x.clickHandler(c.event), (x, c) => x.focusinHandler(c.event), (x, c) => x.keydownHandler(c.event), (x, c) => x.mousedownHandler(c.event), x => !x.disabled ? '0' : null, getClasses, () => focusTemplate, slotted({
1062
+ filter: ListboxElement.slottedOptionFilter,
1063
+ flatten: true,
1064
+ property: 'slottedOptions'
1065
+ }));
249
1066
  };
250
1067
 
251
- var css_248z = "/**\n * Do not edit directly\n * Generated on Wed, 14 Dec 2022 16:38:57 GMT\n */\n.base {\n position: relative; /* this is needed for the focus */\n display: flex;\n box-sizing: border-box;\n align-items: center;\n background-color: var(--_appearance-color-fill);\n border-radius: 6px;\n box-shadow: inset 0 0 0 1px var(--_appearance-color-outline);\n color: var(--_appearance-color-text);\n font: var(--vvd-typography-base);\n gap: 12px;\n hyphens: auto;\n inline-size: 100%;\n min-block-size: calc(1px * (40 + 4 * clamp(-1, var(--vvd-size-density, 0), 2)));\n padding-block: 10px;\n padding-inline: 16px;\n vertical-align: middle;\n word-break: break-word;\n}\n.base {\n --_connotation-color-primary: var(--vvd-color-canvas-text);\n --_connotation-color-primary-text: var(--vvd-color-canvas);\n --_connotation-color-primary-increment: var(--vvd-color-neutral-800);\n --_connotation-color-faint: var(--vvd-color-neutral-50);\n --_connotation-color-soft: var(--vvd-color-neutral-100);\n}\n.base {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: transparent;\n --_appearance-color-outline: transparent;\n}\n.base:where(:hover, .hover):where(:not(:disabled, .disabled, .readonly)) {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: var(--_connotation-color-faint);\n --_appearance-color-outline: transparent;\n}\n.base:where(:disabled, .disabled) {\n --_appearance-color-text: var(--vvd-color-neutral-400);\n --_appearance-color-fill: transparent;\n --_appearance-color-outline: transparent;\n}\n.base:where(:active, .active):where(:not(:disabled, .disabled)) {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: var(--_connotation-color-soft);\n --_appearance-color-outline: transparent;\n}\n.base:where(.selected, [aria-current]):where(:not(:disabled, .disabled, :hover, .hover)) {\n --_appearance-color-text: var(--_connotation-color-primary-text);\n --_appearance-color-fill: var(--_connotation-color-primary);\n --_appearance-color-outline: transparent;\n}\n.base:where(.selected, [aria-current]):where(:hover, .hover) {\n --_appearance-color-text: var(--_connotation-color-primary-text);\n --_appearance-color-fill: var(--_connotation-color-primary-increment);\n --_appearance-color-outline: transparent;\n}\n@supports (user-select: none) {\n .base {\n user-select: none;\n }\n}\n.base:not(.disabled) {\n cursor: pointer;\n}\n.base.disabled {\n cursor: not-allowed;\n}\n.base .text {\n font: var(--vvd-typography-base);\n}\n\n.icon {\n font-size: 20px;\n}\n.base:not(.disabled, .selected) .icon {\n color: var(--vvd-color-neutral-600);\n}\n\n.focus-indicator {\n --focus-stroke-color: var(--vvd-color-neutral-500);\n --focus-stroke-gap-color: transparent;\n}\n:host(:not([aria-checked=true])) .focus-indicator {\n display: none;\n}";
1068
+ var css_248z = "/**\n * Do not edit directly\n * Generated on Sun, 18 Dec 2022 17:21:55 GMT\n */\n:host {\n display: block;\n}\n\n:host(:focus-within) {\n outline: none;\n}\n\n.base {\n position: relative;\n padding: 4px;\n background-color: var(--_appearance-color-fill);\n border-radius: 6px;\n box-shadow: inset 0 0 0 1px var(--_appearance-color-outline);\n contain: paint;\n}\n.base {\n --_connotation-color-backdrop: var(--vvd-color-canvas);\n --_connotation-color-intermediate: var(--vvd-color-neutral-500);\n --_connotation-color-primary: var(--vvd-color-canvas-text);\n --_connotation-color-soft: var(--vvd-color-neutral-100);\n}\n.base {\n --_appearance-color-text: var(--vvd-color-canvas-text);\n --_appearance-color-fill: var(--_connotation-color-backdrop);\n --_appearance-color-outline: var(--_connotation-color-intermediate);\n}\n.base.appearance-ghost {\n --_appearance-color-text: var(--_connotation-color-primary);\n --_appearance-color-fill: transparent;\n --_appearance-color-outline: transparent;\n}\n.base:where(:disabled, .disabled) {\n --_appearance-color-text: var(--vvd-color-neutral-400);\n --_appearance-color-fill: var(--vvd-color-neutral-200);\n --_appearance-color-outline: var(--vvd-color-neutral-400);\n}\n.base:where(:disabled, .disabled).appearance-ghost {\n --_appearance-color-text: var(--vvd-color-neutral-400);\n --_appearance-color-fill: transparent;\n --_appearance-color-outline: transparent;\n}\n\n.focus-indicator {\n pointer-events: none;\n}\n:host(:not(:focus-within)) .focus-indicator {\n display: none;\n}\n\nslot {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}";
252
1069
 
253
- const listboxOption = ListboxOption.compose({
254
- baseName: 'option',
255
- template: ListboxOptionTemplate,
1070
+ const listboxDefinition = Listbox.compose({
1071
+ baseName: 'listbox',
1072
+ template: ListboxTemplate,
256
1073
  styles: css_248z
257
- })();
258
- const listboxOptionElements = [listboxOption, ...iconElements, ...focusElements];
259
- const registerOption = registerFactorial(listboxOptionElements);
1074
+ });
1075
+ const listboxRegistries = [listboxDefinition(), ...listboxOptionRegistries, ...focusRegistries];
1076
+ const registerListbox = registerFactory(listboxRegistries);
260
1077
 
261
- export { listboxOption as a, isListboxOption as i, listboxOptionElements as l, registerOption as r };
1078
+ export { listboxRegistries as a, listboxDefinition as l, registerListbox as r };