@oscarpalmer/oui 0.34.0 → 0.35.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.
- package/dist/js/combobox/constants.combobox.d.mts +1 -1
- package/dist/js/combobox/data.combobox.d.mts +1 -1
- package/dist/js/combobox/data.combobox.mjs +1 -1
- package/dist/js/combobox/dom.combobox.d.mts +1 -1
- package/dist/js/combobox/dom.combobox.mjs +1 -1
- package/dist/js/combobox/event.combobox.d.mts +1 -1
- package/dist/js/combobox/event.combobox.mjs +1 -1
- package/dist/js/combobox/form.combobox.d.mts +1 -1
- package/dist/js/combobox/form.combobox.mjs +1 -1
- package/dist/js/combobox/index.d.mts +1 -1
- package/dist/js/combobox/index.mjs +3 -2
- package/dist/js/combobox/misc.combobox.d.mts +2 -14
- package/dist/js/combobox/misc.combobox.mjs +2 -2
- package/dist/js/combobox/models.combobox.d.mts +1 -1
- package/dist/js/combobox/state.combobox.d.mts +4 -2
- package/dist/js/combobox/state.combobox.mjs +2 -2
- package/dist/js/{constants.combobox-DqNUGBLS.d.mts → constants.combobox-h_kyDegw.d.mts} +12 -7
- package/dist/js/{data.combobox-8RwBv5ey.mjs → data.combobox-B8HMkDOh.mjs} +245 -292
- package/dist/js/index.d.mts +1 -1
- package/dist/js/index.mjs +1 -1
- package/dist/js/l10n.d.mts +20 -0
- package/dist/js/l10n.mjs +80 -0
- package/package.json +1 -1
- package/src/js/combobox/dom.combobox.ts +57 -26
- package/src/js/combobox/form.combobox.ts +26 -25
- package/src/js/combobox/index.ts +10 -4
- package/src/js/combobox/misc.combobox.ts +50 -0
- package/src/js/combobox/state.combobox.ts +13 -1
- package/src/js/l10n.ts +192 -0
- package/dist/js/combobox/i18n.combobox.d.mts +0 -2
- package/dist/js/combobox/i18n.combobox.mjs +0 -2
- package/src/js/combobox/i18n.combobox.ts +0 -179
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createEmbeddedFloatable } from "./floatable/floatable.embedded.mjs";
|
|
2
|
+
import { getLocalization, getLocalizations, localize, updateLocalizations } from "./l10n.mjs";
|
|
2
3
|
import { COMBOBOX_ATTRIBUTE_ANCHOR, COMBOBOX_ATTRIBUTE_CONTENT, COMBOBOX_ATTRIBUTE_FILTER, COMBOBOX_ATTRIBUTE_FILTER_INPUT, COMBOBOX_ATTRIBUTE_HEADER, COMBOBOX_ATTRIBUTE_HIDDEN, COMBOBOX_ATTRIBUTE_LIST, COMBOBOX_ATTRIBUTE_MESSAGE, COMBOBOX_ATTRIBUTE_OPTION, COMBOBOX_ATTRIBUTE_OPTION_ACTIVE, COMBOBOX_ATTRIBUTE_SELECTION, COMBOBOX_ATTRIBUTE_SELECTION_ITEM, COMBOBOX_AUTOCOMPLETES, COMBOBOX_KEYS_ACTIVATION, COMBOBOX_KEYS_NAVIGATION, COMBOBOX_KEYS_SELECTION, COMBOBOX_MESSAGE_LABEL, COMBOBOX_MESSAGE_SELECT, COMBOBOX_SELECTOR_ANCHOR, COMBOBOX_SELECTOR_OPTION, COMBOBOX_SELECTOR_SELECTION_ITEM, COMBOBOX_TAGNAME, COMBOBOX_TYPES, comboboxScrollOptions } from "./combobox/constants.combobox.mjs";
|
|
3
4
|
import { getAria, setAria } from "@oscarpalmer/toretto/aria";
|
|
4
5
|
import { dispatch, on } from "@oscarpalmer/toretto/event";
|
|
@@ -8,145 +9,70 @@ import { getString } from "@oscarpalmer/atoms/string";
|
|
|
8
9
|
import { getData } from "@oscarpalmer/toretto/data";
|
|
9
10
|
import { createElement } from "@oscarpalmer/toretto/create";
|
|
10
11
|
import { dispatch as dispatch$1, findAncestor, getData as getData$1 } from "@oscarpalmer/toretto";
|
|
11
|
-
//#region src/js/combobox/
|
|
12
|
-
function
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
select.remove();
|
|
20
|
-
state.floatable = createEmbeddedFloatable(anchor.container ?? anchor.element, content, {
|
|
21
|
-
position: "below-start",
|
|
22
|
-
reusable: false
|
|
23
|
-
});
|
|
24
|
-
state.floatable.update();
|
|
25
|
-
listeners.push(on(state.host, "focusout", () => {
|
|
26
|
-
setTimeout(() => {
|
|
27
|
-
onComboboxFocusout(state);
|
|
28
|
-
});
|
|
29
|
-
}), on(content, "click", (event) => {
|
|
30
|
-
onComboboxClickContent(event, content);
|
|
31
|
-
}), on(content, "toggle", () => {
|
|
32
|
-
setAria(anchor.element, "expanded", state.floatable.open);
|
|
33
|
-
setAria(filter.element, "activedescendant", state.floatable.open ? state.active?.id : void 0);
|
|
34
|
-
if (state.floatable.open) filter.element.focus();
|
|
35
|
-
}));
|
|
36
|
-
comboboxStates.map.set(state.host, state);
|
|
37
|
-
comboboxStates.map.set(state.content, state);
|
|
38
|
-
comboboxStates.set.add(state);
|
|
12
|
+
//#region src/js/combobox/misc.combobox.ts
|
|
13
|
+
function generateComboboxIds(prefix, select) {
|
|
14
|
+
const elements = [...select.children].flatMap((child) => child instanceof HTMLOptGroupElement ? [child, ...[...child.children].filter((groupChild) => groupChild instanceof HTMLOptionElement)] : child instanceof HTMLOptionElement ? [child] : []);
|
|
15
|
+
const { length } = elements;
|
|
16
|
+
for (let index = 0; index < length; index += 1) {
|
|
17
|
+
const element = elements[index];
|
|
18
|
+
if (element.id === "") element.id = `${prefix}${element instanceof HTMLOptGroupElement ? "_group_" : "_option_"}${index}`;
|
|
19
|
+
}
|
|
39
20
|
}
|
|
40
|
-
function
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const labelId = label.id;
|
|
55
|
-
label.htmlFor = id;
|
|
56
|
-
label.id = `${id}_label`;
|
|
57
|
-
generateComboboxIds(id, select);
|
|
58
|
-
const anchor = createComboboxAnchor({
|
|
59
|
-
autocomplete,
|
|
60
|
-
id,
|
|
61
|
-
label,
|
|
62
|
-
multiple,
|
|
63
|
-
select,
|
|
64
|
-
type
|
|
65
|
-
});
|
|
66
|
-
const content = createComboboxContent({
|
|
67
|
-
autocomplete,
|
|
68
|
-
id,
|
|
69
|
-
label,
|
|
70
|
-
multiple,
|
|
71
|
-
select,
|
|
72
|
-
type
|
|
73
|
-
});
|
|
74
|
-
const values = content.list.selected.length === 0 ? [""] : content.list.selected.map((option) => getData(option, "value", false) ?? "");
|
|
75
|
-
const state = {
|
|
76
|
-
autocomplete,
|
|
77
|
-
disabled,
|
|
78
|
-
id,
|
|
79
|
-
internals,
|
|
80
|
-
multiple,
|
|
81
|
-
readonly,
|
|
82
|
-
required,
|
|
83
|
-
select,
|
|
84
|
-
type,
|
|
85
|
-
anchor: {
|
|
86
|
-
container: anchor.container,
|
|
87
|
-
element: anchor.element
|
|
88
|
-
},
|
|
89
|
-
active: content.list.selected[0],
|
|
90
|
-
content: content.element,
|
|
91
|
-
filter: {
|
|
92
|
-
element: content.filter?.element ?? anchor.element,
|
|
93
|
-
value: ""
|
|
94
|
-
},
|
|
95
|
-
floatable: void 0,
|
|
96
|
-
groups: content.list.groups,
|
|
97
|
-
host: element,
|
|
98
|
-
label: {
|
|
99
|
-
element: label,
|
|
100
|
-
id: labelId
|
|
101
|
-
},
|
|
102
|
-
listeners: [],
|
|
103
|
-
localizations: {},
|
|
104
|
-
message: content.message,
|
|
105
|
-
name: element.name,
|
|
106
|
-
options: {
|
|
107
|
-
all: content.list.options,
|
|
108
|
-
selected: content.list.selected
|
|
109
|
-
},
|
|
110
|
-
selection: anchor.selection,
|
|
111
|
-
values: {
|
|
112
|
-
current: values.slice(),
|
|
113
|
-
initial: values.slice()
|
|
114
|
-
}
|
|
21
|
+
function getComboboxAttributeValue(element, attribute, possible, defaultValue) {
|
|
22
|
+
const value = getAttribute(element, attribute);
|
|
23
|
+
return possible.has(value) ? value : defaultValue;
|
|
24
|
+
}
|
|
25
|
+
function getComboboxAutoComplete(element, select) {
|
|
26
|
+
let value;
|
|
27
|
+
if (select) value = "list";
|
|
28
|
+
else value = getComboboxAttributeValue(element, "autocomplete", COMBOBOX_AUTOCOMPLETES, "none");
|
|
29
|
+
return {
|
|
30
|
+
value,
|
|
31
|
+
both: value === "both",
|
|
32
|
+
inline: value === "inline",
|
|
33
|
+
list: value === "list",
|
|
34
|
+
none: value === "none"
|
|
115
35
|
};
|
|
116
|
-
attachCombobox(state);
|
|
117
|
-
setComboboxDisabled(state, disabled);
|
|
118
|
-
setComboboxLimit("max", state, getAttribute(element, "max"));
|
|
119
|
-
setComboboxLimit("min", state, getAttribute(element, "min"));
|
|
120
|
-
setComboboxReadonly(state, readonly);
|
|
121
|
-
setComboboxRequired(state, required);
|
|
122
|
-
filterComboboxOptions(state);
|
|
123
|
-
if (content.list.selected.length > 0) updateComboboxPreview("set", state, content.list.selected[0]);
|
|
124
|
-
updateComboboxForm(state, state.values.current, false);
|
|
125
|
-
updateComboboxMessage(state, getComboboxVisibleOptions(state).length);
|
|
126
|
-
updateComboboxSelectionItems(state);
|
|
127
|
-
return state;
|
|
128
36
|
}
|
|
129
|
-
function
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
const { length } = listeners;
|
|
133
|
-
for (let index = 0; index < length; index += 1) listeners[index]();
|
|
134
|
-
floatable.destroy();
|
|
135
|
-
const anchor = state.anchor.container ?? state.anchor.element;
|
|
136
|
-
anchor.insertAdjacentElement("beforebegin", select);
|
|
137
|
-
anchor.remove();
|
|
138
|
-
content.remove();
|
|
139
|
-
label.element.htmlFor = select.id;
|
|
140
|
-
label.element.id = state.label.id;
|
|
141
|
-
select.hidden = false;
|
|
142
|
-
comboboxStates.map.delete(host);
|
|
143
|
-
comboboxStates.map.delete(content);
|
|
144
|
-
comboboxStates.set.delete(state);
|
|
37
|
+
function getComboboxBooleanAria(element, attribute) {
|
|
38
|
+
const value = getAria(element, attribute);
|
|
39
|
+
return value === true || value === "true";
|
|
145
40
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
41
|
+
function getComboboxId() {
|
|
42
|
+
index += 1;
|
|
43
|
+
return `oui_combobox_${index}`;
|
|
44
|
+
}
|
|
45
|
+
function getComboboxVisibleOptions(state) {
|
|
46
|
+
return state.options.all.filter((option) => !option.hidden);
|
|
47
|
+
}
|
|
48
|
+
function hasTextSelection(element) {
|
|
49
|
+
return element instanceof HTMLInputElement && element.selectionStart !== element.selectionEnd;
|
|
50
|
+
}
|
|
51
|
+
function setComboboxFilter(state, value) {
|
|
52
|
+
if (typeof value !== "string") return;
|
|
53
|
+
const type = value.length < state.filter.element.value.length ? "deleteContentBackward" : "insertText";
|
|
54
|
+
state.filter.element.value = value;
|
|
55
|
+
onComboboxFilter(type, state);
|
|
56
|
+
}
|
|
57
|
+
function setComboboxLimit(type, state, value) {
|
|
58
|
+
let actual = value;
|
|
59
|
+
if (typeof actual === "string") actual = Number.parseInt(actual, 10);
|
|
60
|
+
if (typeof actual === "number" && !Number.isNaN(actual) && actual >= 0 ? actual !== state[type] : actual == null) {
|
|
61
|
+
state[type] = actual;
|
|
62
|
+
setAttribute(state.host, type, actual);
|
|
63
|
+
updateComboboxValidity(state);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function setComboboxLocalizations(first, second) {
|
|
67
|
+
updateLocalizations(comboboxLocalizations, typeof first === "string" ? { [first]: second } : first, comboboxLocalizations.values, () => {
|
|
68
|
+
for (const state of comboboxStates.set) {
|
|
69
|
+
updateComboboxAnchor(state);
|
|
70
|
+
updateComboboxMessage(state, getComboboxVisibleOptions(state).length);
|
|
71
|
+
updateComboboxSelectionItems(state);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
let index = 0;
|
|
150
76
|
//#endregion
|
|
151
77
|
//#region src/js/combobox/event.combobox.ts
|
|
152
78
|
function onComboboxClickContent(event, content) {
|
|
@@ -355,139 +281,154 @@ on(document, "click", onComboboxClickDocument);
|
|
|
355
281
|
on(document, "input", onComboboxInput, { passive: false });
|
|
356
282
|
on(document, "keydown", onComboboxKeydown, { passive: false });
|
|
357
283
|
//#endregion
|
|
358
|
-
//#region src/js/combobox/
|
|
359
|
-
function
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
284
|
+
//#region src/js/combobox/state.combobox.ts
|
|
285
|
+
function attachCombobox(state) {
|
|
286
|
+
const { anchor, content, filter, label, listeners, select } = state;
|
|
287
|
+
label.element.htmlFor = filter.element.id;
|
|
288
|
+
label.element.id = `${state.id}_label`;
|
|
289
|
+
select.hidden = true;
|
|
290
|
+
select.insertAdjacentElement("afterend", anchor.container ?? anchor.element);
|
|
291
|
+
(anchor.container ?? anchor.element).insertAdjacentElement("afterend", content);
|
|
292
|
+
select.remove();
|
|
293
|
+
state.floatable = createEmbeddedFloatable(anchor.container ?? anchor.element, content, {
|
|
294
|
+
position: "below-start",
|
|
295
|
+
reusable: false
|
|
296
|
+
});
|
|
297
|
+
state.floatable.update();
|
|
298
|
+
listeners.push(on(state.host, "focusout", () => {
|
|
299
|
+
setTimeout(() => {
|
|
300
|
+
onComboboxFocusout(state);
|
|
301
|
+
});
|
|
302
|
+
}), on(content, "click", (event) => {
|
|
303
|
+
onComboboxClickContent(event, content);
|
|
304
|
+
}), on(content, "toggle", () => {
|
|
305
|
+
setAria(anchor.element, "expanded", state.floatable.open);
|
|
306
|
+
setAria(filter.element, "activedescendant", state.floatable.open ? state.active?.id : void 0);
|
|
307
|
+
if (state.floatable.open) filter.element.focus();
|
|
308
|
+
}));
|
|
309
|
+
comboboxStates.map.set(state.host, state);
|
|
310
|
+
comboboxStates.map.set(state.content, state);
|
|
311
|
+
comboboxStates.set.add(state);
|
|
370
312
|
}
|
|
371
|
-
function
|
|
372
|
-
|
|
373
|
-
if (select
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
313
|
+
function createComboboxState(element, internals) {
|
|
314
|
+
const select = element.querySelector("select");
|
|
315
|
+
if (select == null || select.id === "") throw new Error(COMBOBOX_MESSAGE_SELECT);
|
|
316
|
+
const label = element.querySelector(`label[for="${select.id}"]`);
|
|
317
|
+
if (label == null) throw new Error(COMBOBOX_MESSAGE_LABEL);
|
|
318
|
+
element.id = select.id;
|
|
319
|
+
setAttribute(element, "name", select.name === "" ? select.id : select.name);
|
|
320
|
+
const disabled = getComboboxBooleanAria(element, "disabled") || select.disabled;
|
|
321
|
+
const multiple = element.multiple || select.multiple;
|
|
322
|
+
const readonly = getComboboxBooleanAria(element, "readonly");
|
|
323
|
+
const required = getComboboxBooleanAria(element, "required") || select.required;
|
|
324
|
+
const id = getComboboxId();
|
|
325
|
+
const type = multiple ? "select" : getComboboxAttributeValue(element, "type", COMBOBOX_TYPES, "select");
|
|
326
|
+
const autocomplete = getComboboxAutoComplete(element, type === "select");
|
|
327
|
+
const labelId = label.id;
|
|
328
|
+
label.htmlFor = id;
|
|
329
|
+
label.id = `${id}_label`;
|
|
330
|
+
generateComboboxIds(id, select);
|
|
331
|
+
const anchor = createComboboxAnchor({
|
|
332
|
+
autocomplete,
|
|
333
|
+
id,
|
|
334
|
+
label,
|
|
335
|
+
multiple,
|
|
336
|
+
select,
|
|
337
|
+
type
|
|
338
|
+
});
|
|
339
|
+
const content = createComboboxContent({
|
|
340
|
+
autocomplete,
|
|
341
|
+
id,
|
|
342
|
+
label,
|
|
343
|
+
multiple,
|
|
344
|
+
select,
|
|
345
|
+
type
|
|
346
|
+
});
|
|
347
|
+
const values = content.list.selected.length === 0 ? [""] : content.list.selected.map((option) => getData(option, "value", false) ?? "");
|
|
348
|
+
const state = {
|
|
349
|
+
autocomplete,
|
|
350
|
+
disabled,
|
|
351
|
+
id,
|
|
352
|
+
internals,
|
|
353
|
+
multiple,
|
|
354
|
+
readonly,
|
|
355
|
+
required,
|
|
356
|
+
select,
|
|
357
|
+
type,
|
|
358
|
+
anchor: {
|
|
359
|
+
container: anchor.container,
|
|
360
|
+
element: anchor.element
|
|
361
|
+
},
|
|
362
|
+
active: content.list.selected[0],
|
|
363
|
+
content: content.element,
|
|
364
|
+
filter: {
|
|
365
|
+
element: content.filter?.element ?? anchor.element,
|
|
366
|
+
value: ""
|
|
367
|
+
},
|
|
368
|
+
floatable: void 0,
|
|
369
|
+
groups: content.list.groups,
|
|
370
|
+
host: element,
|
|
371
|
+
label: {
|
|
372
|
+
element: label,
|
|
373
|
+
id: labelId
|
|
374
|
+
},
|
|
375
|
+
listeners: [],
|
|
376
|
+
localizations: {},
|
|
377
|
+
message: content.message,
|
|
378
|
+
name: element.name,
|
|
379
|
+
options: {
|
|
380
|
+
all: content.list.options,
|
|
381
|
+
selected: content.list.selected
|
|
382
|
+
},
|
|
383
|
+
selection: anchor.selection,
|
|
384
|
+
values: {
|
|
385
|
+
current: values.slice(),
|
|
386
|
+
initial: values.slice()
|
|
387
|
+
}
|
|
381
388
|
};
|
|
389
|
+
attachCombobox(state);
|
|
390
|
+
setComboboxDisabled(state, disabled);
|
|
391
|
+
setComboboxLimit("max", state, getAttribute(element, "max"));
|
|
392
|
+
setComboboxLimit("min", state, getAttribute(element, "min"));
|
|
393
|
+
setComboboxReadonly(state, readonly);
|
|
394
|
+
setComboboxRequired(state, required);
|
|
395
|
+
filterComboboxOptions(state);
|
|
396
|
+
if (content.list.selected.length > 0) updateComboboxPreview("set", state, content.list.selected[0]);
|
|
397
|
+
updateComboboxForm(state, state.values.current, false);
|
|
398
|
+
updateComboboxMessage(state, getComboboxVisibleOptions(state).length);
|
|
399
|
+
updateComboboxSelectionItems(state);
|
|
400
|
+
return state;
|
|
382
401
|
}
|
|
383
|
-
function
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
const type = value.length < state.filter.element.value.length ? "deleteContentBackward" : "insertText";
|
|
400
|
-
state.filter.element.value = value;
|
|
401
|
-
onComboboxFilter(type, state);
|
|
402
|
-
}
|
|
403
|
-
function setComboboxLimit(type, state, value) {
|
|
404
|
-
let actual = value;
|
|
405
|
-
if (typeof actual === "string") actual = Number.parseInt(actual, 10);
|
|
406
|
-
if (typeof actual === "number" && !Number.isNaN(actual) && actual >= 0 ? actual !== state[type] : actual == null) {
|
|
407
|
-
state[type] = actual;
|
|
408
|
-
setAttribute(state.host, type, actual);
|
|
409
|
-
updateComboboxValidity(state);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
let index = 0;
|
|
413
|
-
//#endregion
|
|
414
|
-
//#region src/js/combobox/i18n.combobox.ts
|
|
415
|
-
function getComboboxLanguage(state) {
|
|
416
|
-
return (state.host.closest("[lang]")?.getAttribute("lang") ?? document.documentElement.lang).toLowerCase();
|
|
417
|
-
}
|
|
418
|
-
function getComboboxLocalization(key, state) {
|
|
419
|
-
const language = getComboboxLanguage(state);
|
|
420
|
-
const allLocalizations = [state.localizations, LOCALIZATIONS.globals];
|
|
421
|
-
const { length } = allLocalizations;
|
|
422
|
-
let localization;
|
|
423
|
-
let shortLanguage;
|
|
424
|
-
for (let index = 0; index < length; index += 1) {
|
|
425
|
-
const localizations = allLocalizations[index];
|
|
426
|
-
localization = localizations?.[language]?.[key];
|
|
427
|
-
if (localization != null) break;
|
|
428
|
-
shortLanguage ??= language.split("-")[0];
|
|
429
|
-
if (shortLanguage === language) continue;
|
|
430
|
-
localization = localizations?.[shortLanguage]?.[key];
|
|
431
|
-
if (localization != null) break;
|
|
432
|
-
}
|
|
433
|
-
return localization ?? LOCALIZATIONS.defaults[key];
|
|
434
|
-
}
|
|
435
|
-
function setComboboxLocalizations(first, second) {
|
|
436
|
-
updateComboboxLocalizations(typeof first === "string" ? { [first]: second } : first);
|
|
437
|
-
}
|
|
438
|
-
function updateComboboxLocalizations(values, destination) {
|
|
439
|
-
if (typeof values !== "object" || values == null) return;
|
|
440
|
-
const localizations = destination ?? LOCALIZATIONS.globals;
|
|
441
|
-
const languages = Object.keys(values);
|
|
442
|
-
const languagesLength = languages.length;
|
|
443
|
-
let updated = false;
|
|
444
|
-
for (let languagesIndex = 0; languagesIndex < languagesLength; languagesIndex += 1) {
|
|
445
|
-
const language = languages[languagesIndex];
|
|
446
|
-
const languageValue = values[language];
|
|
447
|
-
if (typeof languageValue !== "object" || languageValue == null) continue;
|
|
448
|
-
const normalizedLanguage = language.toLowerCase();
|
|
449
|
-
localizations[normalizedLanguage] ??= {};
|
|
450
|
-
const keys = Object.keys(languageValue);
|
|
451
|
-
const keysLength = keys.length;
|
|
452
|
-
for (let keysIndex = 0; keysIndex < keysLength; keysIndex += 1) {
|
|
453
|
-
const key = keys[keysIndex];
|
|
454
|
-
const keyValue = languageValue[key];
|
|
455
|
-
const normalizedKey = key.toLowerCase();
|
|
456
|
-
if (LOCALIZATIONS.keys.has(normalizedKey) && (typeof keyValue === "string" || typeof keyValue === "function")) {
|
|
457
|
-
updated = true;
|
|
458
|
-
localizations[normalizedLanguage][normalizedKey] = keyValue;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
if (!updated) return;
|
|
463
|
-
for (const state of comboboxStates.set) {
|
|
464
|
-
updateComboboxAnchor(state);
|
|
465
|
-
updateComboboxMessage(state, getComboboxVisibleOptions(state).length);
|
|
466
|
-
updateComboboxSelectionItems(state);
|
|
467
|
-
}
|
|
402
|
+
function detachCombobox(state) {
|
|
403
|
+
const { content, floatable, host, label, select } = state;
|
|
404
|
+
const listeners = state.listeners.splice(0);
|
|
405
|
+
const { length } = listeners;
|
|
406
|
+
for (let index = 0; index < length; index += 1) listeners[index]();
|
|
407
|
+
floatable.destroy();
|
|
408
|
+
const anchor = state.anchor.container ?? state.anchor.element;
|
|
409
|
+
anchor.insertAdjacentElement("beforebegin", select);
|
|
410
|
+
anchor.remove();
|
|
411
|
+
content.remove();
|
|
412
|
+
label.element.htmlFor = select.id;
|
|
413
|
+
label.element.id = state.label.id;
|
|
414
|
+
select.hidden = false;
|
|
415
|
+
comboboxStates.map.delete(host);
|
|
416
|
+
comboboxStates.map.delete(content);
|
|
417
|
+
comboboxStates.set.delete(state);
|
|
468
418
|
}
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
"empty",
|
|
483
|
-
"input",
|
|
484
|
-
"invalid",
|
|
485
|
-
"max",
|
|
486
|
-
"min",
|
|
487
|
-
"remove",
|
|
488
|
-
"results",
|
|
489
|
-
"selected"
|
|
490
|
-
])
|
|
419
|
+
const comboboxLocalizations = getLocalizations({
|
|
420
|
+
empty: "No results found",
|
|
421
|
+
input: "Please enter a value",
|
|
422
|
+
invalid: "Please select an option from the list",
|
|
423
|
+
max: (max) => `Please select fewer options (maximum is ${max})`,
|
|
424
|
+
min: (min) => `Please select more options (minimum is ${min})`,
|
|
425
|
+
remove: (label) => `Remove ${label}`,
|
|
426
|
+
results: (amount) => `${amount} results available`,
|
|
427
|
+
selected: (amount) => `${amount} selected`
|
|
428
|
+
});
|
|
429
|
+
const comboboxStates = {
|
|
430
|
+
map: /* @__PURE__ */ new WeakMap(),
|
|
431
|
+
set: /* @__PURE__ */ new Set()
|
|
491
432
|
};
|
|
492
433
|
//#endregion
|
|
493
434
|
//#region src/js/combobox/form.combobox.ts
|
|
@@ -507,33 +448,34 @@ function updateComboboxForm(state, values, emit) {
|
|
|
507
448
|
function updateComboboxValidity(state) {
|
|
508
449
|
if (state.autocomplete.none) {
|
|
509
450
|
const valueMissing = state.required && state.filter.element.value.length === 0;
|
|
510
|
-
const localization =
|
|
511
|
-
state.internals.setValidity({ valueMissing },
|
|
451
|
+
const localization = getLocalization(comboboxLocalizations, state.host, "invalid", state.localizations);
|
|
452
|
+
state.internals.setValidity({ valueMissing }, localize(localization, {}, []));
|
|
512
453
|
state.internals.checkValidity();
|
|
513
454
|
return;
|
|
514
455
|
}
|
|
456
|
+
let data = {};
|
|
515
457
|
let error;
|
|
516
|
-
let
|
|
458
|
+
let key;
|
|
459
|
+
let parameters = [];
|
|
517
460
|
switch (true) {
|
|
518
|
-
case state.required && state.options.selected.length === 0:
|
|
461
|
+
case state.required && state.options.selected.length === 0:
|
|
519
462
|
error = "badInput";
|
|
520
|
-
|
|
521
|
-
message = typeof localization === "function" ? localization() : localization;
|
|
463
|
+
key = "input";
|
|
522
464
|
break;
|
|
523
|
-
|
|
524
|
-
|
|
465
|
+
case state.multiple && typeof state.max === "number" && state.options.selected.length > state.max:
|
|
466
|
+
data = { amount: state.max };
|
|
525
467
|
error = "rangeOverflow";
|
|
526
|
-
|
|
527
|
-
|
|
468
|
+
key = "max";
|
|
469
|
+
parameters = [state.max];
|
|
528
470
|
break;
|
|
529
|
-
|
|
530
|
-
|
|
471
|
+
case state.multiple && typeof state.min === "number" && state.options.selected.length < state.min:
|
|
472
|
+
data = { amount: state.min };
|
|
531
473
|
error = "rangeUnderflow";
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
break;
|
|
535
|
-
}
|
|
474
|
+
key = "min";
|
|
475
|
+
parameters = [state.min];
|
|
536
476
|
}
|
|
477
|
+
const localization = key == null ? void 0 : getLocalization(comboboxLocalizations, state.host, key, state.localizations);
|
|
478
|
+
const message = localization == null ? void 0 : localize(localization, data, parameters);
|
|
537
479
|
state.internals.setValidity(error == null ? {} : { [error]: true }, message);
|
|
538
480
|
state.internals.checkValidity();
|
|
539
481
|
}
|
|
@@ -805,10 +747,15 @@ function createComboboxSelection(id, select) {
|
|
|
805
747
|
};
|
|
806
748
|
}
|
|
807
749
|
function createComboboxSelectionItem(option, state) {
|
|
750
|
+
const optionLabel = option.textContent;
|
|
751
|
+
const optionValue = getData(option, "value", false) ?? "";
|
|
808
752
|
const element = createElement("li");
|
|
809
|
-
const localization = state == null ? option.textContent :
|
|
753
|
+
const localization = state == null ? option.textContent : getLocalization(comboboxLocalizations, state.host, "remove", state.localizations);
|
|
810
754
|
const button = createElement("button", {
|
|
811
|
-
aria: { label:
|
|
755
|
+
aria: { label: localize(localization, {
|
|
756
|
+
label: optionLabel,
|
|
757
|
+
value: optionValue
|
|
758
|
+
}, [optionLabel, optionValue]) },
|
|
812
759
|
attribute: {
|
|
813
760
|
[COMBOBOX_ATTRIBUTE_SELECTION_ITEM]: "",
|
|
814
761
|
tabindex: -1
|
|
@@ -875,8 +822,9 @@ function updateComboboxTabindices(state, active) {
|
|
|
875
822
|
}
|
|
876
823
|
function updateComboboxAnchor(state) {
|
|
877
824
|
if (!state.multiple) return;
|
|
878
|
-
const localization =
|
|
879
|
-
|
|
825
|
+
const localization = getLocalization(comboboxLocalizations, state.host, "selected", state.localizations);
|
|
826
|
+
const { length } = state.options.selected;
|
|
827
|
+
setAria(state.anchor.element, "label", localize(localization, { amount: length }, [length]));
|
|
880
828
|
}
|
|
881
829
|
function updateComboboxAutocomplete(preview, state, active) {
|
|
882
830
|
if (state.multiple) return;
|
|
@@ -894,11 +842,11 @@ function updateComboboxAutocomplete(preview, state, active) {
|
|
|
894
842
|
function updateComboboxMessage(state, visible) {
|
|
895
843
|
setAttribute(state.message, COMBOBOX_ATTRIBUTE_HIDDEN, visible > 0 ? "" : void 0);
|
|
896
844
|
if (visible === 0) {
|
|
897
|
-
const localization =
|
|
898
|
-
state.message.textContent =
|
|
845
|
+
const localization = getLocalization(comboboxLocalizations, state.host, "empty", state.localizations);
|
|
846
|
+
state.message.textContent = localize(localization, {}, []);
|
|
899
847
|
} else {
|
|
900
|
-
const localization =
|
|
901
|
-
state.message.textContent =
|
|
848
|
+
const localization = getLocalization(comboboxLocalizations, state.host, "results", state.localizations);
|
|
849
|
+
state.message.textContent = localize(localization, { amount: visible }, [visible]);
|
|
902
850
|
}
|
|
903
851
|
state.message.hidden = false;
|
|
904
852
|
}
|
|
@@ -916,7 +864,7 @@ function updateComboboxPreview(preview, state, active) {
|
|
|
916
864
|
function updateComboboxSelection(state, active, added, selected) {
|
|
917
865
|
if (state.selection == null) return;
|
|
918
866
|
let options = active == null ? [] : [active];
|
|
919
|
-
if (selected != null) {
|
|
867
|
+
if (added && selected != null) {
|
|
920
868
|
options = selected;
|
|
921
869
|
const { length } = state.selection.items;
|
|
922
870
|
for (let index = 0; index < length; index += 1) state.selection.items[index].element.remove();
|
|
@@ -950,13 +898,18 @@ function updateComboboxSelection(state, active, added, selected) {
|
|
|
950
898
|
}
|
|
951
899
|
function updateComboboxSelectionItems(state) {
|
|
952
900
|
if (state.selection == null) return;
|
|
953
|
-
const localization =
|
|
901
|
+
const localization = getLocalization(comboboxLocalizations, state.host, "remove", state.localizations);
|
|
954
902
|
const { length } = state.selection.items;
|
|
955
903
|
for (let index = 0; index < length; index += 1) {
|
|
956
904
|
const item = state.selection.items[index];
|
|
957
905
|
const option = state.options.selected.find((option) => option.id === getData(item.button, "option", false));
|
|
958
906
|
if (option == null) continue;
|
|
959
|
-
|
|
907
|
+
const optionLabel = option.textContent;
|
|
908
|
+
const optionValue = getData(option, "value", false) ?? "";
|
|
909
|
+
setAria(item.button, "label", localize(localization, {
|
|
910
|
+
label: optionLabel,
|
|
911
|
+
value: optionValue
|
|
912
|
+
}, [optionLabel, optionValue]));
|
|
960
913
|
}
|
|
961
914
|
}
|
|
962
915
|
//#endregion
|
|
@@ -1074,4 +1027,4 @@ function toggleComboboxOption(state, option) {
|
|
|
1074
1027
|
if (!state.multiple) state.floatable.hide();
|
|
1075
1028
|
}
|
|
1076
1029
|
//#endregion
|
|
1077
|
-
export {
|
|
1030
|
+
export { getComboboxAutoComplete as $, updateComboboxTabindices as A, onComboboxEnter as B, setComboboxRequired as C, updateComboboxPreview as D, updateComboboxMessage as E, comboboxStates as F, onComboboxKeydown as G, onComboboxFilter as H, createComboboxState as I, onComboboxRemoveSelection as J, onComboboxKeydownSelection as K, detachCombobox as L, updateComboboxValidity as M, attachCombobox as N, updateComboboxSelection as O, comboboxLocalizations as P, getComboboxAttributeValue as Q, onComboboxClickContent as R, setComboboxReadonly as S, updateComboboxAutocomplete as T, onComboboxFocusout as U, onComboboxEscape as V, onComboboxInput as W, onComboboxTab as X, onComboboxSelection as Y, generateComboboxIds as Z, createComboboxOptions as _, setComboboxValues as a, setComboboxLimit as at, createComboboxSelectionItems as b, createComboboxButton as c, createComboboxGroup as d, getComboboxBooleanAria as et, createComboboxHeader as f, createComboboxOption as g, createComboboxMessage as h, setComboboxValue as i, setComboboxFilter as it, updateComboboxForm as j, updateComboboxSelectionItems as k, createComboboxContent as l, createComboboxList as m, filterComboboxOption as n, getComboboxVisibleOptions as nt, toggleComboboxOption as o, setComboboxLocalizations as ot, createComboboxInput as p, onComboboxNavigation as q, filterComboboxOptions as r, hasTextSelection as rt, createComboboxAnchor as s, applyComboboxSelection as t, getComboboxId as tt, createComboboxFilter as u, createComboboxSelection as v, updateComboboxAnchor as w, setComboboxDisabled as x, createComboboxSelectionItem as y, onComboboxClickDocument as z };
|
package/dist/js/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as OuiFloatablePosition, n as CreateOuiFloatableOptions, r as OuiFloatable, s as createFloatable } from "./floatable.embedded-Bct4U5Dm.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Y as setComboboxLocalizations, z as OuiComboboxElement } from "./constants.combobox-h_kyDegw.mjs";
|
|
3
3
|
import { d as OuiSortable, f as createSortable, g as createMovable, h as OuiMovable, t as CreateOuiDraggableOptions } from "./draggable-a6w0J1OD.mjs";
|
|
4
4
|
import "./movable/movable.standalone.mjs";
|
|
5
5
|
import { a as createResizable, n as OuiResizable, t as CreateOuiResizableOptions } from "./resizable.embedded-3qoR0Bjm.mjs";
|
package/dist/js/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { createResizable } from "./resizable/resizable.embedded.mjs";
|
|
|
5
5
|
import { getDialog } from "./dialog.mjs";
|
|
6
6
|
import "./menu.mjs";
|
|
7
7
|
import "./toolbar.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { ot as setComboboxLocalizations } from "./data.combobox-B8HMkDOh.mjs";
|
|
9
9
|
import { OuiComboboxElement } from "./combobox/index.mjs";
|
|
10
10
|
import "./floatable/floatable.standalone.mjs";
|
|
11
11
|
import { createFocusTrap } from "./focus-trap/focus-trap.embedded.mjs";
|