@oscarpalmer/oui 0.32.0 → 0.33.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/index.mjs CHANGED
@@ -1,18 +1,4875 @@
1
- import { createFloatable } from "./floatable/floatable.embedded.mjs";
2
- import { OuiComboboxElement } from "./combobox.mjs";
3
- import { createMovable } from "./movable/movable.embedded.mjs";
4
- import "./movable/movable.standalone.mjs";
5
- import { createResizable } from "./resizable/resizable.embedded.mjs";
6
- import { getDialog } from "./dialog.mjs";
7
- import "./menu.mjs";
8
- import "./toolbar.mjs";
9
- import "./floatable/floatable.standalone.mjs";
10
- import { createFocusTrap } from "./focus-trap/focus-trap.embedded.mjs";
11
- import "./focus-trap/focus-trap.standalone.mjs";
12
- import { getPopover } from "./popover.mjs";
13
- import "./resizable/resizable.standalone.mjs";
14
- import { createSortable } from "./sortable/sortable.embedded.mjs";
15
- import "./sortable/sortable.standalone.mjs";
16
- import { OuiSplitterElement } from "./splitter.mjs";
17
- import { getTooltip, setTooltipDelay } from "./tooltip.mjs";
18
- export { OuiComboboxElement, OuiSplitterElement, createFloatable, createFocusTrap, createMovable, createResizable as createOuiResizable, createSortable, getDialog, getPopover, getTooltip, setTooltipDelay };
1
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/is.mjs
2
+ /**
3
+ * Is the value an event position?
4
+ *
5
+ * @param value Value to check
6
+ * @returns `true` if it's an event position, otherwise `false`
7
+ */
8
+ function isEventPosition(value) {
9
+ return typeof value === "object" && value != null && typeof value.x === "number" && typeof value.y === "number";
10
+ }
11
+ /**
12
+ * Is the value an event target?
13
+ *
14
+ * @param value Value to check
15
+ * @returns `true` if it's an event target, otherwise `false`
16
+ */
17
+ function isEventTarget(value) {
18
+ return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
19
+ }
20
+ /**
21
+ * Is the value an _HTML_ or _SVG_ element?
22
+ *
23
+ * @param value Value to check
24
+ * @returns `true` if it's an _HTML_ or _SVG_ element, otherwise `false`
25
+ */
26
+ function isHTMLOrSVGElement(value) {
27
+ return value instanceof HTMLElement || value instanceof SVGElement;
28
+ }
29
+ /**
30
+ * Is the value an input element? _(`<input>`, `<select>`, or `<textarea>`)_
31
+ *
32
+ * @param value Value to check
33
+ * @returns `true` if it's an input element, otherwise `false`
34
+ */
35
+ function isInputElement(value) {
36
+ return value instanceof HTMLInputElement || value instanceof HTMLSelectElement || value instanceof HTMLTextAreaElement;
37
+ }
38
+ //#endregion
39
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/is.mjs
40
+ /**
41
+ * Is the value a number?
42
+ *
43
+ * @param value Value to check
44
+ * @returns `true` if the value is a `number`, otherwise `false`
45
+ */
46
+ function isNumber(value) {
47
+ return typeof value === "number" && !Number.isNaN(value);
48
+ }
49
+ /**
50
+ * Is the value a plain object?
51
+ *
52
+ * @param value Value to check
53
+ * @returns `true` if the value is a plain object, otherwise `false`
54
+ */
55
+ function isPlainObject(value) {
56
+ if (value === null || typeof value !== "object") return false;
57
+ if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
58
+ const prototype = Object.getPrototypeOf(value);
59
+ return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
60
+ }
61
+ //#endregion
62
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
63
+ /**
64
+ * Get the string value from any value
65
+ *
66
+ * @param value Original value
67
+ * @returns String representation of the value
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * getString(null) // => ''
72
+ * getString('foo') // => 'foo'
73
+ * getString(123) // => '123'
74
+ * getString(true) // => 'true'
75
+ * getString([1, 2, 3]) // => '1,2,3'
76
+ * getString({a: 1}) // => '{"a":1}'
77
+ * getString(() => 123) // => '123'
78
+ * ```
79
+ */
80
+ function getString(value) {
81
+ if (typeof value === "string") return value;
82
+ if (value == null) return "";
83
+ if (typeof value === "function") return getString(value());
84
+ if (typeof value !== "object") return String(value);
85
+ const asString = String(value.valueOf?.() ?? value);
86
+ return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
87
+ }
88
+ /**
89
+ * Join an array of values into a string _(while ignoring empty values)_
90
+ *
91
+ * _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
92
+ *
93
+ * @param array Array of values
94
+ * @param delimiter Delimiter to use between values
95
+ * @returns Joined string
96
+ */
97
+ function join(array, delimiter) {
98
+ if (!Array.isArray(array)) return "";
99
+ const { length } = array;
100
+ if (length === 0) return "";
101
+ const values = [];
102
+ for (let index = 0; index < length; index += 1) {
103
+ const item = getString(array[index]);
104
+ if (item.length > 0) values.push(item);
105
+ }
106
+ return values.join(typeof delimiter === "string" ? delimiter : "");
107
+ }
108
+ /**
109
+ * Split a string into words _(and other readable parts)_
110
+ *
111
+ * @param value Original string
112
+ * @returns Array of words found in the string
113
+ */
114
+ function words(value) {
115
+ return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
116
+ }
117
+ const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
118
+ //#endregion
119
+ //#region node_modules/@oscarpalmer/atoms/dist/string/index.mjs
120
+ /**
121
+ * Parse a JSON string into its proper value _(or `undefined` if it fails)_
122
+ *
123
+ * @param value JSON string to parse
124
+ * @param reviver Reviver function to transform the parsed values
125
+ * @returns Parsed value or `undefined` if parsing fails
126
+ */
127
+ function parse(value, reviver) {
128
+ try {
129
+ return JSON.parse(value, reviver);
130
+ } catch {
131
+ return;
132
+ }
133
+ }
134
+ //#endregion
135
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
136
+ /**
137
+ * Clamp a number between a minimum and maximum value
138
+ *
139
+ * @param value Value to clamp
140
+ * @param minimum Minimum value
141
+ * @param maximum Maximum value
142
+ * @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
143
+ * @returns Clamped value
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * clamp(10, 0, 5); // => 5
148
+ * clamp(10, 0, 5, true); // => 0
149
+ * ```
150
+ */
151
+ function clamp(value, minimum, maximum, loop) {
152
+ if (![
153
+ value,
154
+ minimum,
155
+ maximum
156
+ ].every(isNumber)) return NaN;
157
+ if (value < minimum) return loop === true ? maximum : minimum;
158
+ return value > maximum ? loop === true ? minimum : maximum : value;
159
+ }
160
+ /**
161
+ * Get the number value from an unknown value
162
+ *
163
+ * _(Based on Lodash)_
164
+ *
165
+ * @param value Original value
166
+ * @returns Original value as a number, or `Number.NaN` if the value is unable to be parsed
167
+ */
168
+ function getNumber(value) {
169
+ if (typeof value === "number") return value;
170
+ if (typeof value === "bigint" || typeof value === "boolean") return Number(value);
171
+ if (value == null || typeof value === "symbol") return NaN;
172
+ if (typeof value === "function") return getNumber(value());
173
+ let parsed = value.valueOf();
174
+ if (typeof parsed === "object") parsed = parsed.toString();
175
+ if (typeof parsed !== "string") return getNumber(parsed);
176
+ const trimmed = parsed.trim();
177
+ if (trimmed.length === 0) return NaN;
178
+ if (EXPRESSION_ZEROISH.test(parsed)) return 0;
179
+ const isBinary = EXPRESSION_BINARY.test(trimmed);
180
+ if (isBinary || EXPRESSION_OCTAL.test(trimmed)) return Number.parseInt(trimmed.slice(2), isBinary ? 2 : OCTAL_VALUE);
181
+ return Number(trimmed);
182
+ }
183
+ const EXPRESSION_BINARY = /^0b[01]+$/i;
184
+ const EXPRESSION_OCTAL = /^0o[0-7]+$/i;
185
+ const EXPRESSION_ZEROISH = /^\s*0+\s*$/;
186
+ const OCTAL_VALUE = 8;
187
+ //#endregion
188
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/sized.mjs
189
+ function getSizedMaximum(first, second) {
190
+ let actual;
191
+ if (typeof first === "number") actual = first;
192
+ else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
193
+ return clamp(actual, 1, MAXIMUM_ABSOLUTE);
194
+ }
195
+ const MAXIMUM_ABSOLUTE = 16777216;
196
+ const MAXIMUM_DEFAULT = 1048576;
197
+ //#endregion
198
+ //#region node_modules/@oscarpalmer/atoms/dist/sized/map.mjs
199
+ /**
200
+ * A _Map_ with a maximum size
201
+ *
202
+ * Behavior is similar to a _LRU_ cache, where the least recently used entries are removed
203
+ */
204
+ var SizedMap = class extends Map {
205
+ /**
206
+ * The maximum size of the _Map_
207
+ */
208
+ #maximumSize;
209
+ /**
210
+ * Is the _Map_ full?
211
+ */
212
+ get full() {
213
+ return super.size >= this.#maximumSize;
214
+ }
215
+ get maximum() {
216
+ return this.#maximumSize;
217
+ }
218
+ constructor(first, second) {
219
+ const maximum = getSizedMaximum(first, second);
220
+ super();
221
+ this.#maximumSize = maximum;
222
+ if (Array.isArray(first)) {
223
+ const { length } = first;
224
+ if (length <= maximum) for (let index = 0; index < length; index += 1) this.set(...first[index]);
225
+ else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
226
+ }
227
+ }
228
+ /**
229
+ * @inheritdoc
230
+ */
231
+ get(key) {
232
+ if (super.has(key)) {
233
+ const value = super.get(key);
234
+ this.#setValue(key, value, true);
235
+ return value;
236
+ }
237
+ }
238
+ /**
239
+ * @inheritdoc
240
+ */
241
+ set(key, value) {
242
+ return this.#setValue(key, value, super.has(key));
243
+ }
244
+ #setValue(key, value, has) {
245
+ if (has) super.delete(key);
246
+ else if (super.size >= this.#maximumSize) super.delete(super.keys().next().value);
247
+ super.set(key, value);
248
+ return this;
249
+ }
250
+ };
251
+ //#endregion
252
+ //#region node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
253
+ /**
254
+ * A _Memoized_ function instance, caching and retrieving results based on the its parameters _(or a custom cache key)_
255
+ */
256
+ var Memoized = class {
257
+ #state;
258
+ /**
259
+ * Maximum cache size
260
+ *
261
+ * @returns Maximum cache size _(or `Number.NaN` if the instance has been destroyed)_
262
+ */
263
+ get maximum() {
264
+ return this.#state.cache?.maximum ?? NaN;
265
+ }
266
+ /**
267
+ * Current cache size
268
+ *
269
+ * @returns Current cache size _(or `Number.NaN` if the instance has been destroyed)_
270
+ */
271
+ get size() {
272
+ return this.#state.cache?.size ?? NaN;
273
+ }
274
+ constructor(callback, options) {
275
+ const cache = new SizedMap(options.cacheSize);
276
+ const getter = (...parameters) => {
277
+ const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), SEPARATOR));
278
+ if (cache.has(key)) return cache.get(key);
279
+ const value = callback(...parameters);
280
+ cache.set(key, value);
281
+ return value;
282
+ };
283
+ this.#state = {
284
+ cache,
285
+ getter
286
+ };
287
+ }
288
+ /**
289
+ * Clear the cache
290
+ */
291
+ clear() {
292
+ this.#state.cache?.clear();
293
+ }
294
+ /**
295
+ * Delete a result from the cache
296
+ *
297
+ * @param key Key to delete
298
+ * @returns `true` if the key existed and was removed, otherwise `false`
299
+ */
300
+ delete(key) {
301
+ return this.#state.cache?.delete(key) ?? false;
302
+ }
303
+ /**
304
+ * Destroy the instance
305
+ *
306
+ * _(When a Memoized instance is destroyed, its cache and callback are removed, and calls to `run` will throw an error)_
307
+ */
308
+ destroy() {
309
+ this.#state.cache?.clear();
310
+ this.#state.cache = void 0;
311
+ this.#state.getter = void 0;
312
+ }
313
+ /**
314
+ * Get a result from the cache
315
+ *
316
+ * @param key Key to get
317
+ * @returns Cached result or `undefined` if it does not exist
318
+ */
319
+ get(key) {
320
+ return this.#state.cache?.get(key);
321
+ }
322
+ /**
323
+ * Does the result exist?
324
+ *
325
+ * @param key Key to check
326
+ * @returns `true` if the result exists, otherwise `false`
327
+ */
328
+ has(key) {
329
+ return this.#state.cache?.has(key) ?? false;
330
+ }
331
+ /**
332
+ * Run the callback with the provided parameters
333
+ *
334
+ * @param parameters Parameters to pass to the callback
335
+ * @returns Cached or computed _(then cached)_ result
336
+ */
337
+ run(...parameters) {
338
+ if (this.#state.cache == null || this.#state.getter == null) throw new Error(MEMOIZED_ERROR_DESTROYED);
339
+ return this.#state.getter(...parameters);
340
+ }
341
+ };
342
+ function getMemoizationOptions(input) {
343
+ const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
344
+ return {
345
+ cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
346
+ cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
347
+ };
348
+ }
349
+ /**
350
+ * Memoize a function, caching and retrieving results based on the first parameter
351
+ *
352
+ * @param callback Callback to memoize
353
+ * @param options Memoization options
354
+ * @returns _Memoized_ instance
355
+ */
356
+ function memoize(callback, options) {
357
+ if (typeof callback !== "function") throw new TypeError(MEMOIZED_ERROR_CALLBACK);
358
+ return new Memoized(callback, getMemoizationOptions(options));
359
+ }
360
+ const DEFAULT_CACHE_SIZE = 1024;
361
+ const MEMOIZED_ERROR_CALLBACK = "Memoized requires a callback function";
362
+ const MEMOIZED_ERROR_DESTROYED = "The Memoized instance has been destroyed";
363
+ const SEPARATOR = "_";
364
+ //#endregion
365
+ //#region node_modules/@oscarpalmer/atoms/dist/string/case.mjs
366
+ /**
367
+ * Convert a string to camel case _(thisIsCamelCase)_
368
+ *
369
+ * @param value String to convert
370
+ * @returns Camel-cased string
371
+ */
372
+ function camelCase(value) {
373
+ return toCase(CASE_CAMEL, value, true, false);
374
+ }
375
+ /**
376
+ * Capitalize the first letter of a string _(and lowercase the rest)_
377
+ *
378
+ * @param value String to capitalize
379
+ * @returns Capitalized string
380
+ */
381
+ function capitalize(value) {
382
+ if (typeof value !== "string" || value.length === 0) return "";
383
+ memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
384
+ return memoizedCapitalize.run(value);
385
+ }
386
+ /**
387
+ * Convert a string to kebab case _(this-is-kebab-case)_
388
+ *
389
+ * @param value String to convert
390
+ * @returns Kebab-cased string
391
+ */
392
+ function kebabCase(value) {
393
+ return toCase(CASE_KEBAB, value, false, false);
394
+ }
395
+ function toCase(type, value, capitalizeAny, capitalizeFirst) {
396
+ caseMemoizers[type] ??= memoize(toCaseCallback.bind({
397
+ type,
398
+ capitalizeAny,
399
+ capitalizeFirst
400
+ }));
401
+ return caseMemoizers[type].run(value);
402
+ }
403
+ function toCaseCallback(value) {
404
+ if (typeof value !== "string") return "";
405
+ if (value.length < 1) return value;
406
+ const { capitalizeAny, capitalizeFirst, type } = this;
407
+ const parts = words(value);
408
+ const partsLength = parts.length;
409
+ const cased = [];
410
+ for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
411
+ const items = parts[partIndex].replace(EXPRESSION_ACRONYM, (full, one, two, three) => three === S ? full : `${one}-${two}${three}`).replace(EXPRESSION_CAMEL_CASE, REPLACEMENT_CAMEL_CASE).split("-");
412
+ const itemsLength = items.length;
413
+ const partResult = [];
414
+ let itemCount = 0;
415
+ for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
416
+ const item = items[itemIndex];
417
+ if (item.length === 0) continue;
418
+ if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
419
+ else partResult.push(capitalize(item));
420
+ itemCount += 1;
421
+ }
422
+ cased.push(join(partResult, delimiters[type]));
423
+ }
424
+ return join(cased, delimiters[type]);
425
+ }
426
+ const CASE_CAMEL = "camel";
427
+ const CASE_KEBAB = "kebab";
428
+ const CASE_PASCAL = "pascal";
429
+ const CASE_SNAKE = "snake";
430
+ const DELIMTER_EMPTY = "";
431
+ const DELIMITER_HYPHEN = "-";
432
+ const DELIMITER_UNDERSCORE = "_";
433
+ const EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
434
+ const EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
435
+ const REPLACEMENT_CAMEL_CASE = "$1-$2";
436
+ const S = "s";
437
+ const caseMemoizers = {};
438
+ const delimiters = {
439
+ [CASE_CAMEL]: DELIMTER_EMPTY,
440
+ [CASE_KEBAB]: DELIMITER_HYPHEN,
441
+ [CASE_PASCAL]: DELIMTER_EMPTY,
442
+ [CASE_SNAKE]: DELIMITER_UNDERSCORE
443
+ };
444
+ let memoizedCapitalize;
445
+ //#endregion
446
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/property.mjs
447
+ function getPropertyValue(element, name, value) {
448
+ if (isInputElement(element) && name === "value") return getString(value);
449
+ return value;
450
+ }
451
+ function updateProperty(element, name, value, dispatch) {
452
+ let property = name;
453
+ if (!(property in element)) property = camelCase(name);
454
+ const next = getPropertyValue(element, name, value);
455
+ if (!(property in element) || Object.is(element[property], next)) return;
456
+ element[property] = next;
457
+ const event = dispatch && elementEvents[element.tagName]?.[property];
458
+ if (typeof event === "string") element.dispatchEvent(new Event(event, {
459
+ bubbles: true,
460
+ cancelable: true
461
+ }));
462
+ }
463
+ const elementEvents = {
464
+ DETAILS: { open: "toggle" },
465
+ INPUT: {
466
+ checked: "change",
467
+ value: "input"
468
+ },
469
+ SELECT: { value: "change" },
470
+ TEXTAREA: { value: "input" }
471
+ };
472
+ //#endregion
473
+ //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
474
+ /**
475
+ * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
476
+ *
477
+ * @param value Value to check
478
+ * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
479
+ */
480
+ function isNullableOrWhitespace(value) {
481
+ return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
482
+ }
483
+ const EXPRESSION_WHITESPACE$1 = /^\s*$/;
484
+ //#endregion
485
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/attribute.mjs
486
+ function isAttribute(value) {
487
+ return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && "value" in value;
488
+ }
489
+ function updateAttribute(element, name, value, dispatch) {
490
+ const lowerCaseName = name.toLowerCase();
491
+ const isBoolean = booleanAttributesSet.has(lowerCaseName);
492
+ const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === lowerCaseName) : value == null ? "" : value;
493
+ if (isBoolean || dispatchedAttributes.has(name)) updateProperty(element, name, next, dispatch);
494
+ updateElementValue(element, name, isBoolean ? next ? "" : null : value, element.setAttribute, element.removeAttribute, false);
495
+ }
496
+ /**
497
+ * List of boolean attributes
498
+ */
499
+ const booleanAttributes = Object.freeze([
500
+ "async",
501
+ "autofocus",
502
+ "autoplay",
503
+ "checked",
504
+ "controls",
505
+ "default",
506
+ "defer",
507
+ "disabled",
508
+ "formnovalidate",
509
+ "hidden",
510
+ "inert",
511
+ "ismap",
512
+ "itemscope",
513
+ "loop",
514
+ "multiple",
515
+ "muted",
516
+ "nomodule",
517
+ "novalidate",
518
+ "open",
519
+ "playsinline",
520
+ "readonly",
521
+ "required",
522
+ "reversed",
523
+ "selected"
524
+ ]);
525
+ const booleanAttributesSet = new Set(booleanAttributes);
526
+ const dispatchedAttributes = /* @__PURE__ */ new Set([
527
+ "checked",
528
+ "open",
529
+ "value"
530
+ ]);
531
+ document.createElement("form");
532
+ //#endregion
533
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/element-value.mjs
534
+ function getValueForAttribute(value, json) {
535
+ if (typeof value === "string") return value;
536
+ return json ? JSON.stringify(value) : getString(value);
537
+ }
538
+ function ignoreSetAttribute(element, name) {
539
+ if (element instanceof HTMLTextAreaElement && name === "value") return true;
540
+ return false;
541
+ }
542
+ function normalizeKey(key, style) {
543
+ return style && key.startsWith(CSS_VARIABLE_PREFIX$1) ? key : kebabCase(key);
544
+ }
545
+ function setElementValue(element, first, second, third, callback, style) {
546
+ if (!(element instanceof Element)) return;
547
+ if (typeof first === "string") setElementValues(element, first, second, third, callback, style);
548
+ else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback, style);
549
+ }
550
+ function setElementValues(element, first, second, third, callback, style) {
551
+ if (!(element instanceof Element)) return;
552
+ const dispatch = third !== false;
553
+ if (typeof first === "string") {
554
+ callback(element, normalizeKey(first, style), second, dispatch);
555
+ return;
556
+ }
557
+ const isArray = Array.isArray(first);
558
+ if (!isArray && !(typeof first === "object" && first !== null)) return;
559
+ const entries = isArray ? first : Object.entries(first).map(([name, value]) => ({
560
+ name,
561
+ value
562
+ }));
563
+ const { length } = entries;
564
+ for (let index = 0; index < length; index += 1) {
565
+ const entry = entries[index];
566
+ if (typeof entry === "object" && typeof entry?.name === "string") callback(element, normalizeKey(entry.name, style), entry.value, dispatch);
567
+ }
568
+ }
569
+ function updateElementValue(element, key, value, set, remove, json) {
570
+ if (value == null) remove.call(element, key);
571
+ else if (!ignoreSetAttribute(element, key)) set.call(element, key, getValueForAttribute(value, json));
572
+ }
573
+ const CSS_VARIABLE_PREFIX$1 = "--";
574
+ //#endregion
575
+ //#region node_modules/@oscarpalmer/toretto/dist/aria.mjs
576
+ function getAria(element, value) {
577
+ if (!(element instanceof Element)) return Array.isArray(value) ? {} : void 0;
578
+ if (!Array.isArray(value)) return typeof value === "string" ? getAriaValue(element, value) : void 0;
579
+ const arias = {};
580
+ const { length } = value;
581
+ for (let index = 0; index < length; index += 1) {
582
+ const attribute = value[index];
583
+ if (typeof attribute === "string") arias[attribute.replace(ATTRIBUTE_ARIA_PREFIX, "")] = getAriaValue(element, attribute);
584
+ }
585
+ return arias;
586
+ }
587
+ function getAriaValue(element, attribute) {
588
+ const name = getName$1(attribute);
589
+ const value = element.getAttribute(name) ?? void 0;
590
+ if (ariaBooleanAttributesSet.has(name) && typeof value === "string" && EXPRESSION_BOOLEAN.test(value)) return value.toLowerCase() === "true";
591
+ return value;
592
+ }
593
+ function getName$1(value) {
594
+ return EXPRESSION_ARIA_PREFIX.test(value) ? value : `${ATTRIBUTE_ARIA_PREFIX}${value}`;
595
+ }
596
+ function setAria(element, first, second) {
597
+ setElementValues(element, first, second, null, updateAriaAttribute);
598
+ }
599
+ /**
600
+ * Set the role of an element
601
+ *
602
+ * @param element Element for role
603
+ * @param role Role to set _(or `undefined` to remove it)_
604
+ */
605
+ function setRole(element, role) {
606
+ if (!(element instanceof Element)) return;
607
+ if (typeof role === "string") element.setAttribute("role", role);
608
+ else element.removeAttribute("role");
609
+ }
610
+ function updateAriaAttribute(element, key, value) {
611
+ const name = getName$1(key);
612
+ let actual = value;
613
+ if (ariaBooleanAttributesSet.has(name) && typeof value === "string" && EXPRESSION_BOOLEAN.test(value)) actual = value.toLowerCase() === "true";
614
+ updateElementValue(element, name, actual, element.setAttribute, element.removeAttribute, false);
615
+ }
616
+ const ATTRIBUTE_ARIA_PREFIX = "aria-";
617
+ const EXPRESSION_ARIA_PREFIX = /^aria-/i;
618
+ const EXPRESSION_BOOLEAN = /^(true|false)$/i;
619
+ /**
620
+ * List of _ARIA_ attributes that can be treated as boolean values
621
+ */
622
+ const ariaBooleanAttributes = Object.freeze([
623
+ "aria-atomic",
624
+ "aria-busy",
625
+ "aria-checked",
626
+ "aria-current",
627
+ "aria-disabled",
628
+ "aria-expanded",
629
+ "aria-haspopup",
630
+ "aria-hidden",
631
+ "aria-invalid",
632
+ "aria-modal",
633
+ "aria-multiline",
634
+ "aria-multiselectable",
635
+ "aria-pressed",
636
+ "aria-readonly",
637
+ "aria-required",
638
+ "aria-selected"
639
+ ]);
640
+ /**
641
+ * Set of _ARIA_ attributes that can be treated as boolean values
642
+ */
643
+ const ariaBooleanAttributesSet = new Set(ariaBooleanAttributes);
644
+ //#endregion
645
+ //#region node_modules/@oscarpalmer/toretto/dist/internal/get-value.mjs
646
+ function getBoolean(value, defaultValue) {
647
+ return typeof value === "boolean" ? value : defaultValue ?? false;
648
+ }
649
+ function getAttributeValue$1(element, name, parseValue) {
650
+ const normalized = kebabCase(name);
651
+ const attribute = element.attributes[normalized];
652
+ const value = attribute instanceof Attr ? attribute.value : void 0;
653
+ return EXPRESSION_DATA_PREFIX.test(normalized) && typeof value === "string" && parseValue ? parse(value) ?? value : value;
654
+ }
655
+ function getStyleValue(element, property, computed) {
656
+ if (property.startsWith(CSS_VARIABLE_PREFIX)) return element.style.getPropertyValue(property);
657
+ const name = camelCase(property);
658
+ return computed ? getComputedStyle(element)[name] : element.style[name];
659
+ }
660
+ const EXPRESSION_DATA_PREFIX = /^data-/i;
661
+ const CSS_VARIABLE_PREFIX = "--";
662
+ //#endregion
663
+ //#region node_modules/@oscarpalmer/toretto/dist/attribute/get.attribute.mjs
664
+ function getAttribute(element, name, parseValues) {
665
+ if (element instanceof Element && typeof name === "string") return getAttributeValue$1(element, kebabCase(name), parseValues !== false);
666
+ }
667
+ //#endregion
668
+ //#region node_modules/@oscarpalmer/toretto/dist/attribute/set.attribute.mjs
669
+ function setAttribute(element, first, second, third) {
670
+ setElementValue(element, first, second, third, updateAttribute);
671
+ }
672
+ function setAttributes(element, attributes, dispatch) {
673
+ setElementValues(element, attributes, null, dispatch, updateAttribute);
674
+ }
675
+ //#endregion
676
+ //#region node_modules/@oscarpalmer/toretto/dist/event/delegation.mjs
677
+ function addDelegatedHandler(doc, type, name, passive) {
678
+ if (DELEGATED.has(name)) return;
679
+ DELEGATED.add(name);
680
+ doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
681
+ }
682
+ function addDelegatedListener(target, type, name, listener, passive) {
683
+ target[name] ??= /* @__PURE__ */ new Set();
684
+ target[name].add(listener);
685
+ addDelegatedHandler(document, type, name, passive);
686
+ return () => {
687
+ removeDelegatedListener(target, name, listener);
688
+ };
689
+ }
690
+ function delegatedEventHandler(event) {
691
+ const key = `@${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
692
+ const items = event.composedPath();
693
+ const { length } = items;
694
+ let cancelled = false;
695
+ let target = items[0];
696
+ const originalStopPropagation = event.stopPropagation;
697
+ event.stopPropagation = function() {
698
+ cancelled = true;
699
+ originalStopPropagation.call(event);
700
+ };
701
+ event.stopImmediatePropagation = event.stopPropagation.bind(event);
702
+ Object.defineProperties(event, {
703
+ currentTarget: {
704
+ configurable: true,
705
+ get() {
706
+ return target;
707
+ }
708
+ },
709
+ target: {
710
+ configurable: true,
711
+ value: target
712
+ }
713
+ });
714
+ for (let index = 0; index < length; index += 1) {
715
+ const item = items[index];
716
+ const listeners = item[key];
717
+ if (item.disabled || listeners == null) continue;
718
+ target = item;
719
+ for (const listener of listeners) {
720
+ listener.call(item, event);
721
+ if (cancelled) return;
722
+ }
723
+ }
724
+ }
725
+ function getDelegatedName(target, type, options) {
726
+ if (isEventTarget(target) && EVENT_TYPES.has(type) && !options.capture && !options.once && options.signal == null) return `@${type}${options.passive ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
727
+ }
728
+ function removeDelegatedListener(target, name, listener) {
729
+ const handlers = target[name];
730
+ if (handlers == null || !handlers.has(listener)) return false;
731
+ handlers.delete(listener);
732
+ if (handlers.size === 0) target[name] = void 0;
733
+ return true;
734
+ }
735
+ const DELEGATED = /* @__PURE__ */ new Set();
736
+ const EVENT_SUFFIX_ACTIVE = ":active";
737
+ const EVENT_SUFFIX_PASSIVE = ":passive";
738
+ const EVENT_TYPES = /* @__PURE__ */ new Set([
739
+ "beforeinput",
740
+ "click",
741
+ "dblclick",
742
+ "contextmenu",
743
+ "focusin",
744
+ "focusout",
745
+ "input",
746
+ "keydown",
747
+ "keyup",
748
+ "mousedown",
749
+ "mousemove",
750
+ "mouseout",
751
+ "mouseover",
752
+ "mouseup",
753
+ "pointerdown",
754
+ "pointermove",
755
+ "pointerout",
756
+ "pointerover",
757
+ "pointerup",
758
+ "touchend",
759
+ "touchmove",
760
+ "touchstart"
761
+ ]);
762
+ const HANDLER_ACTIVE = delegatedEventHandler.bind(false);
763
+ const HANDLER_PASSIVE = delegatedEventHandler.bind(true);
764
+ //#endregion
765
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
766
+ /**
767
+ * A function that does nothing, which can be useful, I guess…
768
+ */
769
+ function noop() {}
770
+ //#endregion
771
+ //#region node_modules/@oscarpalmer/toretto/dist/event/index.mjs
772
+ function createDispatchOptions(options) {
773
+ return {
774
+ bubbles: getBoolean(options?.bubbles, true),
775
+ cancelable: getBoolean(options?.cancelable, true),
776
+ composed: getBoolean(options?.composed)
777
+ };
778
+ }
779
+ function createEvent(type, options) {
780
+ const hasOptions = isPlainObject(options);
781
+ if (hasOptions && "detail" in options) return new CustomEvent(type, {
782
+ ...createDispatchOptions(options),
783
+ detail: options?.detail
784
+ });
785
+ return new Event(type, createDispatchOptions(hasOptions ? options : {}));
786
+ }
787
+ function createEventOptions(options) {
788
+ return {
789
+ capture: getBoolean(options?.capture),
790
+ once: getBoolean(options?.once),
791
+ passive: getBoolean(options?.passive, true),
792
+ signal: options?.signal instanceof AbortSignal ? options.signal : void 0
793
+ };
794
+ }
795
+ function dispatch(target, type, options) {
796
+ if (!isEventTarget(target) || typeof type !== "string") return;
797
+ const event = createEvent(type, options);
798
+ target.dispatchEvent(event);
799
+ return event;
800
+ }
801
+ /**
802
+ * Get the X- and Y-coordinates from a pointer event
803
+ *
804
+ * @param event Pointer event
805
+ * @returns X- and Y-coordinates
806
+ */
807
+ function getPosition$1(event) {
808
+ let x;
809
+ let y;
810
+ if (event instanceof MouseEvent) {
811
+ x = event.clientX;
812
+ y = event.clientY;
813
+ } else if (event instanceof TouchEvent) {
814
+ x = event.touches[0]?.clientX;
815
+ y = event.touches[0]?.clientY;
816
+ }
817
+ return typeof x === "number" && typeof y === "number" ? {
818
+ x,
819
+ y
820
+ } : void 0;
821
+ }
822
+ function on(target, type, listener, options) {
823
+ if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
824
+ const extended = createEventOptions(options);
825
+ const delegated = getDelegatedName(target, type, extended);
826
+ if (delegated != null) return addDelegatedListener(target, type, delegated, listener, extended.passive);
827
+ target.addEventListener(type, listener, extended);
828
+ if (extended.once) return noop;
829
+ return () => {
830
+ target.removeEventListener(type, listener, extended);
831
+ };
832
+ }
833
+ //#endregion
834
+ //#region node_modules/@oscarpalmer/toretto/dist/find/relative.mjs
835
+ function findAncestor(origin, selector) {
836
+ const element = getElement(origin);
837
+ if (element == null || selector == null) return null;
838
+ if (typeof selector === "string") {
839
+ if (Element.prototype.matches.call(element, selector)) return element;
840
+ return Element.prototype.closest.call(element, selector);
841
+ }
842
+ if (typeof selector !== "function") return null;
843
+ if (selector(element)) return element;
844
+ let parent = element.parentElement;
845
+ while (parent != null && !selector(parent)) {
846
+ if (parent === document.body) return null;
847
+ parent = parent.parentElement;
848
+ }
849
+ return parent;
850
+ }
851
+ function getElement(origin) {
852
+ if (origin instanceof Element) return origin;
853
+ return origin instanceof Event && origin.target instanceof Element ? origin.target : void 0;
854
+ }
855
+ //#endregion
856
+ //#region node_modules/@oscarpalmer/toretto/dist/find/index.mjs
857
+ /**
858
+ * Get elements from an event position
859
+ *
860
+ * @param position Event position
861
+ * @returns Elements at the event position
862
+ */
863
+ function getElementFromPosition(position) {
864
+ if (!isEventPosition(position) || typeof document.elementFromPoint !== "function") return [];
865
+ const { x, y } = position;
866
+ const elements = [];
867
+ const events = [];
868
+ let current;
869
+ while (true) {
870
+ current = document.elementFromPoint(x, y);
871
+ if (current == null || elements.indexOf(current) !== -1) break;
872
+ if (!(current instanceof HTMLElement)) continue;
873
+ elements.push(current);
874
+ events.push({
875
+ value: current.style.getPropertyValue(STYLE_POINTER_EVENTS),
876
+ priority: current.style.getPropertyPriority(STYLE_POINTER_EVENTS)
877
+ });
878
+ current.style.setProperty(STYLE_POINTER_EVENTS, STYLE_NONE$1, STYLE_IMPORTANT);
879
+ }
880
+ const { length } = elements;
881
+ for (let index = 0; index < length; index += 1) {
882
+ const element = elements[index];
883
+ const event = events[index];
884
+ if (element instanceof HTMLElement) element.style.setProperty(STYLE_POINTER_EVENTS, event.value ?? "", event.priority);
885
+ }
886
+ return elements;
887
+ }
888
+ const STYLE_IMPORTANT = "important";
889
+ const STYLE_NONE$1 = "none";
890
+ const STYLE_POINTER_EVENTS = "pointer-events";
891
+ Node.ELEMENT_NODE, Node.TEXT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE;
892
+ //#endregion
893
+ //#region node_modules/@oscarpalmer/toretto/dist/style.mjs
894
+ /**
895
+ * Get styles from an element
896
+ *
897
+ * @param element Element to get the styles from
898
+ * @param names Styles to get
899
+ * @param computed Get the computed styles? _(defaults to `false`)_
900
+ * @returns Style values
901
+ */
902
+ function getStyles(element, names, computed) {
903
+ const styles = {};
904
+ if (!(element instanceof Element && Array.isArray(names))) return styles;
905
+ const { length } = names;
906
+ for (let index = 0; index < length; index += 1) {
907
+ const name = names[index];
908
+ if (typeof name === "string") styles[name] = getStyleValue(element, name, computed === true);
909
+ }
910
+ return styles;
911
+ }
912
+ /**
913
+ * Set a style on an element
914
+ *
915
+ * @param element Element to set the style on
916
+ * @param name Style name
917
+ * @param value Style value
918
+ */
919
+ function setStyle(element, name, value) {
920
+ setElementValues(element, name, value, null, updateStyleProperty, true);
921
+ }
922
+ /**
923
+ * Set styles on an element
924
+ *
925
+ * @param element Element to set the styles on
926
+ * @param styles Styles to set
927
+ */
928
+ function setStyles(element, styles) {
929
+ setElementValues(element, styles, null, null, updateStyleProperty, true);
930
+ }
931
+ /**
932
+ * Toggle styles for an element
933
+ *
934
+ * @param element Element to style
935
+ * @param styles Styles to be set or removed
936
+ * @returns Style toggler
937
+ */
938
+ function toggleStyles(element, styles) {
939
+ function toggle(set) {
940
+ hasSet = set;
941
+ let next;
942
+ if (set) {
943
+ values = getStyles(element, keys);
944
+ next = styles;
945
+ } else {
946
+ next = { ...values };
947
+ values = {};
948
+ for (let index = 0; index < length; index += 1) values[keys[index]] = void 0;
949
+ }
950
+ setStyles(element, next);
951
+ }
952
+ const keys = Object.keys(styles);
953
+ const { length } = keys;
954
+ let hasSet = false;
955
+ let values = {};
956
+ return {
957
+ set() {
958
+ if (!hasSet) toggle(true);
959
+ },
960
+ remove() {
961
+ if (hasSet) toggle(false);
962
+ }
963
+ };
964
+ }
965
+ function updateStyleProperty(element, key, value) {
966
+ updateElementValue(element, key, value, function(name, style) {
967
+ if (name.startsWith(VARIABLE_PREFIX)) this.style.setProperty(name, getString(style));
968
+ else this.style[name] = getString(style);
969
+ }, function(name) {
970
+ if (name.startsWith(VARIABLE_PREFIX)) this.style.removeProperty(name);
971
+ else this.style[name] = "";
972
+ if (this.getAttribute(ATTRIBUTE_STYLE) === "") this.removeAttribute(ATTRIBUTE_STYLE);
973
+ }, false);
974
+ }
975
+ const ATTRIBUTE_STYLE = "style";
976
+ const VARIABLE_PREFIX = "--";
977
+ //#endregion
978
+ //#region src/js/floatable/floatable.embedded.ts
979
+ var OuiFloatable = class {
980
+ #destroyed = false;
981
+ #state;
982
+ /**
983
+ * Is the floatable open?
984
+ */
985
+ get open() {
986
+ return this.#state.content.checkVisibility();
987
+ }
988
+ /**
989
+ * Open or close the floatable
990
+ */
991
+ set open(value) {
992
+ if (value === true) this.show();
993
+ else if (value === false) this.hide();
994
+ }
995
+ constructor(state, standalone) {
996
+ this.#state = state;
997
+ const { anchor, content } = state;
998
+ if (standalone) {
999
+ setAttribute(content, ATTRIBUTE_FLOATABLE, "");
1000
+ content.popover = "manual";
1001
+ } else content.popover ??= "auto";
1002
+ setStyle(anchor, "anchorName", state.name);
1003
+ setStyle(content, "positionAnchor", state.name);
1004
+ }
1005
+ /**
1006
+ * Destroy the floatable, removing it from the DOM and cleaning up references
1007
+ */
1008
+ destroy() {
1009
+ if (this.#destroyed) return;
1010
+ this.#destroyed = true;
1011
+ removeFloatable(this.#state.content);
1012
+ this.#state.anchor = null;
1013
+ this.#state.content = null;
1014
+ }
1015
+ /**
1016
+ * Closes the floatable
1017
+ */
1018
+ hide() {
1019
+ if (!this.#destroyed && this.open) this.#state.content.hidePopover();
1020
+ }
1021
+ /**
1022
+ * Opens the floatable
1023
+ */
1024
+ show() {
1025
+ if (!this.#destroyed && !this.open) this.#state.content.showPopover();
1026
+ }
1027
+ /**
1028
+ * Update the position of the floatable, with an optional new position
1029
+ *
1030
+ * @param position Optional new position
1031
+ */
1032
+ update(position) {
1033
+ if (!this.#destroyed) setPosition(this.#state, position);
1034
+ }
1035
+ };
1036
+ function getAnchorName(anchor) {
1037
+ let { anchorName } = anchor.style;
1038
+ if (anchorName.length > 0) return anchorName;
1039
+ index$4 += 1;
1040
+ return `--oui-floatable-anchor-${index$4}`;
1041
+ }
1042
+ function createEmbeddedFloatable(anchor, content, options) {
1043
+ return createInstance(anchor, content, options, false);
1044
+ }
1045
+ /**
1046
+ * Create a _OuiFloatable_ for an anchor and content element
1047
+ *
1048
+ * @param anchor Anchor element
1049
+ * @param content Content element
1050
+ * @param options _OuiFloatable_ options
1051
+ * @returns _OuiFloatable_ instance
1052
+ */
1053
+ function createFloatable(anchor, content, options) {
1054
+ const { open, position } = getOptions$1(options);
1055
+ const floatable = createInstance(anchor, content, {
1056
+ position,
1057
+ reusable: false
1058
+ }, true);
1059
+ floatable?.update(position);
1060
+ if (open) floatable?.show();
1061
+ return floatable;
1062
+ }
1063
+ function createInstance(anchor, content, options, standalone) {
1064
+ if (!isHTMLOrSVGElement(anchor) || !isHTMLOrSVGElement(content)) throw new TypeError(MESSAGE$6);
1065
+ let floatable = options.reusable ? void 0 : instances$2.get(content);
1066
+ if (floatable == null) {
1067
+ floatable = new OuiFloatable(getState$5(anchor, content, options), standalone);
1068
+ if (!options.reusable) instances$2.set(content, floatable);
1069
+ }
1070
+ return floatable;
1071
+ }
1072
+ function getOnBeforeToggleListener(element) {
1073
+ return on(element, "beforetoggle", (event) => {
1074
+ const { newState, source } = event;
1075
+ if (newState === "open" && source != null && getAria(source, "disabled") === "true") event.preventDefault();
1076
+ }, { passive: false });
1077
+ }
1078
+ function getOptions$1(input) {
1079
+ const object = isPlainObject(input) ? input : {};
1080
+ return {
1081
+ open: typeof object.open === "boolean" ? object.open : true,
1082
+ position: object.position != null && object.position in AREAS ? object.position : "below"
1083
+ };
1084
+ }
1085
+ function getPosition(state, override) {
1086
+ if (override != null && override in AREAS) return override;
1087
+ const { anchor, options } = state;
1088
+ if (options.attribute == null) return options.position;
1089
+ const attribute = getAttribute(anchor, options.attribute);
1090
+ return attribute != null && attribute in AREAS ? attribute : options.position;
1091
+ }
1092
+ function getState$5(anchor, content, options) {
1093
+ return {
1094
+ anchor,
1095
+ content,
1096
+ name: getAnchorName(anchor),
1097
+ options
1098
+ };
1099
+ }
1100
+ function removeFloatable(content) {
1101
+ instances$2.get(content)?.destroy();
1102
+ instances$2.delete(content);
1103
+ }
1104
+ function setPosition(state, override) {
1105
+ const position = getPosition(state, override);
1106
+ const area = AREAS[position];
1107
+ setAttribute(state.content, ATTRIBUTE_POSITION, POSITIONS[area]);
1108
+ setStyles(state.content, {
1109
+ positionAnchor: state.name,
1110
+ positionArea: area
1111
+ });
1112
+ }
1113
+ const AREAS = {
1114
+ above: "block-start",
1115
+ "above-end": "start span-start",
1116
+ "above-start": "start span-end",
1117
+ below: "block-end",
1118
+ "below-end": "end span-start",
1119
+ "below-start": "end span-end",
1120
+ end: "center end",
1121
+ "end-bottom": "span-start end",
1122
+ "end-top": "span-end end",
1123
+ start: "center start",
1124
+ "start-bottom": "span-start start",
1125
+ "start-top": "span-end start"
1126
+ };
1127
+ const ATTRIBUTE_FLOATABLE = "oui-floatable";
1128
+ const ATTRIBUTE_POSITION = "oui-position";
1129
+ const MESSAGE$6 = "Anchor and content must be an HTMLElement or SVGElement";
1130
+ const POSITIONS = Object.fromEntries(Object.entries(AREAS).map(([position, area]) => [area, position]));
1131
+ const instances$2 = /* @__PURE__ */ new WeakMap();
1132
+ let index$4 = 0;
1133
+ //#endregion
1134
+ //#region src/js/internal/attributable.ts
1135
+ function attributable(attribute, add, remove) {
1136
+ new MutationObserver((entries) => {
1137
+ const { length } = entries;
1138
+ for (let index = 0; index < length; index += 1) {
1139
+ const entry = entries[index];
1140
+ if (entry.type === "attributes" && entry.target instanceof Element) if (entry.target.hasAttribute(attribute)) handleAdded(attribute, [entry.target], add);
1141
+ else handleRemoved([entry.target], remove);
1142
+ else if (entry.type === "childList") {
1143
+ handleAdded(attribute, entry.addedNodes, add);
1144
+ handleRemoved(entry.removedNodes, remove);
1145
+ }
1146
+ }
1147
+ }).observe(document, {
1148
+ attributeFilter: [attribute],
1149
+ attributes: true,
1150
+ childList: true,
1151
+ subtree: true
1152
+ });
1153
+ requestAnimationFrame(() => {
1154
+ handleAdded(attribute, document.querySelectorAll(`[${attribute}]`), add);
1155
+ });
1156
+ }
1157
+ function handleAdded(attribute, nodes, add) {
1158
+ const elements = [...nodes].filter((node) => node instanceof Element);
1159
+ const { length } = elements;
1160
+ for (let index = 0; index < length; index += 1) {
1161
+ const element = elements[index];
1162
+ if (element.hasAttribute(attribute)) add(element);
1163
+ if (element.hasChildNodes()) handleAdded(attribute, element.childNodes, add);
1164
+ }
1165
+ }
1166
+ function handleRemoved(nodes, remove) {
1167
+ const elements = [...nodes].filter((node) => node instanceof Element);
1168
+ const { length } = elements;
1169
+ for (let index = 0; index < length; index += 1) {
1170
+ const element = elements[index];
1171
+ remove(element);
1172
+ if (element.hasChildNodes()) handleRemoved(element.childNodes, remove);
1173
+ }
1174
+ }
1175
+ //#endregion
1176
+ //#region src/js/internal/navigable.ts
1177
+ var OuiNavigable = class {
1178
+ active = { index: 0 };
1179
+ element;
1180
+ listeners;
1181
+ options;
1182
+ orientation;
1183
+ constructor(element, options) {
1184
+ this.element = element;
1185
+ this.options = options;
1186
+ this.listeners = [on(element, "focusin", (event) => {
1187
+ onFocusin$1(this, event);
1188
+ }), on(element, "keydown", (event) => {
1189
+ onKeydown$5(this, event);
1190
+ }, { passive: false })];
1191
+ this.orientation = getOrientation(element, options);
1192
+ if (options.role != null) setRole(element, options.role);
1193
+ }
1194
+ destroy() {
1195
+ const listeners = this.listeners.splice(0);
1196
+ for (const listener of listeners) listener();
1197
+ this.active.element = void 0;
1198
+ this.element = void 0;
1199
+ }
1200
+ };
1201
+ function getItems(container, selector) {
1202
+ return [...container.querySelectorAll(selector)].filter(isValidItem);
1203
+ }
1204
+ function getNavigable(element, options) {
1205
+ return new OuiNavigable(element, options);
1206
+ }
1207
+ function getOrientation(element, options) {
1208
+ const attribute = getAria(element, "orientation");
1209
+ return ORIENTATIONS.has(attribute) ? attribute : options.vertical ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL;
1210
+ }
1211
+ function isValidItem(element) {
1212
+ return "disabled" in element ? element.disabled !== true : true;
1213
+ }
1214
+ function onFocusin$1(navigable, event) {
1215
+ const item = findAncestor(event, navigable.options.selector);
1216
+ if (!isHTMLOrSVGElement(item) || !isValidItem(item)) return;
1217
+ const items = getItems(navigable.element, navigable.options.selector);
1218
+ const index = items.indexOf(item);
1219
+ if (index === -1) return;
1220
+ navigable.active.element = item;
1221
+ navigable.active.index = index;
1222
+ updateNavigableFocus(navigable, false, items);
1223
+ }
1224
+ function onKeydown$5(navigable, event) {
1225
+ const escaped = event.key === "Escape";
1226
+ const stopPropagation = navigable.options.onShouldDeactivate?.(event, navigable);
1227
+ if (escaped || stopPropagation != null) {
1228
+ if (escaped || stopPropagation) event.stopPropagation();
1229
+ navigable.options.onDeactivate?.(event, navigable);
1230
+ return;
1231
+ }
1232
+ if (!KEYS_ALL$1.has(event.key)) return;
1233
+ const mustActivate = KEYS_ACTIVATE.has(event.key);
1234
+ const shouldActivate = navigable.options.onShouldActivate?.(event, navigable) === true;
1235
+ if (mustActivate || shouldActivate || navigable.options.onPreventNavigation?.(event, navigable) === true) event.stopPropagation();
1236
+ if (mustActivate || shouldActivate) return;
1237
+ const items = getItems(navigable.element, navigable.options.selector);
1238
+ const { length } = items;
1239
+ if (length === 0) return;
1240
+ let index;
1241
+ if (KEYS_ABSOLUTE$1.has(event.key)) index = event.key === "Home" ? 0 : items.length - 1;
1242
+ else {
1243
+ const direction = NAVIGABLE_KEYS_HORIZONTAL.has(event.key) ? ORIENTATION_HORIZONTAL : ORIENTATION_VERTICAL;
1244
+ if (navigable.orientation === direction) {
1245
+ if (navigable.active.element instanceof HTMLSelectElement) event.preventDefault();
1246
+ index = clamp(navigable.active.index + (KEYS_NEXT.has(event.key) ? 1 : -1), 0, length - 1, true);
1247
+ }
1248
+ }
1249
+ if (index == null || index === navigable.active.index) return;
1250
+ navigable.active.element = items[index];
1251
+ navigable.active.index = index;
1252
+ updateNavigableFocus(navigable, true, items);
1253
+ }
1254
+ function updateNavigableFocus(navigable, focus, items) {
1255
+ const updated = items ?? getItems(navigable.element, navigable.options.selector);
1256
+ const { length } = updated;
1257
+ if (length === 0) return;
1258
+ for (let index = 0; index < length; index += 1) updated[index].tabIndex = index === navigable.active.index ? 0 : -1;
1259
+ navigable.active.element ??= updated[navigable.active.index];
1260
+ if (focus) navigable.active.element?.focus();
1261
+ dispatch(navigable.active.element, "navigable:change", { detail: { ...navigable.active } });
1262
+ }
1263
+ const KEYS_ABSOLUTE$1 = /* @__PURE__ */ new Set(["End", "Home"]);
1264
+ const KEYS_ACTIVATE = /* @__PURE__ */ new Set(["Enter", " "]);
1265
+ const NAVIGABLE_KEYS_HORIZONTAL = /* @__PURE__ */ new Set(["ArrowRight", "ArrowLeft"]);
1266
+ const NAVIGABLE_KEYS_VERTICAL = /* @__PURE__ */ new Set(["ArrowDown", "ArrowUp"]);
1267
+ const KEYS_ALL$1 = /* @__PURE__ */ new Set([
1268
+ ...KEYS_ABSOLUTE$1,
1269
+ ...KEYS_ACTIVATE,
1270
+ ...NAVIGABLE_KEYS_HORIZONTAL,
1271
+ ...NAVIGABLE_KEYS_VERTICAL
1272
+ ]);
1273
+ const KEYS_NEXT = /* @__PURE__ */ new Set(["ArrowDown", "ArrowRight"]);
1274
+ const ORIENTATION_HORIZONTAL = "horizontal";
1275
+ const ORIENTATION_VERTICAL = "vertical";
1276
+ const ORIENTATIONS = /* @__PURE__ */ new Set([ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL]);
1277
+ //#endregion
1278
+ //#region src/js/menu.ts
1279
+ var OuiMenu = class {
1280
+ content;
1281
+ element;
1282
+ floatable;
1283
+ navigable;
1284
+ toggle;
1285
+ get open() {
1286
+ return this.floatable.open;
1287
+ }
1288
+ constructor(element, navigable) {
1289
+ this.element = element;
1290
+ this.navigable = navigable;
1291
+ this.content = navigable.element;
1292
+ this.toggle = element.querySelector(SELECTOR_MENU_TOGGLE);
1293
+ this.floatable = createEmbeddedFloatable(this.toggle, this.content, {
1294
+ attribute: ATTRIBUTE_MENU_POSITION,
1295
+ position: findAncestor(element.parentElement, SELECTOR_MENU_CONTENT) == null ? "below-start" : "end-top",
1296
+ reusable: false
1297
+ });
1298
+ this.navigable.listeners.push(getOnBeforeToggleListener(this.content), on(this.content, "click", (event) => {
1299
+ event.stopPropagation();
1300
+ if (findAncestor(event, SELECTOR_MENU_TOGGLE) != null) return;
1301
+ const elements = document.querySelectorAll(SELECTOR_MENU_CONTENT);
1302
+ for (const element of elements) menus.get(element)?.floatable.hide();
1303
+ const menu = menus.get(elements[0]);
1304
+ if (menu != null && event.pointerId === -1) updateNavigableFocus(menu.navigable, true);
1305
+ }), on(this.content, "toggle", (event) => {
1306
+ const expanded = event.newState === "open";
1307
+ if (expanded) {
1308
+ this.floatable?.update();
1309
+ updateNavigableFocus(this.navigable, true);
1310
+ }
1311
+ setAria(this.toggle, "expanded", expanded);
1312
+ }));
1313
+ this.floatable.update();
1314
+ initializeMenu(this);
1315
+ updateNavigableFocus(this.navigable, false);
1316
+ }
1317
+ destroy() {
1318
+ this.floatable.destroy();
1319
+ this.navigable.destroy();
1320
+ this.floatable = void 0;
1321
+ this.navigable = void 0;
1322
+ }
1323
+ };
1324
+ var OuiMenubar = class {
1325
+ element;
1326
+ navigable;
1327
+ constructor(element, navigable) {
1328
+ this.element = element;
1329
+ this.navigable = navigable;
1330
+ updateNavigableFocus(this.navigable, false);
1331
+ }
1332
+ destroy() {
1333
+ this.navigable.destroy();
1334
+ this.navigable = void 0;
1335
+ }
1336
+ };
1337
+ function addInstance(instances, ctor, element, content, options) {
1338
+ if (!instances.has(content)) instances.set(content, new ctor(element, getNavigable(content, {
1339
+ ...options,
1340
+ onDeactivate,
1341
+ onPreventNavigation,
1342
+ onShouldActivate,
1343
+ onShouldDeactivate
1344
+ })));
1345
+ }
1346
+ function addMenu(element) {
1347
+ const content = element.querySelector(SELECTOR_MENU_CONTENT);
1348
+ const toggle = element.querySelector(SELECTOR_MENU_TOGGLE);
1349
+ if (content != null && toggle != null) addInstance(menus, OuiMenu, element, content, {
1350
+ selector: SELECTOR_MENU_ITEM,
1351
+ vertical: true
1352
+ });
1353
+ }
1354
+ function addMenubar(element) {
1355
+ addInstance(menubars, OuiMenubar, element, element, {
1356
+ role: "menubar",
1357
+ selector: SELECTOR_MENUBAR_ITEM,
1358
+ vertical: false
1359
+ });
1360
+ }
1361
+ function getId$2(element, value) {
1362
+ let { id } = element;
1363
+ if (id == null || id.trim().length === 0) {
1364
+ id = value == null ? `oui_menu_${++index$3}` : `${value}_toggle`;
1365
+ element.id = id;
1366
+ }
1367
+ return id;
1368
+ }
1369
+ function initializeMenu(menu) {
1370
+ const id = getId$2(menu.content);
1371
+ setAttribute(menu.toggle, "popovertarget", id);
1372
+ setAria(menu.toggle, {
1373
+ controls: id,
1374
+ expanded: "false",
1375
+ haspopup: "menu"
1376
+ });
1377
+ setAttributes(menu.content, {
1378
+ popover: "",
1379
+ tabindex: "-1"
1380
+ });
1381
+ setRole(menu.content, "menu");
1382
+ }
1383
+ function onDeactivate(_, navigable) {
1384
+ const menu = menus.get(navigable.element);
1385
+ if (menu == null) return;
1386
+ menu.floatable.hide();
1387
+ const element = findAncestor(menu.element.parentElement, SELECTORS);
1388
+ if (element == null) return;
1389
+ const instance = menubars.get(element) ?? menus.get(element);
1390
+ if (instance != null) updateNavigableFocus(instance.navigable, true);
1391
+ }
1392
+ function onPreventNavigation(_, navigable) {
1393
+ return findAncestor((menubars.get(navigable.element) ?? menus.get(navigable.element))?.element.parentElement, SELECTORS) != null;
1394
+ }
1395
+ function onShouldActivate(event, navigable) {
1396
+ let activate = false;
1397
+ if (menubars.has(navigable.element)) activate = navigable.orientation === "horizontal" ? NAVIGABLE_KEYS_VERTICAL.has(event.key) : NAVIGABLE_KEYS_HORIZONTAL.has(event.key);
1398
+ else if (menus.has(navigable.element)) activate = navigable.orientation === "horizontal" ? NAVIGABLE_KEYS_VERTICAL.has(event.key) : event.key === "ArrowRight";
1399
+ if (activate) {
1400
+ const target = event.target instanceof HTMLElement && event.target.matches(SELECTOR_MENU_TOGGLE) ? event.target : void 0;
1401
+ if (target == null) activate = false;
1402
+ else target.click();
1403
+ }
1404
+ return activate;
1405
+ }
1406
+ function onShouldDeactivate(event, navigable) {
1407
+ if (menubars.has(navigable.element)) return;
1408
+ const menu = menus.get(navigable.element);
1409
+ if (menu == null) return;
1410
+ const horizontal = navigable.orientation === "horizontal";
1411
+ const altKey = horizontal ? "ArrowDown" : "ArrowRight";
1412
+ const baseKey = horizontal ? "ArrowUp" : "ArrowLeft";
1413
+ if (event.key === baseKey) return findAncestor(menu.element.parentElement, SELECTOR_MENU_CONTENT) != null;
1414
+ if (event.key === altKey && event.target instanceof HTMLElement && !event.target.hasAttribute("popovertarget")) return false;
1415
+ }
1416
+ function removeInstance$1(instances, element) {
1417
+ instances.get(element)?.destroy();
1418
+ instances.delete(element);
1419
+ }
1420
+ function removeMenu(element) {
1421
+ removeInstance$1(menus, element);
1422
+ }
1423
+ function removeMenubar(element) {
1424
+ removeInstance$1(menubars, element);
1425
+ }
1426
+ const ATTRIBUTE_MENU = "oui-menu";
1427
+ const ATTRIBUTE_MENU_POSITION = "oui-menu-position";
1428
+ const ATTRIBUTE_MENUBAR = "oui-menubar";
1429
+ const SELECTOR_MENUBAR = `[${ATTRIBUTE_MENUBAR}]`;
1430
+ const SELECTOR_MENUBAR_ITEM = `:scope > [${ATTRIBUTE_MENUBAR}-item], :scope > * > [${ATTRIBUTE_MENUBAR}-item]`;
1431
+ const SELECTOR_MENU_CONTENT = `[${ATTRIBUTE_MENU}-content]`;
1432
+ const SELECTOR_MENU_ITEM = `:scope > [${ATTRIBUTE_MENU}-item], :scope > * > [${ATTRIBUTE_MENU}-item]`;
1433
+ const SELECTOR_MENU_TOGGLE = `[${ATTRIBUTE_MENU}-toggle]`;
1434
+ const SELECTORS = `${SELECTOR_MENUBAR}, ${SELECTOR_MENU_CONTENT}`;
1435
+ const menubars = /* @__PURE__ */ new WeakMap();
1436
+ const menus = /* @__PURE__ */ new WeakMap();
1437
+ let index$3 = 0;
1438
+ attributable(ATTRIBUTE_MENU, addMenu, removeMenu);
1439
+ attributable(ATTRIBUTE_MENUBAR, addMenubar, removeMenubar);
1440
+ //#endregion
1441
+ //#region src/js/toolbar.ts
1442
+ var OuiToolbar = class {
1443
+ #navigable;
1444
+ constructor(navigable) {
1445
+ this.#navigable = navigable;
1446
+ updateNavigableFocus(this.#navigable, false);
1447
+ }
1448
+ destroy() {
1449
+ this.#navigable.destroy();
1450
+ this.#navigable = void 0;
1451
+ }
1452
+ };
1453
+ function addToolbar(element) {
1454
+ if (!instances$1.has(element)) instances$1.set(element, new OuiToolbar(getNavigable(element, {
1455
+ role: "toolbar",
1456
+ selector: SELECTOR$5,
1457
+ vertical: false
1458
+ })));
1459
+ }
1460
+ function removeToolbar(element) {
1461
+ instances$1.get(element)?.destroy();
1462
+ instances$1.delete(element);
1463
+ }
1464
+ const ATTRIBUTE$4 = "oui-toolbar";
1465
+ const SELECTOR$5 = `[${ATTRIBUTE$4}-item]`;
1466
+ const instances$1 = /* @__PURE__ */ new WeakMap();
1467
+ attributable(ATTRIBUTE$4, addToolbar, removeToolbar);
1468
+ //#endregion
1469
+ //#region node_modules/@oscarpalmer/toretto/dist/data.mjs
1470
+ function getData(element, keys, parseValues) {
1471
+ if (!(element instanceof Element)) return;
1472
+ const noParse = parseValues === false;
1473
+ if (typeof keys === "string") return getDataValue(element, keys, noParse);
1474
+ const { length } = keys;
1475
+ const data = {};
1476
+ for (let index = 0; index < length; index += 1) {
1477
+ const key = keys[index];
1478
+ data[key] = getDataValue(element, key, noParse);
1479
+ }
1480
+ return data;
1481
+ }
1482
+ function getDataValue(element, key, noParse) {
1483
+ const value = element.dataset[camelCase(key)];
1484
+ if (value == null) return;
1485
+ if (noParse) return value;
1486
+ return parse(value) ?? value;
1487
+ }
1488
+ function getName(original) {
1489
+ return `${ATTRIBUTE_DATA_PREFIX}${kebabCase(original.replace(EXPRESSION_DATA_PREFIX, ""))}`;
1490
+ }
1491
+ function setData(element, first, second) {
1492
+ setElementValues(element, first, second, null, updateDataAttribute);
1493
+ }
1494
+ function updateDataAttribute(element, key, value) {
1495
+ updateElementValue(element, getName(key), value, element.setAttribute, element.removeAttribute, true);
1496
+ }
1497
+ const ATTRIBUTE_DATA_PREFIX = "data-";
1498
+ //#endregion
1499
+ //#region node_modules/@oscarpalmer/toretto/dist/property/set.property.mjs
1500
+ /**
1501
+ * Set the values of one or more properties on an element
1502
+ *
1503
+ * Also updates attributes for boolean/dispatchable properties, and if `dispatch` is `true`, will dispatch events for dispatchable properties
1504
+ *
1505
+ * @param target Target element
1506
+ * @param properties Properties to set
1507
+ * @param dispatch Dispatch events for properties? _(defaults to `true`)_
1508
+ */
1509
+ function setProperties$1(target, properties, dispatch) {
1510
+ if (!(target instanceof Element) || !isPlainObject(properties)) return;
1511
+ const shouldDispatch = dispatch !== false;
1512
+ const keys = Object.keys(properties);
1513
+ const { length } = keys;
1514
+ for (let index = 0; index < length; index += 1) setPropertyValue(target, keys[index], properties[keys[index]], shouldDispatch);
1515
+ }
1516
+ function setPropertyValue(element, property, value, dispatch) {
1517
+ if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) setAttribute(element, property, value, dispatch);
1518
+ else updateProperty(element, property, value, dispatch);
1519
+ }
1520
+ //#endregion
1521
+ //#region node_modules/@oscarpalmer/toretto/dist/create.mjs
1522
+ function createElement(tag, values) {
1523
+ if (typeof tag !== "string") throw new TypeError(MESSAGE$5);
1524
+ const element = document.createElement(tag);
1525
+ const { aria, attribute, data, property, style } = getElementValues(values);
1526
+ setAria(element, aria ?? {});
1527
+ setAttributes(element, attribute ?? {});
1528
+ setData(element, data ?? {});
1529
+ setProperties$1(element, property ?? {});
1530
+ setStyles(element, style ?? {});
1531
+ return element;
1532
+ }
1533
+ function getElementValues(input) {
1534
+ if (!isPlainObject(input)) return {};
1535
+ return {
1536
+ aria: isPlainObject(input.aria) ? input.aria : void 0,
1537
+ attribute: isPlainObject(input.attribute) ? input.attribute : void 0,
1538
+ data: isPlainObject(input.data) ? input.data : void 0,
1539
+ property: isPlainObject(input.property) ? input.property : void 0,
1540
+ style: isPlainObject(input.style) ? input.style : void 0
1541
+ };
1542
+ }
1543
+ const MESSAGE$5 = "Tag name must be a string";
1544
+ //#endregion
1545
+ //#region src/js/combobox.ts
1546
+ var OuiComboboxElement = class extends HTMLElement {
1547
+ static formAssociated = true;
1548
+ static observedAttributes = [
1549
+ "max",
1550
+ "min",
1551
+ "required",
1552
+ "value"
1553
+ ];
1554
+ #internals;
1555
+ #restored;
1556
+ #state;
1557
+ /**
1558
+ * Is the combobox disabled?
1559
+ */
1560
+ get disabled() {
1561
+ return this.#state?.disabled ?? false;
1562
+ }
1563
+ /**
1564
+ * Should the combobox be disabled?
1565
+ */
1566
+ set disabled(value) {
1567
+ if (typeof value === "boolean" && value !== this.disabled) setDisabled$1(this.#state, value);
1568
+ }
1569
+ /**
1570
+ * Current filter value
1571
+ */
1572
+ get filter() {
1573
+ return this.#state.filter.element.value;
1574
+ }
1575
+ /**
1576
+ * Set the filter value
1577
+ */
1578
+ set filter(value) {
1579
+ setFilter(this.#state, value);
1580
+ }
1581
+ /**
1582
+ * Maximum number of selected options
1583
+ */
1584
+ get max() {
1585
+ return this.#state?.max;
1586
+ }
1587
+ /**
1588
+ * Set the maximum number of selected options
1589
+ */
1590
+ set max(value) {
1591
+ setLimit("max", this.#state, value);
1592
+ }
1593
+ /**
1594
+ * Minimum number of selected options
1595
+ */
1596
+ get min() {
1597
+ return this.#state?.min;
1598
+ }
1599
+ /**
1600
+ * Set the minimum number of selected options
1601
+ */
1602
+ set min(value) {
1603
+ setLimit("min", this.#state, value);
1604
+ }
1605
+ /**
1606
+ * Does the combobox allow multiple values?
1607
+ */
1608
+ get multiple() {
1609
+ return this.hasAttribute("multiple");
1610
+ }
1611
+ /**
1612
+ * Name of the combobox
1613
+ */
1614
+ get name() {
1615
+ return getAttribute(this, "name") ?? "";
1616
+ }
1617
+ /**
1618
+ * Is the combobox readonly?
1619
+ */
1620
+ get readonly() {
1621
+ return this.#state?.readonly ?? false;
1622
+ }
1623
+ /**
1624
+ * Should the combobox be readonly?
1625
+ */
1626
+ set readonly(value) {
1627
+ if (typeof value === "boolean" && value !== this.readonly) setReadonly(this.#state, value);
1628
+ }
1629
+ /**
1630
+ * Is the combobox required?
1631
+ */
1632
+ get required() {
1633
+ return this.#state?.required ?? false;
1634
+ }
1635
+ /**
1636
+ * Should the combobox be required?
1637
+ */
1638
+ set required(value) {
1639
+ if (typeof value === "boolean" && value !== this.required) setRequired(this.#state, value);
1640
+ }
1641
+ /**
1642
+ * Selected options
1643
+ */
1644
+ get selected() {
1645
+ return this.#state.options.selected.slice();
1646
+ }
1647
+ /**
1648
+ * Type of combobox
1649
+ */
1650
+ get type() {
1651
+ return this.#state.type;
1652
+ }
1653
+ /**
1654
+ * Current value
1655
+ */
1656
+ get value() {
1657
+ return this.#state.values.current[0];
1658
+ }
1659
+ /**
1660
+ * Set the value
1661
+ */
1662
+ set value(value) {
1663
+ setValue(this.#state, value);
1664
+ }
1665
+ /**
1666
+ * Current values
1667
+ */
1668
+ get values() {
1669
+ return this.#state.values.current.slice();
1670
+ }
1671
+ /**
1672
+ * Set the values
1673
+ */
1674
+ set values(value) {
1675
+ setValues(this.#state, value);
1676
+ }
1677
+ constructor() {
1678
+ super();
1679
+ this.#internals = this.attachInternals();
1680
+ }
1681
+ attributeChangedCallback(name, _, value) {
1682
+ if (this.#state == null) return;
1683
+ switch (name) {
1684
+ case "required":
1685
+ this[name] = this.hasAttribute(name);
1686
+ break;
1687
+ case "max":
1688
+ case "min":
1689
+ setLimit(name, this.#state, value);
1690
+ break;
1691
+ case "value":
1692
+ this.value = value ?? "";
1693
+ break;
1694
+ default: break;
1695
+ }
1696
+ }
1697
+ /**
1698
+ * Clear all selected options
1699
+ */
1700
+ clear() {
1701
+ setValues(this.#state, []);
1702
+ }
1703
+ connectedCallback() {
1704
+ if (this.#state == null) this.#initialize();
1705
+ else attachCombobox(this.#state);
1706
+ }
1707
+ disconnectedCallback() {
1708
+ if (this.#state != null) detachCombobox(this.#state);
1709
+ }
1710
+ formDisabledCallback(disabled) {
1711
+ this.disabled = disabled;
1712
+ }
1713
+ formResetCallback() {
1714
+ setValues(this.#state, this.#state.values.initial, false);
1715
+ }
1716
+ formStateRestoreCallback(state, reason) {
1717
+ if (reason !== "restore") return;
1718
+ const parsed = typeof state === "string" ? parse(state) : void 0;
1719
+ if (!Array.isArray(parsed)) return;
1720
+ if (this.#state == null) this.#restored = parsed;
1721
+ else setValues(this.#state, parsed);
1722
+ }
1723
+ setLocalizations(first, second) {
1724
+ updateLocalizations(typeof first === "string" ? { [first]: second } : first, this.#state.localizations);
1725
+ }
1726
+ #initialize() {
1727
+ this.tabIndex = -1;
1728
+ this.#state = createState(this, this.#internals);
1729
+ if (this.#restored != null) {
1730
+ setValues(this.#state, this.#restored, false);
1731
+ this.#restored = void 0;
1732
+ }
1733
+ }
1734
+ };
1735
+ function applySelection(parameters) {
1736
+ const { added, emit, option, selected, state } = parameters;
1737
+ const { length } = state.options.all;
1738
+ for (let index = 0; index < length; index += 1) {
1739
+ const option = state.options.all[index];
1740
+ setAria(option, "selected", (selected ?? state.options.selected).includes(option));
1741
+ }
1742
+ const values = parameters.values ?? (state.autocomplete.none ? [state.filter.element.value] : (selected ?? state.options.selected).map((option) => getData(option, "value", false) ?? ""));
1743
+ if (values.length === 0) values.push("");
1744
+ if (selected != null) state.options.selected = selected;
1745
+ if (!(values.length === state.values.current.length ? values.some((value) => !state.values.current.includes(value)) : true)) return;
1746
+ updateForm(state, values, emit);
1747
+ updatePreview("set", state, option);
1748
+ updateSelection(state, option, added, selected);
1749
+ }
1750
+ function attachCombobox(state) {
1751
+ const { anchor, content, filter, label, listeners, select } = state;
1752
+ label.element.htmlFor = filter.element.id;
1753
+ label.element.id = `${state.id}_label`;
1754
+ select.hidden = true;
1755
+ select.insertAdjacentElement("afterend", anchor.container ?? anchor.element);
1756
+ (anchor.container ?? anchor.element).insertAdjacentElement("afterend", content);
1757
+ select.remove();
1758
+ state.floatable = createEmbeddedFloatable(anchor.container ?? anchor.element, content, {
1759
+ position: "below-start",
1760
+ reusable: false
1761
+ });
1762
+ state.floatable.update();
1763
+ listeners.push(on(state.host, "focusout", () => {
1764
+ setTimeout(() => {
1765
+ onFocusout$1(state);
1766
+ });
1767
+ }), on(content, "click", (event) => {
1768
+ onClickContent(event, content);
1769
+ }), on(content, "toggle", () => {
1770
+ setAria(anchor.element, "expanded", state.floatable.open);
1771
+ setAria(filter.element, "activedescendant", state.floatable.open ? state.active?.id : void 0);
1772
+ if (state.floatable.open) filter.element.focus();
1773
+ }));
1774
+ states$4.map.set(state.host, state);
1775
+ states$4.map.set(state.content, state);
1776
+ states$4.set.add(state);
1777
+ }
1778
+ function createAnchor(parameters) {
1779
+ const { autocomplete, id, label, select, type } = parameters;
1780
+ let container;
1781
+ let element;
1782
+ let selection;
1783
+ if (parameters.type === "autocomplete") element = createInput({
1784
+ id,
1785
+ label,
1786
+ type,
1787
+ autocomplete: autocomplete.value,
1788
+ value: select.selectedOptions[0]?.textContent ?? ""
1789
+ });
1790
+ else ({container, element, selection} = createButton(parameters));
1791
+ setAttribute(container ?? element, ATTRIBUTE_ANCHOR, "");
1792
+ return {
1793
+ container,
1794
+ element,
1795
+ selection
1796
+ };
1797
+ }
1798
+ function createButton(parameters) {
1799
+ const { id, label, multiple, select } = parameters;
1800
+ const element = createElement("button", {
1801
+ aria: {
1802
+ controls: `${id}_content`,
1803
+ expanded: false,
1804
+ haspopup: "listbox",
1805
+ labelledby: `${label.id} ${id}`
1806
+ },
1807
+ property: {
1808
+ id,
1809
+ textContent: multiple ? "" : select.selectedOptions[0]?.textContent ?? ""
1810
+ }
1811
+ });
1812
+ if (!multiple) return { element };
1813
+ const container = createElement("div");
1814
+ const selection = createSelection(id, select);
1815
+ container.append(selection.container, element);
1816
+ return {
1817
+ container,
1818
+ element,
1819
+ selection
1820
+ };
1821
+ }
1822
+ function createContent(parameters) {
1823
+ const { autocomplete, id, label, multiple, select, type } = parameters;
1824
+ const element = createElement("div", {
1825
+ aria: { labelledby: label.id },
1826
+ attribute: {
1827
+ [ATTRIBUTE_CONTENT$1]: "",
1828
+ popover: ""
1829
+ },
1830
+ property: {
1831
+ id: `${id}_content`,
1832
+ tabIndex: -1
1833
+ }
1834
+ });
1835
+ const filter = createFilter({
1836
+ id,
1837
+ label,
1838
+ type,
1839
+ autocomplete: autocomplete.value
1840
+ });
1841
+ const list = createList({
1842
+ autocomplete,
1843
+ id,
1844
+ label,
1845
+ multiple,
1846
+ select
1847
+ });
1848
+ const message = createMessage();
1849
+ if (filter != null) element.append(filter.container);
1850
+ element.append(list.element, message);
1851
+ return {
1852
+ element,
1853
+ filter,
1854
+ list,
1855
+ message
1856
+ };
1857
+ }
1858
+ function createFilter(parameters) {
1859
+ const { autocomplete, id, label, type } = parameters;
1860
+ if (type === "autocomplete") return;
1861
+ const container = createElement("div", { attribute: { [ATTRIBUTE_FILTER]: "" } });
1862
+ const element = createInput({
1863
+ autocomplete,
1864
+ id,
1865
+ label,
1866
+ type,
1867
+ value: ""
1868
+ });
1869
+ setAttribute(element, ATTRIBUTE_FILTER_INPUT, "");
1870
+ container.append(element);
1871
+ return {
1872
+ container,
1873
+ element
1874
+ };
1875
+ }
1876
+ function createGroup(parameters) {
1877
+ const { autocomplete, group, groupOptions, selected } = parameters;
1878
+ const element = createElement("li", {
1879
+ aria: { label: group.label },
1880
+ property: { role: "group" }
1881
+ });
1882
+ const list = createElement("ul", { property: { role: "none" } });
1883
+ const header = createHeader(group);
1884
+ element.append(header, list);
1885
+ return {
1886
+ element,
1887
+ header,
1888
+ options: createOptions({
1889
+ autocomplete,
1890
+ list,
1891
+ selected,
1892
+ group: header.id,
1893
+ options: groupOptions
1894
+ })
1895
+ };
1896
+ }
1897
+ function createHeader(group) {
1898
+ return createElement("div", {
1899
+ aria: { hidden: true },
1900
+ attribute: { [ATTRIBUTE_HEADER]: "" },
1901
+ property: {
1902
+ id: group.id,
1903
+ textContent: group.label
1904
+ }
1905
+ });
1906
+ }
1907
+ function createInput(parameters) {
1908
+ const { autocomplete, id, label, type, value } = parameters;
1909
+ return createElement("input", {
1910
+ aria: {
1911
+ autocomplete,
1912
+ controls: `${id}_list`,
1913
+ expanded: type === "select",
1914
+ haspopup: "listbox",
1915
+ labelledby: label.id
1916
+ },
1917
+ attribute: {
1918
+ autocorrect: "off",
1919
+ autocomplete: "off",
1920
+ form: "",
1921
+ spellcheck: "false",
1922
+ type: "text"
1923
+ },
1924
+ property: {
1925
+ id,
1926
+ value,
1927
+ role: "combobox"
1928
+ }
1929
+ });
1930
+ }
1931
+ function createList(parameters) {
1932
+ const { autocomplete, id, label, multiple, select } = parameters;
1933
+ const element = createElement("ul", {
1934
+ aria: {
1935
+ labelledby: label.id,
1936
+ multiselectable: multiple
1937
+ },
1938
+ attribute: {
1939
+ [ATTRIBUTE_LIST]: "",
1940
+ tabindex: -1
1941
+ },
1942
+ property: {
1943
+ id: `${id}_list`,
1944
+ role: "listbox"
1945
+ }
1946
+ });
1947
+ const children = [...select.children];
1948
+ const childrenLength = children.length;
1949
+ const options = [];
1950
+ const selected = [];
1951
+ let groups;
1952
+ for (let childIndex = 0; childIndex < childrenLength; childIndex += 1) {
1953
+ const child = children[childIndex];
1954
+ if (child instanceof HTMLOptionElement) {
1955
+ const option = createOption({
1956
+ autocomplete,
1957
+ index: childIndex,
1958
+ option: child
1959
+ });
1960
+ element.append(option);
1961
+ options.push(option);
1962
+ if (child.selected) selected.push(option);
1963
+ continue;
1964
+ }
1965
+ if (!(child instanceof HTMLOptGroupElement)) continue;
1966
+ const group = createGroup({
1967
+ autocomplete,
1968
+ selected,
1969
+ group: child,
1970
+ groupOptions: [...child.children]
1971
+ });
1972
+ groups ??= [];
1973
+ element.append(group.element, ...group.options);
1974
+ groups.push(group);
1975
+ options.push(...group.options);
1976
+ }
1977
+ return {
1978
+ element,
1979
+ groups,
1980
+ options,
1981
+ selected
1982
+ };
1983
+ }
1984
+ function createMessage() {
1985
+ return createElement("div", {
1986
+ aria: { live: "polite" },
1987
+ attribute: { [ATTRIBUTE_MESSAGE]: "" },
1988
+ property: {
1989
+ hidden: true,
1990
+ role: "status"
1991
+ }
1992
+ });
1993
+ }
1994
+ function createOption(parameters) {
1995
+ const { autocomplete, group, option } = parameters;
1996
+ const item = createElement("li", {
1997
+ aria: { selected: !autocomplete.none && option.selected },
1998
+ attribute: { [ATTRIBUTE_OPTION]: "" },
1999
+ property: {
2000
+ id: option.id,
2001
+ role: "option",
2002
+ textContent: option.textContent
2003
+ }
2004
+ });
2005
+ setData(item, {
2006
+ group,
2007
+ value: option.value
2008
+ });
2009
+ return item;
2010
+ }
2011
+ function createOptions(parameters) {
2012
+ const { autocomplete, group, list, options, selected } = parameters;
2013
+ const items = [];
2014
+ for (let index = 0; index < options.length; index += 1) {
2015
+ const option = options[index];
2016
+ const item = createOption({
2017
+ autocomplete,
2018
+ group,
2019
+ index,
2020
+ option
2021
+ });
2022
+ items.push(item);
2023
+ if (option.selected) selected.push(item);
2024
+ list.append(item);
2025
+ }
2026
+ return items;
2027
+ }
2028
+ function createSelection(id, select) {
2029
+ const container = createElement("ul", {
2030
+ attribute: { [ATTRIBUTE_SELECTION]: "" },
2031
+ property: { id: `${id}_selection` }
2032
+ });
2033
+ const options = [...select.selectedOptions];
2034
+ const items = [];
2035
+ createSelectionItems({
2036
+ container,
2037
+ items,
2038
+ options
2039
+ });
2040
+ const { button } = items[0] ?? {};
2041
+ if (button != null) button.tabIndex = 0;
2042
+ return {
2043
+ items,
2044
+ container
2045
+ };
2046
+ }
2047
+ function createSelectionItem(option, state) {
2048
+ const element = createElement("li");
2049
+ const localization = state == null ? option.textContent : getLocalization("remove", state);
2050
+ const button = createElement("button", {
2051
+ aria: { label: typeof localization === "function" ? localization(option.textContent ?? "", getData(option, "value", false) ?? "") : localization },
2052
+ attribute: {
2053
+ [ATTRIBUTE_SELECTION_ITEM]: "",
2054
+ tabindex: -1
2055
+ },
2056
+ data: { option: option.id }
2057
+ });
2058
+ const icon = createElement("span", {
2059
+ aria: { hidden: true },
2060
+ property: { innerHTML: "&times;" }
2061
+ });
2062
+ const label = createElement("span", { property: { textContent: option.textContent } });
2063
+ button.append(icon, label);
2064
+ element.append(button);
2065
+ return {
2066
+ button,
2067
+ element
2068
+ };
2069
+ }
2070
+ function createSelectionItems(parameters) {
2071
+ const { container, items, options, state } = parameters;
2072
+ const { length } = options;
2073
+ for (let index = 0; index < length; index += 1) {
2074
+ const option = options[index];
2075
+ const item = createSelectionItem(option, state);
2076
+ container.append(item.element);
2077
+ items.push(item);
2078
+ }
2079
+ }
2080
+ function createState(element, internals) {
2081
+ const select = element.querySelector("select");
2082
+ if (select == null || select.id === "") throw new Error(MESSAGE_SELECT);
2083
+ const label = element.querySelector(`label[for="${select.id}"]`);
2084
+ if (label == null) throw new Error(MESSAGE_LABEL);
2085
+ element.id = select.id;
2086
+ setAttribute(element, "name", select.name === "" ? select.id : select.name);
2087
+ const disabled = getBooleanAria(element, "disabled") || select.disabled;
2088
+ const multiple = element.multiple || select.multiple;
2089
+ const readonly = getBooleanAria(element, "readonly");
2090
+ const required = getBooleanAria(element, "required") || select.required;
2091
+ const id = getId$1();
2092
+ const type = multiple ? "select" : getAttributeValue(element, "type", TYPES, "select");
2093
+ const autocomplete = getAutoComplete(element, type === "select");
2094
+ const labelId = label.id;
2095
+ label.htmlFor = id;
2096
+ label.id = `${id}_label`;
2097
+ generateIds(id, select);
2098
+ const anchor = createAnchor({
2099
+ autocomplete,
2100
+ id,
2101
+ label,
2102
+ multiple,
2103
+ select,
2104
+ type
2105
+ });
2106
+ const content = createContent({
2107
+ autocomplete,
2108
+ id,
2109
+ label,
2110
+ multiple,
2111
+ select,
2112
+ type
2113
+ });
2114
+ const values = content.list.selected.length === 0 ? [""] : content.list.selected.map((option) => getData(option, "value", false) ?? "");
2115
+ const state = {
2116
+ autocomplete,
2117
+ disabled,
2118
+ id,
2119
+ internals,
2120
+ multiple,
2121
+ readonly,
2122
+ required,
2123
+ select,
2124
+ type,
2125
+ anchor: {
2126
+ container: anchor.container,
2127
+ element: anchor.element
2128
+ },
2129
+ active: content.list.selected[0],
2130
+ content: content.element,
2131
+ filter: {
2132
+ element: content.filter?.element ?? anchor.element,
2133
+ value: ""
2134
+ },
2135
+ floatable: void 0,
2136
+ groups: content.list.groups,
2137
+ host: element,
2138
+ label: {
2139
+ element: label,
2140
+ id: labelId
2141
+ },
2142
+ listeners: [],
2143
+ localizations: {},
2144
+ message: content.message,
2145
+ name: element.name,
2146
+ options: {
2147
+ all: content.list.options,
2148
+ selected: content.list.selected
2149
+ },
2150
+ selection: anchor.selection,
2151
+ values: {
2152
+ current: values.slice(),
2153
+ initial: values.slice()
2154
+ }
2155
+ };
2156
+ attachCombobox(state);
2157
+ setDisabled$1(state, disabled);
2158
+ setLimit("max", state, getAttribute(element, "max"));
2159
+ setLimit("min", state, getAttribute(element, "min"));
2160
+ setReadonly(state, readonly);
2161
+ setRequired(state, required);
2162
+ filterOptions(state);
2163
+ if (content.list.selected.length > 0) updatePreview("set", state, content.list.selected[0]);
2164
+ updateForm(state, state.values.current, false);
2165
+ updateMessage(state, getVisible(state).length);
2166
+ return state;
2167
+ }
2168
+ function detachCombobox(state) {
2169
+ const { content, floatable, host, label, select } = state;
2170
+ const listeners = state.listeners.splice(0);
2171
+ const { length } = listeners;
2172
+ for (let index = 0; index < length; index += 1) listeners[index]();
2173
+ floatable.destroy();
2174
+ const anchor = state.anchor.container ?? state.anchor.element;
2175
+ anchor.insertAdjacentElement("beforebegin", select);
2176
+ anchor.remove();
2177
+ content.remove();
2178
+ label.element.htmlFor = select.id;
2179
+ label.element.id = state.label.id;
2180
+ select.hidden = false;
2181
+ states$4.map.delete(host);
2182
+ states$4.map.delete(content);
2183
+ states$4.set.delete(state);
2184
+ }
2185
+ function filterOptions(state) {
2186
+ function filter(options) {
2187
+ const { length } = options;
2188
+ let count = 0;
2189
+ for (let index = 0; index < length; index += 1) {
2190
+ const option = options[index];
2191
+ option.hidden = !state.autocomplete.none && !option.textContent.toLocaleLowerCase().includes(value);
2192
+ if (!option.hidden) {
2193
+ count += 1;
2194
+ visible.push(option);
2195
+ }
2196
+ }
2197
+ return count === 0;
2198
+ }
2199
+ const value = state.filter.element.value.toLocaleLowerCase();
2200
+ const visible = [];
2201
+ if (state.groups == null) filter(state.options.all);
2202
+ else {
2203
+ const groupsLength = state.groups.length;
2204
+ for (let groupIndex = 0; groupIndex < groupsLength; groupIndex += 1) {
2205
+ const { element, options } = state.groups[groupIndex];
2206
+ element.hidden = filter(options);
2207
+ }
2208
+ }
2209
+ updateMessage(state, visible.length);
2210
+ return state.active != null && visible.includes(state.active) ? state.active : visible[0];
2211
+ }
2212
+ function filterOption(state, value, textContent) {
2213
+ const filterTextContent = textContent ?? false;
2214
+ const filter = getString(value).toLocaleLowerCase();
2215
+ filterOptions(state);
2216
+ const { length } = state.options.all;
2217
+ let match;
2218
+ for (let index = 0; index < length; index += 1) {
2219
+ const option = state.options.all[index];
2220
+ if ((filterTextContent ? option.textContent : getData(option, "value", false) ?? "").toLocaleLowerCase() === filter) {
2221
+ match = option;
2222
+ break;
2223
+ }
2224
+ }
2225
+ return match;
2226
+ }
2227
+ function generateIds(prefix, select) {
2228
+ const elements = [...select.children].flatMap((child) => child instanceof HTMLOptGroupElement ? [child, ...[...child.children].filter((groupChild) => groupChild instanceof HTMLOptionElement)] : child instanceof HTMLOptionElement ? [child] : []);
2229
+ const { length } = elements;
2230
+ for (let index = 0; index < length; index += 1) {
2231
+ const element = elements[index];
2232
+ if (element.id === "") element.id = `${prefix}${element instanceof HTMLOptGroupElement ? "_group_" : "_option_"}${index}`;
2233
+ }
2234
+ }
2235
+ function getAttributeValue(element, attribute, possible, defaultValue) {
2236
+ const value = getAttribute(element, attribute);
2237
+ return possible.has(value) ? value : defaultValue;
2238
+ }
2239
+ function getAutoComplete(element, select) {
2240
+ let value;
2241
+ if (select) value = "list";
2242
+ else value = getAttributeValue(element, "autocomplete", AUTOCOMPLETES, "none");
2243
+ return {
2244
+ value,
2245
+ both: value === "both",
2246
+ inline: value === "inline",
2247
+ list: value === "list",
2248
+ none: value === "none"
2249
+ };
2250
+ }
2251
+ function getBooleanAria(element, attribute) {
2252
+ const value = getAria(element, attribute);
2253
+ return value === true || value === "true";
2254
+ }
2255
+ function getId$1() {
2256
+ index$2 += 1;
2257
+ return `oui_combobox_${index$2}`;
2258
+ }
2259
+ function getLanguage(state) {
2260
+ return (state.host.closest("[lang]")?.getAttribute("lang") ?? document.documentElement.lang).toLowerCase();
2261
+ }
2262
+ function getLocalization(key, state) {
2263
+ const language = getLanguage(state);
2264
+ const allLocalizations = [state.localizations, LOCALIZATIONS.globals];
2265
+ const { length } = allLocalizations;
2266
+ let localization;
2267
+ let shortLanguage;
2268
+ for (let index = 0; index < length; index += 1) {
2269
+ const localizations = allLocalizations[index];
2270
+ localization = localizations?.[language]?.[key];
2271
+ if (localization != null) break;
2272
+ shortLanguage ??= language.split("-")[0];
2273
+ if (shortLanguage === language) continue;
2274
+ localization = localizations?.[shortLanguage]?.[key];
2275
+ if (localization != null) break;
2276
+ }
2277
+ return localization ?? LOCALIZATIONS.defaults[key];
2278
+ }
2279
+ function getVisible(state) {
2280
+ return state.options.all.filter((option) => !option.hidden);
2281
+ }
2282
+ function hasTextSelection(element) {
2283
+ return element instanceof HTMLInputElement && element.selectionStart !== element.selectionEnd;
2284
+ }
2285
+ function onClickContent(event, content) {
2286
+ const state = states$4.map.get(content);
2287
+ if (state == null) return;
2288
+ if (state.disabled) return;
2289
+ const option = findAncestor(event, SELECTOR_OPTION);
2290
+ if (!(option instanceof HTMLElement)) state.filter.element.focus();
2291
+ else if (state.readonly) updatePreview("set", state, option);
2292
+ else toggleOption(state, option);
2293
+ }
2294
+ function onClickDocument(event) {
2295
+ const combobox = findAncestor(event, TAGNAME$1);
2296
+ const state = states$4.map.get(combobox);
2297
+ if (combobox == null || state == null) return;
2298
+ const label = findAncestor(event, "label");
2299
+ if (label != null) {
2300
+ if (label === state.label.element && combobox.type === "select") {
2301
+ state.anchor.element.focus();
2302
+ if (!state.disabled) state.floatable.show();
2303
+ }
2304
+ return;
2305
+ }
2306
+ const selection = findAncestor(event, `[${ATTRIBUTE_SELECTION_ITEM}]`);
2307
+ if (selection != null) {
2308
+ const option = state.options.selected.find((option) => option.id === getData(selection, "option", false));
2309
+ if (state.disabled) state.anchor.element.focus();
2310
+ else if (state.readonly) updateTabindices(state, option);
2311
+ else toggleOption(state, option);
2312
+ return;
2313
+ }
2314
+ if (findAncestor(event, SELECTOR_ANCHOR) != null && !state.disabled) {
2315
+ state.floatable.show();
2316
+ return;
2317
+ }
2318
+ }
2319
+ function onEnter(state) {
2320
+ if (state.disabled || state.readonly) return;
2321
+ if (hasTextSelection(state.anchor.element)) onSelection(state);
2322
+ else toggleOption(state, state.active);
2323
+ }
2324
+ function onEscape$1(state) {
2325
+ state.floatable.hide();
2326
+ }
2327
+ function onFilter(type, state, manual, emit) {
2328
+ if (state.disabled || state.readonly) return;
2329
+ const diff = state.filter.value !== state.filter.element.value;
2330
+ if (!state.autocomplete.inline && state.filter.element.value.length > 0 && !(manual ?? false)) state.floatable.show();
2331
+ const option = state.autocomplete.none ? state.active ?? state.options.all[0] : filterOptions(state);
2332
+ let update;
2333
+ if (type.includes("delete")) update = "none";
2334
+ else if (type.includes("insert")) update = "typed";
2335
+ if (update != null) if (state.autocomplete.none) applySelection({
2336
+ state,
2337
+ added: false,
2338
+ emit: (emit ?? true) && diff
2339
+ });
2340
+ else updatePreview(update, state, option);
2341
+ if (diff) {
2342
+ state.filter.value = state.filter.element.value;
2343
+ dispatch(state.host, "input");
2344
+ }
2345
+ }
2346
+ function onFocusout$1(state) {
2347
+ if (state.disabled || state.readonly || state.type === "select" || state.host === document.activeElement || state.host.contains(document.activeElement)) return;
2348
+ const option = filterOption(state, state.filter.element.value, true);
2349
+ applySelection({
2350
+ option,
2351
+ state,
2352
+ added: false,
2353
+ selected: option == null ? [] : [option]
2354
+ });
2355
+ }
2356
+ function onInput(event) {
2357
+ const combobox = findAncestor(event, TAGNAME$1);
2358
+ const state = states$4.map.get(combobox);
2359
+ if (combobox != null && state != null && event.target === state.filter.element) onFilter(event.inputType, state);
2360
+ }
2361
+ function onKeydown$4(event) {
2362
+ const combobox = findAncestor(event, TAGNAME$1);
2363
+ const state = states$4.map.get(combobox);
2364
+ if (combobox == null || state == null) return;
2365
+ const item = findAncestor(event, SELECTOR_SELECTION_ITEM);
2366
+ if (item instanceof HTMLElement) {
2367
+ onKeydownSelection(event, state, item);
2368
+ return;
2369
+ }
2370
+ onKeydownFilter(event, state);
2371
+ }
2372
+ function onKeydownFilter(event, state) {
2373
+ const ignore = state.disabled || state.readonly;
2374
+ const isSelect = state.type === "select";
2375
+ let preventDefault = ignore;
2376
+ switch (true) {
2377
+ case event.key === " ":
2378
+ if (!state.disabled) state.floatable.show();
2379
+ break;
2380
+ case event.key === "Enter":
2381
+ preventDefault = state.floatable.open;
2382
+ if (preventDefault) onEnter(state);
2383
+ else if (!ignore && state.type === "select") state.floatable.show();
2384
+ else if (!ignore) state.internals.form?.requestSubmit();
2385
+ break;
2386
+ case event.key === "Escape":
2387
+ preventDefault = false;
2388
+ onEscape$1(state);
2389
+ break;
2390
+ case !isSelect && KEYS_SELECTION.has(event.key):
2391
+ if (!ignore && hasTextSelection(state.anchor.element)) onSelection(state);
2392
+ break;
2393
+ case KEYS_NAVIGATION.has(event.key):
2394
+ if (!state.disabled) onNavigation(event, state);
2395
+ break;
2396
+ default:
2397
+ preventDefault = false;
2398
+ if (event.key === "Tab") onTab$1(state);
2399
+ break;
2400
+ }
2401
+ if (preventDefault) {
2402
+ event.preventDefault();
2403
+ event.stopPropagation();
2404
+ }
2405
+ }
2406
+ function onKeydownSelection(event, state, item) {
2407
+ if (KEYS_ACTIVATION.has(event.key)) {
2408
+ event.preventDefault();
2409
+ onRemoveSelection(state, item);
2410
+ return;
2411
+ }
2412
+ if (state.disabled || state.selection == null) return;
2413
+ const { length } = state.selection.items;
2414
+ const index = state.selection.items.findIndex((selection) => selection.button === item);
2415
+ let next;
2416
+ switch (event.key) {
2417
+ case "ArrowDown":
2418
+ state.anchor.element.focus();
2419
+ state.anchor.element.click();
2420
+ return;
2421
+ case "ArrowRight":
2422
+ case "ArrowLeft":
2423
+ next = clamp(index + (event.key === "ArrowRight" ? 1 : -1), 0, length - 1, true);
2424
+ break;
2425
+ case "End":
2426
+ next = length - 1;
2427
+ break;
2428
+ case "Home":
2429
+ next = 0;
2430
+ break;
2431
+ default: break;
2432
+ }
2433
+ if (next == null) return;
2434
+ event.preventDefault();
2435
+ for (let index = 0; index < length; index += 1) {
2436
+ const { button } = state.selection.items[index];
2437
+ const selected = index === next;
2438
+ button.tabIndex = selected ? 0 : -1;
2439
+ if (selected) button.focus();
2440
+ }
2441
+ }
2442
+ function onNavigation(event, state) {
2443
+ let skip = false;
2444
+ if (!state.floatable.open) {
2445
+ skip = true;
2446
+ state.floatable.show();
2447
+ }
2448
+ const visible = getVisible(state);
2449
+ if (visible.length === 0) return;
2450
+ let next;
2451
+ if (skip || state.active == null) next = state.active ?? visible.at(event.key === "ArrowDown" ? 0 : -1);
2452
+ else {
2453
+ const current = visible.findIndex((option) => option.id === state.active?.id);
2454
+ let index;
2455
+ switch (event.key) {
2456
+ case "ArrowDown":
2457
+ case "ArrowUp":
2458
+ index = clamp(current + (event.key === "ArrowDown" ? 1 : -1), 0, visible.length - 1, true);
2459
+ break;
2460
+ case "End":
2461
+ index = visible.length - 1;
2462
+ break;
2463
+ case "Home":
2464
+ index = 0;
2465
+ break;
2466
+ case "PageDown":
2467
+ case "PageUp":
2468
+ index = clamp(current + (event.key === "PageDown" ? 10 : -10), 0, visible.length - 1);
2469
+ break;
2470
+ default: break;
2471
+ }
2472
+ if (index != null) next = visible[index];
2473
+ }
2474
+ let preview;
2475
+ if (state.type === "autocomplete" && (state.autocomplete.both || state.autocomplete.inline)) preview = "set";
2476
+ else preview = "none";
2477
+ updatePreview(preview, state, next ?? state.active ?? visible[0]);
2478
+ }
2479
+ function onRemoveSelection(state, item) {
2480
+ if (state.disabled || state.readonly) return;
2481
+ const option = state.options.selected.find((option) => option.id === getData(item, "option", false));
2482
+ if (option != null) toggleOption(state, option);
2483
+ }
2484
+ function onSelection(state) {
2485
+ state.filter.value = state.anchor.element === state.filter.element ? state.filter.element.value : "";
2486
+ filterOptions(state);
2487
+ toggleOption(state, state.active);
2488
+ }
2489
+ function onTab$1(state) {
2490
+ setTimeout(() => {
2491
+ if (state.host === document.activeElement) return;
2492
+ if (state.selection?.container.contains(document.activeElement) || !state.host.contains(document.activeElement)) state.floatable.hide();
2493
+ });
2494
+ }
2495
+ function setDisabled$1(state, value) {
2496
+ state.filter.element.readOnly = state.readonly || value;
2497
+ setProperties("disabled", state, value);
2498
+ }
2499
+ function setFilter(state, value) {
2500
+ if (typeof value !== "string") return;
2501
+ const type = value.length < state.filter.element.value.length ? "deleteContentBackward" : "insertText";
2502
+ state.filter.element.value = value;
2503
+ onFilter(type, state);
2504
+ }
2505
+ function setLimit(type, state, value) {
2506
+ let actual = value;
2507
+ if (typeof actual === "string") actual = Number.parseInt(actual, 10);
2508
+ if (typeof actual === "number" && !Number.isNaN(actual) && actual >= 0 ? actual !== state[type] : actual == null) {
2509
+ state[type] = actual;
2510
+ setAttribute(state.host, type, actual);
2511
+ updateValidity(state);
2512
+ }
2513
+ }
2514
+ function setLocalizations(first, second) {
2515
+ updateLocalizations(typeof first === "string" ? { [first]: second } : first);
2516
+ }
2517
+ function setProperties(key, state, value) {
2518
+ state[key] = value;
2519
+ const elements = [
2520
+ state.host,
2521
+ state.anchor.element,
2522
+ state.filter.element
2523
+ ];
2524
+ const { length } = elements;
2525
+ for (let index = 0; index < length; index += 1) {
2526
+ const element = elements[index];
2527
+ setAria(element, key, key !== "readonly" || !(element instanceof HTMLButtonElement) ? value : void 0);
2528
+ }
2529
+ }
2530
+ function setReadonly(state, value) {
2531
+ state.filter.element.readOnly = state.disabled || value;
2532
+ setProperties("readonly", state, value);
2533
+ }
2534
+ function setRequired(state, value) {
2535
+ setProperties("required", state, value);
2536
+ updateValidity(state);
2537
+ }
2538
+ function setValue(state, value, emit) {
2539
+ if (state.autocomplete.none) {
2540
+ state.filter.element.value = getString(value);
2541
+ onFilter("insertText", state, true, emit);
2542
+ return;
2543
+ }
2544
+ if (filterOption(state, value) != null) setValues(state, [value], emit);
2545
+ }
2546
+ function setValues(state, value, emit) {
2547
+ if (!Array.isArray(value)) return;
2548
+ const values = (state.multiple ? value : value.slice(0, 1)).map((value) => getString(value).toLocaleLowerCase());
2549
+ if (values.length === 0) values.push("");
2550
+ if (state.autocomplete.none) {
2551
+ setValue(state, values[0], emit);
2552
+ return;
2553
+ }
2554
+ const { length } = state.options.all;
2555
+ const selected = [];
2556
+ for (let index = 0; index < length; index += 1) {
2557
+ const option = state.options.all[index];
2558
+ if (values.includes(getData(option, "value", false)?.toLocaleLowerCase() ?? "")) selected.push(option);
2559
+ }
2560
+ applySelection({
2561
+ emit,
2562
+ selected,
2563
+ state,
2564
+ added: true,
2565
+ option: selected[0] ?? state.options.all[0],
2566
+ values: state.autocomplete.none ? values : void 0
2567
+ });
2568
+ }
2569
+ function toggleOption(state, option) {
2570
+ if (option == null || !state.multiple && state.options.selected.includes(option)) {
2571
+ state.floatable.hide();
2572
+ return;
2573
+ }
2574
+ const selected = state.options.selected.slice();
2575
+ let added = true;
2576
+ if (state.multiple) {
2577
+ const index = selected.indexOf(option);
2578
+ if (index === -1) selected.push(option);
2579
+ else {
2580
+ added = false;
2581
+ selected.splice(index, 1);
2582
+ }
2583
+ } else selected.splice(0, selected.length, option);
2584
+ applySelection({
2585
+ added,
2586
+ option,
2587
+ selected,
2588
+ state,
2589
+ values: state.autocomplete.none && option != null ? [option.textContent] : void 0
2590
+ });
2591
+ if (!state.multiple) state.floatable.hide();
2592
+ }
2593
+ function updateAnchor(state) {
2594
+ if (!state.multiple) return;
2595
+ const localization = getLocalization("selected", state);
2596
+ setAria(state.anchor.element, "label", typeof localization === "function" ? localization(state.options.selected.length) : localization.replace("{amount}", state.options.selected.length.toString()));
2597
+ }
2598
+ function updateAutocomplete(preview, state, active) {
2599
+ if (state.multiple) return;
2600
+ const content = active?.textContent ?? state.filter.element.value;
2601
+ if (preview === "typed" && !content.toLocaleLowerCase().startsWith(state.filter.element.value.toLocaleLowerCase())) return;
2602
+ if (state.anchor.element instanceof HTMLInputElement) {
2603
+ const contentLength = content.length;
2604
+ const filterLength = state.filter.element.value.length;
2605
+ if (preview === "set" || preview === "typed") {
2606
+ state.anchor.element.value = content;
2607
+ state.anchor.element.setSelectionRange(preview === "typed" ? filterLength : contentLength, contentLength);
2608
+ }
2609
+ } else state.anchor.element.textContent = content;
2610
+ }
2611
+ function updateForm(state, values, emit) {
2612
+ let value;
2613
+ if (state.multiple) {
2614
+ const { length } = values;
2615
+ value = new FormData();
2616
+ for (let index = 0; index < length; index += 1) value.append(state.name, values[index]);
2617
+ } else value = values[0];
2618
+ state.values.current = values;
2619
+ state.internals.setFormValue(value, JSON.stringify(values));
2620
+ updateAnchor(state);
2621
+ updateValidity(state);
2622
+ if (emit ?? true) dispatch(state.host, "change");
2623
+ }
2624
+ function updateLocalizations(values, destination) {
2625
+ if (typeof values !== "object" || values == null) return;
2626
+ const localizations = destination ?? LOCALIZATIONS.globals;
2627
+ const languages = Object.keys(values);
2628
+ const languagesLength = languages.length;
2629
+ let updated = false;
2630
+ for (let languagesIndex = 0; languagesIndex < languagesLength; languagesIndex += 1) {
2631
+ const language = languages[languagesIndex];
2632
+ const languageValue = values[language];
2633
+ if (typeof languageValue !== "object" || languageValue == null) continue;
2634
+ const normalizedLanguage = language.toLowerCase();
2635
+ localizations[normalizedLanguage] ??= {};
2636
+ const keys = Object.keys(languageValue);
2637
+ const keysLength = keys.length;
2638
+ for (let keysIndex = 0; keysIndex < keysLength; keysIndex += 1) {
2639
+ const key = keys[keysIndex];
2640
+ const keyValue = languageValue[key];
2641
+ const normalizedKey = key.toLowerCase();
2642
+ if (LOCALIZATIONS.keys.has(normalizedKey) && (typeof keyValue === "string" || typeof keyValue === "function")) {
2643
+ updated = true;
2644
+ localizations[normalizedLanguage][normalizedKey] = keyValue;
2645
+ }
2646
+ }
2647
+ }
2648
+ if (!updated) return;
2649
+ for (const state of states$4.set) {
2650
+ updateAnchor(state);
2651
+ updateMessage(state, getVisible(state).length);
2652
+ updateSelectionItems(state);
2653
+ }
2654
+ }
2655
+ function updateMessage(state, visible) {
2656
+ setAttribute(state.message, ATTRIBUTE_HIDDEN, visible > 0 ? "" : void 0);
2657
+ if (visible === 0) {
2658
+ const localization = getLocalization("empty", state);
2659
+ state.message.textContent = typeof localization === "function" ? localization() : localization;
2660
+ } else {
2661
+ const localization = getLocalization("results", state);
2662
+ state.message.textContent = typeof localization === "function" ? localization(visible) : localization.replace("{amount}", visible.toString());
2663
+ }
2664
+ state.message.hidden = false;
2665
+ }
2666
+ function updatePreview(preview, state, active) {
2667
+ const { length } = state.options.all;
2668
+ for (let index = 0; index < length; index += 1) {
2669
+ const option = state.options.all[index];
2670
+ setAttribute(option, ATTRIBUTE_OPTION_ACTIVE, option === active ? "" : void 0);
2671
+ }
2672
+ state.active = active;
2673
+ setAria(state.filter.element, "activedescendant", state.floatable.open ? active?.id : void 0);
2674
+ if (state.floatable.open) active?.scrollIntoView(scrollOptions);
2675
+ if (preview !== "none") updateAutocomplete(preview, state, active);
2676
+ }
2677
+ function updateSelection(state, active, added, selected) {
2678
+ if (state.selection == null) return;
2679
+ let options = active == null ? [] : [active];
2680
+ if (selected != null) {
2681
+ options = selected;
2682
+ const { length } = state.selection.items;
2683
+ for (let index = 0; index < length; index += 1) state.selection.items[index].element.remove();
2684
+ state.selection.items.splice(0);
2685
+ }
2686
+ if (added) {
2687
+ createSelectionItems({
2688
+ options,
2689
+ state,
2690
+ container: state.selection.container,
2691
+ items: state.selection.items
2692
+ });
2693
+ return;
2694
+ }
2695
+ let current = state.selection.items.findIndex((item) => getData(item.button, "option", false) === active?.id);
2696
+ if (current === -1) return;
2697
+ state.selection.items[current].element.remove();
2698
+ state.selection.items.splice(current, 1);
2699
+ if (state.selection.items.length === 0) {
2700
+ state.anchor.element.focus();
2701
+ return;
2702
+ }
2703
+ const { length } = state.selection.items;
2704
+ if (current < 0) current = 0;
2705
+ else if (current >= length) current = length - 1;
2706
+ for (let index = 0; index < length; index += 1) {
2707
+ const { button } = state.selection.items[index];
2708
+ button.tabIndex = index === current ? 0 : -1;
2709
+ }
2710
+ state.selection.items[current].button.focus();
2711
+ }
2712
+ function updateSelectionItems(state) {
2713
+ if (state.selection == null) return;
2714
+ const localization = getLocalization("remove", state);
2715
+ const { length } = state.selection.items;
2716
+ for (let index = 0; index < length; index += 1) {
2717
+ const item = state.selection.items[index];
2718
+ const option = state.options.selected.find((option) => option.id === getData(item.button, "option", false));
2719
+ if (option == null) continue;
2720
+ setAria(item.button, "label", typeof localization === "function" ? localization(option?.textContent ?? "", getData(option, "value", false) ?? "") : localization.replace("{label}", option?.textContent ?? ""));
2721
+ }
2722
+ }
2723
+ function updateTabindices(state, active) {
2724
+ if (active == null || state.selection == null) return;
2725
+ const next = state.selection.items.find((item) => getData(item.button, "option", false) === active.id);
2726
+ if (next == null) return;
2727
+ const { length } = state.selection.items;
2728
+ for (let index = 0; index < length; index += 1) {
2729
+ const item = state.selection.items[index];
2730
+ item.button.tabIndex = item === next ? 0 : -1;
2731
+ }
2732
+ next.button.focus();
2733
+ }
2734
+ function updateValidity(state) {
2735
+ if (state.autocomplete.none) {
2736
+ const valueMissing = state.required && state.filter.element.value.length === 0;
2737
+ const localization = getLocalization("input", state);
2738
+ state.internals.setValidity({ valueMissing }, typeof localization === "function" ? localization() : localization);
2739
+ state.internals.checkValidity();
2740
+ return;
2741
+ }
2742
+ let error;
2743
+ let message;
2744
+ switch (true) {
2745
+ case state.required && state.options.selected.length === 0: {
2746
+ error = "badInput";
2747
+ const localization = getLocalization("input", state);
2748
+ message = typeof localization === "function" ? localization() : localization;
2749
+ break;
2750
+ }
2751
+ case state.multiple && typeof state.max === "number" && state.options.selected.length > state.max: {
2752
+ error = "rangeOverflow";
2753
+ const localization = getLocalization("max", state);
2754
+ message = typeof localization === "function" ? localization(state.max) : localization.replace("{max}", state.max.toString());
2755
+ break;
2756
+ }
2757
+ case state.multiple && typeof state.min === "number" && state.options.selected.length < state.min: {
2758
+ error = "rangeUnderflow";
2759
+ const localization = getLocalization("min", state);
2760
+ message = typeof localization === "function" ? localization(state.min) : localization.replace("{min}", state.min.toString());
2761
+ break;
2762
+ }
2763
+ default: break;
2764
+ }
2765
+ state.internals.setValidity(error == null ? {} : { [error]: true }, message);
2766
+ state.internals.checkValidity();
2767
+ }
2768
+ const TAGNAME$1 = "oui-combobox";
2769
+ const ATTRIBUTE_ANCHOR = `${TAGNAME$1}-anchor`;
2770
+ const ATTRIBUTE_CONTENT$1 = `${TAGNAME$1}-content`;
2771
+ const ATTRIBUTE_FILTER = `${TAGNAME$1}-filter`;
2772
+ const ATTRIBUTE_FILTER_INPUT = `${ATTRIBUTE_FILTER}-input`;
2773
+ const ATTRIBUTE_HEADER = `${TAGNAME$1}-header`;
2774
+ const ATTRIBUTE_HIDDEN = `${TAGNAME$1}-hidden`;
2775
+ const ATTRIBUTE_LIST = `${TAGNAME$1}-list`;
2776
+ const ATTRIBUTE_MESSAGE = `${TAGNAME$1}-message`;
2777
+ const ATTRIBUTE_OPTION = `${TAGNAME$1}-option`;
2778
+ const ATTRIBUTE_OPTION_ACTIVE = `${TAGNAME$1}-option-active`;
2779
+ const ATTRIBUTE_SELECTION = `${TAGNAME$1}-selection`;
2780
+ const ATTRIBUTE_SELECTION_ITEM = `${TAGNAME$1}-selection-item`;
2781
+ const AUTOCOMPLETES = /* @__PURE__ */ new Set([
2782
+ "both",
2783
+ "inline",
2784
+ "list",
2785
+ "none"
2786
+ ]);
2787
+ const KEYS_ACTIVATION = /* @__PURE__ */ new Set([
2788
+ " ",
2789
+ "Backspace",
2790
+ "Delete",
2791
+ "Enter"
2792
+ ]);
2793
+ const KEYS_NAVIGATION = /* @__PURE__ */ new Set([
2794
+ "ArrowDown",
2795
+ "ArrowUp",
2796
+ "PageDown",
2797
+ "PageUp"
2798
+ ]);
2799
+ const KEYS_SELECTION = /* @__PURE__ */ new Set(["ArrowRight", "End"]);
2800
+ const LOCALIZATIONS = {
2801
+ defaults: {
2802
+ empty: "No results found",
2803
+ input: "Please enter a value",
2804
+ invalid: "Please select an option from the list",
2805
+ max: (max) => `Please select fewer options (maximum is ${max})`,
2806
+ min: (min) => `Please select more options (minimum is ${min})`,
2807
+ remove: (label) => `Remove ${label}`,
2808
+ results: (amount) => `${amount} results available`,
2809
+ selected: (amount) => `${amount} selected`
2810
+ },
2811
+ globals: {},
2812
+ keys: /* @__PURE__ */ new Set([
2813
+ "empty",
2814
+ "input",
2815
+ "invalid",
2816
+ "max",
2817
+ "min",
2818
+ "remove",
2819
+ "results",
2820
+ "selected"
2821
+ ])
2822
+ };
2823
+ const MESSAGE_LABEL = `<${TAGNAME$1}> must contain a <label> element for the <select> element`;
2824
+ const MESSAGE_SELECT = `<${TAGNAME$1}> must contain a valid <select> element`;
2825
+ const SELECTOR_ANCHOR = `[${ATTRIBUTE_ANCHOR}]`;
2826
+ const SELECTOR_SELECTION_ITEM = `[${ATTRIBUTE_SELECTION_ITEM}]`;
2827
+ const SELECTOR_OPTION = `[${ATTRIBUTE_OPTION}]`;
2828
+ const TYPES = /* @__PURE__ */ new Set(["autocomplete", "select"]);
2829
+ const scrollOptions = {
2830
+ behavior: "auto",
2831
+ block: "nearest",
2832
+ inline: "nearest"
2833
+ };
2834
+ const states$4 = {
2835
+ map: /* @__PURE__ */ new WeakMap(),
2836
+ set: /* @__PURE__ */ new Set()
2837
+ };
2838
+ let index$2 = 0;
2839
+ on(document, "click", onClickDocument);
2840
+ on(document, "input", onInput, { passive: false });
2841
+ on(document, "keydown", onKeydown$4, { passive: false });
2842
+ customElements.define(TAGNAME$1, OuiComboboxElement);
2843
+ //#endregion
2844
+ //#region node_modules/@oscarpalmer/toretto/dist/touch.mjs
2845
+ function getSupport() {
2846
+ if (window == null || navigator == null) return false;
2847
+ if ("matchMedia" in window) {
2848
+ const media = matchMedia?.("(pointer: coarse)");
2849
+ if (typeof media?.matches === "boolean" && media.matches) return true;
2850
+ }
2851
+ if ("ontouchstart" in window) return true;
2852
+ if (typeof navigator.maxTouchPoints === "number" && navigator.maxTouchPoints > 0) return true;
2853
+ if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
2854
+ return false;
2855
+ }
2856
+ /**
2857
+ * Does the device support touch events?
2858
+ */
2859
+ const supportsTouch = (() => {
2860
+ let support = getSupport();
2861
+ const instance = Object.create({
2862
+ get() {
2863
+ return support;
2864
+ },
2865
+ update() {
2866
+ support = getSupport();
2867
+ return support;
2868
+ }
2869
+ });
2870
+ Object.defineProperty(instance, "value", { get() {
2871
+ return support;
2872
+ } });
2873
+ return instance;
2874
+ })();
2875
+ //#endregion
2876
+ //#region src/js/internal/draggable.ts
2877
+ var OuiDraggable = class {
2878
+ #destroyed = false;
2879
+ #state;
2880
+ get element() {
2881
+ return this.#state.element;
2882
+ }
2883
+ constructor(name, event, attribute, element, options, extras) {
2884
+ this.#state = {
2885
+ ...extras,
2886
+ attribute,
2887
+ element,
2888
+ event,
2889
+ name,
2890
+ options,
2891
+ horizontal: true,
2892
+ vertical: true,
2893
+ styling: toggleStyles(element, styles$1)
2894
+ };
2895
+ const item = {
2896
+ instance: this,
2897
+ state: this.#state
2898
+ };
2899
+ setContainer(item);
2900
+ setDirection(item);
2901
+ setAttribute(element, attribute, "");
2902
+ let states = globals.states.get(element);
2903
+ states ??= {};
2904
+ states[this.#state.name] = this.#state;
2905
+ globals.states.set(element, states);
2906
+ }
2907
+ destroy() {
2908
+ if (this.#destroyed) return;
2909
+ this.#destroyed = true;
2910
+ destroyInstance(this, this.#state);
2911
+ }
2912
+ };
2913
+ function addDraggable(element, options) {
2914
+ let instances = globals.instances.get(element);
2915
+ if (instances == null) {
2916
+ instances = {};
2917
+ globals.instances.set(element, instances);
2918
+ }
2919
+ instances[this.property] ??= new this.constructor(element, options);
2920
+ return instances[this.property];
2921
+ }
2922
+ function cancelDrag(item) {
2923
+ if (item == null) return;
2924
+ item.state.options.drag.onCancel?.(globals, item);
2925
+ dispatch(item.state.element, `${item.state.name}:cancel`, { detail: { element: item.state.options.getOrigin() } });
2926
+ reset();
2927
+ }
2928
+ function destroyInstance(instance, state) {
2929
+ unsetContainer({
2930
+ instance,
2931
+ state
2932
+ });
2933
+ state.element.removeAttribute(state.attribute);
2934
+ state.styling.remove();
2935
+ state.container = void 0;
2936
+ state.element = void 0;
2937
+ state.options = void 0;
2938
+ state.styling = void 0;
2939
+ }
2940
+ function getDraggableStates(element) {
2941
+ return globals.states.get(element);
2942
+ }
2943
+ function getHandle(event, isMovable) {
2944
+ return findAncestor(event, isMovable ? SELECTOR_MOVABLE_HANDLE : SELECTOR_SORTABLE_HANDLE);
2945
+ }
2946
+ function getNextPosition(item, position) {
2947
+ let x = globals.original?.x ?? 0;
2948
+ let y = globals.original?.y ?? 0;
2949
+ if (item.state.horizontal) {
2950
+ x = position.x - (globals.offset?.x ?? 0);
2951
+ if (globals.container != null && globals.element != null) x = clamp(x, globals.container.left, globals.container.right - globals.element.rectangle.width);
2952
+ }
2953
+ if (item.state.vertical) {
2954
+ y = position.y - (globals.offset?.y ?? 0);
2955
+ if (globals.container != null && globals.element != null) y = clamp(y, globals.container.top, globals.container.bottom - globals.element.rectangle.height);
2956
+ }
2957
+ return {
2958
+ x,
2959
+ y
2960
+ };
2961
+ }
2962
+ function onKeydown$3(event) {
2963
+ if (current$1 != null && event.key === KEY_ESCAPE) cancelDrag(current$1);
2964
+ }
2965
+ function onPointerdown$4(event) {
2966
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || (supportsTouch.value ? event.type === "mousedown" : event.type === "touchstart" || event.button !== 0)) return;
2967
+ const container = findAncestor(event, SELECTOR$4);
2968
+ const instances = globals.instances.get(container);
2969
+ const states = globals.states.get(container);
2970
+ if (instances == null || states == null) return;
2971
+ const isMovable = container.hasAttribute(ATTRIBUTE_MOVABLE$1);
2972
+ const item = {
2973
+ instance: isMovable ? instances.movable : instances.sortable,
2974
+ state: isMovable ? states.movable : states.sortable
2975
+ };
2976
+ if (item.instance == null || item.state == null) return;
2977
+ if (supportsTouch.value) event.preventDefault();
2978
+ let element = container;
2979
+ if (!isMovable) {
2980
+ element = findAncestor(event, SELECTOR_SORTABLE_ITEM);
2981
+ if (element == null || element.parentElement !== container) return;
2982
+ }
2983
+ let handle = element;
2984
+ item.state.hasHandles ??= element.querySelector(SELECTOR_SORTABLE_HANDLE) != null;
2985
+ if (item.state.hasHandles) handle = getHandle(event, isMovable);
2986
+ if (handle == null) return;
2987
+ const dragged = item.state.options.getDragged();
2988
+ const rectangle = dragged.getBoundingClientRect();
2989
+ const position = getPosition$1(event) ?? {
2990
+ x: 0,
2991
+ y: 0
2992
+ };
2993
+ current$1 = item;
2994
+ globals.container = item.state.container?.getBoundingClientRect();
2995
+ globals.element = {
2996
+ rectangle,
2997
+ node: dragged
2998
+ };
2999
+ globals.offset = item.state.options.position.getOffset(globals, item, element, position);
3000
+ globals.original = item.state.options.position.getOriginal(globals, item, position);
3001
+ const dispatched = dispatch(item.state.element, `${item.state.name}:begin`, { detail: {
3002
+ element,
3003
+ position: { ...globals.original }
3004
+ } });
3005
+ setTimeout(() => {
3006
+ if (dispatched.defaultPrevented) {
3007
+ item.state.options.drag.onCancel?.(globals, item);
3008
+ reset();
3009
+ return;
3010
+ }
3011
+ const next = getNextPosition(item, position);
3012
+ setStyles(dragged, {
3013
+ position: "fixed",
3014
+ inset: `${next.y}px auto auto ${next.x}px`,
3015
+ transform: "translate3d(0, 0, 0)"
3016
+ });
3017
+ item.state.options.drag.onBegin?.(event, globals, item, element, handle, next);
3018
+ item.state.styling.set();
3019
+ styleToggler$1.set();
3020
+ });
3021
+ }
3022
+ function onPointermove$3(event) {
3023
+ if (current$1 == null) return;
3024
+ const position = getPosition$1(event);
3025
+ if (position == null) return;
3026
+ const next = getNextPosition(current$1, position);
3027
+ if (globals.element != null) setStyle(globals.element.node, "inset", `${next.y}px auto auto ${next.x}px`);
3028
+ const detail = current$1.state.options.drag.onMove(event, globals, current$1, {
3029
+ calculated: next,
3030
+ original: position
3031
+ });
3032
+ const dispatched = dispatch(current$1.state.element, `${current$1.state.name}:move`, { detail });
3033
+ setTimeout(() => {
3034
+ if (dispatched.defaultPrevented) cancelDrag(current$1);
3035
+ });
3036
+ }
3037
+ function onPointerup$2(event) {
3038
+ current$1?.state.options.drag.onEnd?.(event, globals, current$1, reset);
3039
+ }
3040
+ function removeDraggable(element) {
3041
+ const { property } = this;
3042
+ removeInstance(globals.instances, property, element);
3043
+ removeInstance(globals.states, property, element);
3044
+ }
3045
+ function removeInstance(map, name, element) {
3046
+ const instances = map.get(element);
3047
+ if (instances == null || instances[name] == null) return;
3048
+ if (typeof instances[name].destroy === "function") instances[name].destroy();
3049
+ instances[name] = void 0;
3050
+ if (instances[properties[name]] == null) map.delete(element);
3051
+ }
3052
+ function reset() {
3053
+ current$1?.state.styling.remove();
3054
+ styleToggler$1.remove();
3055
+ current$1 = void 0;
3056
+ globals.container = void 0;
3057
+ globals.element = void 0;
3058
+ globals.offset = void 0;
3059
+ globals.original = void 0;
3060
+ }
3061
+ function setContainer(item) {
3062
+ const { container } = item.state.options.input ?? {};
3063
+ if (isHTMLOrSVGElement(container)) {
3064
+ setContainerElement(item, container);
3065
+ return;
3066
+ }
3067
+ const selector = container ?? getAttribute(item.instance.element, item.state.options.container.attribute);
3068
+ if (typeof selector !== "string") return;
3069
+ const element = containers.has(selector) ? item.state.element.ownerDocument.body : document.querySelector(selector) ?? void 0;
3070
+ if (isHTMLOrSVGElement(element)) setContainerElement(item, element);
3071
+ }
3072
+ function setContainerElement(item, element) {
3073
+ item.state.container = element;
3074
+ const set = item.state.options.container.map.get(element);
3075
+ if (set == null) item.state.options.container.map.set(element, /* @__PURE__ */ new Set([item.instance]));
3076
+ else set.add(item.instance);
3077
+ item.state.options.container.onInitialize?.(item);
3078
+ }
3079
+ function setDirection(item) {
3080
+ const direction = getAttribute(item.state.element, item.state.options.direction.attribute);
3081
+ if (horizontals.has(direction)) item.state.vertical = false;
3082
+ else if (verticals.has(direction)) item.state.horizontal = false;
3083
+ item.state.options.direction.onAfter?.(item);
3084
+ }
3085
+ function unsetContainer(item) {
3086
+ const { container } = item.state;
3087
+ if (container == null) return;
3088
+ const set = item.state.options.container.map.get(container);
3089
+ let empty = false;
3090
+ if (set != null) {
3091
+ set.delete(item.instance);
3092
+ if (set.size === 0) {
3093
+ empty = true;
3094
+ item.state.options.container.map.delete(container);
3095
+ }
3096
+ }
3097
+ item.state.options.container.onDestroy?.(item, container, empty);
3098
+ }
3099
+ const ATTRIBUTE_MOVABLE$1 = "oui-movable";
3100
+ const ATTRIBUTE_SORTABLE = "oui-sortable";
3101
+ const KEY_ESCAPE = "Escape";
3102
+ const SELECTOR$4 = `[${ATTRIBUTE_MOVABLE$1}], [${ATTRIBUTE_SORTABLE}]`;
3103
+ const SELECTOR_MOVABLE_HANDLE = `[${ATTRIBUTE_MOVABLE$1}-handle]`;
3104
+ const SELECTOR_SORTABLE_HANDLE = `[${ATTRIBUTE_SORTABLE}-handle]`;
3105
+ const SELECTOR_SORTABLE_ITEM = `[${ATTRIBUTE_SORTABLE}] > *`;
3106
+ const containers = /* @__PURE__ */ new Set([
3107
+ "body",
3108
+ "document",
3109
+ "window"
3110
+ ]);
3111
+ const horizontals = /* @__PURE__ */ new Set(["horizontal", "x"]);
3112
+ const properties = {
3113
+ movable: "sortable",
3114
+ sortable: "movable"
3115
+ };
3116
+ const globals = {
3117
+ container: void 0,
3118
+ element: void 0,
3119
+ instances: /* @__PURE__ */ new WeakMap(),
3120
+ offset: void 0,
3121
+ original: void 0,
3122
+ states: /* @__PURE__ */ new WeakMap()
3123
+ };
3124
+ const styles$1 = {
3125
+ touchAction: "none",
3126
+ userSelect: "none",
3127
+ webkitUserSelect: "none"
3128
+ };
3129
+ const styleToggler$1 = toggleStyles(document.body, styles$1);
3130
+ const verticals = /* @__PURE__ */ new Set(["vertical", "y"]);
3131
+ let current$1;
3132
+ on(document, "keydown", onKeydown$3);
3133
+ on(document, "mousedown", onPointerdown$4);
3134
+ on(document, "pointermove", onPointermove$3);
3135
+ on(document, "pointerup", onPointerup$2);
3136
+ on(document, "touchcancel", onPointerup$2);
3137
+ on(document, "touchstart", onPointerdown$4, { passive: false });
3138
+ //#endregion
3139
+ //#region src/js/movable/movable.embedded.ts
3140
+ var OuiMovable = class extends OuiDraggable {
3141
+ #element;
3142
+ #style;
3143
+ constructor(element, options) {
3144
+ const style = getStyles(element, ["inset", "position"]);
3145
+ super("movable", "move", ATTRIBUTE_MOVABLE, element, {
3146
+ container: {
3147
+ attribute: ATTRIBUTE_CONTAINER$2,
3148
+ map: CONTAINERS$1,
3149
+ onDestroy: destroyContainer,
3150
+ onInitialize: initializeContainer
3151
+ },
3152
+ direction: {
3153
+ attribute: ATTRIBUTE_DIRECTION$1,
3154
+ onAfter: afterDirection
3155
+ },
3156
+ drag: {
3157
+ onBegin: onBegin$1,
3158
+ onCancel: onCancel$1,
3159
+ onEnd: onEnd$2,
3160
+ onMove: onMove$1
3161
+ },
3162
+ input: options,
3163
+ position: {
3164
+ getOffset: getOffsetPosition$1,
3165
+ getOriginal: getOriginalPosition$1
3166
+ },
3167
+ getDragged() {
3168
+ return element;
3169
+ },
3170
+ getOrigin() {
3171
+ return element;
3172
+ }
3173
+ }, {
3174
+ style,
3175
+ hasHandles: element.querySelector(SELECTOR_HANDLE$2) != null,
3176
+ moved: false
3177
+ });
3178
+ this.#element = element;
3179
+ this.#style = style;
3180
+ }
3181
+ /**
3182
+ * Destroys the _Movable_
3183
+ */
3184
+ destroy() {
3185
+ MOVED.delete(this);
3186
+ setStyles(this.#element, this.#style);
3187
+ this.#element = void 0;
3188
+ this.#style = void 0;
3189
+ super.destroy();
3190
+ }
3191
+ };
3192
+ function afterDirection(item) {
3193
+ const container = item.state.container?.getBoundingClientRect();
3194
+ if (container != null) setOffset(item.state, container);
3195
+ }
3196
+ /**
3197
+ * Creates _(or retrieves)_ a _OuiMovable_ instance for an element
3198
+ *
3199
+ * @param element Element to make movable
3200
+ * @returns _OuiMovable_ instance
3201
+ */
3202
+ function createMovable(element, options) {
3203
+ if (!isHTMLOrSVGElement(element)) throw new TypeError(MESSAGE$4);
3204
+ return addMovable(element, options);
3205
+ }
3206
+ function destroyContainer(_, container, empty) {
3207
+ if (empty) resizer.unobserve(container);
3208
+ }
3209
+ function getOffsetPosition$1(globals, _, __, position) {
3210
+ return {
3211
+ x: position.x - (globals.element?.rectangle.left ?? 0),
3212
+ y: position.y - (globals.element?.rectangle.top ?? 0)
3213
+ };
3214
+ }
3215
+ function getOriginalPosition$1(globals) {
3216
+ return {
3217
+ x: globals.element?.rectangle.left ?? 0,
3218
+ y: globals.element?.rectangle.top ?? 0
3219
+ };
3220
+ }
3221
+ function initializeContainer(item) {
3222
+ resizer.observe(item.state.container);
3223
+ }
3224
+ function onBegin$1() {}
3225
+ function onCancel$1(globals, item) {
3226
+ const { element, moved, style } = item.state;
3227
+ const { x, y } = globals.original ?? {
3228
+ x: 0,
3229
+ y: 0
3230
+ };
3231
+ if (moved) setStyle(element, "inset", `${y}px auto auto ${x}px`);
3232
+ else setStyles(element, style);
3233
+ element.removeAttribute(ATTRIBUTE_MOVING);
3234
+ }
3235
+ function onEnd$2(event, globals, item, reset) {
3236
+ const movable = item.instance;
3237
+ const state = item.state;
3238
+ state.element.removeAttribute(ATTRIBUTE_MOVING);
3239
+ if (!state.moved) {
3240
+ state.moved = true;
3241
+ if (state.container != null) MOVED.add(movable);
3242
+ }
3243
+ const container = state.container?.getBoundingClientRect();
3244
+ if (container != null) setOffset(state, container);
3245
+ const dispatched = dispatch(state.element, "movable:end", { detail: {
3246
+ from: { ...globals.original },
3247
+ to: getPosition$1(event)
3248
+ } });
3249
+ setTimeout(() => {
3250
+ if (dispatched.defaultPrevented) onCancel$1(globals, item);
3251
+ reset();
3252
+ });
3253
+ }
3254
+ function onMove$1(_, globals, __, position) {
3255
+ setAttribute(globals.element?.node, ATTRIBUTE_MOVING, "");
3256
+ return {
3257
+ from: { ...globals.original },
3258
+ to: { ...position.calculated }
3259
+ };
3260
+ }
3261
+ function onResize(entries) {
3262
+ const { length } = entries;
3263
+ for (let index = 0; index < length; index += 1) {
3264
+ const entry = entries[index];
3265
+ const set = CONTAINERS$1.get(entry.target);
3266
+ if (set == null) continue;
3267
+ for (const movable of set) reposition(movable);
3268
+ }
3269
+ }
3270
+ function onScroll() {
3271
+ for (const moved of MOVED) reposition(moved);
3272
+ }
3273
+ function reposition(movable) {
3274
+ const state = getDraggableStates(movable.element)?.movable;
3275
+ if (state == null || !state.moved || state.container == null) return;
3276
+ const container = state.container.getBoundingClientRect();
3277
+ const x = container.left + (state.offset?.x ?? 0);
3278
+ const y = container.top + (state.offset?.y ?? 0);
3279
+ setStyle(state.element, "inset", `${y}px auto auto ${x}px`);
3280
+ }
3281
+ function setOffset(state, container) {
3282
+ state.offset = {};
3283
+ const element = state.element.getBoundingClientRect();
3284
+ state.offset.y = element.top - container.top;
3285
+ state.offset.x = element.left - container.left;
3286
+ }
3287
+ const ATTRIBUTE_MOVABLE = "oui-movable";
3288
+ const ATTRIBUTE_CONTAINER$2 = `${ATTRIBUTE_MOVABLE}-container`;
3289
+ const ATTRIBUTE_DIRECTION$1 = `${ATTRIBUTE_MOVABLE}-direction`;
3290
+ const ATTRIBUTE_MOVABLE_HANDLE = `${ATTRIBUTE_MOVABLE}-handle`;
3291
+ const ATTRIBUTE_MOVING = `${ATTRIBUTE_MOVABLE}-moving`;
3292
+ const CONTAINERS$1 = /* @__PURE__ */ new Map();
3293
+ const MESSAGE$4 = "The element must be an instance of HTMLElement or SVGElement";
3294
+ const MOVED = /* @__PURE__ */ new Set();
3295
+ const SELECTOR_HANDLE$2 = `[${ATTRIBUTE_MOVABLE_HANDLE}]`;
3296
+ const bound$1 = {
3297
+ constructor: OuiMovable,
3298
+ property: "movable"
3299
+ };
3300
+ const resizer = new ResizeObserver(onResize);
3301
+ const addMovable = addDraggable.bind(bound$1);
3302
+ const removeMovable = removeDraggable.bind(bound$1);
3303
+ on(document, "scroll", onScroll);
3304
+ attributable(ATTRIBUTE_MOVABLE, addMovable, removeMovable);
3305
+ //#endregion
3306
+ //#region src/js/resizable/resizable.embedded.ts
3307
+ var OuiResizable = class {
3308
+ #state;
3309
+ constructor(state) {
3310
+ this.#state = state;
3311
+ }
3312
+ destroy() {
3313
+ destroyResizable(this.#state);
3314
+ }
3315
+ set() {
3316
+ const [width, height] = getAndSetDimensions(this.#state.element, this.#state.options);
3317
+ this.#state.width = width;
3318
+ this.#state.height = height;
3319
+ }
3320
+ reset() {
3321
+ setStyles(this.#state.element, {
3322
+ height: "",
3323
+ width: ""
3324
+ });
3325
+ }
3326
+ };
3327
+ function addResizable(element, options) {
3328
+ let item = items.get(element);
3329
+ if (item == null) {
3330
+ const handle = element.querySelector(SELECTOR_HANDLE_SCOPED);
3331
+ if (!isHTMLOrSVGElement(handle)) return;
3332
+ const state = getState$4(element, handle, options);
3333
+ item = {
3334
+ instance: new OuiResizable(state),
3335
+ state
3336
+ };
3337
+ items.set(element, item);
3338
+ }
3339
+ return item?.instance;
3340
+ }
3341
+ function cancelResize(item) {
3342
+ if (item == null) return;
3343
+ setStyles(item.state.element, {
3344
+ height: `${item.state.height}px`,
3345
+ width: `${item.state.width}px`
3346
+ });
3347
+ resetResizable();
3348
+ dispatch(item.state.element, "resizable:cancel");
3349
+ }
3350
+ /**
3351
+ * Creates _(or retrieves)_ a _OuiResizable_ instance for an element
3352
+ *
3353
+ * @param element Element to make resizable
3354
+ * @returns _OuiResizable_ instance
3355
+ */
3356
+ function createResizable(element, options) {
3357
+ if (!isHTMLOrSVGElement(element)) throw new TypeError(MESSAGE_ELEMENT);
3358
+ if (!isHTMLOrSVGElement(element.querySelector(SELECTOR_HANDLE_SCOPED))) throw new Error(MESSAGE_HANDLE);
3359
+ return addResizable(element, options ?? {});
3360
+ }
3361
+ function destroyResizable(state) {
3362
+ state.element = void 0;
3363
+ state.handle = void 0;
3364
+ }
3365
+ function getAndSetDimensions(element, options, input) {
3366
+ let { height, width } = input ?? element.getBoundingClientRect();
3367
+ if (options.maximumWidth > -1 && width > options.maximumWidth) width = options.maximumWidth;
3368
+ else if (options.minimumWidth > -1 && width < options.minimumWidth) width = options.minimumWidth;
3369
+ if (options.maximumHeight > -1 && height > options.maximumHeight) height = options.maximumHeight;
3370
+ else if (options.minimumHeight > -1 && height < options.minimumHeight) height = options.minimumHeight;
3371
+ if (element.checkVisibility()) setStyles(element, {
3372
+ height: `${height}px`,
3373
+ width: `${width}px`
3374
+ });
3375
+ return [width, height];
3376
+ }
3377
+ function getProperties(element, widthProperty, heightProperty) {
3378
+ const computed = getComputedStyle(element);
3379
+ return [computed[widthProperty], computed[heightProperty]];
3380
+ }
3381
+ function getRestrictions(maximum, minimum) {
3382
+ const [maximumWidth, maximumHeight] = getXAndY.apply(null, typeof maximum === "string" ? [maximum] : maximum);
3383
+ const [minimumWidth, minimumHeight] = getXAndY.apply(null, typeof minimum === "string" ? [minimum] : minimum);
3384
+ if (maximumWidth > -1 && minimumWidth > -1 && maximumWidth <= minimumWidth) throw new Error(MESSAGE_WIDTH);
3385
+ if (maximumHeight > -1 && minimumHeight > -1 && maximumHeight <= minimumHeight) throw new Error(MESSAGE_HEIGHT);
3386
+ return {
3387
+ maximumHeight,
3388
+ maximumWidth,
3389
+ minimumHeight,
3390
+ minimumWidth
3391
+ };
3392
+ }
3393
+ function getState$4(element, handle, input) {
3394
+ setAttribute(element, RESIZABLE_ATTRIBUTE, "");
3395
+ const options = getValidOptions(element, input);
3396
+ const [width, height] = getAndSetDimensions(element, options);
3397
+ return {
3398
+ element,
3399
+ handle,
3400
+ height,
3401
+ options,
3402
+ width,
3403
+ styles: toggleStyles(element, styles)
3404
+ };
3405
+ }
3406
+ function getValidOptions(element, input) {
3407
+ const original = isPlainObject(input) ? input : {};
3408
+ return { ...getRestrictions(input == null ? getAttribute(element, ATTRIBUTE_MAXIMUM) ?? getProperties(element, "maxWidth", "maxHeight") : [original.maximumWidth, original.maximumHeight], input == null ? getAttribute(element, ATTRIBUTE_MINIMUM) ?? getProperties(element, "minWidth", "minHeight") : [original.minimumWidth, original.minimumHeight]) };
3409
+ }
3410
+ function getXAndY(first, second) {
3411
+ const [x, y] = typeof first === "string" && second == null ? first.split(",") : [first, second];
3412
+ let xAsNumber = typeof x === "string" ? Number.parseFloat(x) : getNumber(x);
3413
+ let yAsNumber = typeof y === "string" ? Number.parseFloat(y) : getNumber(y);
3414
+ if (Number.isNaN(xAsNumber) || xAsNumber <= 0) xAsNumber = -1;
3415
+ if (Number.isNaN(yAsNumber) || yAsNumber <= 0) yAsNumber = -1;
3416
+ return [xAsNumber, yAsNumber];
3417
+ }
3418
+ function onKeydown$2(event) {
3419
+ if (current != null && event.key === "Escape") cancelResize(current);
3420
+ }
3421
+ function onPointerdown$3(event) {
3422
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || (supportsTouch.value ? event.type === "mousedown" : event.type === "touchstart" || event.button !== 0)) return;
3423
+ const handle = findAncestor(event, SELECTOR_HANDLE$1);
3424
+ const element = handle && findAncestor(handle, SELECTOR$3);
3425
+ const stored = element && items.get(element);
3426
+ const position = getPosition$1(event);
3427
+ if (stored == null || position == null) return;
3428
+ if (supportsTouch.value) event.preventDefault();
3429
+ const dispatched = dispatch(element, "resizable:begin");
3430
+ setTimeout(() => {
3431
+ if (dispatched.defaultPrevented) return;
3432
+ current = stored;
3433
+ start = position;
3434
+ current.state.styles.set();
3435
+ styleToggler.set();
3436
+ });
3437
+ }
3438
+ function onPointermove$2(event) {
3439
+ if (current == null) return;
3440
+ const { x, y } = getPosition$1(event) ?? {};
3441
+ if (x == null || y == null) return;
3442
+ const width = current.state.width + (x - (start?.x ?? 0));
3443
+ const height = current.state.height + (y - (start?.y ?? 0));
3444
+ getAndSetDimensions(current.state.element, current.state.options, {
3445
+ height,
3446
+ width
3447
+ });
3448
+ const dispatched = dispatch(current.state.element, "resizable:resize", { detail: {
3449
+ height,
3450
+ width
3451
+ } });
3452
+ setTimeout(() => {
3453
+ if (dispatched.defaultPrevented) cancelResize(current);
3454
+ });
3455
+ }
3456
+ function onPointerup$1() {
3457
+ if (current == null) return;
3458
+ const dispatched = dispatch(current.state.element, "resizable:end");
3459
+ setTimeout(() => {
3460
+ if (current == null || dispatched.defaultPrevented) {
3461
+ cancelResize(current);
3462
+ return;
3463
+ }
3464
+ const { height, width } = current.state.element.getBoundingClientRect();
3465
+ current.state.height = height;
3466
+ current.state.width = width;
3467
+ resetResizable();
3468
+ });
3469
+ }
3470
+ function removeResizable(element) {
3471
+ items.get(element)?.instance.destroy();
3472
+ items.delete(element);
3473
+ }
3474
+ function resetResizable() {
3475
+ current?.state.styles.remove();
3476
+ styleToggler.remove();
3477
+ current = void 0;
3478
+ start = void 0;
3479
+ }
3480
+ const RESIZABLE_ATTRIBUTE = "oui-resizable";
3481
+ const RESIZABLE_ATTRIBUTE_HANDLE = `${RESIZABLE_ATTRIBUTE}-handle`;
3482
+ const ATTRIBUTE_MAXIMUM = `${RESIZABLE_ATTRIBUTE}-maximum`;
3483
+ const ATTRIBUTE_MINIMUM = `${RESIZABLE_ATTRIBUTE}-minimum`;
3484
+ const MESSAGE_ELEMENT = "The element must be an instance of HTMLElement or SVGElement";
3485
+ const MESSAGE_HEIGHT = "The maximum height must be greater than the minimum height";
3486
+ const MESSAGE_HANDLE = `The element must contain a child with the attribute "${RESIZABLE_ATTRIBUTE_HANDLE}"`;
3487
+ const MESSAGE_WIDTH = "The maximum width must be greater than the minimum width";
3488
+ const SELECTOR$3 = `[${RESIZABLE_ATTRIBUTE}]`;
3489
+ const SELECTOR_HANDLE$1 = `[${RESIZABLE_ATTRIBUTE_HANDLE}]`;
3490
+ const SELECTOR_HANDLE_SCOPED = `:scope > ${SELECTOR_HANDLE$1}`;
3491
+ const items = /* @__PURE__ */ new WeakMap();
3492
+ const styles = {
3493
+ touchAction: "none",
3494
+ userSelect: "none",
3495
+ webkitUserSelect: "none"
3496
+ };
3497
+ const styleToggler = toggleStyles(document.body, styles);
3498
+ let current;
3499
+ let start;
3500
+ on(document, "keydown", onKeydown$2);
3501
+ on(document, "mousedown", onPointerdown$3);
3502
+ on(document, "pointermove", onPointermove$2);
3503
+ on(document, "pointerup", onPointerup$1);
3504
+ on(document, "touchcancel", onPointerup$1);
3505
+ on(document, "touchstart", onPointerdown$3, { passive: false });
3506
+ attributable(RESIZABLE_ATTRIBUTE, addResizable, removeResizable);
3507
+ //#endregion
3508
+ //#region src/js/dialog.ts
3509
+ var OuiDialog = class {
3510
+ #state;
3511
+ /**
3512
+ * Is the dialog open?
3513
+ */
3514
+ get open() {
3515
+ return this.#state.element.open;
3516
+ }
3517
+ /**
3518
+ * Open or close the dialog
3519
+ */
3520
+ set open(value) {
3521
+ if (value === true) this.show();
3522
+ else if (value === false) this.hide();
3523
+ }
3524
+ constructor(state) {
3525
+ this.#state = state;
3526
+ }
3527
+ hide(first, second) {
3528
+ if (!this.#state.element.open) return;
3529
+ if (first === true) this.#state.element.requestClose(typeof second === "string" ? second : void 0);
3530
+ else this.#state.element.close(typeof first === "string" ? first : void 0);
3531
+ }
3532
+ /**
3533
+ * Opens the dialog
3534
+ */
3535
+ show(modal) {
3536
+ const { element } = this.#state;
3537
+ if (element == null || element.open) return;
3538
+ const isModal = modal !== false;
3539
+ setAria(element, "modal", isModal);
3540
+ if (isModal) element.showModal();
3541
+ else element.show();
3542
+ }
3543
+ };
3544
+ function addDialog(element) {
3545
+ if (!(element instanceof HTMLDialogElement)) throw new TypeError(MESSAGE$3);
3546
+ if (!states$3.has(element)) states$3.set(element, getState$3(element));
3547
+ }
3548
+ function destroyDialog(state) {
3549
+ state.element.close();
3550
+ setAria(state.element, "modal", state.modal);
3551
+ state.element.removeAttribute(ATTRIBUTE_OPEN$1);
3552
+ for (const listener of state.listeners) listener();
3553
+ state.movable?.destroy();
3554
+ state.resizable?.destroy();
3555
+ state.dialog = void 0;
3556
+ state.element = void 0;
3557
+ state.listeners = void 0;
3558
+ state.movable = void 0;
3559
+ state.resizable = void 0;
3560
+ }
3561
+ /**
3562
+ * Get the _OuiDialog_ for an element
3563
+ *
3564
+ * @param element Element to get _OuiDialog_ for
3565
+ * @returns _OuiDialog_ instance
3566
+ */
3567
+ function getDialog(element) {
3568
+ return states$3.get(element)?.dialog;
3569
+ }
3570
+ function getMovable(element) {
3571
+ const handles = element.querySelectorAll(SELECTOR_MOVER);
3572
+ if (handles.length === 0) return;
3573
+ for (const handle of handles) setAttribute(handle, ATTRIBUTE_MOVABLE_HANDLE, "");
3574
+ return createMovable(element, { container: getAttribute(element, ATTRIBUTE_CONTAINER$1) });
3575
+ }
3576
+ function getResizable(element) {
3577
+ const handle = element.querySelector(SELECTOR_RESIZER);
3578
+ if (handle == null) return;
3579
+ setAttribute(handle, RESIZABLE_ATTRIBUTE_HANDLE, "");
3580
+ return createResizable(element);
3581
+ }
3582
+ function getState$3(element) {
3583
+ const state = {
3584
+ element,
3585
+ dialog: void 0,
3586
+ listeners: [getOnBeforeToggleListener(element), on(element, "toggle", (event) => {
3587
+ const { source } = event;
3588
+ if (element.open) {
3589
+ setAria(element, "modal", source instanceof HTMLButtonElement && source.command === "show-modal" || element.matches(":modal"));
3590
+ setAttribute(element, ATTRIBUTE_OPEN$1, "");
3591
+ element.focus();
3592
+ setTimeout(() => {
3593
+ state.resizable?.set();
3594
+ }, 500);
3595
+ } else {
3596
+ setAttribute(element, ATTRIBUTE_OPEN$1);
3597
+ setAria(element, "modal", state.modal);
3598
+ setStyles(element, {
3599
+ inset: "",
3600
+ position: "",
3601
+ transform: ""
3602
+ });
3603
+ state.resizable?.reset();
3604
+ }
3605
+ })],
3606
+ modal: getAria(element, "modal") === "true" || element.matches(":modal")
3607
+ };
3608
+ state.dialog = new OuiDialog(state);
3609
+ state.movable = getMovable(element);
3610
+ state.resizable = getResizable(element);
3611
+ return state;
3612
+ }
3613
+ function removeDialog(element) {
3614
+ const state = states$3.get(element);
3615
+ if (state == null) return;
3616
+ destroyDialog(state);
3617
+ states$3.delete(element);
3618
+ }
3619
+ const ATTRIBUTE$3 = "oui-dialog";
3620
+ const ATTRIBUTE_CONTAINER$1 = `${ATTRIBUTE$3}-container`;
3621
+ const ATTRIBUTE_OPEN$1 = `${ATTRIBUTE$3}-open`;
3622
+ const MESSAGE$3 = "The element must be an instance of HTMLDialogElement";
3623
+ const SELECTOR_MOVER = `[${ATTRIBUTE$3}-mover]`;
3624
+ const SELECTOR_RESIZER = `[${ATTRIBUTE$3}-resizer]`;
3625
+ const states$3 = /* @__PURE__ */ new WeakMap();
3626
+ attributable(ATTRIBUTE$3, addDialog, removeDialog);
3627
+ //#endregion
3628
+ //#region node_modules/@oscarpalmer/toretto/dist/focusable.mjs
3629
+ /**
3630
+ * Get a list of focusable elements within a parent element
3631
+ *
3632
+ * @param parent Parent element
3633
+ * @returns Focusable elements
3634
+ */
3635
+ function getFocusable(parent) {
3636
+ return getValidElements(parent, FILTERS_FOCUSABLE, false);
3637
+ }
3638
+ function getItem(element, tabbable) {
3639
+ return {
3640
+ element,
3641
+ tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
3642
+ };
3643
+ }
3644
+ function getTabIndex(element) {
3645
+ const tabIndex = element?.tabIndex ?? TABINDEX_DEFAULT;
3646
+ if (tabIndex < TABINDEX_BASE && (EXPRESSION_SPECIAL_TABINDEX.test(element.tagName) || isEditable(element)) && !hasTabIndex(element)) return TABINDEX_BASE;
3647
+ return tabIndex;
3648
+ }
3649
+ function getValidElements(parent, filters, tabbable) {
3650
+ if (!(parent instanceof Element)) return [];
3651
+ const elements = [...parent.querySelectorAll(SELECTOR_FULL)];
3652
+ const items = [];
3653
+ let { length } = elements;
3654
+ for (let index = 0; index < length; index += 1) {
3655
+ const item = getItem(elements[index], tabbable);
3656
+ if (!filters.some((filter) => filter(item))) items.push(item);
3657
+ }
3658
+ if (!tabbable) return items.map((item) => item.element);
3659
+ const indiced = [];
3660
+ const zeroed = [];
3661
+ length = items.length;
3662
+ for (let index = 0; index < length; index += 1) {
3663
+ const item = items[index];
3664
+ if (item.tabIndex === TABINDEX_BASE) zeroed.push(item.element);
3665
+ else indiced[item.tabIndex] = [...indiced[item.tabIndex] ?? [], item.element];
3666
+ }
3667
+ return [...indiced.flat(), ...zeroed];
3668
+ }
3669
+ function hasTabIndex(element) {
3670
+ return !Number.isNaN(Number.parseInt(element.getAttribute(ATTRIBUTE_TABINDEX), 10));
3671
+ }
3672
+ function isDisabled(item) {
3673
+ if (EXPRESSION_DISABLEABLE.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
3674
+ return item.element.disabled ?? false;
3675
+ }
3676
+ function isDisabledFromFieldset(element) {
3677
+ let parent = element.parentElement;
3678
+ while (parent != null) {
3679
+ if (parent instanceof HTMLFieldSetElement && parent.disabled) {
3680
+ const children = Array.from(parent.children);
3681
+ const { length } = children;
3682
+ for (let index = 0; index < length; index += 1) {
3683
+ const child = children[index];
3684
+ if (child instanceof HTMLLegendElement) return parent.matches(SELECTOR_FIELDSET_DISABLED) || !child.contains(element);
3685
+ }
3686
+ return true;
3687
+ }
3688
+ parent = parent.parentElement;
3689
+ }
3690
+ return false;
3691
+ }
3692
+ function isEditable(element) {
3693
+ return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
3694
+ }
3695
+ function isHidden(item) {
3696
+ if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === STYLE_HIDDEN) return true;
3697
+ if ((item.element.matches(SELECTOR_SUMMARY_FIRST) ? item.element.parentElement : item.element)?.matches(SELECTOR_DETAILS_CLOSED_CHILDREN) ?? false) return true;
3698
+ const style = getComputedStyle(item.element);
3699
+ if (style.display === STYLE_NONE || style.visibility === STYLE_HIDDEN) return true;
3700
+ const { height, width } = item.element.getBoundingClientRect();
3701
+ return height === 0 && width === 0;
3702
+ }
3703
+ function isInert(item) {
3704
+ return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
3705
+ element: item.element.parentElement,
3706
+ tabIndex: TABINDEX_DEFAULT
3707
+ });
3708
+ }
3709
+ function isSummarised(item) {
3710
+ return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
3711
+ }
3712
+ const ATTRIBUTE_CONTENTEDITABLE = "contenteditable";
3713
+ const ATTRIBUTE_INERT = "inert";
3714
+ const ATTRIBUTE_TABINDEX = "tabindex";
3715
+ const EXPRESSION_DISABLEABLE = /^(button|input|select|textarea)$/i;
3716
+ const EXPRESSION_SPECIAL_TABINDEX = /^(audio|details|video)$/i;
3717
+ const EXPRESSION_SUMMARY = /^summary$/i;
3718
+ const EXPRESSION_TRUEISH = /^(|true)$/i;
3719
+ const FILTERS_FOCUSABLE = [
3720
+ isDisabled,
3721
+ isInert,
3722
+ isHidden,
3723
+ isSummarised
3724
+ ];
3725
+ [...FILTERS_FOCUSABLE];
3726
+ const SELECTOR_DETAILS_CLOSED_CHILDREN = "details:not([open]) *";
3727
+ const SELECTOR_FIELDSET_DISABLED = "fieldset[disabled] *";
3728
+ const SELECTOR_SUMMARY_FIRST = "details > summary:first-of-type";
3729
+ const SELECTOR_FULL = [
3730
+ "[contenteditable]:not([contenteditable=\"false\"])",
3731
+ "[tabindex]:not(slot)",
3732
+ "a[href]",
3733
+ "audio[controls]",
3734
+ "button",
3735
+ "details",
3736
+ SELECTOR_SUMMARY_FIRST,
3737
+ "input",
3738
+ "select",
3739
+ "textarea",
3740
+ "video[controls]"
3741
+ ].map((selector) => `${selector}:not([inert])`).join(",");
3742
+ const STYLE_HIDDEN = "hidden";
3743
+ const STYLE_NONE = "none";
3744
+ const TABINDEX_BASE = 0;
3745
+ const TABINDEX_DEFAULT = -1;
3746
+ //#endregion
3747
+ //#region src/js/focus-trap/focus-trap.embedded.ts
3748
+ var OuiFocusTrap = class {
3749
+ #destroyed = false;
3750
+ #tabIndex;
3751
+ #state;
3752
+ /**
3753
+ * Is focused maintained within the _focus trap_ when clicking outside of it?
3754
+ */
3755
+ get contain() {
3756
+ return this.#state.element.hasAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
3757
+ }
3758
+ /**
3759
+ * Should focus be maintained within the _focus trap_ when clicking outside of it?
3760
+ */
3761
+ set contain(value) {
3762
+ if (value === true) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_CONTAIN, "");
3763
+ else if (value === false) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_CONTAIN, void 0);
3764
+ }
3765
+ /**
3766
+ * Is the _focus trap_ disabled?
3767
+ */
3768
+ get disabled() {
3769
+ return this.#state.disabled;
3770
+ }
3771
+ /**
3772
+ * Should the _focus trap_ be disabled?
3773
+ */
3774
+ set disabled(value) {
3775
+ if (value === true) this.disable();
3776
+ else if (value === false) this.enable();
3777
+ }
3778
+ /**
3779
+ * Is focus allowed to escape when pressing _Escape_ within the _focus trap_?
3780
+ */
3781
+ get noescape() {
3782
+ return this.#state.element.hasAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
3783
+ }
3784
+ /**
3785
+ * Should the _focus trap_ allow focus to escape when pressing _Escape_?
3786
+ */
3787
+ set noescape(value) {
3788
+ if (value === true) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_NOESCAPE, "");
3789
+ else if (value === false) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_NOESCAPE, void 0);
3790
+ }
3791
+ constructor(state) {
3792
+ this.#state = state;
3793
+ this.#tabIndex = state.element.tabIndex;
3794
+ state.element.tabIndex = -1;
3795
+ setAttribute(state.element, ATTRIBUTE_FOCUSTRAP, "");
3796
+ this.contain = state.options.contain;
3797
+ this.noescape = state.options.noescape;
3798
+ states$2.set(this, state);
3799
+ }
3800
+ /**
3801
+ * Destroys the _focus trap_
3802
+ */
3803
+ destroy() {
3804
+ if (this.#destroyed) return;
3805
+ this.#destroyed = true;
3806
+ disabled.delete(this);
3807
+ instances.delete(this.#state.element);
3808
+ states$2.delete(this);
3809
+ this.#state.element.tabIndex = this.#tabIndex;
3810
+ this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP);
3811
+ this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
3812
+ this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
3813
+ this.#state.element = void 0;
3814
+ }
3815
+ /**
3816
+ * Disables the _focus trap_
3817
+ */
3818
+ disable() {
3819
+ if (!this.#destroyed && !(this.disabled || this.#state.options.noescape)) setDisabled(this, this.#state, true);
3820
+ }
3821
+ /**
3822
+ * Enables the _focus trap_
3823
+ */
3824
+ enable() {
3825
+ if (!this.#destroyed && this.disabled) setDisabled(this, this.#state, false);
3826
+ }
3827
+ /**
3828
+ * Focuses the _focus trap_
3829
+ *
3830
+ * @param last When `true`, focuses the last focusable element within the _focus trap_ instead of the first
3831
+ */
3832
+ focus(last) {
3833
+ if (!this.#destroyed && !this.disabled) tabToTrap(this, getFocusable(this.#state.element), this.#state.element, last ? -1 : 0);
3834
+ }
3835
+ };
3836
+ /**
3837
+ * Creates _(or retrieves)_ a _focus trap_ for an element
3838
+ *
3839
+ * @param element Element to trap focus within
3840
+ * @param options _Focus trap_ options
3841
+ * @returns _Focus trap_ instance
3842
+ */
3843
+ function createFocusTrap(element, options) {
3844
+ if (!isHTMLOrSVGElement(element)) throw new TypeError(MESSAGE$2);
3845
+ let instance = instances.get(element);
3846
+ if (instance == null) {
3847
+ instance = new OuiFocusTrap(getState$2(element, options));
3848
+ instances.set(element, instance);
3849
+ }
3850
+ return instance;
3851
+ }
3852
+ function getOptions(element, input) {
3853
+ const options = isPlainObject(input) ? input : {};
3854
+ return {
3855
+ contain: typeof options.contain === "boolean" ? options.contain : element.hasAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN),
3856
+ noescape: typeof options.noescape === "boolean" ? options.noescape : element.hasAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE)
3857
+ };
3858
+ }
3859
+ function getState$2(element, options) {
3860
+ return {
3861
+ element,
3862
+ disabled: false,
3863
+ options: getOptions(element, options)
3864
+ };
3865
+ }
3866
+ function onEscape(event) {
3867
+ let element = findAncestor(event, SELECTOR$2);
3868
+ let instance = instances.get(element);
3869
+ let state = states$2.get(instance);
3870
+ if (element == null || instance == null || state == null) return;
3871
+ while (state.disabled) {
3872
+ element = findAncestor(state.element.parentElement, SELECTOR$2);
3873
+ instance = instances.get(element);
3874
+ state = states$2.get(instance);
3875
+ if (element == null || instance == null || state == null) return;
3876
+ if (!state.disabled) break;
3877
+ }
3878
+ instance?.disable();
3879
+ }
3880
+ function onFocusIn(event) {
3881
+ lastTarget = instances.get(findAncestor(event, SELECTOR$2)) == null ? void 0 : event.target;
3882
+ }
3883
+ function onKeydown$1(event) {
3884
+ switch (event.key) {
3885
+ case "Escape":
3886
+ onEscape(event);
3887
+ break;
3888
+ case "Tab":
3889
+ onTab(event);
3890
+ break;
3891
+ default: return;
3892
+ }
3893
+ }
3894
+ function onPointerdown$2(event) {
3895
+ const last = findAncestor(lastTarget, SELECTOR$2);
3896
+ const next = findAncestor(event, SELECTOR$2);
3897
+ if (last != null && next !== last) {
3898
+ if (states$2.get(instances.get(last))?.options.contain ?? false) {
3899
+ event.preventDefault();
3900
+ lastTarget?.focus();
3901
+ }
3902
+ }
3903
+ if (disabled.size === 0) return;
3904
+ for (const focusTrap of disabled) {
3905
+ const state = states$2.get(focusTrap);
3906
+ if (state != null && state.element !== next) focusTrap.enable();
3907
+ }
3908
+ }
3909
+ function onTab(event) {
3910
+ const element = findAncestor(event, SELECTOR$2);
3911
+ const instance = instances.get(element);
3912
+ if (instance == null) return;
3913
+ const dispatched = dispatch(element, "focus-trap");
3914
+ setTimeout(() => {
3915
+ if (dispatched.defaultPrevented) return;
3916
+ if (!instance.disabled) event.preventDefault();
3917
+ const elements = getFocusable(element);
3918
+ const index = elements.indexOf(event.target);
3919
+ if (index === -1 || elements.length === 0) tabToTrap(instance, elements, element);
3920
+ else tabToElement(instance, elements, index, event.shiftKey ? -1 : 1);
3921
+ });
3922
+ }
3923
+ function removeFocusTrap(element) {
3924
+ instances.get(element)?.destroy();
3925
+ instances.delete(element);
3926
+ }
3927
+ function setDisabled(focusTrap, state, value) {
3928
+ state.disabled = value;
3929
+ if (value) disabled.add(focusTrap);
3930
+ else disabled.delete(focusTrap);
3931
+ }
3932
+ function tabToElement(instance, elements, index, modifier) {
3933
+ const { length } = elements;
3934
+ const next = clamp(index + modifier, 0, length - 1, true);
3935
+ if (instance.disabled) {
3936
+ if (index === length - 1 && next === 0 || index === 0 && next === length - 1) {
3937
+ lastTarget = void 0;
3938
+ instance.enable();
3939
+ }
3940
+ return;
3941
+ }
3942
+ const element = elements[next];
3943
+ const elementFocusTrap = instances.get(element);
3944
+ if (elementFocusTrap != null) elementFocusTrap.focus(modifier === -1);
3945
+ else {
3946
+ elements[next].focus();
3947
+ lastTarget = elements[next];
3948
+ }
3949
+ }
3950
+ function tabToTrap(instance, elements, element, index) {
3951
+ if (instance.disabled) {
3952
+ lastTarget = void 0;
3953
+ instance.enable();
3954
+ } else {
3955
+ const next = elements.length === 0 ? element : elements.at(index ?? 0);
3956
+ next.focus();
3957
+ lastTarget = next;
3958
+ }
3959
+ }
3960
+ const ATTRIBUTE_FOCUSTRAP = "oui-focus-trap";
3961
+ const ATTRIBUTE_FOCUSTRAP_CONTAIN = `${ATTRIBUTE_FOCUSTRAP}-contain`;
3962
+ const ATTRIBUTE_FOCUSTRAP_NOESCAPE = `${ATTRIBUTE_FOCUSTRAP}-noescape`;
3963
+ const EVENT_OPTIONS = {
3964
+ capture: true,
3965
+ passive: false
3966
+ };
3967
+ const MESSAGE$2 = "Element must be an HTMLElement or SVGElement";
3968
+ const SELECTOR$2 = `[${ATTRIBUTE_FOCUSTRAP}]`;
3969
+ const disabled = /* @__PURE__ */ new Set();
3970
+ const instances = /* @__PURE__ */ new WeakMap();
3971
+ const states$2 = /* @__PURE__ */ new WeakMap();
3972
+ let lastTarget;
3973
+ attributable(ATTRIBUTE_FOCUSTRAP, createFocusTrap, removeFocusTrap);
3974
+ on(document, "focusin", onFocusIn, EVENT_OPTIONS);
3975
+ on(document, "keydown", onKeydown$1, EVENT_OPTIONS);
3976
+ on(document, "mousedown", onPointerdown$2, EVENT_OPTIONS);
3977
+ on(document, "touchstart", onPointerdown$2, EVENT_OPTIONS);
3978
+ //#endregion
3979
+ //#region src/js/popover.ts
3980
+ var OuiPopover = class {
3981
+ #state;
3982
+ /**
3983
+ * Is the popover open?
3984
+ */
3985
+ get open() {
3986
+ return this.#state.content.checkVisibility();
3987
+ }
3988
+ set open(value) {
3989
+ if (value === true) this.show();
3990
+ else if (value === false) this.hide();
3991
+ }
3992
+ constructor(state) {
3993
+ this.#state = state;
3994
+ initialize(state);
3995
+ this.#state.floatable.update();
3996
+ }
3997
+ /**
3998
+ * Closes the popover
3999
+ */
4000
+ hide() {
4001
+ this.#state.floatable.hide();
4002
+ }
4003
+ /**
4004
+ * Opens the popover
4005
+ */
4006
+ show() {
4007
+ this.#state.floatable.show();
4008
+ }
4009
+ };
4010
+ function addPopover(element) {
4011
+ if (states$1.has(element) || element.hasAttribute("oui-floatable")) return;
4012
+ const anchor = element.ownerDocument.querySelector(`[popovertarget="${element.id}"]`);
4013
+ if (isHTMLOrSVGElement(anchor)) states$1.set(element, getState$1(anchor, element));
4014
+ }
4015
+ function destroyPopover(state) {
4016
+ state.floatable.destroy();
4017
+ state.focusTrap?.destroy();
4018
+ for (const listener of state.listeners) listener();
4019
+ state.anchor = void 0;
4020
+ state.content = void 0;
4021
+ state.floatable = void 0;
4022
+ state.focusTrap = void 0;
4023
+ state.listeners = void 0;
4024
+ state.popover = void 0;
4025
+ }
4026
+ function getId(element, value) {
4027
+ let { id } = element;
4028
+ if (id == null || id.trim().length === 0) {
4029
+ id = value == null ? `oui_popover_${++index$1}` : `${value}_toggle`;
4030
+ element.id = id;
4031
+ }
4032
+ return id;
4033
+ }
4034
+ /**
4035
+ * Get the _OuiPopover_ for an element
4036
+ *
4037
+ * @param element Element to get _OuiPopover_ for
4038
+ * @returns _OuiPopover_ instance
4039
+ */
4040
+ function getPopover(element) {
4041
+ return states$1.get(element)?.popover;
4042
+ }
4043
+ function getState$1(anchor, content) {
4044
+ const state = {
4045
+ anchor,
4046
+ content,
4047
+ floatable: createEmbeddedFloatable(anchor, content, options$1),
4048
+ focusTrap: getAria(content, "modal") === "true" ? createFocusTrap(content, { noescape: true }) : void 0,
4049
+ listeners: [getOnBeforeToggleListener(content), on(content, "toggle", (event) => {
4050
+ const expanded = event.newState === "open";
4051
+ if (expanded) {
4052
+ ignoreFocus = false;
4053
+ state.floatable?.update();
4054
+ content.focus();
4055
+ } else if (!ignoreFocus) anchor?.focus();
4056
+ setAria(anchor, "expanded", expanded);
4057
+ setAttribute(content, ATTRIBUTE_OPEN, expanded ? "" : void 0);
4058
+ })],
4059
+ popover: void 0
4060
+ };
4061
+ state.popover = new OuiPopover(state);
4062
+ return state;
4063
+ }
4064
+ function initialize(state) {
4065
+ const id = getId(state.content);
4066
+ setAria(state.anchor, {
4067
+ controls: id,
4068
+ expanded: "false"
4069
+ });
4070
+ if ((getAria(state.content, "label") ?? getAria(state.content, "labelledby")) == null) setAria(state.content, "labelledby", getId(state.anchor, id));
4071
+ }
4072
+ function onPointerdown$1() {
4073
+ ignoreFocus = true;
4074
+ }
4075
+ function removePopover(element) {
4076
+ const state = states$1.get(element);
4077
+ if (state == null) return;
4078
+ destroyPopover(state);
4079
+ states$1.delete(element);
4080
+ }
4081
+ const ATTRIBUTE$2 = "oui-popover";
4082
+ const ATTRIBUTE_OPEN = `${ATTRIBUTE$2}-open`;
4083
+ const options$1 = {
4084
+ attribute: `${ATTRIBUTE$2}-position`,
4085
+ position: "below-start",
4086
+ reusable: false
4087
+ };
4088
+ const states$1 = /* @__PURE__ */ new WeakMap();
4089
+ let ignoreFocus = false;
4090
+ let index$1 = 0;
4091
+ on(document, "pointerdown", onPointerdown$1, { capture: true });
4092
+ attributable(ATTRIBUTE$2, addPopover, removePopover);
4093
+ //#endregion
4094
+ //#region src/js/sortable/sortable.embedded.ts
4095
+ var OuiSortable = class extends OuiDraggable {
4096
+ constructor(element, options) {
4097
+ super("sortable", "sort", ATTRIBUTE$1, element, {
4098
+ container: {
4099
+ attribute: ATTRIBUTE_CONTAINER,
4100
+ map: CONTAINERS
4101
+ },
4102
+ direction: { attribute: ATTRIBUTE_DIRECTION },
4103
+ drag: {
4104
+ onBegin,
4105
+ onCancel,
4106
+ onEnd: onEnd$1,
4107
+ onMove
4108
+ },
4109
+ input: options,
4110
+ position: {
4111
+ getOffset: getOffsetPosition,
4112
+ getOriginal: getOriginalPosition
4113
+ },
4114
+ getDragged: getDragPlaceholder,
4115
+ getOrigin: () => (getDraggableStates(element)?.sortable)?.origin
4116
+ }, { connections: getAttribute(element, ATTRIBUTE_CONNECTIONS) });
4117
+ }
4118
+ };
4119
+ function afterEnd(insert, from, events, elements, position, valid) {
4120
+ elements.origin?.removeAttribute(ATTRIBUTE_ORIGIN);
4121
+ from.state.origin = void 0;
4122
+ resetPlaceholders();
4123
+ if (!valid || events.some((event) => event?.defaultPrevented)) return;
4124
+ if (insert !== "insert") {
4125
+ elements.target.append(elements.origin);
4126
+ return;
4127
+ }
4128
+ if (position == null) return;
4129
+ const { height, top } = elements.target.getBoundingClientRect();
4130
+ let insertion;
4131
+ if (position.y < top + height / 2) insertion = "beforebegin";
4132
+ else insertion = "afterend";
4133
+ elements.target?.insertAdjacentElement(insertion, elements.origin);
4134
+ document.body.removeAttribute(ATTRIBUTE_ACTIVE$1);
4135
+ }
4136
+ /**
4137
+ * Creates _(or retrieves)_ a _OuiSortable_ instance for an element
4138
+ *
4139
+ * @param element Element to make sortable
4140
+ * @returns _OuiSortable_ instance
4141
+ */
4142
+ function createSortable(element, options) {
4143
+ if (!isHTMLOrSVGElement(element)) throw new TypeError(MESSAGE$1);
4144
+ return addSortable(element, options);
4145
+ }
4146
+ function getDragPlaceholder() {
4147
+ placeholder.drag.default ??= createElement("div");
4148
+ return placeholder.drag.custom ?? placeholder.drag.default;
4149
+ }
4150
+ function getOffsetPosition(_, item, element, position) {
4151
+ const rectangle = element.getBoundingClientRect();
4152
+ return {
4153
+ x: item.state.horizontal ? 0 : position.x - rectangle.left,
4154
+ y: item.state.vertical ? 0 : position.y - rectangle.top
4155
+ };
4156
+ }
4157
+ function getOriginalPosition(_, __, position) {
4158
+ return position;
4159
+ }
4160
+ function getPositionPlaceholder(item) {
4161
+ placeholder.position ??= createElement("div");
4162
+ setAttribute(placeholder.position, ATTRIBUTE_PLACEHOLDER_POSITION, "");
4163
+ if (item.state.origin != null) setStyle(placeholder.position, "--placeholder-height", `${item.state.origin.getBoundingClientRect().height}px`);
4164
+ return placeholder.position;
4165
+ }
4166
+ function onBegin(_, globals, item, element) {
4167
+ item.state.origin = element;
4168
+ setPlaceholder(globals, item, element);
4169
+ setAttribute(element, ATTRIBUTE_ORIGIN, "");
4170
+ setAttribute(document.body, ATTRIBUTE_ACTIVE$1, "");
4171
+ }
4172
+ function onCancel(_, item) {
4173
+ item.state.origin?.removeAttribute(ATTRIBUTE_ORIGIN);
4174
+ document.body.removeAttribute(ATTRIBUTE_ACTIVE$1);
4175
+ resetPlaceholders();
4176
+ item.state.origin = void 0;
4177
+ }
4178
+ function onEnd$1(event, globals, item, reset) {
4179
+ const { origin } = item.state;
4180
+ const position = getPosition$1(event) ?? {
4181
+ x: 0,
4182
+ y: 0
4183
+ };
4184
+ const target = getElementFromPosition(position)[0];
4185
+ let element = findAncestor(target, SELECTOR_ITEM);
4186
+ if (element?.hasAttribute(ATTRIBUTE_PLACEHOLDER_POSITION)) if (getAttribute(element, ATTRIBUTE_PLACEHOLDER_POSITION) === "after") element = element.previousElementSibling;
4187
+ else element = element.nextElementSibling;
4188
+ let insert = "insert";
4189
+ let toInstance;
4190
+ let toState;
4191
+ if (element == null) {
4192
+ element = findAncestor(target, SELECTOR$1);
4193
+ toInstance = globals.instances.get(element)?.sortable;
4194
+ toState = globals.states.get(element)?.sortable;
4195
+ insert = element == null ? void 0 : element.children.length === 0 ? "append" : "prepend";
4196
+ } else {
4197
+ toInstance = globals.instances.get(element.parentElement)?.sortable;
4198
+ toState = globals.states.get(element.parentElement)?.sortable;
4199
+ }
4200
+ const valid = insert != null && validatePosition(globals, item, {
4201
+ instance: toInstance,
4202
+ state: toState
4203
+ }, position);
4204
+ const options = {
4205
+ detail: valid ? {
4206
+ from: {
4207
+ element: origin,
4208
+ position: { ...globals.original }
4209
+ },
4210
+ to: {
4211
+ element,
4212
+ position: { ...position }
4213
+ }
4214
+ } : void 0,
4215
+ bubbles: false,
4216
+ cancelable: true
4217
+ };
4218
+ const dispatchedFrom = dispatch(item.instance.element, "sortable:end", options);
4219
+ let dispatchedTo;
4220
+ if (item.instance !== toInstance && toInstance != null) dispatchedTo = dispatch(toInstance.element, "sortable:end", options);
4221
+ setTimeout(() => {
4222
+ afterEnd(insert, item, [dispatchedFrom, dispatchedTo], {
4223
+ origin,
4224
+ target: element
4225
+ }, position, valid);
4226
+ reset();
4227
+ });
4228
+ }
4229
+ function onMove(event, globals, item, position) {
4230
+ const fromElement = item.state.origin;
4231
+ const toElement = findAncestor(event, SELECTOR_ITEM);
4232
+ let toInstance;
4233
+ let toState;
4234
+ if (toElement == null) {
4235
+ const element = findAncestor(event, SELECTOR$1);
4236
+ toInstance = globals.instances.get(element)?.sortable;
4237
+ toState = globals.states.get(element)?.sortable;
4238
+ } else {
4239
+ toInstance = globals.instances.get(toElement.parentElement)?.sortable;
4240
+ toState = globals.states.get(toElement.parentElement)?.sortable;
4241
+ }
4242
+ if (toInstance == null || !validatePosition(globals, item, {
4243
+ instance: toInstance,
4244
+ state: toState
4245
+ }, position.original)) return;
4246
+ const placeholder = getPositionPlaceholder(item);
4247
+ if (toElement != null && toElement !== fromElement) {
4248
+ const { height, top } = toElement.getBoundingClientRect();
4249
+ let place;
4250
+ if (position.calculated.y < top + height / 2) {
4251
+ place = "before";
4252
+ toElement.insertAdjacentElement("beforebegin", placeholder);
4253
+ } else {
4254
+ place = "after";
4255
+ toElement.insertAdjacentElement("afterend", placeholder);
4256
+ }
4257
+ setAttribute(placeholder, ATTRIBUTE_PLACEHOLDER_POSITION, place);
4258
+ } else placeholder.remove();
4259
+ return {
4260
+ from: {
4261
+ element: fromElement,
4262
+ position: { ...globals.original }
4263
+ },
4264
+ to: {
4265
+ element: toElement,
4266
+ position: { ...position.calculated }
4267
+ }
4268
+ };
4269
+ }
4270
+ function resetPlaceholders() {
4271
+ placeholder.drag.custom?.remove();
4272
+ placeholder.drag.default?.remove();
4273
+ placeholder.position?.remove();
4274
+ placeholder.drag.custom = void 0;
4275
+ }
4276
+ function setPlaceholder(state, item, origin) {
4277
+ const element = getDragPlaceholder();
4278
+ placeholder.drag.default.innerHTML = "";
4279
+ updatePlaceholder(item, element);
4280
+ const dispatched = dispatch(item.instance.element, "sortable:placeholder", { detail: {
4281
+ origin,
4282
+ parent: item.state.element,
4283
+ placeholder: element,
4284
+ create: (value) => {
4285
+ if (!isHTMLOrSVGElement(value)) return;
4286
+ const element = value;
4287
+ placeholder.drag.custom = element;
4288
+ updatePlaceholder(item, element);
4289
+ state.element = {
4290
+ rectangle: element.getBoundingClientRect(),
4291
+ node: element
4292
+ };
4293
+ }
4294
+ } });
4295
+ setTimeout(() => {
4296
+ if (!dispatched.defaultPrevented && placeholder.drag.custom == null) placeholder.drag.default?.append(element.cloneNode(true));
4297
+ document.body.append(placeholder.drag.custom ?? placeholder.drag.default ?? "");
4298
+ });
4299
+ }
4300
+ function updatePlaceholder(item, element) {
4301
+ setAttribute(element, ATTRIBUTE_PLACEHOLDER_DRAG, "");
4302
+ setStyle(element, "position", "fixed");
4303
+ const state = getDraggableStates(item.state.element)?.sortable;
4304
+ if (state == null) return;
4305
+ setAttributes(element, {
4306
+ [ATTRIBUTE_HORIZONTAL$1]: state.horizontal ? "" : void 0,
4307
+ [ATTRIBUTE_VERTICAL]: state.vertical ? "" : void 0
4308
+ });
4309
+ }
4310
+ function validatePosition(_, from, to, position) {
4311
+ let valid = true;
4312
+ const rectangle = from.state.origin?.getBoundingClientRect();
4313
+ const fromState = getDraggableStates(from.state.element)?.sortable;
4314
+ if (rectangle != null && !(fromState?.horizontal ?? true)) valid = position.x >= rectangle.left && position.x <= rectangle.right;
4315
+ if (valid && rectangle != null && !(fromState?.vertical ?? true)) valid = position.y >= rectangle.top && position.y <= rectangle.bottom;
4316
+ if (valid && from.state.connections != null) valid = to?.state.element.matches(from.state.connections) ?? true;
4317
+ if (valid && to?.state.connections != null) valid = from.state.element.matches(to.state.connections);
4318
+ return valid;
4319
+ }
4320
+ const ATTRIBUTE$1 = "oui-sortable";
4321
+ const ATTRIBUTE_ACTIVE$1 = `${ATTRIBUTE$1}-active`;
4322
+ const ATTRIBUTE_CONNECTIONS = `${ATTRIBUTE$1}-connections`;
4323
+ const ATTRIBUTE_CONTAINER = `${ATTRIBUTE$1}-container`;
4324
+ const ATTRIBUTE_DIRECTION = `${ATTRIBUTE$1}-direction`;
4325
+ const ATTRIBUTE_HORIZONTAL$1 = `${ATTRIBUTE$1}-horizontal`;
4326
+ const ATTRIBUTE_ORIGIN = `${ATTRIBUTE$1}-origin`;
4327
+ const ATTRIBUTE_PLACEHOLDER_DRAG = `${ATTRIBUTE$1}-placeholder-drag`;
4328
+ const ATTRIBUTE_PLACEHOLDER_POSITION = `${ATTRIBUTE$1}-placeholder-position`;
4329
+ const ATTRIBUTE_VERTICAL = `${ATTRIBUTE$1}-vertical`;
4330
+ const CONTAINERS = /* @__PURE__ */ new Map();
4331
+ const MESSAGE$1 = "The element must be an instance of HTMLElement or SVGElement";
4332
+ const SELECTOR$1 = `[${ATTRIBUTE$1}]`;
4333
+ const SELECTOR_ITEM = `[${ATTRIBUTE$1}] > *`;
4334
+ const bound = {
4335
+ constructor: OuiSortable,
4336
+ property: "sortable"
4337
+ };
4338
+ const placeholder = {
4339
+ drag: {
4340
+ custom: void 0,
4341
+ default: void 0
4342
+ },
4343
+ position: void 0
4344
+ };
4345
+ const addSortable = addDraggable.bind(bound);
4346
+ attributable(ATTRIBUTE$1, addSortable, removeDraggable.bind(bound));
4347
+ //#endregion
4348
+ //#region node_modules/@oscarpalmer/atoms/dist/math.mjs
4349
+ /**
4350
+ * Round a number
4351
+ *
4352
+ * @param value Number to round
4353
+ * @param decimals Number of decimal places to round to _(defaults to `0`)_
4354
+ * @returns Rounded number, or `Number.NaN` if the value if unable to be rounded
4355
+ */
4356
+ function round(value, decimals) {
4357
+ return roundNumber(Math.round, value, decimals);
4358
+ }
4359
+ function roundNumber(callback, value, decimals) {
4360
+ if (typeof value !== "number") return NaN;
4361
+ if (typeof decimals !== "number" || decimals < 1) return callback(value);
4362
+ const mod = 10 ** decimals;
4363
+ return callback((value + Number.EPSILON) * mod) / mod;
4364
+ }
4365
+ //#endregion
4366
+ //#region src/js/splitter.ts
4367
+ const ATTRIBUTE_MAX = "max";
4368
+ const ATTRIBUTE_MIN = "min";
4369
+ const ATTRIBUTE_SIZE = "size";
4370
+ const ATTRIBUTE_TYPE = "type";
4371
+ var OuiSplitter = class {
4372
+ element;
4373
+ handle;
4374
+ panels;
4375
+ rectangle;
4376
+ separator;
4377
+ types;
4378
+ values;
4379
+ constructor(element, panels) {
4380
+ this.element = element;
4381
+ this.panels = panels;
4382
+ if (isNullableOrWhitespace(element.id)) element.id = `oui_splitter_${++index}`;
4383
+ this.values = getValues(element);
4384
+ this.handle = createHandle();
4385
+ this.rectangle = element.getBoundingClientRect();
4386
+ this.separator = createSeparator(this);
4387
+ this.separator.append(this.handle);
4388
+ panels[0].insertAdjacentElement("afterend", this.separator);
4389
+ this.updateOrientation();
4390
+ this.updateValues();
4391
+ }
4392
+ updateConnections(add) {
4393
+ const method = METHODS_CONNECT[add];
4394
+ MAPPED_ELEMENTS[method](this.element, this);
4395
+ MAPPED_ELEMENTS[method](this.handle, this);
4396
+ MAPPED_ELEMENTS[method](this.separator, this);
4397
+ if (this.types.auto) RESIZE_OBSERVER[METHODS_OBSERVE[add]](this.element);
4398
+ }
4399
+ updateOrientation() {
4400
+ this.types = getTypes(this);
4401
+ if (this.types.auto) RESIZE_OBSERVER.observe(this.element);
4402
+ else RESIZE_OBSERVER.unobserve(this.element);
4403
+ setAttribute(this.element, ATTRIBUTE_HORIZONTAL, this.types.horizontal ? "" : void 0);
4404
+ setAriaOrientation(this);
4405
+ }
4406
+ updateValues() {
4407
+ this.values = getValues(this.element);
4408
+ requestAnimationFrame(() => {
4409
+ setSize(this, this.values.now.current);
4410
+ setAriaValue(this);
4411
+ });
4412
+ }
4413
+ };
4414
+ var OuiSplitterElement = class extends HTMLElement {
4415
+ static observedAttributes = [
4416
+ ATTRIBUTE_MAX,
4417
+ ATTRIBUTE_MIN,
4418
+ ATTRIBUTE_SIZE,
4419
+ ATTRIBUTE_TYPE
4420
+ ];
4421
+ #splitter;
4422
+ /**
4423
+ * Maximum size for the first panel
4424
+ */
4425
+ get max() {
4426
+ return this.#splitter.values.max;
4427
+ }
4428
+ /**
4429
+ * Maximum size for the first panel
4430
+ */
4431
+ set max(value) {
4432
+ if (typeof value === "number") setAttribute(this, ATTRIBUTE_MAX, value.toString());
4433
+ }
4434
+ /**
4435
+ * Minimum size for the first panel
4436
+ */
4437
+ get min() {
4438
+ return this.#splitter.values.min;
4439
+ }
4440
+ /**
4441
+ * Minimum size for the first panel
4442
+ */
4443
+ set min(value) {
4444
+ if (typeof value === "number") setAttribute(this, ATTRIBUTE_MIN, value.toString());
4445
+ }
4446
+ /**
4447
+ * Current size for the first panel
4448
+ */
4449
+ get size() {
4450
+ return this.#splitter.values.now.current;
4451
+ }
4452
+ /**
4453
+ * Current size for the first panel
4454
+ */
4455
+ set size(value) {
4456
+ if (typeof value === "number") setAttribute(this, ATTRIBUTE_SIZE, value.toString());
4457
+ }
4458
+ /**
4459
+ * Orientation of the splitter
4460
+ */
4461
+ get type() {
4462
+ return getAttribute(this, ATTRIBUTE_TYPE) ?? "vertical";
4463
+ }
4464
+ /**
4465
+ * Orientation of the splitter
4466
+ */
4467
+ set type(value) {
4468
+ setAttribute(this, ATTRIBUTE_TYPE, value);
4469
+ }
4470
+ constructor() {
4471
+ super();
4472
+ const panels = [...this.children].filter((child) => child instanceof Element);
4473
+ if (panels.length !== 2) throw new Error(MESSAGE);
4474
+ this.#splitter = new OuiSplitter(this, panels);
4475
+ }
4476
+ connectedCallback() {
4477
+ this.#splitter.updateConnections(1);
4478
+ }
4479
+ disconnectedCallback() {
4480
+ this.#splitter.updateConnections(0);
4481
+ }
4482
+ attributeChangedCallback(name) {
4483
+ switch (name) {
4484
+ case ATTRIBUTE_MAX:
4485
+ case ATTRIBUTE_MIN:
4486
+ case ATTRIBUTE_SIZE:
4487
+ this.#splitter.updateValues();
4488
+ break;
4489
+ case ATTRIBUTE_TYPE:
4490
+ this.#splitter.updateOrientation();
4491
+ break;
4492
+ default: break;
4493
+ }
4494
+ }
4495
+ };
4496
+ function createHandle() {
4497
+ const handle = document.createElement("span");
4498
+ setAria(handle, "hidden", "true");
4499
+ setAttribute(handle, ATTRIBUTE_HANDLE, "");
4500
+ return handle;
4501
+ }
4502
+ function createSeparator(splitter) {
4503
+ const separator = document.createElement("div");
4504
+ separator.role = "separator";
4505
+ separator.tabIndex = 0;
4506
+ setAria(separator, {
4507
+ controls: splitter.element.id,
4508
+ label: "Resize panels"
4509
+ });
4510
+ setAttribute(separator, ATTRIBUTE_SEPARATOR, "");
4511
+ return separator;
4512
+ }
4513
+ function getContained(min, value, max) {
4514
+ return round(clamp(value, min, max), VALUE_DECIMALS);
4515
+ }
4516
+ function getSize(splitter, value) {
4517
+ const { height, left, top, width } = splitter.rectangle;
4518
+ const fraction = (value - (splitter.types.horizontal ? top : left)) / (splitter.types.horizontal ? height : width);
4519
+ return getContained(splitter.values.min, fraction, splitter.values.max);
4520
+ }
4521
+ function getTypes(splitter, width, height) {
4522
+ const type = getAttribute(splitter.element, "type");
4523
+ if (type === "horizontal") return {
4524
+ auto: false,
4525
+ horizontal: true
4526
+ };
4527
+ if (type === "auto") return {
4528
+ auto: true,
4529
+ horizontal: (height ?? splitter.rectangle.height) > (width ?? splitter.rectangle.width)
4530
+ };
4531
+ return {
4532
+ auto: false,
4533
+ horizontal: false
4534
+ };
4535
+ }
4536
+ function getValue(element, name, defaultValue) {
4537
+ const value = getAttribute(element, name);
4538
+ if (isNullableOrWhitespace(value)) return defaultValue;
4539
+ const parsed = Number.parseFloat(value);
4540
+ if (Number.isNaN(parsed)) return defaultValue;
4541
+ if (parsed < 0) return defaultValue;
4542
+ return parsed > 1 ? parsed / NAVIGATION_MAXIMUM_TOTAL : parsed;
4543
+ }
4544
+ function getValues(element) {
4545
+ const values = {
4546
+ max: getValue(element, ATTRIBUTE_MAX, NAVIGATION_MAXIMUM_PERCENTAGE),
4547
+ min: getValue(element, ATTRIBUTE_MIN, NAVIGATION_MINIMUM_PERCENTAGE),
4548
+ now: {
4549
+ current: .5,
4550
+ previous: .5
4551
+ }
4552
+ };
4553
+ const value = getContained(values.min, getValue(element, ATTRIBUTE_SIZE, values.now.current), values.max);
4554
+ values.now.current = value;
4555
+ values.now.previous = value;
4556
+ return values;
4557
+ }
4558
+ function onEnd(reset) {
4559
+ if (splitter == null) return;
4560
+ splitter.handle.removeAttribute(ATTRIBUTE_ACTIVE);
4561
+ splitter.separator.removeAttribute(ATTRIBUTE_ACTIVE);
4562
+ if (reset) setSize(splitter, splitter.values.now.previous);
4563
+ else splitter.values.now.previous = splitter.values.now.current;
4564
+ splitter = void 0;
4565
+ STYLING_TOGGLER.remove();
4566
+ }
4567
+ function onKeydown(event) {
4568
+ switch (true) {
4569
+ case KEYS_ALL.has(event.key):
4570
+ onNavigate(event);
4571
+ break;
4572
+ case event.key === "Escape":
4573
+ onEnd(true);
4574
+ break;
4575
+ default: break;
4576
+ }
4577
+ }
4578
+ function onNavigate(event) {
4579
+ const splitter = MAPPED_ELEMENTS.get(findAncestor(event, "[oui-splitter-separator]"));
4580
+ if (splitter == null) return;
4581
+ const { types, values } = splitter;
4582
+ if (KEYS_ABSOLUTE.has(event.key)) {
4583
+ setSize(splitter, event.key === "End" ? values.max : values.min, true);
4584
+ return;
4585
+ }
4586
+ if (types.horizontal && !KEYS_HORIZONTAL.has(event.key) || !(types.horizontal || KEYS_VERTICAL.has(event.key))) return;
4587
+ const offset = KEYS_NEGATIVE.has(event.key) ? -1 : 1;
4588
+ setSize(splitter, getContained(values.min, values.now.current + offset * NAVIGATION_MODIFIER, values.max), true);
4589
+ }
4590
+ function onObservation(entries) {
4591
+ if (frame != null) cancelAnimationFrame(frame);
4592
+ frame = requestAnimationFrame(() => {
4593
+ for (const entry of entries) {
4594
+ const splitter = MAPPED_ELEMENTS.get(entry.target);
4595
+ if (splitter == null) return;
4596
+ splitter.types = getTypes(splitter, entry.contentRect.width, entry.contentRect.height);
4597
+ setAttribute(splitter.element, ATTRIBUTE_HORIZONTAL, splitter.types.horizontal ? "" : void 0);
4598
+ setAriaOrientation(splitter);
4599
+ }
4600
+ frame = void 0;
4601
+ });
4602
+ }
4603
+ function onPointerdown(event) {
4604
+ if (supportsTouch.value ? event.type === "mousedown" : event.type === "touchstart") return;
4605
+ splitter = MAPPED_ELEMENTS.get(findAncestor(event, SELECTOR_HANDLE));
4606
+ if (splitter == null) return;
4607
+ if (supportsTouch.value) event.preventDefault();
4608
+ setAttribute(splitter.handle, ATTRIBUTE_ACTIVE, "");
4609
+ setAttribute(splitter.separator, ATTRIBUTE_ACTIVE, "");
4610
+ splitter.rectangle = splitter.element.getBoundingClientRect();
4611
+ STYLING_TOGGLER.set();
4612
+ }
4613
+ function onPointermove$1(event) {
4614
+ if (splitter == null) return;
4615
+ const position = getPosition$1(event);
4616
+ if (position != null) {
4617
+ splitter.values.now.current = getSize(splitter, splitter.types.horizontal ? position.y : position.x);
4618
+ setSize(splitter, splitter.values.now.current);
4619
+ }
4620
+ }
4621
+ function onPointerup() {
4622
+ if (splitter != null) onEnd(false);
4623
+ }
4624
+ function setAriaOrientation(splitter) {
4625
+ setAria(splitter.separator, "orientation", splitter.types.horizontal ? "horizontal" : "vertical");
4626
+ }
4627
+ function setAriaValue(splitter) {
4628
+ setAria(splitter.separator, {
4629
+ valuemax: splitter.values.max,
4630
+ valuemin: splitter.values.min,
4631
+ valuenow: splitter.values.now.current
4632
+ });
4633
+ }
4634
+ function setSize(splitter, size, previous) {
4635
+ splitter.values.now.current = size;
4636
+ if (previous) splitter.values.now.previous = size;
4637
+ setStyle(splitter.element, "--oui-splitter-size", `${size}`);
4638
+ setAriaValue(splitter);
4639
+ }
4640
+ const TAGNAME = "oui-splitter";
4641
+ const ATTRIBUTE_ACTIVE = `${TAGNAME}-active`;
4642
+ const ATTRIBUTE_HANDLE = `${TAGNAME}-handle`;
4643
+ const ATTRIBUTE_HORIZONTAL = `${TAGNAME}-horizontal`;
4644
+ const ATTRIBUTE_SEPARATOR = `${TAGNAME}-separator`;
4645
+ const KEYS_ABSOLUTE = /* @__PURE__ */ new Set(["End", "Home"]);
4646
+ const KEYS_HORIZONTAL = /* @__PURE__ */ new Set(["ArrowDown", "ArrowUp"]);
4647
+ const KEYS_NEGATIVE = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowUp"]);
4648
+ const KEYS_VERTICAL = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight"]);
4649
+ const KEYS_ALL = /* @__PURE__ */ new Set([
4650
+ ...KEYS_ABSOLUTE,
4651
+ ...KEYS_HORIZONTAL,
4652
+ ...KEYS_VERTICAL
4653
+ ]);
4654
+ const MAPPED_ELEMENTS = /* @__PURE__ */ new WeakMap();
4655
+ const MESSAGE = `<${TAGNAME}> must have exactly two panels.`;
4656
+ const METHODS_CONNECT = ["delete", "set"];
4657
+ const METHODS_OBSERVE = ["unobserve", "observe"];
4658
+ const NAVIGATION_MAXIMUM_PERCENTAGE = .9;
4659
+ const NAVIGATION_MAXIMUM_TOTAL = 100;
4660
+ const NAVIGATION_MINIMUM_PERCENTAGE = .1;
4661
+ const NAVIGATION_MODIFIER = .05;
4662
+ const RESIZE_OBSERVER = new ResizeObserver(onObservation);
4663
+ const SELECTOR_HANDLE = `[${ATTRIBUTE_HANDLE}]`;
4664
+ const STYLING_TOGGLER = toggleStyles(document.body, {
4665
+ touchAction: "none",
4666
+ userSelect: "none",
4667
+ webkitUserSelect: "none"
4668
+ });
4669
+ const VALUE_DECIMALS = 6;
4670
+ let index = 0;
4671
+ let frame;
4672
+ let splitter;
4673
+ on(document, "keydown", onKeydown);
4674
+ on(document, "mousedown", onPointerdown);
4675
+ on(document, "pointermove", onPointermove$1);
4676
+ on(document, "pointerup", onPointerup);
4677
+ on(document, "touchcancel", onPointerup);
4678
+ on(document, "touchstart", onPointerdown, { passive: false });
4679
+ customElements.define(TAGNAME, OuiSplitterElement);
4680
+ //#endregion
4681
+ //#region src/js/tooltip.ts
4682
+ var OuiTooltip = class {
4683
+ #state;
4684
+ /**
4685
+ * Is the tooltip open?
4686
+ */
4687
+ get open() {
4688
+ return this === activeTooltip && content.checkVisibility();
4689
+ }
4690
+ /**
4691
+ * Open or close the tooltip
4692
+ */
4693
+ set open(value) {
4694
+ if (value === true) this.show();
4695
+ else if (value === false) this.hide();
4696
+ }
4697
+ constructor(state) {
4698
+ this.#state = state;
4699
+ state.floatable.update();
4700
+ }
4701
+ /**
4702
+ * Closes the tooltip
4703
+ */
4704
+ hide() {
4705
+ this.#state.floatable.hide();
4706
+ }
4707
+ /**
4708
+ * Opens the tooltip
4709
+ */
4710
+ show() {
4711
+ this.#state.floatable.show();
4712
+ }
4713
+ };
4714
+ function activate(event, focus) {
4715
+ const targetAnchor = findAncestor(event, SELECTOR);
4716
+ const targetContent = findAncestor(event, SELECTOR_CONTENT);
4717
+ if (targetAnchor == null && targetContent == null) {
4718
+ if (!focused) {
4719
+ closeTooltip(true, activeState);
4720
+ activeState = void 0;
4721
+ activeTooltip = void 0;
4722
+ }
4723
+ return;
4724
+ }
4725
+ const state = states.get(targetAnchor ?? targetContent);
4726
+ if (state == null || state.tooltip === activeTooltip) return;
4727
+ const shouldDelay = activeTooltip == null;
4728
+ closeTooltip(false, activeState);
4729
+ activeState = state;
4730
+ activeTooltip = state.tooltip;
4731
+ focused = focus;
4732
+ state.timer = setTimeout(() => {
4733
+ content.innerHTML = "";
4734
+ content.append(...state.elements);
4735
+ state.floatable.show();
4736
+ setTimeout(() => {
4737
+ state.floatable.update();
4738
+ });
4739
+ }, shouldDelay ? delay : 0);
4740
+ }
4741
+ function addTooltip(element) {
4742
+ if (!states.has(element)) createTooltip(element);
4743
+ }
4744
+ function closeTooltip(clear, state) {
4745
+ if (state == null) return;
4746
+ if (state.timer != null) clearTimeout(state.timer);
4747
+ if (clear) content?.hidePopover();
4748
+ }
4749
+ function createTooltip(anchor) {
4750
+ const elements = getElements(anchor);
4751
+ if (elements == null) return;
4752
+ states.set(anchor, getState(anchor, elements));
4753
+ }
4754
+ function destroyTooltip(state) {
4755
+ clearTimeout(state.timer);
4756
+ state.floatable.destroy();
4757
+ state.anchor = void 0;
4758
+ state.elements = void 0;
4759
+ state.floatable = void 0;
4760
+ state.tooltip = void 0;
4761
+ }
4762
+ function findElements(attribute) {
4763
+ if (attribute == null) return;
4764
+ const ids = attribute?.split(EXPRESSION_WHITESPACE) ?? [];
4765
+ const elements = [];
4766
+ for (const id of ids) {
4767
+ if (isNullableOrWhitespace(id)) continue;
4768
+ const element = document.querySelector(`#${id}`);
4769
+ if (element != null) {
4770
+ const cloned = element.cloneNode(true);
4771
+ cloned.hidden = false;
4772
+ elements.push(cloned);
4773
+ }
4774
+ }
4775
+ return elements;
4776
+ }
4777
+ function getContent() {
4778
+ const content = createElement("div", {
4779
+ popover: "hint",
4780
+ role: "tooltip",
4781
+ tabIndex: -1
4782
+ });
4783
+ setAttribute(content, ATTRIBUTE_CONTENT, "");
4784
+ return content;
4785
+ }
4786
+ function getElements(anchor) {
4787
+ let elements = findElements(getAria(anchor, "labelledby"));
4788
+ if (elements == null || elements.length === 0) elements = findElements(getAria(anchor, "describedby"));
4789
+ if (elements != null && elements.length > 0) return elements;
4790
+ let text = getAria(anchor, "label");
4791
+ if (isNullableOrWhitespace(text)) text = getAria(anchor, "description");
4792
+ if (isNullableOrWhitespace(text)) return;
4793
+ const paragraph = document.createElement("p");
4794
+ paragraph.textContent = text;
4795
+ return [paragraph];
4796
+ }
4797
+ function getState(anchor, elements) {
4798
+ const state = {
4799
+ anchor,
4800
+ elements,
4801
+ floatable: createEmbeddedFloatable(anchor, content, options),
4802
+ tooltip: null
4803
+ };
4804
+ state.tooltip = new OuiTooltip(state);
4805
+ return state;
4806
+ }
4807
+ /**
4808
+ * Get the _OuiTooltip_ for an element
4809
+ *
4810
+ * @param element Element to get _OuiTooltip_ for
4811
+ * @returns _OuiTooltip_ instance
4812
+ */
4813
+ function getTooltip(element) {
4814
+ return states.get(element)?.tooltip;
4815
+ }
4816
+ function onFocusin(event) {
4817
+ activate(event, true);
4818
+ }
4819
+ function onFocusout() {
4820
+ if (activeTooltip == null) return;
4821
+ if (focusTimer != null) clearTimeout(focusTimer);
4822
+ focusTimer = setTimeout(() => {
4823
+ if (activeTooltip == null || document.activeElement == null || findAncestor(document.activeElement, SELECTOR) != null) return;
4824
+ closeTooltip(true, activeState);
4825
+ activeState = void 0;
4826
+ activeTooltip = void 0;
4827
+ });
4828
+ }
4829
+ function onPointermove(event) {
4830
+ activate(event, false);
4831
+ }
4832
+ function onToggle(event) {
4833
+ setAttribute(content, ATTRIBUTE_CONTENT_OPEN, event.newState === "open" ? "" : void 0);
4834
+ }
4835
+ function removeTooltip(element) {
4836
+ const state = states.get(element);
4837
+ if (state == null) return;
4838
+ destroyTooltip(state);
4839
+ states.delete(element);
4840
+ }
4841
+ /**
4842
+ * Set the delay before showing the tooltip, in milliseconds
4843
+ *
4844
+ * _(Default delay is half a second, or 500 milliseconds)_
4845
+ * @param value Delay in milliseconds
4846
+ */
4847
+ function setTooltipDelay(value) {
4848
+ if (typeof value === "number" && !Number.isNaN(value) && value >= 0) delay = value;
4849
+ }
4850
+ const EXPRESSION_WHITESPACE = /\s+/;
4851
+ const ATTRIBUTE = "oui-tooltip";
4852
+ const ATTRIBUTE_CONTENT = `${ATTRIBUTE}-content`;
4853
+ const ATTRIBUTE_CONTENT_OPEN = `${ATTRIBUTE_CONTENT}-open`;
4854
+ const SELECTOR = `[${ATTRIBUTE}]`;
4855
+ const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
4856
+ const content = getContent();
4857
+ const states = /* @__PURE__ */ new WeakMap();
4858
+ const options = {
4859
+ attribute: `${ATTRIBUTE}-position`,
4860
+ position: "above",
4861
+ reusable: true
4862
+ };
4863
+ let delay = 500;
4864
+ let focused = false;
4865
+ let activeState;
4866
+ let activeTooltip;
4867
+ let focusTimer;
4868
+ document.body.append(content);
4869
+ on(content, "toggle", onToggle);
4870
+ on(document, "focusin", onFocusin);
4871
+ on(document, "focusout", onFocusout);
4872
+ on(document, "pointermove", onPointermove);
4873
+ attributable(ATTRIBUTE, addTooltip, removeTooltip);
4874
+ //#endregion
4875
+ export { OuiComboboxElement, OuiSplitterElement, createFloatable, createFocusTrap, createMovable, createResizable as createOuiResizable, createSortable, getDialog, getPopover, getTooltip, setLocalizations, setTooltipDelay };