@oscarpalmer/oui 0.32.0 → 0.34.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/css/combobox.css +93 -42
- package/dist/js/combobox/constants.combobox.d.mts +2 -0
- package/dist/js/combobox/constants.combobox.mjs +46 -0
- package/dist/js/combobox/data.combobox.d.mts +18 -0
- package/dist/js/combobox/data.combobox.mjs +2 -0
- package/dist/js/combobox/dom.combobox.d.mts +110 -0
- package/dist/js/combobox/dom.combobox.mjs +2 -0
- package/dist/js/combobox/event.combobox.d.mts +17 -0
- package/dist/js/combobox/event.combobox.mjs +2 -0
- package/dist/js/combobox/form.combobox.d.mts +6 -0
- package/dist/js/combobox/form.combobox.mjs +2 -0
- package/dist/js/combobox/i18n.combobox.d.mts +2 -0
- package/dist/js/combobox/i18n.combobox.mjs +2 -0
- package/dist/js/combobox/index.d.mts +2 -0
- package/dist/js/combobox/index.mjs +194 -0
- package/dist/js/combobox/misc.combobox.d.mts +14 -0
- package/dist/js/combobox/misc.combobox.mjs +2 -0
- package/dist/js/combobox/models.combobox.d.mts +2 -0
- package/dist/js/combobox/models.combobox.mjs +1 -0
- package/dist/js/combobox/state.combobox.d.mts +11 -0
- package/dist/js/combobox/state.combobox.mjs +2 -0
- package/dist/js/constants.combobox-DqNUGBLS.d.mts +243 -0
- package/dist/js/data.combobox-8RwBv5ey.mjs +1077 -0
- package/dist/js/dialog.mjs +3 -2
- package/dist/js/floatable/floatable.embedded.mjs +4 -4
- package/dist/js/focus-trap/focus-trap.embedded.mjs +3 -3
- package/dist/js/index.d.mts +3 -3
- package/dist/js/index.mjs +3 -2
- package/dist/js/internal/draggable.mjs +6 -6
- package/dist/js/internal/navigable.mjs +3 -3
- package/dist/js/menu.mjs +3 -2
- package/dist/js/movable/movable.embedded.mjs +3 -3
- package/dist/js/popover.mjs +1 -1
- package/dist/js/resizable/resizable.embedded.mjs +7 -7
- package/dist/js/sortable/sortable.embedded.mjs +7 -6
- package/dist/js/splitter.mjs +7 -13
- package/dist/js/tooltip.mjs +3 -3
- package/package.json +6 -6
- package/src/css/combobox.scss +98 -31
- package/src/js/combobox/constants.combobox.ts +62 -0
- package/src/js/combobox/data.combobox.ts +236 -0
- package/src/js/combobox/dom.combobox.ts +794 -0
- package/src/js/combobox/event.combobox.ts +454 -0
- package/src/js/combobox/form.combobox.ts +115 -0
- package/src/js/combobox/i18n.combobox.ts +179 -0
- package/src/js/combobox/index.ts +307 -0
- package/src/js/combobox/misc.combobox.ts +138 -0
- package/src/js/combobox/models.combobox.ts +94 -0
- package/src/js/combobox/state.combobox.ts +235 -0
- package/src/js/index.ts +1 -1
- package/src/js/internal/draggable.ts +3 -3
- package/src/js/internal/navigable.ts +10 -3
- package/src/js/movable/movable.embedded.ts +2 -2
- package/src/js/resizable/resizable.embedded.ts +3 -3
- package/src/js/sortable/sortable.embedded.ts +2 -2
- package/src/js/splitter.ts +2 -2
- package/dist/js/combobox.d.mts +0 -91
- package/dist/js/combobox.mjs +0 -855
- package/src/js/combobox.ts +0 -1634
package/dist/js/combobox.mjs
DELETED
|
@@ -1,855 +0,0 @@
|
|
|
1
|
-
import { createEmbeddedFloatable } from "./floatable/floatable.embedded.mjs";
|
|
2
|
-
import { clamp } from "@oscarpalmer/atoms/number";
|
|
3
|
-
import { getString, join } from "@oscarpalmer/atoms/string";
|
|
4
|
-
import { getAria, setAria, setRole } from "@oscarpalmer/toretto/aria";
|
|
5
|
-
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
6
|
-
import { createElement } from "@oscarpalmer/toretto/create";
|
|
7
|
-
import { dispatch, on } from "@oscarpalmer/toretto/event";
|
|
8
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
9
|
-
import { setProperty } from "@oscarpalmer/toretto/property";
|
|
10
|
-
import { setStyle } from "@oscarpalmer/toretto/style";
|
|
11
|
-
//#region src/js/combobox.ts
|
|
12
|
-
var OuiComboboxElement = class extends HTMLElement {
|
|
13
|
-
static formAssociated = true;
|
|
14
|
-
static observedAttributes = [
|
|
15
|
-
"disabled",
|
|
16
|
-
"max",
|
|
17
|
-
"min",
|
|
18
|
-
"readonly",
|
|
19
|
-
"required",
|
|
20
|
-
"value"
|
|
21
|
-
];
|
|
22
|
-
#internals;
|
|
23
|
-
#state;
|
|
24
|
-
/**
|
|
25
|
-
* Is the combobox disabled?
|
|
26
|
-
*/
|
|
27
|
-
get disabled() {
|
|
28
|
-
return this.hasAttribute("disabled");
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Should the combobox be disabled?
|
|
32
|
-
*/
|
|
33
|
-
set disabled(value) {
|
|
34
|
-
if (typeof value === "boolean" && value !== this.#state.disabled) setDisabled(this, this.#state, value);
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Maximum number of selected options
|
|
38
|
-
*/
|
|
39
|
-
get max() {
|
|
40
|
-
return this.#state.max;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Set the maximum number of selected options
|
|
44
|
-
*/
|
|
45
|
-
set max(value) {
|
|
46
|
-
setLimit("max", this, this.#state, value);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Minimum number of selected options
|
|
50
|
-
*/
|
|
51
|
-
get min() {
|
|
52
|
-
return this.#state.min;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Set the minimum number of selected options
|
|
56
|
-
*/
|
|
57
|
-
set min(value) {
|
|
58
|
-
setLimit("min", this, this.#state, value);
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Does the combobox allow multiple values?
|
|
62
|
-
*/
|
|
63
|
-
get multiple() {
|
|
64
|
-
return this.hasAttribute("multiple");
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Name of the combobox
|
|
68
|
-
*/
|
|
69
|
-
get name() {
|
|
70
|
-
return getAttribute(this, "name") ?? "";
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Is the combobox readonly?
|
|
74
|
-
*/
|
|
75
|
-
get readonly() {
|
|
76
|
-
return this.hasAttribute("readonly");
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Should the combobox be readonly?
|
|
80
|
-
*/
|
|
81
|
-
set readonly(value) {
|
|
82
|
-
if (typeof value === "boolean" && value !== this.#state.readonly) setReadonly(this, this.#state, value);
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Is the combobox required?
|
|
86
|
-
*/
|
|
87
|
-
get required() {
|
|
88
|
-
return this.hasAttribute("required");
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Should the combobox be required?
|
|
92
|
-
*/
|
|
93
|
-
set required(value) {
|
|
94
|
-
if (typeof value === "boolean" && value !== this.#state.required) setRequired(this, this.#state, value);
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Selected options
|
|
98
|
-
*/
|
|
99
|
-
get selected() {
|
|
100
|
-
return this.#state.selected.slice();
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Type of combobox
|
|
104
|
-
*/
|
|
105
|
-
get type() {
|
|
106
|
-
return this.#state.type;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Current value
|
|
110
|
-
*/
|
|
111
|
-
get value() {
|
|
112
|
-
return this.#state.values[0];
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Set the value
|
|
116
|
-
*/
|
|
117
|
-
set value(value) {
|
|
118
|
-
const [option, all] = getOption(this.#state, value);
|
|
119
|
-
if (option != null) setNext("set", this, this.#state, all, option);
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Current values
|
|
123
|
-
*/
|
|
124
|
-
get values() {
|
|
125
|
-
return this.#state.values.slice();
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Set the values
|
|
129
|
-
*/
|
|
130
|
-
set values(value) {
|
|
131
|
-
setValues(this, this.#state, value);
|
|
132
|
-
}
|
|
133
|
-
constructor() {
|
|
134
|
-
super();
|
|
135
|
-
this.#internals = this.attachInternals();
|
|
136
|
-
this.#state = getState(this, this.#internals);
|
|
137
|
-
comboboxes.set(this.#state.content, this);
|
|
138
|
-
states.set(this, this.#state);
|
|
139
|
-
states.set(this.#state.content, this.#state);
|
|
140
|
-
}
|
|
141
|
-
attributeChangedCallback(name, _, value) {
|
|
142
|
-
switch (name) {
|
|
143
|
-
case "disabled":
|
|
144
|
-
case "readonly":
|
|
145
|
-
case "required":
|
|
146
|
-
case "value":
|
|
147
|
-
this[name] = this.hasAttribute(name);
|
|
148
|
-
break;
|
|
149
|
-
case "max":
|
|
150
|
-
case "min":
|
|
151
|
-
setLimit(name, this, this.#state, value == null ? void 0 : Number.parseInt(value, 10));
|
|
152
|
-
break;
|
|
153
|
-
default: break;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
clear() {
|
|
157
|
-
setValues(this, this.#state, []);
|
|
158
|
-
}
|
|
159
|
-
formResetCallback() {
|
|
160
|
-
this.#state.touched = false;
|
|
161
|
-
this.clear();
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
function createAnchor(type, id, label, select, autocomplete, multiple) {
|
|
165
|
-
const [anchor, selection] = type === "autocomplete" ? [createInput(id, select)] : createBox(id, select, multiple);
|
|
166
|
-
setAria(anchor, {
|
|
167
|
-
autocomplete: type === "autocomplete" ? autocomplete.value : void 0,
|
|
168
|
-
controls: `${id}_content`,
|
|
169
|
-
expanded: false,
|
|
170
|
-
haspopup: "listbox",
|
|
171
|
-
labelledby: label.id
|
|
172
|
-
});
|
|
173
|
-
setAttribute(anchor, ATTRIBUTE_ANCHOR, "");
|
|
174
|
-
setRole(anchor, "combobox");
|
|
175
|
-
return [anchor, selection];
|
|
176
|
-
}
|
|
177
|
-
function createBox(id, select, multiple) {
|
|
178
|
-
const box = createElement("div", {
|
|
179
|
-
id,
|
|
180
|
-
tabIndex: 0,
|
|
181
|
-
textContent: multiple ? "" : select.selectedOptions[0]?.textContent ?? ""
|
|
182
|
-
});
|
|
183
|
-
let selection;
|
|
184
|
-
if (multiple) {
|
|
185
|
-
selection = createSelection(select);
|
|
186
|
-
box.append(selection);
|
|
187
|
-
}
|
|
188
|
-
return [box, selection];
|
|
189
|
-
}
|
|
190
|
-
function createContent(type, id, label, select, autocomplete, multiple) {
|
|
191
|
-
const content = createElement("div", { id: `${id}_content` }, {
|
|
192
|
-
[ATTRIBUTE_CONTENT]: "",
|
|
193
|
-
popover: "",
|
|
194
|
-
tabindex: -1,
|
|
195
|
-
"aria-labelledby": label.id
|
|
196
|
-
});
|
|
197
|
-
const [filter, input] = createFilter(type, id) ?? [];
|
|
198
|
-
const [list, headers, selected] = createList(label, select, autocomplete, multiple);
|
|
199
|
-
const empty = createEmpty();
|
|
200
|
-
if (filter != null) content.append(filter);
|
|
201
|
-
content.append(list, empty);
|
|
202
|
-
return [
|
|
203
|
-
content,
|
|
204
|
-
input,
|
|
205
|
-
headers,
|
|
206
|
-
selected,
|
|
207
|
-
empty
|
|
208
|
-
];
|
|
209
|
-
}
|
|
210
|
-
function createEmpty() {
|
|
211
|
-
return createElement("div", {
|
|
212
|
-
hidden: true,
|
|
213
|
-
role: "status",
|
|
214
|
-
textContent: "No results found"
|
|
215
|
-
}, {
|
|
216
|
-
[ATTRIBUTE_EMPTY]: "",
|
|
217
|
-
"aria-live": "polite"
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
function createFilter(type, id) {
|
|
221
|
-
if (type === "autocomplete") return;
|
|
222
|
-
const container = createElement("div", {}, { [ATTRIBUTE_FILTER]: "" });
|
|
223
|
-
const label = createElement("label", {
|
|
224
|
-
htmlFor: `${id}_filter`,
|
|
225
|
-
textContent: "Filter options"
|
|
226
|
-
}, { [ATTRIBUTE_FILTER_LABEL]: "" });
|
|
227
|
-
const filter = createElement("input", { id: `${id}_filter` }, { [ATTRIBUTE_FILTER_INPUT]: "" });
|
|
228
|
-
container.append(label, filter);
|
|
229
|
-
return [container, filter];
|
|
230
|
-
}
|
|
231
|
-
function createHeader(group) {
|
|
232
|
-
return createElement("li", {
|
|
233
|
-
id: group.id,
|
|
234
|
-
role: "presentation",
|
|
235
|
-
textContent: group.label
|
|
236
|
-
}, { [ATTRIBUTE_HEADER]: "" });
|
|
237
|
-
}
|
|
238
|
-
function createInput(id, select) {
|
|
239
|
-
return createElement("input", {
|
|
240
|
-
id,
|
|
241
|
-
value: select.selectedOptions[0]?.textContent ?? ""
|
|
242
|
-
}, {
|
|
243
|
-
[ATTRIBUTE_ANCHOR]: "",
|
|
244
|
-
autocomplete: "off",
|
|
245
|
-
type: "text"
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
function createList(label, select, autocomplete, multiple) {
|
|
249
|
-
const list = createElement("ul", { role: "listbox" }, {
|
|
250
|
-
[ATTRIBUTE_LIST]: "",
|
|
251
|
-
"aria-labelledby": label.id,
|
|
252
|
-
"aria-multiselectable": multiple
|
|
253
|
-
});
|
|
254
|
-
const groups = [...select.querySelectorAll("optgroup")];
|
|
255
|
-
const groupsLength = groups.length;
|
|
256
|
-
const selected = [];
|
|
257
|
-
let headers;
|
|
258
|
-
if (groupsLength > 0) {
|
|
259
|
-
headers = [];
|
|
260
|
-
let firstGroup;
|
|
261
|
-
for (let groupIndex = 0; groupIndex < groupsLength; groupIndex += 1) {
|
|
262
|
-
const group = groups[groupIndex];
|
|
263
|
-
const options = [...group.querySelectorAll("option")];
|
|
264
|
-
if (options.length === 0) continue;
|
|
265
|
-
firstGroup ??= groupIndex;
|
|
266
|
-
const header = createHeader(group);
|
|
267
|
-
headers.push(header);
|
|
268
|
-
list.append(header);
|
|
269
|
-
createOptions(options, autocomplete, list, selected, groupIndex === firstGroup, header.id);
|
|
270
|
-
}
|
|
271
|
-
} else createOptions([...select.options], autocomplete, list, selected, true);
|
|
272
|
-
return [
|
|
273
|
-
list,
|
|
274
|
-
headers,
|
|
275
|
-
selected
|
|
276
|
-
];
|
|
277
|
-
}
|
|
278
|
-
function createOption(index, option, autocomplete, active, group) {
|
|
279
|
-
return createElement("li", {
|
|
280
|
-
id: option.id,
|
|
281
|
-
role: "option",
|
|
282
|
-
textContent: option.textContent
|
|
283
|
-
}, {
|
|
284
|
-
group,
|
|
285
|
-
[ATTRIBUTE_OPTION]: "",
|
|
286
|
-
[ATTRIBUTE_OPTION_ACTIVE]: active && index === 0 ? "" : void 0,
|
|
287
|
-
value: option.value,
|
|
288
|
-
"aria-selected": !autocomplete.none && option.selected
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
function createOptions(options, autocomplete, list, selected, active, group) {
|
|
292
|
-
for (let index = 0; index < options.length; index += 1) {
|
|
293
|
-
const option = options[index];
|
|
294
|
-
const item = createOption(index, option, autocomplete, active, group);
|
|
295
|
-
if (option.selected) selected.push(item);
|
|
296
|
-
list.append(item);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
function createSelection(select) {
|
|
300
|
-
const selection = createElement("ul", {}, { [ATTRIBUTE_SELECTION]: "" });
|
|
301
|
-
for (const option of select.selectedOptions) selection.append(getSelectionItem(option));
|
|
302
|
-
return selection;
|
|
303
|
-
}
|
|
304
|
-
function filterOptions(state, options, clear) {
|
|
305
|
-
if (clear || state.autocomplete.none) state.filter.value = "";
|
|
306
|
-
const filter = state.filter.value.toLocaleLowerCase();
|
|
307
|
-
const groups = state.headers?.reduce((record, header) => {
|
|
308
|
-
record[header.id] = 0;
|
|
309
|
-
return record;
|
|
310
|
-
}, {}) ?? {};
|
|
311
|
-
const all = options ?? getOptions(state)[0];
|
|
312
|
-
let { length } = all;
|
|
313
|
-
const visible = [];
|
|
314
|
-
for (let index = 0; index < length; index += 1) {
|
|
315
|
-
const option = all[index];
|
|
316
|
-
option.hidden = option.textContent?.toLocaleLowerCase().includes(filter) === false;
|
|
317
|
-
if (!option.hidden) {
|
|
318
|
-
groups[getAttribute(option, "group") ?? ""] += 1;
|
|
319
|
-
visible.push(option);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
if (state.headers != null) {
|
|
323
|
-
length = state.headers.length;
|
|
324
|
-
for (let index = 0; index < length; index += 1) {
|
|
325
|
-
const header = state.headers[index];
|
|
326
|
-
header.hidden = groups[header.id] === 0;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
state.empty.hidden = visible.length > 0;
|
|
330
|
-
if (state.empty.hidden) return state.active != null && visible.includes(state.active) ? state.active : visible[0];
|
|
331
|
-
}
|
|
332
|
-
function generateIds(select, prefix) {
|
|
333
|
-
const elements = [...select.querySelectorAll("optgroup"), ...select.options];
|
|
334
|
-
const { length } = elements;
|
|
335
|
-
for (let index = 0; index < length; index += 1) {
|
|
336
|
-
const element = elements[index];
|
|
337
|
-
if (element.id === "") element.id = `${prefix}${element instanceof HTMLOptGroupElement ? "_group_" : "_option_"}${index}`;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
function getAttributeValue(element, attribute, possible, defaultValue) {
|
|
341
|
-
const value = getAttribute(element, attribute);
|
|
342
|
-
return possible.has(value) ? value : defaultValue;
|
|
343
|
-
}
|
|
344
|
-
function getAutoComplete(element, select) {
|
|
345
|
-
let value;
|
|
346
|
-
if (select) value = "list";
|
|
347
|
-
else value = getAttributeValue(element, "autocomplete", AUTOCOMPLETES, "none");
|
|
348
|
-
return {
|
|
349
|
-
value,
|
|
350
|
-
both: value === "both",
|
|
351
|
-
inline: value === "inline",
|
|
352
|
-
list: value === "list",
|
|
353
|
-
none: value === "none"
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
function getFormValue(state, values) {
|
|
357
|
-
if (values.length === 0 || !state.multiple) return values[0];
|
|
358
|
-
let formValues = [];
|
|
359
|
-
for (const value of values) formValues.push(`${state.name}=${value}`);
|
|
360
|
-
return join(formValues, "&");
|
|
361
|
-
}
|
|
362
|
-
function getFormValues(state, added) {
|
|
363
|
-
let values;
|
|
364
|
-
if (state.multiple) values = typeof added === "boolean" ? state.selected.map((option) => getAttribute(option, "value") ?? "") : state.values;
|
|
365
|
-
else values = [getAttribute(state.selected[0], "value") ?? ""];
|
|
366
|
-
const previous = getFormValue(state, state.values);
|
|
367
|
-
const next = getFormValue(state, values);
|
|
368
|
-
return [values, next !== previous];
|
|
369
|
-
}
|
|
370
|
-
function getId() {
|
|
371
|
-
index += 1;
|
|
372
|
-
return `oui_combobox_${index}`;
|
|
373
|
-
}
|
|
374
|
-
function getOption(state, value) {
|
|
375
|
-
const [all] = getOptions(state);
|
|
376
|
-
const valueAsString = getString(value).toLocaleLowerCase();
|
|
377
|
-
filterOptions(state, all, true);
|
|
378
|
-
let match;
|
|
379
|
-
for (const option of all) if (getAttribute(option, "value")?.toLocaleLowerCase() === valueAsString) {
|
|
380
|
-
match = option;
|
|
381
|
-
break;
|
|
382
|
-
}
|
|
383
|
-
return [match, all];
|
|
384
|
-
}
|
|
385
|
-
function getOptions(state) {
|
|
386
|
-
const all = [...state.content.querySelectorAll(`[${ATTRIBUTE_OPTION}]`)].filter((option) => option instanceof HTMLElement);
|
|
387
|
-
return [all, all.filter((option) => !option.hidden)];
|
|
388
|
-
}
|
|
389
|
-
function getSelected(update, state, element, next) {
|
|
390
|
-
if (state.autocomplete.none) return false;
|
|
391
|
-
const selected = getAria(element, "selected") === "true";
|
|
392
|
-
if (update === "navigation") {
|
|
393
|
-
if (state.autocomplete.both) return element === next;
|
|
394
|
-
return selected;
|
|
395
|
-
}
|
|
396
|
-
if (update === "none") return selected;
|
|
397
|
-
if (update === "set") {
|
|
398
|
-
if (next == null) return selected;
|
|
399
|
-
if (state.multiple) return element === next ? !selected : selected;
|
|
400
|
-
return element === next;
|
|
401
|
-
}
|
|
402
|
-
return selected;
|
|
403
|
-
}
|
|
404
|
-
function getSelectionItem(option) {
|
|
405
|
-
const icon = createElement("span", { innerHTML: "×" }, { "aria-hidden": true });
|
|
406
|
-
const label = createElement("span", { textContent: option.textContent });
|
|
407
|
-
const item = createElement("li", {}, {
|
|
408
|
-
[ATTRIBUTE_SELECTION_ITEM]: "",
|
|
409
|
-
option: option.id
|
|
410
|
-
});
|
|
411
|
-
item.append(icon, label);
|
|
412
|
-
return item;
|
|
413
|
-
}
|
|
414
|
-
function getState(element, internals) {
|
|
415
|
-
const select = element.querySelector("select");
|
|
416
|
-
if (select == null || select.id === "") throw new Error(MESSAGE_SELECT);
|
|
417
|
-
const label = element.querySelector(`label[for="${select.id}"]`);
|
|
418
|
-
if (label == null) throw new Error(MESSAGE_LABEL);
|
|
419
|
-
select.hidden = true;
|
|
420
|
-
element.id = select.id;
|
|
421
|
-
setAttribute(element, "name", select.name === "" ? select.id : select.name);
|
|
422
|
-
const disabled = element.disabled || select.disabled;
|
|
423
|
-
const multiple = element.multiple || select.multiple;
|
|
424
|
-
const readonly = element.readonly;
|
|
425
|
-
const required = element.required || select.required;
|
|
426
|
-
const id = getId();
|
|
427
|
-
const type = multiple ? "select" : getAttributeValue(element, "type", TYPES, "select");
|
|
428
|
-
const autocomplete = getAutoComplete(element, type === "select");
|
|
429
|
-
label.htmlFor = id;
|
|
430
|
-
label.id = `${id}_label`;
|
|
431
|
-
generateIds(select, id);
|
|
432
|
-
const [anchor, selection] = createAnchor(type, id, label, select, autocomplete, multiple);
|
|
433
|
-
const [content, filter, headers, selected, empty] = createContent(type, id, label, select, autocomplete, multiple);
|
|
434
|
-
const values = selected.length === 0 ? [""] : selected.map((option) => getAttribute(option, "value") ?? "");
|
|
435
|
-
const floatable = createEmbeddedFloatable(anchor, content, {
|
|
436
|
-
position: "below-start",
|
|
437
|
-
reusable: false
|
|
438
|
-
});
|
|
439
|
-
floatable.update();
|
|
440
|
-
select.insertAdjacentElement("afterend", anchor);
|
|
441
|
-
anchor.insertAdjacentElement("afterend", content);
|
|
442
|
-
select.remove();
|
|
443
|
-
const state = {
|
|
444
|
-
anchor,
|
|
445
|
-
autocomplete,
|
|
446
|
-
content,
|
|
447
|
-
disabled,
|
|
448
|
-
empty,
|
|
449
|
-
floatable,
|
|
450
|
-
headers,
|
|
451
|
-
id,
|
|
452
|
-
internals,
|
|
453
|
-
label,
|
|
454
|
-
multiple,
|
|
455
|
-
readonly,
|
|
456
|
-
required,
|
|
457
|
-
select,
|
|
458
|
-
selected,
|
|
459
|
-
selection,
|
|
460
|
-
type,
|
|
461
|
-
values,
|
|
462
|
-
active: selected[0],
|
|
463
|
-
filter: {
|
|
464
|
-
element: filter,
|
|
465
|
-
value: ""
|
|
466
|
-
},
|
|
467
|
-
listeners: [],
|
|
468
|
-
name: element.name,
|
|
469
|
-
touched: false
|
|
470
|
-
};
|
|
471
|
-
state.listeners.push(on(element, "focusout", () => {
|
|
472
|
-
state.touched = true;
|
|
473
|
-
updateValidity(state);
|
|
474
|
-
}), on(content, "click", (event) => {
|
|
475
|
-
onContent(event, content);
|
|
476
|
-
}), on(content, "toggle", () => {
|
|
477
|
-
setAria(anchor, {
|
|
478
|
-
activedescendant: floatable.open ? state.active?.id : void 0,
|
|
479
|
-
expanded: floatable.open
|
|
480
|
-
});
|
|
481
|
-
if (floatable.open) {
|
|
482
|
-
state.filter.element?.focus();
|
|
483
|
-
updateWidth(state);
|
|
484
|
-
}
|
|
485
|
-
}));
|
|
486
|
-
setDisabled(element, state, disabled);
|
|
487
|
-
setLimit("max", element, state, getAttribute(element, "max"));
|
|
488
|
-
setLimit("min", element, state, getAttribute(element, "min"));
|
|
489
|
-
setReadonly(element, state, readonly);
|
|
490
|
-
setRequired(element, state, required);
|
|
491
|
-
return state;
|
|
492
|
-
}
|
|
493
|
-
function hasTextSelection(element) {
|
|
494
|
-
return element instanceof HTMLInputElement && element.selectionStart !== element.selectionEnd;
|
|
495
|
-
}
|
|
496
|
-
function onClick(event) {
|
|
497
|
-
const combobox = findAncestor(event, TAGNAME);
|
|
498
|
-
const state = states.get(combobox);
|
|
499
|
-
if (combobox == null || state == null) return;
|
|
500
|
-
const label = findAncestor(event, "label");
|
|
501
|
-
if (label != null) {
|
|
502
|
-
if (label === state.label && combobox.type === "select") {
|
|
503
|
-
state.anchor.focus();
|
|
504
|
-
state.floatable.show();
|
|
505
|
-
}
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
const selection = findAncestor(event, `[${ATTRIBUTE_SELECTION_ITEM}]`);
|
|
509
|
-
if (selection != null) {
|
|
510
|
-
setValue("set", combobox, state, state.selected.find((option) => option.id === getAttribute(selection, "option")));
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
if (findAncestor(event, SELECTOR_ANCHOR) != null) {
|
|
514
|
-
state.floatable.show();
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
function onContent(event, content) {
|
|
519
|
-
const combobox = comboboxes.get(content);
|
|
520
|
-
const state = states.get(content);
|
|
521
|
-
if (combobox == null || state == null) return;
|
|
522
|
-
const option = findAncestor(event, SELECTOR_OPTION);
|
|
523
|
-
if (option instanceof HTMLElement) setNext("set", combobox, state, getOptions(state)[0], option);
|
|
524
|
-
(state.filter.element ?? state.anchor).focus();
|
|
525
|
-
}
|
|
526
|
-
function onEnter(combobox, state) {
|
|
527
|
-
if (hasTextSelection(state.anchor)) {
|
|
528
|
-
onSelection(combobox, state);
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
if (!state.floatable.open) {
|
|
532
|
-
state.floatable.show();
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
setNext("set", combobox, state, getOptions(state)[0], state.active);
|
|
536
|
-
}
|
|
537
|
-
function onEscape(state) {
|
|
538
|
-
state.floatable.hide();
|
|
539
|
-
}
|
|
540
|
-
function onInput(event, handler) {
|
|
541
|
-
if (event.ctrlKey || event.metaKey) return;
|
|
542
|
-
const combobox = findAncestor(event, TAGNAME);
|
|
543
|
-
const state = states.get(combobox);
|
|
544
|
-
if (combobox == null || state == null) return;
|
|
545
|
-
if ((findAncestor(event, SELECTOR_ANCHOR) ?? findAncestor(event, SELECTOR_FILTER)) != null) handler(event, combobox, state);
|
|
546
|
-
}
|
|
547
|
-
function onInputKeydown(event, combobox, state) {
|
|
548
|
-
const isSelect = state.type === "select";
|
|
549
|
-
let preventDefault = true;
|
|
550
|
-
switch (true) {
|
|
551
|
-
case event.key === "Enter":
|
|
552
|
-
onEnter(combobox, state);
|
|
553
|
-
break;
|
|
554
|
-
case event.key === "Escape":
|
|
555
|
-
onEscape(state);
|
|
556
|
-
break;
|
|
557
|
-
case !isSelect && KEYS_SELECTION.has(event.key):
|
|
558
|
-
preventDefault = false;
|
|
559
|
-
if (hasTextSelection(state.anchor)) onSelection(combobox, state);
|
|
560
|
-
break;
|
|
561
|
-
case KEYS_NAVIGATION.has(event.key):
|
|
562
|
-
onNavigation(event, combobox, state);
|
|
563
|
-
break;
|
|
564
|
-
default:
|
|
565
|
-
preventDefault = false;
|
|
566
|
-
if (event.key === "Tab") onTab(combobox, state);
|
|
567
|
-
break;
|
|
568
|
-
}
|
|
569
|
-
if (preventDefault) {
|
|
570
|
-
event.preventDefault();
|
|
571
|
-
event.stopPropagation();
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
function onInputKeyup(event, combobox, state) {
|
|
575
|
-
const filter = state.filter.element ?? state.anchor;
|
|
576
|
-
const typed = event.key.length === 1 && EXPRESSION_TYPED.test(event.key);
|
|
577
|
-
if (!(filter instanceof HTMLInputElement) || !(typed || KEYS_REMOVE.has(event.key) || filter.value.length < state.filter.value.length)) return;
|
|
578
|
-
event.preventDefault();
|
|
579
|
-
event.stopPropagation();
|
|
580
|
-
if (typed) state.filter.value += event.key;
|
|
581
|
-
else state.filter.value = filter.value;
|
|
582
|
-
const [options] = getOptions(state);
|
|
583
|
-
const next = filterOptions(state, options);
|
|
584
|
-
if (typed) onTyped(combobox, state, options, next);
|
|
585
|
-
else setNext("remove", combobox, state, options, next);
|
|
586
|
-
}
|
|
587
|
-
function onKeydown(event) {
|
|
588
|
-
onInput(event, onInputKeydown);
|
|
589
|
-
}
|
|
590
|
-
function onKeyup(event) {
|
|
591
|
-
onInput(event, onInputKeyup);
|
|
592
|
-
}
|
|
593
|
-
function onNavigation(event, combobox, state) {
|
|
594
|
-
let skip = false;
|
|
595
|
-
if (!state.floatable.open) {
|
|
596
|
-
skip = true;
|
|
597
|
-
state.floatable.show();
|
|
598
|
-
}
|
|
599
|
-
const [all, visible] = getOptions(state);
|
|
600
|
-
if (visible.length === 0) return;
|
|
601
|
-
let next;
|
|
602
|
-
if (skip || state.active == null) next = state.active ?? visible.at(event.key === "ArrowDown" ? 0 : -1);
|
|
603
|
-
else {
|
|
604
|
-
const current = visible.findIndex((option) => option.id === state.active?.id);
|
|
605
|
-
let index;
|
|
606
|
-
switch (event.key) {
|
|
607
|
-
case "ArrowDown":
|
|
608
|
-
case "ArrowUp":
|
|
609
|
-
index = clamp(current + (event.key === "ArrowDown" ? 1 : -1), 0, visible.length - 1, true);
|
|
610
|
-
break;
|
|
611
|
-
case "End":
|
|
612
|
-
index = visible.length - 1;
|
|
613
|
-
break;
|
|
614
|
-
case "Home":
|
|
615
|
-
index = 0;
|
|
616
|
-
break;
|
|
617
|
-
case "PageDown":
|
|
618
|
-
case "PageUp":
|
|
619
|
-
index = clamp(current + (event.key === "PageDown" ? 10 : -10), 0, visible.length - 1);
|
|
620
|
-
break;
|
|
621
|
-
default: break;
|
|
622
|
-
}
|
|
623
|
-
if (index != null) next = visible[index];
|
|
624
|
-
}
|
|
625
|
-
setNext(state.autocomplete.none ? "none" : "navigation", combobox, state, all, next);
|
|
626
|
-
}
|
|
627
|
-
function onSelection(combobox, state) {
|
|
628
|
-
state.filter.value = state.anchor instanceof HTMLInputElement ? state.anchor.value : "";
|
|
629
|
-
filterOptions(state);
|
|
630
|
-
setNext("set", combobox, state, getOptions(state)[0], state.active);
|
|
631
|
-
}
|
|
632
|
-
function onTab(combobox, state) {
|
|
633
|
-
if (combobox !== document.activeElement || !combobox.contains(document.activeElement)) state.floatable.hide();
|
|
634
|
-
}
|
|
635
|
-
function onTyped(combobox, state, options, next) {
|
|
636
|
-
const filter = state.filter.element ?? state.anchor;
|
|
637
|
-
if (!state.autocomplete.inline && filter instanceof HTMLInputElement && filter.value.length > 0) state.floatable.show();
|
|
638
|
-
const all = options ?? getOptions(state)[0];
|
|
639
|
-
setNext("typed", combobox, state, all, state.autocomplete.none ? state.active ?? all[0] : next ?? filterOptions(state, options));
|
|
640
|
-
}
|
|
641
|
-
function setDisabled(combobox, state, value) {
|
|
642
|
-
setProperties("disabled", "disabled", combobox, state, value);
|
|
643
|
-
}
|
|
644
|
-
function setLimit(type, combobox, state, value) {
|
|
645
|
-
if (typeof value === "number" && !Number.isNaN(value) ? value !== state[type] : value == null) {
|
|
646
|
-
state[type] = value;
|
|
647
|
-
setAttribute(combobox, type, value);
|
|
648
|
-
updateValidity(state);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
function setNext(update, combobox, state, all, next) {
|
|
652
|
-
for (const option of all) setAttribute(option, ATTRIBUTE_OPTION_ACTIVE, option === next ? "" : void 0);
|
|
653
|
-
state.active = next;
|
|
654
|
-
setAria(state.anchor, "activedescendant", next?.id);
|
|
655
|
-
next?.scrollIntoView(scrollOptions);
|
|
656
|
-
setValue(update, combobox, state, next);
|
|
657
|
-
}
|
|
658
|
-
function setProperties(key, property, combobox, state, value) {
|
|
659
|
-
state[key] = value;
|
|
660
|
-
setAria(state.anchor, key, value);
|
|
661
|
-
setProperty(combobox, key, value);
|
|
662
|
-
if (state.filter.element != null) state.filter.element[property] = value;
|
|
663
|
-
if (state.anchor instanceof HTMLInputElement) state.anchor[property] = value;
|
|
664
|
-
}
|
|
665
|
-
function setReadonly(combobox, state, value) {
|
|
666
|
-
setProperties("readonly", "readOnly", combobox, state, value);
|
|
667
|
-
}
|
|
668
|
-
function setRequired(combobox, state, value) {
|
|
669
|
-
setProperties("required", "required", combobox, state, value);
|
|
670
|
-
updateValidity(state);
|
|
671
|
-
}
|
|
672
|
-
function setValue(update, combobox, state, next) {
|
|
673
|
-
if (state.disabled || state.readonly || state.type === "select" && update !== "set") return;
|
|
674
|
-
let added;
|
|
675
|
-
let shouldUpdate;
|
|
676
|
-
let values;
|
|
677
|
-
if (update === "set" || !(state.anchor instanceof HTMLInputElement)) {
|
|
678
|
-
added = updateSelected(update, state, next);
|
|
679
|
-
[values, shouldUpdate] = getFormValues(state, added);
|
|
680
|
-
} else {
|
|
681
|
-
const [all] = getOptions(state);
|
|
682
|
-
for (const option of all) setAria(option, "selected", false);
|
|
683
|
-
const input = state.anchor.value;
|
|
684
|
-
const content = next?.textContent ?? "";
|
|
685
|
-
const value = next == null ? "" : getAttribute(next, "value") ?? "";
|
|
686
|
-
let selected;
|
|
687
|
-
if (content.toLocaleLowerCase() === input.toLocaleLowerCase()) {
|
|
688
|
-
values = [value];
|
|
689
|
-
if (next != null) {
|
|
690
|
-
selected = next;
|
|
691
|
-
setAria(next, "selected", true);
|
|
692
|
-
}
|
|
693
|
-
} else values = [state.autocomplete.none ? input : ""];
|
|
694
|
-
state.selected = selected == null ? [] : [selected];
|
|
695
|
-
shouldUpdate = state.values[0] !== values[0];
|
|
696
|
-
}
|
|
697
|
-
if (shouldUpdate) updateForm(combobox, state, values);
|
|
698
|
-
if (next == null) return;
|
|
699
|
-
if (state.type === "select") updateSelect(update, state, next, added);
|
|
700
|
-
else if (update !== "remove") updateAutoComplete(update, state, next);
|
|
701
|
-
if (update === "set" && !state.multiple) state.floatable.hide();
|
|
702
|
-
setTimeout(() => {
|
|
703
|
-
updateWidth(state);
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
function setValues(combobox, state, value) {
|
|
707
|
-
if (!Array.isArray(value)) return;
|
|
708
|
-
const strings = (state.multiple ? value : [value]).map((value) => getString(value).toLocaleLowerCase());
|
|
709
|
-
const [all] = getOptions(state);
|
|
710
|
-
const selected = [];
|
|
711
|
-
const values = [];
|
|
712
|
-
let next;
|
|
713
|
-
for (const option of all) {
|
|
714
|
-
const value = getAttribute(option, "value");
|
|
715
|
-
if (value == null || !strings.includes(value.toLocaleLowerCase())) continue;
|
|
716
|
-
selected.push(option);
|
|
717
|
-
values.push(value);
|
|
718
|
-
next ??= option;
|
|
719
|
-
}
|
|
720
|
-
for (const option of state.selected) {
|
|
721
|
-
setAria(option, "selected", false);
|
|
722
|
-
state.selection?.querySelector(`[option="${option.id}"]`)?.remove();
|
|
723
|
-
}
|
|
724
|
-
for (const option of selected) {
|
|
725
|
-
setAria(option, "selected", true);
|
|
726
|
-
state.selection?.append(getSelectionItem(option));
|
|
727
|
-
}
|
|
728
|
-
state.selected = selected.slice();
|
|
729
|
-
setNext("navigation", combobox, state, all, next);
|
|
730
|
-
updateForm(combobox, state, values);
|
|
731
|
-
}
|
|
732
|
-
function updateAutoComplete(update, state, next) {
|
|
733
|
-
if (!(update === "set" || state.autocomplete.both || state.autocomplete.inline)) return;
|
|
734
|
-
const content = next.textContent ?? "";
|
|
735
|
-
if (update === "typed" && !content.toLocaleLowerCase().startsWith(state.filter.value.toLocaleLowerCase())) return;
|
|
736
|
-
const { length } = content;
|
|
737
|
-
if (state.anchor instanceof HTMLInputElement) {
|
|
738
|
-
state.anchor.value = content;
|
|
739
|
-
state.anchor.setSelectionRange(update === "typed" ? state.filter.value.length : length, length);
|
|
740
|
-
} else state.anchor.textContent = content;
|
|
741
|
-
}
|
|
742
|
-
function updateForm(combobox, state, values) {
|
|
743
|
-
const formValues = values.length === 0 ? [""] : values;
|
|
744
|
-
const formData = new FormData();
|
|
745
|
-
for (const value of formValues) formData.append(state.name, value);
|
|
746
|
-
state.values = formValues;
|
|
747
|
-
state.internals.setFormValue(formData);
|
|
748
|
-
updateValidity(state);
|
|
749
|
-
dispatch(combobox, "change");
|
|
750
|
-
}
|
|
751
|
-
function updateSelect(update, state, next, added) {
|
|
752
|
-
if (update !== "set") return;
|
|
753
|
-
if (!state.multiple) {
|
|
754
|
-
state.anchor.textContent = next.textContent ?? "";
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
if (added === true) state.selection?.append(getSelectionItem(next));
|
|
758
|
-
else if (added === false) state.selection?.querySelector(`[option="${next.id}"]`)?.remove();
|
|
759
|
-
}
|
|
760
|
-
function updateSelected(update, state, next) {
|
|
761
|
-
const [all] = getOptions(state);
|
|
762
|
-
for (const option of all) setAria(option, "selected", getSelected(update, state, option, next));
|
|
763
|
-
if (next == null) return;
|
|
764
|
-
if (state.type !== "select") {
|
|
765
|
-
state.selected = [next];
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
768
|
-
if (update !== "set") return;
|
|
769
|
-
if (!state.multiple) {
|
|
770
|
-
state.selected = [next];
|
|
771
|
-
return;
|
|
772
|
-
}
|
|
773
|
-
const index = state.selected.indexOf(next);
|
|
774
|
-
const added = index === -1;
|
|
775
|
-
if (added) state.selected.push(next);
|
|
776
|
-
else state.selected.splice(index, 1);
|
|
777
|
-
return added;
|
|
778
|
-
}
|
|
779
|
-
function updateValidity(state) {
|
|
780
|
-
if (state.autocomplete.none) {
|
|
781
|
-
const valueMissing = state.required && state.values[0].length === 0;
|
|
782
|
-
state.internals.setValidity({ valueMissing }, INVALID_INPUT);
|
|
783
|
-
state.internals.checkValidity();
|
|
784
|
-
return;
|
|
785
|
-
}
|
|
786
|
-
const rangeOverflow = state.multiple && typeof state.max === "number" && state.selected.length > state.max;
|
|
787
|
-
const rangeUnderflow = state.multiple && typeof state.min === "number" && state.selected.length < state.min;
|
|
788
|
-
const badInput = state.required && state.selected.length === 0;
|
|
789
|
-
state.internals.setValidity({
|
|
790
|
-
badInput,
|
|
791
|
-
rangeOverflow,
|
|
792
|
-
rangeUnderflow
|
|
793
|
-
}, join([
|
|
794
|
-
badInput ? INVALID_BAD : void 0,
|
|
795
|
-
rangeOverflow ? getString(INVALID_OVERFLOW).replace("{max}", state.max.toString()) : void 0,
|
|
796
|
-
rangeUnderflow ? getString(INVALID_UNDERFLOW).replace("{min}", state.min.toString()) : void 0
|
|
797
|
-
], "; "));
|
|
798
|
-
state.internals.checkValidity();
|
|
799
|
-
}
|
|
800
|
-
function updateWidth(state) {
|
|
801
|
-
setStyle(state.content, PROPERTY_STYLE, `${state.anchor.getBoundingClientRect().width}px`);
|
|
802
|
-
}
|
|
803
|
-
const TAGNAME = "oui-combobox";
|
|
804
|
-
const ATTRIBUTE_ANCHOR = `${TAGNAME}-anchor`;
|
|
805
|
-
const ATTRIBUTE_CONTENT = `${TAGNAME}-content`;
|
|
806
|
-
const ATTRIBUTE_EMPTY = `${TAGNAME}-empty`;
|
|
807
|
-
const ATTRIBUTE_FILTER = `${TAGNAME}-filter`;
|
|
808
|
-
const ATTRIBUTE_FILTER_INPUT = `${ATTRIBUTE_FILTER}-input`;
|
|
809
|
-
const ATTRIBUTE_FILTER_LABEL = `${ATTRIBUTE_FILTER}-label`;
|
|
810
|
-
const ATTRIBUTE_HEADER = `${TAGNAME}-header`;
|
|
811
|
-
const ATTRIBUTE_LIST = `${TAGNAME}-list`;
|
|
812
|
-
const ATTRIBUTE_OPTION = `${TAGNAME}-option`;
|
|
813
|
-
const ATTRIBUTE_OPTION_ACTIVE = `${TAGNAME}-option-active`;
|
|
814
|
-
const ATTRIBUTE_SELECTION = `${TAGNAME}-selection`;
|
|
815
|
-
const ATTRIBUTE_SELECTION_ITEM = `${TAGNAME}-selection-item`;
|
|
816
|
-
const AUTOCOMPLETES = /* @__PURE__ */ new Set([
|
|
817
|
-
"both",
|
|
818
|
-
"inline",
|
|
819
|
-
"list",
|
|
820
|
-
"none"
|
|
821
|
-
]);
|
|
822
|
-
const EXPRESSION_TYPED = /\p{L}|\s/u;
|
|
823
|
-
const INVALID_BAD = "Please select an option from the list";
|
|
824
|
-
const INVALID_INPUT = "Please enter a value";
|
|
825
|
-
const INVALID_OVERFLOW = "Please select fewer options (maximum is {max})";
|
|
826
|
-
const INVALID_UNDERFLOW = "Please select more options (minimum is {min})";
|
|
827
|
-
const KEYS_NAVIGATION = /* @__PURE__ */ new Set([
|
|
828
|
-
"ArrowDown",
|
|
829
|
-
"ArrowUp",
|
|
830
|
-
"PageDown",
|
|
831
|
-
"PageUp"
|
|
832
|
-
]);
|
|
833
|
-
const KEYS_REMOVE = /* @__PURE__ */ new Set(["Backspace", "Delete"]);
|
|
834
|
-
const KEYS_SELECTION = /* @__PURE__ */ new Set(["ArrowRight", "End"]);
|
|
835
|
-
const MESSAGE_LABEL = `<${TAGNAME}> must contain a <label> element for the <select> element`;
|
|
836
|
-
const MESSAGE_SELECT = `<${TAGNAME}> must contain a valid <select> element`;
|
|
837
|
-
const PROPERTY_STYLE = "--oui-combobox-width";
|
|
838
|
-
const SELECTOR_ANCHOR = `[${ATTRIBUTE_ANCHOR}]`;
|
|
839
|
-
const SELECTOR_FILTER = `[${ATTRIBUTE_FILTER_INPUT}]`;
|
|
840
|
-
const SELECTOR_OPTION = `[${ATTRIBUTE_OPTION}]`;
|
|
841
|
-
const TYPES = /* @__PURE__ */ new Set(["autocomplete", "select"]);
|
|
842
|
-
const comboboxes = /* @__PURE__ */ new WeakMap();
|
|
843
|
-
const scrollOptions = {
|
|
844
|
-
behavior: "smooth",
|
|
845
|
-
block: "nearest",
|
|
846
|
-
inline: "nearest"
|
|
847
|
-
};
|
|
848
|
-
const states = /* @__PURE__ */ new WeakMap();
|
|
849
|
-
let index = 0;
|
|
850
|
-
on(document, "click", onClick);
|
|
851
|
-
on(document, "keydown", onKeydown, { passive: false });
|
|
852
|
-
on(document, "keyup", onKeyup, { passive: false });
|
|
853
|
-
customElements.define(TAGNAME, OuiComboboxElement);
|
|
854
|
-
//#endregion
|
|
855
|
-
export { OuiComboboxElement };
|