@oscarpalmer/oui 0.34.0 → 0.36.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.
Files changed (93) hide show
  1. package/dist/css/combobox.css +1 -1
  2. package/dist/css/listbox.css +152 -0
  3. package/dist/js/combobox/constants.combobox.d.mts +2 -2
  4. package/dist/js/combobox/constants.combobox.mjs +40 -33
  5. package/dist/js/combobox/dom.combobox.d.mts +8 -91
  6. package/dist/js/combobox/dom.combobox.mjs +204 -2
  7. package/dist/js/combobox/event.combobox.d.mts +14 -8
  8. package/dist/js/combobox/event.combobox.mjs +2 -2
  9. package/dist/js/combobox/index.d.mts +1 -1
  10. package/dist/js/combobox/index.mjs +21 -18
  11. package/dist/js/combobox/misc.combobox.d.mts +2 -14
  12. package/dist/js/combobox/misc.combobox.mjs +2 -2
  13. package/dist/js/combobox/models.combobox.d.mts +44 -2
  14. package/dist/js/combobox/state.combobox.d.mts +9 -8
  15. package/dist/js/combobox/state.combobox.mjs +2 -2
  16. package/dist/js/constants.combobox-DmRAMC64.d.mts +26 -0
  17. package/dist/js/constants.listbox-DRsXUxd3.d.mts +14 -0
  18. package/dist/js/index-EfkUSals.d.mts +139 -0
  19. package/dist/js/index.d.mts +4 -2
  20. package/dist/js/index.mjs +4 -2
  21. package/dist/js/internal/attributable.mjs +4 -3
  22. package/dist/js/internal/listbox/listbox.constants.d.mts +11 -0
  23. package/dist/js/internal/listbox/listbox.constants.mjs +23 -0
  24. package/dist/js/internal/listbox/listbox.data.d.mts +20 -0
  25. package/dist/js/internal/listbox/listbox.data.mjs +2 -0
  26. package/dist/js/internal/listbox/listbox.dom.d.mts +66 -0
  27. package/dist/js/internal/listbox/listbox.dom.mjs +2 -0
  28. package/dist/js/internal/listbox/listbox.event.d.mts +5 -0
  29. package/dist/js/internal/listbox/listbox.event.mjs +63 -0
  30. package/dist/js/internal/listbox/listbox.form.d.mts +6 -0
  31. package/dist/js/internal/listbox/listbox.form.mjs +52 -0
  32. package/dist/js/internal/listbox/listbox.misc.d.mts +12 -0
  33. package/dist/js/internal/listbox/listbox.misc.mjs +2 -0
  34. package/dist/js/internal/listbox/listbox.model.d.mts +2 -0
  35. package/dist/js/internal/listbox/listbox.model.mjs +1 -0
  36. package/dist/js/internal/listbox/listbox.state.d.mts +7 -0
  37. package/dist/js/internal/listbox/listbox.state.mjs +40 -0
  38. package/dist/js/internal/misc.d.mts +6 -0
  39. package/dist/js/internal/misc.mjs +13 -0
  40. package/dist/js/l10n-Bn-7RcwR.d.mts +20 -0
  41. package/dist/js/l10n.d.mts +2 -0
  42. package/dist/js/l10n.mjs +80 -0
  43. package/dist/js/listbox/constants.listbox.d.mts +2 -0
  44. package/dist/js/listbox/constants.listbox.mjs +40 -0
  45. package/dist/js/listbox/event.listbox.d.mts +8 -0
  46. package/dist/js/listbox/event.listbox.mjs +2 -0
  47. package/dist/js/listbox/index.d.mts +116 -0
  48. package/dist/js/listbox/index.mjs +189 -0
  49. package/dist/js/listbox/misc.listbox.d.mts +2 -0
  50. package/dist/js/listbox/misc.listbox.mjs +2 -0
  51. package/dist/js/listbox/state.listbox.d.mts +11 -0
  52. package/dist/js/listbox/state.listbox.mjs +2 -0
  53. package/dist/js/listbox.data-BWd0PCy7.mjs +424 -0
  54. package/dist/js/listbox.model-CRReGOmu.d.mts +125 -0
  55. package/dist/js/misc.listbox-BI-XsTOf.mjs +197 -0
  56. package/dist/js/misc.listbox-gnoJhrTr.d.mts +20 -0
  57. package/dist/js/sortable/sortable.embedded.mjs +4 -2
  58. package/dist/js/state.combobox-4xq0FPCF.mjs +365 -0
  59. package/package.json +7 -3
  60. package/src/css/combobox.scss +1 -1
  61. package/src/css/listbox.scss +149 -0
  62. package/src/js/combobox/constants.combobox.ts +46 -25
  63. package/src/js/combobox/dom.combobox.ts +65 -452
  64. package/src/js/combobox/event.combobox.ts +129 -218
  65. package/src/js/combobox/index.ts +43 -30
  66. package/src/js/combobox/misc.combobox.ts +60 -94
  67. package/src/js/combobox/models.combobox.ts +7 -47
  68. package/src/js/combobox/state.combobox.ts +136 -125
  69. package/src/js/index.ts +1 -0
  70. package/src/js/internal/listbox/listbox.constants.ts +25 -0
  71. package/src/js/{combobox/data.combobox.ts → internal/listbox/listbox.data.ts} +94 -43
  72. package/src/js/internal/listbox/listbox.dom.ts +445 -0
  73. package/src/js/internal/listbox/listbox.event.ts +129 -0
  74. package/src/js/{combobox/form.combobox.ts → internal/listbox/listbox.form.ts} +33 -33
  75. package/src/js/internal/listbox/listbox.misc.ts +135 -0
  76. package/src/js/internal/listbox/listbox.model.ts +169 -0
  77. package/src/js/internal/listbox/listbox.state.ts +82 -0
  78. package/src/js/internal/misc.ts +27 -0
  79. package/src/js/l10n.ts +192 -0
  80. package/src/js/listbox/constants.listbox.ts +61 -0
  81. package/src/js/listbox/event.listbox.ts +106 -0
  82. package/src/js/listbox/index.ts +302 -0
  83. package/src/js/listbox/misc.listbox.ts +70 -0
  84. package/src/js/listbox/state.listbox.ts +196 -0
  85. package/dist/js/combobox/data.combobox.d.mts +0 -18
  86. package/dist/js/combobox/data.combobox.mjs +0 -2
  87. package/dist/js/combobox/form.combobox.d.mts +0 -6
  88. package/dist/js/combobox/form.combobox.mjs +0 -2
  89. package/dist/js/combobox/i18n.combobox.d.mts +0 -2
  90. package/dist/js/combobox/i18n.combobox.mjs +0 -2
  91. package/dist/js/constants.combobox-DqNUGBLS.d.mts +0 -243
  92. package/dist/js/data.combobox-8RwBv5ey.mjs +0 -1077
  93. package/src/js/combobox/i18n.combobox.ts +0 -179
@@ -2,32 +2,26 @@ import {setAria} from '@oscarpalmer/toretto/aria';
2
2
  import {setAttribute} from '@oscarpalmer/toretto/attribute';
3
3
  import {createElement} from '@oscarpalmer/toretto/create';
4
4
  import {getData} from '@oscarpalmer/toretto/data';
5
+ import {
6
+ createListboxFilter,
7
+ createListboxInput,
8
+ createListboxList,
9
+ createListboxMessage,
10
+ createListboxValueLabel,
11
+ type CreateListboxContent,
12
+ type CreateListboxContentParameters,
13
+ } from '../internal/listbox/listbox.dom';
14
+ import type {OuiListboxPreview} from '../internal/listbox/listbox.model';
15
+ import {getLocalization, localize} from '../l10n';
5
16
  import {
6
17
  COMBOBOX_ATTRIBUTE_ANCHOR,
7
- COMBOBOX_ATTRIBUTE_CONTENT,
8
- COMBOBOX_ATTRIBUTE_FILTER,
9
- COMBOBOX_ATTRIBUTE_FILTER_INPUT,
10
- COMBOBOX_ATTRIBUTE_HEADER,
11
- COMBOBOX_ATTRIBUTE_HIDDEN,
12
- COMBOBOX_ATTRIBUTE_LIST,
13
- COMBOBOX_ATTRIBUTE_MESSAGE,
14
- COMBOBOX_ATTRIBUTE_OPTION,
15
- COMBOBOX_ATTRIBUTE_OPTION_ACTIVE,
16
18
  COMBOBOX_ATTRIBUTE_SELECTION,
17
19
  COMBOBOX_ATTRIBUTE_SELECTION_ITEM,
18
- comboboxScrollOptions,
19
20
  } from './constants.combobox';
20
- import {updateComboboxValidity} from './form.combobox';
21
- import {getComboboxLocalization} from './i18n.combobox';
22
21
  import type {
23
- OuiComboboxAutoComplete,
24
- OuiComboboxAutoCompleteType,
25
- OuiComboboxGroup,
26
- OuiComboboxPreview,
27
22
  OuiComboboxSelection,
28
23
  OuiComboboxSelectionItem,
29
24
  OuiComboboxState,
30
- OuiComboboxType,
31
25
  } from './models.combobox';
32
26
 
33
27
  // #region Types
@@ -38,88 +32,6 @@ type CreateAnchor = {
38
32
  selection?: OuiComboboxSelection;
39
33
  };
40
34
 
41
- type CreatAnchorParameters = {
42
- autocomplete: OuiComboboxAutoComplete;
43
- id: string;
44
- label: HTMLLabelElement;
45
- multiple: boolean;
46
- select: HTMLSelectElement;
47
- type: OuiComboboxType;
48
- };
49
-
50
- type CreateContent = {
51
- element: HTMLElement;
52
- filter?: CreateFilter;
53
- list: CreateList;
54
- message: HTMLElement;
55
- };
56
-
57
- type CreateContentParameters = {
58
- autocomplete: OuiComboboxAutoComplete;
59
- id: string;
60
- label: HTMLLabelElement;
61
- multiple: boolean;
62
- select: HTMLSelectElement;
63
- type: OuiComboboxType;
64
- };
65
-
66
- type CreateFilter = {
67
- container: HTMLElement;
68
- element: HTMLInputElement;
69
- };
70
-
71
- type CreateFilterParameters = {
72
- autocomplete: OuiComboboxAutoCompleteType;
73
- id: string;
74
- label: HTMLLabelElement;
75
- type: OuiComboboxType;
76
- };
77
-
78
- type CreateGroupParameters = {
79
- autocomplete: OuiComboboxAutoComplete;
80
- group: HTMLOptGroupElement;
81
- groupOptions: HTMLOptionElement[];
82
- selected: HTMLElement[];
83
- };
84
-
85
- type CreateInputParameters = {
86
- autocomplete: OuiComboboxAutoCompleteType;
87
- id: string;
88
- label: HTMLLabelElement;
89
- type: OuiComboboxType;
90
- value: string;
91
- };
92
-
93
- type CreateList = {
94
- element: HTMLElement;
95
- groups?: OuiComboboxGroup[];
96
- options: HTMLElement[];
97
- selected: HTMLElement[];
98
- };
99
-
100
- type CreateListParameters = {
101
- autocomplete: OuiComboboxAutoComplete;
102
- id: string;
103
- label: HTMLLabelElement;
104
- multiple: boolean;
105
- select: HTMLSelectElement;
106
- };
107
-
108
- type CreateOptionParameters = {
109
- autocomplete: OuiComboboxAutoComplete;
110
- group?: string;
111
- index: number;
112
- option: HTMLOptionElement;
113
- };
114
-
115
- type CreateOptionsParameters = {
116
- autocomplete: OuiComboboxAutoComplete;
117
- group?: string;
118
- list: HTMLElement;
119
- options: HTMLOptionElement[];
120
- selected: HTMLElement[];
121
- };
122
-
123
35
  type CreateSelectionItemsParameters = {
124
36
  container: HTMLElement;
125
37
  items: OuiComboboxSelectionItem[];
@@ -131,21 +43,15 @@ type CreateSelectionItemsParameters = {
131
43
 
132
44
  // #region Functions
133
45
 
134
- export function createComboboxAnchor(parameters: CreatAnchorParameters): CreateAnchor {
135
- const {autocomplete, id, label, select, type} = parameters;
46
+ export function createComboboxAnchor(parameters: CreateListboxContentParameters): CreateAnchor {
47
+ const {select} = parameters;
136
48
 
137
49
  let container: HTMLElement | undefined;
138
50
  let element: HTMLElement;
139
51
  let selection: OuiComboboxSelection | undefined;
140
52
 
141
53
  if (parameters.type === 'autocomplete') {
142
- element = createComboboxInput({
143
- id,
144
- label,
145
- type,
146
- autocomplete: autocomplete.value,
147
- value: select.selectedOptions[0]?.textContent ?? '',
148
- });
54
+ element = createListboxInput(parameters, select.selectedOptions[0]?.textContent ?? '');
149
55
  } else {
150
56
  ({container, element, selection} = createComboboxButton(parameters));
151
57
  }
@@ -155,7 +61,7 @@ export function createComboboxAnchor(parameters: CreatAnchorParameters): CreateA
155
61
  return {container, element, selection};
156
62
  }
157
63
 
158
- export function createComboboxButton(parameters: CreatAnchorParameters): CreateAnchor {
64
+ export function createComboboxButton(parameters: CreateListboxContentParameters): CreateAnchor {
159
65
  const {id, label, multiple, select} = parameters;
160
66
 
161
67
  const element = createElement('button', {
@@ -163,7 +69,7 @@ export function createComboboxButton(parameters: CreatAnchorParameters): CreateA
163
69
  controls: `${id}_content`,
164
70
  expanded: false,
165
71
  haspopup: 'listbox',
166
- labelledby: `${label.id} ${id}`,
72
+ labelledby: `${label.id} ${id}_value`, // Non-input anchor, so no implicit value label, so we need to explicitly reference the value label
167
73
  },
168
74
  property: {
169
75
  textContent: multiple ? '' : (select.selectedOptions[0]?.textContent ?? ''),
@@ -182,15 +88,17 @@ export function createComboboxButton(parameters: CreatAnchorParameters): CreateA
182
88
  return {container, element, selection};
183
89
  }
184
90
 
185
- export function createComboboxContent(parameters: CreateContentParameters): CreateContent {
186
- const {autocomplete, id, label, multiple, select, type} = parameters;
91
+ export function createComboboxContent(
92
+ parameters: CreateListboxContentParameters,
93
+ ): CreateListboxContent {
94
+ const {id, label} = parameters;
187
95
 
188
96
  const element = createElement('div', {
189
97
  aria: {
190
98
  labelledby: label.id,
191
99
  },
192
100
  attribute: {
193
- [COMBOBOX_ATTRIBUTE_CONTENT]: '',
101
+ [parameters.attributes.content]: '',
194
102
  popover: '',
195
103
  },
196
104
  property: {
@@ -199,241 +107,18 @@ export function createComboboxContent(parameters: CreateContentParameters): Crea
199
107
  },
200
108
  });
201
109
 
202
- const filter = createComboboxFilter({id, label, type, autocomplete: autocomplete.value});
203
- const list = createComboboxList({autocomplete, id, label, multiple, select});
204
- const message = createComboboxMessage();
110
+ const filter = createListboxFilter(parameters);
111
+ const list = createListboxList(parameters);
112
+ const message = createListboxMessage(parameters.attributes.message);
113
+ const value = createListboxValueLabel(parameters.id);
205
114
 
206
115
  if (filter != null) {
207
116
  element.append(filter.container);
208
117
  }
209
118
 
210
- element.append(list.element, message);
211
-
212
- return {element, filter, list, message};
213
- }
214
-
215
- export function createComboboxFilter(parameters: CreateFilterParameters): CreateFilter | undefined {
216
- const {autocomplete, id, label, type} = parameters;
217
-
218
- if (type === 'autocomplete') {
219
- return;
220
- }
221
-
222
- const container = createElement('div', {
223
- attribute: {
224
- [COMBOBOX_ATTRIBUTE_FILTER]: '',
225
- },
226
- });
227
-
228
- const element = createComboboxInput({autocomplete, id, label, type, value: ''});
229
-
230
- setAttribute(element, COMBOBOX_ATTRIBUTE_FILTER_INPUT, '');
231
-
232
- container.append(element);
233
-
234
- return {container, element};
235
- }
236
-
237
- export function createComboboxGroup(parameters: CreateGroupParameters): OuiComboboxGroup {
238
- const {autocomplete, group, groupOptions, selected} = parameters;
239
-
240
- const element = createElement('li', {
241
- aria: {
242
- label: group.label,
243
- },
244
- property: {
245
- role: 'group',
246
- },
247
- });
248
-
249
- const list = createElement('ul', {
250
- property: {
251
- role: 'none',
252
- },
253
- });
254
-
255
- const header = createComboboxHeader(group);
256
-
257
- element.append(header, list);
258
-
259
- return {
260
- element,
261
- header,
262
- options: createComboboxOptions({
263
- autocomplete,
264
- list,
265
- selected,
266
- group: header.id,
267
- options: groupOptions,
268
- }),
269
- };
270
- }
271
-
272
- export function createComboboxHeader(group: HTMLOptGroupElement): HTMLElement {
273
- return createElement('div', {
274
- aria: {
275
- hidden: true,
276
- },
277
- attribute: {
278
- [COMBOBOX_ATTRIBUTE_HEADER]: '',
279
- },
280
- property: {
281
- id: group.id,
282
- textContent: group.label,
283
- },
284
- });
285
- }
286
-
287
- export function createComboboxInput(parameters: CreateInputParameters): HTMLInputElement {
288
- const {autocomplete, id, label, type, value} = parameters;
289
-
290
- return createElement('input', {
291
- aria: {
292
- autocomplete: autocomplete,
293
- controls: `${id}_list`,
294
- expanded: type === 'select',
295
- haspopup: 'listbox',
296
- labelledby: label.id,
297
- },
298
- attribute: {
299
- autocorrect: 'off',
300
- autocomplete: 'off',
301
- form: '',
302
- spellcheck: 'false',
303
- type: 'text',
304
- },
305
- property: {
306
- id,
307
- value,
308
- role: 'combobox',
309
- },
310
- });
311
- }
312
-
313
- export function createComboboxList(parameters: CreateListParameters): CreateList {
314
- const {autocomplete, id, label, multiple, select} = parameters;
315
-
316
- const element = createElement('ul', {
317
- aria: {
318
- labelledby: label.id,
319
- multiselectable: multiple,
320
- },
321
- attribute: {
322
- [COMBOBOX_ATTRIBUTE_LIST]: '',
323
- tabindex: -1,
324
- },
325
- property: {
326
- id: `${id}_list`,
327
- role: 'listbox',
328
- },
329
- });
330
-
331
- const children = [...select.children];
332
- const childrenLength = children.length;
333
-
334
- const options: HTMLElement[] = [];
335
- const selected: HTMLElement[] = [];
336
-
337
- let groups: OuiComboboxGroup[] | undefined;
338
-
339
- for (let childIndex = 0; childIndex < childrenLength; childIndex += 1) {
340
- const child = children[childIndex];
341
-
342
- if (child instanceof HTMLOptionElement) {
343
- const option = createComboboxOption({
344
- autocomplete,
345
- index: childIndex,
346
- option: child,
347
- });
348
-
349
- element.append(option);
350
- options.push(option);
351
-
352
- if (child.selected) {
353
- selected.push(option);
354
- }
355
-
356
- continue;
357
- }
358
-
359
- if (!(child instanceof HTMLOptGroupElement)) {
360
- continue;
361
- }
362
-
363
- const group = createComboboxGroup({
364
- autocomplete,
365
- selected,
366
- group: child,
367
- groupOptions: [...child.children] as HTMLOptionElement[],
368
- });
369
-
370
- groups ??= [];
371
-
372
- element.append(group.element, ...group.options);
373
- groups.push(group);
374
- options.push(...group.options);
375
- }
376
-
377
- return {element, groups, options, selected};
378
- }
379
-
380
- export function createComboboxMessage(): HTMLElement {
381
- return createElement('div', {
382
- aria: {
383
- live: 'polite',
384
- },
385
- attribute: {
386
- [COMBOBOX_ATTRIBUTE_MESSAGE]: '',
387
- },
388
- property: {
389
- hidden: true,
390
- role: 'status',
391
- },
392
- });
393
- }
394
-
395
- export function createComboboxOption(parameters: CreateOptionParameters): HTMLElement {
396
- const {autocomplete, group, option} = parameters;
119
+ element.append(list.element, message, value);
397
120
 
398
- return createElement('li', {
399
- aria: {
400
- selected: !autocomplete.none && option.selected,
401
- },
402
- attribute: {
403
- [COMBOBOX_ATTRIBUTE_OPTION]: '',
404
- },
405
- data: {
406
- group,
407
- value: option.value,
408
- },
409
- property: {
410
- id: option.id,
411
- role: 'option',
412
- textContent: option.textContent,
413
- },
414
- });
415
- }
416
-
417
- export function createComboboxOptions(parameters: CreateOptionsParameters): HTMLElement[] {
418
- const {autocomplete, group, list, options, selected} = parameters;
419
-
420
- const items: HTMLElement[] = [];
421
-
422
- for (let index = 0; index < options.length; index += 1) {
423
- const option = options[index];
424
-
425
- const item = createComboboxOption({autocomplete, group, index, option});
426
-
427
- items.push(item);
428
-
429
- if (option.selected) {
430
- selected.push(item);
431
- }
432
-
433
- list.append(item);
434
- }
435
-
436
- return items;
121
+ return {element, filter, list, message, value};
437
122
  }
438
123
 
439
124
  export function createComboboxSelection(
@@ -471,17 +156,31 @@ export function createComboboxSelectionItem(
471
156
  option: HTMLElement,
472
157
  state?: OuiComboboxState,
473
158
  ): OuiComboboxSelectionItem {
159
+ const optionLabel = option.textContent;
160
+ const optionValue = getData(option, 'value', false) ?? '';
161
+
474
162
  const element = createElement('li');
475
163
 
476
164
  const localization =
477
- state == null ? option.textContent : getComboboxLocalization('remove', state);
165
+ state == null
166
+ ? option.textContent
167
+ : getLocalization(
168
+ state.localizations.global,
169
+ state.host,
170
+ 'remove',
171
+ state.localizations.component,
172
+ );
478
173
 
479
174
  const button = createElement('button', {
480
175
  aria: {
481
- label:
482
- typeof localization === 'function'
483
- ? localization(option.textContent ?? '', getData(option, 'value', false) ?? '')
484
- : localization,
176
+ label: localize(
177
+ localization,
178
+ {
179
+ label: optionLabel,
180
+ value: optionValue,
181
+ },
182
+ [optionLabel, optionValue],
183
+ ),
485
184
  },
486
185
  attribute: {
487
186
  [COMBOBOX_ATTRIBUTE_SELECTION_ITEM]: '',
@@ -531,44 +230,6 @@ export function createComboboxSelectionItems(parameters: CreateSelectionItemsPar
531
230
  }
532
231
  }
533
232
 
534
- export function setComboboxDisabled(state: OuiComboboxState, value: boolean): void {
535
- state.filter.element.readOnly = state.readonly || value;
536
-
537
- setProperties('disabled', state, value);
538
- }
539
-
540
- function setProperties(
541
- key: 'disabled' | 'readonly' | 'required',
542
- state: OuiComboboxState,
543
- value: boolean,
544
- ): void {
545
- state[key] = value;
546
-
547
- const elements = [state.host, state.anchor.element, state.filter.element];
548
- const {length} = elements;
549
-
550
- for (let index = 0; index < length; index += 1) {
551
- const element = elements[index];
552
-
553
- setAria(
554
- element,
555
- key,
556
- key !== 'readonly' || !(element instanceof HTMLButtonElement) ? value : undefined,
557
- );
558
- }
559
- }
560
-
561
- export function setComboboxReadonly(state: OuiComboboxState, value: boolean): void {
562
- state.filter.element.readOnly = state.disabled || value;
563
-
564
- setProperties('readonly', state, value);
565
- }
566
-
567
- export function setComboboxRequired(state: OuiComboboxState, value: boolean): void {
568
- setProperties('required', state, value);
569
- updateComboboxValidity(state);
570
- }
571
-
572
233
  export function updateComboboxTabindices(state: OuiComboboxState, active?: HTMLElement): void {
573
234
  if (active == null || state.selection == null) {
574
235
  return;
@@ -593,24 +254,8 @@ export function updateComboboxTabindices(state: OuiComboboxState, active?: HTMLE
593
254
  next.button.focus();
594
255
  }
595
256
 
596
- export function updateComboboxAnchor(state: OuiComboboxState): void {
597
- if (!state.multiple) {
598
- return;
599
- }
600
-
601
- const localization = getComboboxLocalization('selected', state);
602
-
603
- setAria(
604
- state.anchor.element,
605
- 'label',
606
- typeof localization === 'function'
607
- ? localization(state.options.selected.length)
608
- : localization.replace('{amount}', state.options.selected.length.toString()),
609
- );
610
- }
611
-
612
257
  export function updateComboboxAutocomplete(
613
- preview: OuiComboboxPreview,
258
+ preview: OuiListboxPreview,
614
259
  state: OuiComboboxState,
615
260
  active?: HTMLElement,
616
261
  ): void {
@@ -644,51 +289,6 @@ export function updateComboboxAutocomplete(
644
289
  }
645
290
  }
646
291
 
647
- export function updateComboboxMessage(state: OuiComboboxState, visible: number): void {
648
- setAttribute(state.message, COMBOBOX_ATTRIBUTE_HIDDEN, visible > 0 ? '' : undefined);
649
-
650
- if (visible === 0) {
651
- const localization = getComboboxLocalization('empty', state);
652
-
653
- state.message.textContent = typeof localization === 'function' ? localization() : localization;
654
- } else {
655
- const localization = getComboboxLocalization('results', state);
656
-
657
- state.message.textContent =
658
- typeof localization === 'function'
659
- ? localization(visible)
660
- : localization.replace('{amount}', visible.toString());
661
- }
662
-
663
- state.message.hidden = false;
664
- }
665
-
666
- export function updateComboboxPreview(
667
- preview: OuiComboboxPreview,
668
- state: OuiComboboxState,
669
- active?: HTMLElement,
670
- ): void {
671
- const {length} = state.options.all;
672
-
673
- for (let index = 0; index < length; index += 1) {
674
- const option = state.options.all[index];
675
-
676
- setAttribute(option, COMBOBOX_ATTRIBUTE_OPTION_ACTIVE, option === active ? '' : undefined);
677
- }
678
-
679
- state.active = active;
680
-
681
- setAria(state.filter.element, 'activedescendant', state.floatable.open ? active?.id : undefined);
682
-
683
- if (state.floatable.open) {
684
- active?.scrollIntoView(comboboxScrollOptions);
685
- }
686
-
687
- if (preview !== 'none') {
688
- updateComboboxAutocomplete(preview, state, active);
689
- }
690
- }
691
-
692
292
  export function updateComboboxSelection(
693
293
  state: OuiComboboxState,
694
294
  active: HTMLElement | undefined,
@@ -701,7 +301,7 @@ export function updateComboboxSelection(
701
301
 
702
302
  let options = active == null ? [] : [active];
703
303
 
704
- if (selected != null) {
304
+ if (added && selected != null) {
705
305
  options = selected;
706
306
 
707
307
  const {length} = state.selection.items;
@@ -766,7 +366,12 @@ export function updateComboboxSelectionItems(state: OuiComboboxState): void {
766
366
  return;
767
367
  }
768
368
 
769
- const localization = getComboboxLocalization('remove', state);
369
+ const localization = getLocalization(
370
+ state.localizations.global,
371
+ state.host,
372
+ 'remove',
373
+ state.localizations.component,
374
+ );
770
375
 
771
376
  const {length} = state.selection.items;
772
377
 
@@ -781,12 +386,20 @@ export function updateComboboxSelectionItems(state: OuiComboboxState): void {
781
386
  continue;
782
387
  }
783
388
 
389
+ const optionLabel = option.textContent;
390
+ const optionValue = getData(option, 'value', false) ?? '';
391
+
784
392
  setAria(
785
393
  item.button,
786
394
  'label',
787
- typeof localization === 'function'
788
- ? localization(option?.textContent ?? '', getData(option, 'value', false) ?? '')
789
- : localization.replace('{label}', option?.textContent ?? ''),
395
+ localize(
396
+ localization,
397
+ {
398
+ label: optionLabel,
399
+ value: optionValue,
400
+ },
401
+ [optionLabel, optionValue],
402
+ ),
790
403
  );
791
404
  }
792
405
  }