@oscarpalmer/oui 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/css/a11y.css +0 -1
  2. package/dist/css/form.css +0 -1
  3. package/dist/css/popover.css +22 -0
  4. package/dist/css/reset.css +8 -8
  5. package/dist/css/table.css +1 -1
  6. package/dist/css/tooltip.css +43 -0
  7. package/dist/js/attributable.d.mts +4 -0
  8. package/dist/js/{attributable.full.js → attributable.mjs} +8 -1
  9. package/dist/js/floatable.d.mts +26 -0
  10. package/dist/js/{floatable.js → floatable.mjs} +73 -50
  11. package/dist/js/focus-trap/embedded.d.mts +26 -0
  12. package/dist/js/focus-trap/{embedded.js → embedded.mjs} +10 -8
  13. package/dist/js/focus-trap/standalone.d.mts +1 -0
  14. package/dist/js/focus-trap/{standalone.js → standalone.mjs} +5 -2
  15. package/dist/js/index.d.mts +4 -0
  16. package/dist/js/index.mjs +5 -0
  17. package/dist/js/popover.d.mts +20 -0
  18. package/dist/js/{popover.js → popover.mjs} +10 -8
  19. package/dist/js/splitter.d.mts +25 -0
  20. package/dist/js/{splitter.js → splitter.mjs} +58 -56
  21. package/dist/js/tooltip.d.mts +4 -0
  22. package/dist/js/{tooltip.js → tooltip.mjs} +20 -18
  23. package/package.json +64 -69
  24. package/src/css/mixins.scss +30 -1
  25. package/src/css/popover.scss +6 -1
  26. package/src/css/reset.scss +4 -4
  27. package/src/css/table.scss +1 -1
  28. package/src/css/tooltip.scss +55 -1
  29. package/src/js/attributable.ts +11 -1
  30. package/src/js/floatable.ts +136 -58
  31. package/src/js/focus-trap/embedded.ts +4 -10
  32. package/src/js/splitter.ts +2 -5
  33. package/src/js/tooltip.ts +5 -5
  34. package/dist/js/attributable.js +0 -36
  35. package/dist/js/floatable.full.js +0 -398
  36. package/dist/js/focus-trap/embedded.full.js +0 -408
  37. package/dist/js/focus-trap/standalone.full.js +0 -447
  38. package/dist/js/index.js +0 -5
  39. package/dist/js/oui.full.js +0 -1573
  40. package/dist/js/popover.full.js +0 -760
  41. package/dist/js/splitter.full.js +0 -769
  42. package/dist/js/tooltip.full.js +0 -613
  43. package/types/attributable.d.ts +0 -1
  44. package/types/floatable.d.ts +0 -24
  45. package/types/focus-trap/embedded.d.ts +0 -24
  46. package/types/focus-trap/standalone.d.ts +0 -1
  47. package/types/index.d.ts +0 -4
  48. package/types/popover.d.ts +0 -17
  49. package/types/splitter.d.ts +0 -23
  50. package/types/tooltip.d.ts +0 -2
@@ -1,1573 +0,0 @@
1
- function attributable(attribute, add, remove) {
2
- new MutationObserver((entries) => {
3
- const { length } = entries;
4
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
5
- const entry = entries[index$3];
6
- if (entry.type === "attributes" && entry.target instanceof HTMLElement) if (entry.target.hasAttribute(attribute)) handleAdded(attribute, [entry.target], add);
7
- else handleRemoved([entry.target], remove);
8
- else if (entry.type === "childList") {
9
- handleAdded(attribute, entry.addedNodes, add);
10
- handleRemoved(entry.removedNodes, remove);
11
- }
12
- }
13
- }).observe(document, {
14
- attributeFilter: [attribute],
15
- attributes: true,
16
- childList: true,
17
- subtree: true
18
- });
19
- requestAnimationFrame(() => {
20
- handleAdded(attribute, document.querySelectorAll(`[${attribute}]`), add);
21
- });
22
- }
23
- function handleAdded(attribute, nodes, add) {
24
- const elements = [...nodes].filter((node) => node instanceof HTMLElement);
25
- const { length } = elements;
26
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
27
- const element = elements[index$3];
28
- if (element.hasAttribute(attribute)) add(element);
29
- }
30
- }
31
- function handleRemoved(nodes, remove) {
32
- const elements = [...nodes].filter((node) => node instanceof HTMLElement);
33
- const { length } = elements;
34
- for (let index$3 = 0; index$3 < length; index$3 += 1) remove(elements[index$3]);
35
- }
36
- function isNumber(value) {
37
- return typeof value === "number" && !Number.isNaN(value);
38
- }
39
- function isPlainObject(value) {
40
- if (value === null || typeof value !== "object") return false;
41
- if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
42
- const prototype = Object.getPrototypeOf(value);
43
- return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
44
- }
45
- function clamp(value, minimum, maximum, loop) {
46
- if (![
47
- value,
48
- minimum,
49
- maximum
50
- ].every(isNumber)) return NaN;
51
- if (value < minimum) return loop === true ? maximum : minimum;
52
- return value > maximum ? loop === true ? minimum : maximum : value;
53
- }
54
- function compact(array, strict) {
55
- if (!Array.isArray(array)) return [];
56
- if (strict === true) return array.filter(Boolean);
57
- const { length } = array;
58
- const compacted = [];
59
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
60
- const item = array[index$3];
61
- if (item != null) compacted.push(item);
62
- }
63
- return compacted;
64
- }
65
- function getString(value) {
66
- if (typeof value === "string") return value;
67
- if (value == null) return "";
68
- if (typeof value === "function") return getString(value());
69
- if (typeof value !== "object") return String(value);
70
- const asString = String(value.valueOf?.() ?? value);
71
- return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
72
- }
73
- function join(value, delimiter) {
74
- return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
75
- }
76
- function words(value) {
77
- return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
78
- }
79
- var EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
80
- function noop() {}
81
- function calculate() {
82
- return new Promise((resolve) => {
83
- const values = [];
84
- let last;
85
- function step(now) {
86
- if (last != null) values.push(now - last);
87
- last = now;
88
- if (values.length >= TOTAL) resolve(values.sort().slice(TRIM_PART, -TRIM_PART).reduce((first, second) => first + second, 0) / (values.length - TRIM_TOTAL));
89
- else requestAnimationFrame(step);
90
- }
91
- requestAnimationFrame(step);
92
- });
93
- }
94
- var TOTAL = 10;
95
- var TRIM_PART = 2;
96
- var TRIM_TOTAL = 4;
97
- await calculate();
98
- var SizedMap = class extends Map {
99
- #maximumSize;
100
- get full() {
101
- return this.size >= this.#maximumSize;
102
- }
103
- get maximum() {
104
- return this.#maximumSize;
105
- }
106
- constructor(first, second) {
107
- const maximum = getMaximum(first, second);
108
- super();
109
- this.#maximumSize = maximum;
110
- if (Array.isArray(first)) {
111
- const { length } = first;
112
- if (length <= maximum) for (let index$3 = 0; index$3 < length; index$3 += 1) this.set(...first[index$3]);
113
- else for (let index$3 = 0; index$3 < maximum; index$3 += 1) this.set(...first[length - maximum + index$3]);
114
- }
115
- }
116
- get(key) {
117
- const value = super.get(key);
118
- if (value !== void 0 || this.has(key)) this.set(key, value);
119
- return value;
120
- }
121
- set(key, value) {
122
- if (this.has(key)) this.delete(key);
123
- else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
124
- return super.set(key, value);
125
- }
126
- };
127
- function getMaximum(first, second) {
128
- let actual;
129
- if (typeof first === "number") actual = first;
130
- else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
131
- return clamp(actual, 1, MAXIMUM_ABSOLUTE);
132
- }
133
- var MAXIMUM_ABSOLUTE = 16777216;
134
- var MAXIMUM_DEFAULT = 1048576;
135
- var Memoized = class {
136
- #state;
137
- get maximum() {
138
- return this.#state.cache?.maximum ?? NaN;
139
- }
140
- get size() {
141
- return this.#state.cache?.size ?? NaN;
142
- }
143
- constructor(callback, options) {
144
- const cache = new SizedMap(options.cacheSize);
145
- const getter = (...parameters) => {
146
- const key = options.cacheKey?.(...parameters) ?? (parameters.length === 1 ? parameters[0] : join(parameters.map(getString), "_"));
147
- if (cache.has(key)) return cache.get(key);
148
- const value = callback(...parameters);
149
- cache.set(key, value);
150
- return value;
151
- };
152
- this.#state = {
153
- cache,
154
- getter
155
- };
156
- }
157
- clear() {
158
- this.#state.cache?.clear();
159
- }
160
- delete(key) {
161
- return this.#state.cache?.delete(key) ?? false;
162
- }
163
- destroy() {
164
- this.#state.cache?.clear();
165
- this.#state.cache = void 0;
166
- this.#state.getter = void 0;
167
- }
168
- get(key) {
169
- return this.#state.cache?.get(key);
170
- }
171
- has(key) {
172
- return this.#state.cache?.has(key) ?? false;
173
- }
174
- run(...parameters) {
175
- if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
176
- return this.#state.getter(...parameters);
177
- }
178
- };
179
- function getMemoizationOptions(input) {
180
- const { cacheKey, cacheSize } = isPlainObject(input) ? input : {};
181
- return {
182
- cacheKey: typeof cacheKey === "function" ? cacheKey : void 0,
183
- cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
184
- };
185
- }
186
- function memoize(callback, options) {
187
- return new Memoized(callback, getMemoizationOptions(options));
188
- }
189
- var DEFAULT_CACHE_SIZE = 1024;
190
- function camelCase(value) {
191
- return toCase("camel", value, true, false);
192
- }
193
- function capitalize(value) {
194
- if (typeof value !== "string" || value.length === 0) return "";
195
- memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
196
- return memoizedCapitalize.run(value);
197
- }
198
- function toCase(type, value, capitalizeAny, capitalizeFirst) {
199
- memoizers[type] ??= memoize(toCaseCallback.bind({
200
- type,
201
- capitalizeAny,
202
- capitalizeFirst
203
- }));
204
- return memoizers[type].run(value);
205
- }
206
- function toCaseCallback(value) {
207
- if (typeof value !== "string") return "";
208
- if (value.length < 1) return value;
209
- const { capitalizeAny, capitalizeFirst, type } = this;
210
- const parts = words(value);
211
- const partsLength = parts.length;
212
- const result = [];
213
- for (let partIndex = 0; partIndex < partsLength; partIndex += 1) {
214
- 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("-");
215
- const itemsLength = items.length;
216
- const partResult = [];
217
- let itemCount = 0;
218
- for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
219
- const item = items[itemIndex];
220
- if (item.length === 0) continue;
221
- if (!capitalizeAny || itemCount === 0 && partIndex === 0 && !capitalizeFirst) partResult.push(item.toLocaleLowerCase());
222
- else partResult.push(capitalize(item));
223
- itemCount += 1;
224
- }
225
- result.push(join(partResult, delimiters[type]));
226
- }
227
- return join(result, delimiters[type]);
228
- }
229
- var EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
230
- var EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
231
- var REPLACEMENT_CAMEL_CASE = "$1-$2";
232
- var delimiters = {
233
- camel: "",
234
- kebab: "-",
235
- pascal: "",
236
- snake: "_"
237
- };
238
- var memoizers = {};
239
- var memoizedCapitalize;
240
- function getBoolean(value, defaultValue) {
241
- return typeof value === "boolean" ? value : defaultValue ?? false;
242
- }
243
- function getStyleValue(element, property, computed) {
244
- const name = camelCase(property);
245
- return computed ? getComputedStyle(element)[name] : element.style[name];
246
- }
247
- function isEventTarget(value) {
248
- return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
249
- }
250
- function isHTMLOrSVGElement(value) {
251
- return value instanceof HTMLElement || value instanceof SVGElement;
252
- }
253
- function addDelegatedHandler(doc, type, name, passive) {
254
- if (DELEGATED.has(name)) return;
255
- DELEGATED.add(name);
256
- doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
257
- }
258
- function addDelegatedListener(target, type, name, listener, passive) {
259
- target[name] ??= /* @__PURE__ */ new Set();
260
- target[name].add(listener);
261
- addDelegatedHandler(document, type, name, passive);
262
- return () => {
263
- removeDelegatedListener(target, name, listener);
264
- };
265
- }
266
- function delegatedEventHandler(event) {
267
- const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
268
- const items = event.composedPath();
269
- const { length } = items;
270
- let target = items[0];
271
- Object.defineProperties(event, {
272
- currentTarget: {
273
- configurable: true,
274
- get() {
275
- return target;
276
- }
277
- },
278
- target: {
279
- configurable: true,
280
- value: target
281
- }
282
- });
283
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
284
- const item = items[index$3];
285
- const listeners = item[key];
286
- if (item.disabled || listeners == null) continue;
287
- target = item;
288
- for (const listener of listeners) {
289
- listener.call(item, event);
290
- if (event.cancelBubble) return;
291
- }
292
- }
293
- }
294
- function getDelegatedName(target, type, options) {
295
- if (isEventTarget(target) && EVENT_TYPES.has(type) && !options.capture && !options.once && options.signal == null) return `${EVENT_PREFIX}${type}${options.passive ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
296
- }
297
- function removeDelegatedListener(target, name, listener) {
298
- const handlers = target[name];
299
- if (handlers == null || !handlers.has(listener)) return false;
300
- handlers.delete(listener);
301
- if (handlers.size === 0) target[name] = void 0;
302
- return true;
303
- }
304
- var DELEGATED = /* @__PURE__ */ new Set();
305
- var EVENT_PREFIX = "@";
306
- var EVENT_SUFFIX_ACTIVE = ":active";
307
- var EVENT_SUFFIX_PASSIVE = ":passive";
308
- var EVENT_TYPES = new Set([
309
- "beforeinput",
310
- "click",
311
- "dblclick",
312
- "contextmenu",
313
- "focusin",
314
- "focusout",
315
- "input",
316
- "keydown",
317
- "keyup",
318
- "mousedown",
319
- "mousemove",
320
- "mouseout",
321
- "mouseover",
322
- "mouseup",
323
- "pointerdown",
324
- "pointermove",
325
- "pointerout",
326
- "pointerover",
327
- "pointerup",
328
- "touchend",
329
- "touchmove",
330
- "touchstart"
331
- ]);
332
- var HANDLER_ACTIVE = delegatedEventHandler.bind(false);
333
- var HANDLER_PASSIVE = delegatedEventHandler.bind(true);
334
- function isNullableOrWhitespace(value) {
335
- return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
336
- }
337
- var EXPRESSION_WHITESPACE$1 = /^\s*$/;
338
- function createEventOptions(options) {
339
- return {
340
- capture: getBoolean(options?.capture),
341
- once: getBoolean(options?.once),
342
- passive: getBoolean(options?.passive, true),
343
- signal: options?.signal instanceof AbortSignal ? options.signal : void 0
344
- };
345
- }
346
- function getPosition(event) {
347
- let x;
348
- let y;
349
- if (event instanceof MouseEvent) {
350
- x = event.clientX;
351
- y = event.clientY;
352
- } else if (event instanceof TouchEvent) {
353
- x = event.touches[0]?.clientX;
354
- y = event.touches[0]?.clientY;
355
- }
356
- return typeof x === "number" && typeof y === "number" ? {
357
- x,
358
- y
359
- } : void 0;
360
- }
361
- function on(target, type, listener, options) {
362
- if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
363
- const extended = createEventOptions(options);
364
- const delegated = getDelegatedName(target, type, extended);
365
- if (delegated != null) return addDelegatedListener(target, type, delegated, listener, extended.passive);
366
- target.addEventListener(type, listener, extended);
367
- if (extended.once) return noop;
368
- return () => {
369
- target.removeEventListener(type, listener, extended);
370
- };
371
- }
372
- function findAncestor(origin, selector) {
373
- if (!(origin instanceof Element) || selector == null) return null;
374
- if (typeof selector === "string") {
375
- if (origin.matches?.(selector)) return origin;
376
- return origin.closest(selector);
377
- }
378
- if (typeof selector !== "function") return null;
379
- if (selector(origin)) return origin;
380
- let parent = origin.parentElement;
381
- while (parent != null && !selector(parent)) {
382
- if (parent === document.body) return null;
383
- parent = parent.parentElement;
384
- }
385
- return parent;
386
- }
387
- function getFocusable(parent) {
388
- return getValidElements(parent, FILTERS_FOCUSABLE, false);
389
- }
390
- function getItem(element, tabbable) {
391
- return {
392
- element,
393
- tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
394
- };
395
- }
396
- function getTabIndex(element) {
397
- const tabIndex = element?.tabIndex ?? TABINDEX_DEFAULT;
398
- if (tabIndex < TABINDEX_BASE && (EXPRESSION_SPECIAL_TABINDEX.test(element.tagName) || isEditable(element)) && !hasTabIndex(element)) return TABINDEX_BASE;
399
- return tabIndex;
400
- }
401
- function getValidElements(parent, filters, tabbable) {
402
- if (!(parent instanceof Element)) return [];
403
- const elements = [...parent.querySelectorAll(SELECTOR_FULL$1)];
404
- const items = [];
405
- let { length } = elements;
406
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
407
- const item = getItem(elements[index$3], tabbable);
408
- if (!filters.some((filter) => filter(item))) items.push(item);
409
- }
410
- if (!tabbable) return items.map((item) => item.element);
411
- const indiced = [];
412
- const zeroed = [];
413
- length = items.length;
414
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
415
- const item = items[index$3];
416
- if (item.tabIndex === TABINDEX_BASE) zeroed.push(item.element);
417
- else indiced[item.tabIndex] = [...indiced[item.tabIndex] ?? [], item.element];
418
- }
419
- return [...indiced.flat(), ...zeroed];
420
- }
421
- function hasTabIndex(element) {
422
- return !Number.isNaN(Number.parseInt(element.getAttribute(ATTRIBUTE_TABINDEX), 10));
423
- }
424
- function isDisabled$1(item) {
425
- if (EXPRESSION_DISABLEABLE.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
426
- return item.element.disabled ?? false;
427
- }
428
- function isDisabledFromFieldset(element) {
429
- let parent = element.parentElement;
430
- while (parent != null) {
431
- if (parent instanceof HTMLFieldSetElement && parent.disabled) {
432
- const children = Array.from(parent.children);
433
- const { length } = children;
434
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
435
- const child = children[index$3];
436
- if (child instanceof HTMLLegendElement) return parent.matches(SELECTOR_FIELDSET_DISABLED) || !child.contains(element);
437
- }
438
- return true;
439
- }
440
- parent = parent.parentElement;
441
- }
442
- return false;
443
- }
444
- function isEditable(element) {
445
- return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
446
- }
447
- function isHidden(item) {
448
- if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === STYLE_HIDDEN) return true;
449
- if ((item.element.matches(SELECTOR_SUMMARY_FIRST) ? item.element.parentElement : item.element)?.matches(SELECTOR_DETAILS_CLOSED_CHILDREN) ?? false) return true;
450
- const style = getComputedStyle(item.element);
451
- if (style.display === STYLE_NONE || style.visibility === STYLE_HIDDEN) return true;
452
- const { height, width } = item.element.getBoundingClientRect();
453
- return height === 0 && width === 0;
454
- }
455
- function isInert(item) {
456
- return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
457
- element: item.element.parentElement,
458
- tabIndex: TABINDEX_DEFAULT
459
- });
460
- }
461
- function isSummarised(item) {
462
- return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
463
- }
464
- var ATTRIBUTE_CONTENTEDITABLE = "contenteditable";
465
- var ATTRIBUTE_INERT = "inert";
466
- var ATTRIBUTE_TABINDEX = "tabindex";
467
- var EXPRESSION_DISABLEABLE = /^(button|input|select|textarea)$/i;
468
- var EXPRESSION_SPECIAL_TABINDEX = /^(audio|details|video)$/i;
469
- var EXPRESSION_SUMMARY = /^summary$/i;
470
- var EXPRESSION_TRUEISH = /^(|true)$/i;
471
- var FILTERS_FOCUSABLE = [
472
- isDisabled$1,
473
- isInert,
474
- isHidden,
475
- isSummarised
476
- ];
477
- [...FILTERS_FOCUSABLE];
478
- var SELECTOR_DETAILS_CLOSED_CHILDREN = "details:not([open]) *";
479
- var SELECTOR_FIELDSET_DISABLED = "fieldset[disabled] *";
480
- var SELECTOR_SUMMARY_FIRST = "details > summary:first-of-type";
481
- var SELECTOR_FULL$1 = [
482
- "[contenteditable]:not([contenteditable=\"false\"])",
483
- "[tabindex]:not(slot)",
484
- "a[href]",
485
- "audio[controls]",
486
- "button",
487
- "details",
488
- SELECTOR_SUMMARY_FIRST,
489
- "input",
490
- "select",
491
- "textarea",
492
- "video[controls]"
493
- ].map((selector) => `${selector}:not([inert])`).join(",");
494
- var STYLE_HIDDEN = "hidden";
495
- var STYLE_NONE = "none";
496
- var TABINDEX_BASE = 0;
497
- var TABINDEX_DEFAULT = -1;
498
- var FocusTrap = class {
499
- disabled = false;
500
- connected = true;
501
- element;
502
- embedded;
503
- get contain() {
504
- return this.element.hasAttribute(FOCUS_TRAP_CONTAIN);
505
- }
506
- get noescape() {
507
- return this.element.hasAttribute(FOCUS_TRAP_NOESCAPE);
508
- }
509
- constructor(element, options) {
510
- this.element = element;
511
- this.embedded = options != null;
512
- element.setAttribute("tabindex", "-1");
513
- if (options != null) element.setAttribute(FOCUS_TRAP_SELECTOR, "");
514
- if (options?.noescape) element.setAttribute(FOCUS_TRAP_NOESCAPE, "");
515
- }
516
- connect() {
517
- setConnected(this, true);
518
- }
519
- destroy() {
520
- this.element = void 0;
521
- }
522
- disable() {
523
- if (!(this.disabled || this.noescape)) setDisabled(this, true);
524
- }
525
- disconnect() {
526
- setConnected(this, false);
527
- }
528
- enable() {
529
- if (this.disabled) setDisabled(this, false);
530
- }
531
- focus(last) {
532
- tabToTrap(this, getFocusable(this.element), this.element, last ? -1 : 0);
533
- }
534
- };
535
- function createFocusTrap(element, options) {
536
- let focusTrap = FOCUSTRAPS_ALL.get(element);
537
- if (focusTrap == null) {
538
- focusTrap = new FocusTrap(element, options);
539
- FOCUSTRAPS_ALL.set(element, focusTrap);
540
- }
541
- return focusTrap;
542
- }
543
- function onEscape(event) {
544
- let element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
545
- let focusTrap = FOCUSTRAPS_ALL.get(element);
546
- if (element == null || focusTrap == null) return;
547
- while (focusTrap.disabled) {
548
- element = findAncestor(focusTrap.element.parentElement, ATTRIBUTE_SELECTOR);
549
- focusTrap = FOCUSTRAPS_ALL.get(element);
550
- if (element == null || focusTrap == null) return;
551
- if (!focusTrap.disabled) break;
552
- }
553
- focusTrap?.disable();
554
- }
555
- function onFocusIn(event) {
556
- lastTarget = FOCUSTRAPS_ALL.get(findAncestor(event.target, ATTRIBUTE_SELECTOR)) == null ? void 0 : event.target;
557
- }
558
- function onKeydown$1(event) {
559
- switch (event.key) {
560
- case "Escape":
561
- onEscape(event);
562
- break;
563
- case "Tab":
564
- onTab(event);
565
- break;
566
- default: return;
567
- }
568
- }
569
- function onPointerdown$1(event) {
570
- const lastFocusTrap = findAncestor(lastTarget, ATTRIBUTE_SELECTOR);
571
- const nextFocusTrap = findAncestor(event.target, ATTRIBUTE_SELECTOR);
572
- if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
573
- if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
574
- event.preventDefault();
575
- lastTarget?.focus();
576
- }
577
- }
578
- if (FOCUSTRAPS_DISABLED.size === 0) return;
579
- for (const focusTrap of FOCUSTRAPS_DISABLED) if (focusTrap.element !== nextFocusTrap) focusTrap.enable();
580
- }
581
- function onTab(event) {
582
- const element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
583
- const focusTrap = FOCUSTRAPS_ALL.get(element);
584
- if (focusTrap == null) return;
585
- if (!focusTrap.disabled) event.preventDefault();
586
- const elements = getFocusable(element);
587
- const index$3 = elements.indexOf(event.target);
588
- if (index$3 === -1 || elements.length === 0) tabToTrap(focusTrap, elements, element);
589
- else tabToElement(focusTrap, elements, index$3, event.shiftKey ? -1 : 1);
590
- }
591
- function setConnected(focusTrap, value) {
592
- if (!focusTrap.embedded || focusTrap.connected === value) return;
593
- focusTrap.connected = value;
594
- }
595
- function setDisabled(focusTrap, value) {
596
- focusTrap.disabled = value;
597
- if (value) FOCUSTRAPS_DISABLED.add(focusTrap);
598
- else FOCUSTRAPS_DISABLED.delete(focusTrap);
599
- }
600
- function tabToElement(focusTrap, elements, index$3, modifier) {
601
- const { length } = elements;
602
- const next = clamp(index$3 + modifier, 0, length - 1, true);
603
- if (focusTrap.disabled) {
604
- if (index$3 === length - 1 && next === 0 || index$3 === 0 && next === length - 1) {
605
- lastTarget = void 0;
606
- focusTrap.enable();
607
- }
608
- return;
609
- }
610
- const element = elements[next];
611
- const elementFocusTrap = FOCUSTRAPS_ALL.get(element);
612
- if (elementFocusTrap != null) elementFocusTrap.focus(modifier === -1);
613
- else {
614
- elements[next].focus();
615
- lastTarget = elements[next];
616
- }
617
- }
618
- function tabToTrap(focusTrap, elements, element, index$3) {
619
- if (focusTrap.disabled) {
620
- lastTarget = void 0;
621
- focusTrap.enable();
622
- } else {
623
- const next = elements.length === 0 ? element : elements.at(index$3 ?? 0);
624
- next.focus();
625
- lastTarget = next;
626
- }
627
- }
628
- const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
629
- const ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
630
- const EVENT_OPTIONS = {
631
- capture: true,
632
- passive: false
633
- };
634
- const FOCUS_TRAP_CONTAIN = `${FOCUS_TRAP_SELECTOR}-contain`;
635
- const FOCUS_TRAP_NOESCAPE = `${FOCUS_TRAP_SELECTOR}-noescape`;
636
- const FOCUSTRAPS_ALL = /* @__PURE__ */ new WeakMap();
637
- const FOCUSTRAPS_DISABLED = /* @__PURE__ */ new Set();
638
- let lastTarget;
639
- on(document, "focusin", onFocusIn, EVENT_OPTIONS);
640
- on(document, "keydown", onKeydown$1, EVENT_OPTIONS);
641
- on(document, "mousedown", onPointerdown$1, EVENT_OPTIONS);
642
- on(document, "touchstart", onPointerdown$1, EVENT_OPTIONS);
643
- function removeFocusTraps(element) {
644
- FOCUSTRAPS_ALL.get(element)?.destroy();
645
- FOCUSTRAPS_ALL.delete(element);
646
- }
647
- attributable(FOCUS_TRAP_SELECTOR, createFocusTrap, removeFocusTraps);
648
- var Floatable = class {
649
- active = false;
650
- disabled = false;
651
- frame;
652
- ignoreFocus = false;
653
- constructor(options) {
654
- this.options = options;
655
- initialize(this);
656
- }
657
- destroy() {
658
- stop(this);
659
- const state = getState();
660
- state?.active.delete(this);
661
- state?.mapped.delete(this.options.anchor);
662
- state?.mapped.delete(this.options.content);
663
- this.options.anchor = void 0;
664
- this.options.content = void 0;
665
- }
666
- disable() {
667
- if (this.disabled) return;
668
- this.disabled = true;
669
- stop(this);
670
- getState()?.active.delete(this);
671
- }
672
- enable() {
673
- if (!this.disabled) return;
674
- this.disabled = false;
675
- initialize(this);
676
- }
677
- toggle(active, ignoreFocus) {
678
- if (this.disabled || this.active === active) return;
679
- const state = getState();
680
- if (state == null) return;
681
- this.ignoreFocus = !active && (ignoreFocus ?? false);
682
- stop(this);
683
- if (active) state.active.add(this);
684
- else state.active.delete(this);
685
- if (this.options.interactive) if (active) state.order.push(this);
686
- else {
687
- const index$3 = state.order.indexOf(this);
688
- if (index$3 > -1) state.order.splice(index$3, 1);
689
- }
690
- if (active) activate(this);
691
- else deactivate(this);
692
- }
693
- };
694
- function activate(floatable) {
695
- floatable.active = true;
696
- document.body.append(floatable.options.content);
697
- floatable.options.content.hidden = false;
698
- updatePosition(floatable);
699
- }
700
- function closeAbove(element) {
701
- const state = getState();
702
- if (state == null) return;
703
- const index$3 = state.order.findIndex((floatable) => floatable.options.anchor === element || floatable.options.content === element);
704
- if (index$3 === -1 || index$3 === state.order.length - 1) return;
705
- while (index$3 < state.order.length - 1) state.order.pop()?.toggle(false, true);
706
- }
707
- function closeAll() {
708
- const state = getState();
709
- const floatables = [...state?.active ?? []];
710
- state?.active.clear();
711
- for (const floatable of floatables) floatable.toggle(false, true);
712
- }
713
- function closeNonInteractive(state) {
714
- for (const floatable of state.active) if (!floatable.options.interactive) floatable.toggle(false);
715
- }
716
- function deactivate(floatable) {
717
- floatable.active = false;
718
- floatable.options.content.hidden = true;
719
- floatable.options.anchor.insertAdjacentElement(INSERT_AFTEREND, floatable.options.content);
720
- floatable.options.onAfter?.(false);
721
- }
722
- function getState() {
723
- return window._oscarpalmer_oui_floatable;
724
- }
725
- function getX(anchor, content, position) {
726
- if (position.endsWith(POSITION_SUFFIX_END)) {
727
- const end = anchor.right - content.width;
728
- return end < 0 ? 0 : end;
729
- }
730
- if (position.endsWith(POSITION_SUFFIX_START)) {
731
- const start = anchor.left;
732
- return start + content.width > window.innerWidth ? window.innerWidth - content.width : start;
733
- }
734
- if (position.startsWith(POSITION_END)) return anchor.right;
735
- if (position.startsWith(POSITION_START)) return anchor.left - content.width;
736
- if (position.startsWith(POSITION_HORIZONTAL)) {
737
- if (anchor.right + content.width <= window.innerWidth) return anchor.right;
738
- return anchor.left - content.width;
739
- }
740
- const left = anchor.left + (anchor.width - content.width) / 2;
741
- return left < 0 ? 0 : left;
742
- }
743
- function getY(anchor, content, position, preferAbove) {
744
- if (position.startsWith(POSITION_ABOVE)) return anchor.top - content.height;
745
- if (position.startsWith(POSITION_BELOW)) return anchor.bottom;
746
- if (position.endsWith(POSITION_BOTTOM)) {
747
- const bottom = anchor.bottom - content.height;
748
- return bottom < 0 ? 0 : bottom;
749
- }
750
- if (position.endsWith(POSITION_TOP)) {
751
- const top = anchor.top;
752
- return top + content.height > window.innerHeight ? window.innerHeight - content.height : top;
753
- }
754
- if (position.startsWith(POSITION_VERTICAL)) {
755
- if (preferAbove && anchor.top - content.height >= 0) return anchor.top - content.height;
756
- if (anchor.bottom + content.height <= document.body.clientHeight) return anchor.bottom;
757
- return anchor.top - content.height;
758
- }
759
- return anchor.top + (anchor.height - content.height) / 2;
760
- }
761
- function initialize(floatable) {
762
- const { anchor, content, interactive } = floatable.options;
763
- if (interactive) {
764
- anchor.setAttribute(ATTRIBUTE_ANCHOR, "");
765
- content.setAttribute(ATTRIBUTE_CONTENT$1, "");
766
- }
767
- content.style.position = "fixed";
768
- content.style.inset = "0 auto auto 0";
769
- content.style.zIndex = "10";
770
- const state = getState();
771
- state?.mapped.set(anchor, floatable);
772
- state?.mapped.set(content, floatable);
773
- }
774
- function isDisabled(element) {
775
- return element.disabled || element.readOnly || element.getAttribute("aria-disabled") === "true";
776
- }
777
- function onClick$1(event) {
778
- const related = findAncestor(event.target, SELECTOR_ALL);
779
- if (!(related instanceof HTMLElement)) closeAll();
780
- else if (related.hasAttribute(ATTRIBUTE_CONTENT$1)) closeAbove(related);
781
- else if (!isDisabled(related)) toggle$1(related);
782
- }
783
- function onKeyDown(event) {
784
- if (event.key !== "Escape") return;
785
- const state = getState();
786
- if (state == null || state.active.size === 0) return;
787
- closeNonInteractive(state);
788
- const related = findAncestor(event.target, SELECTOR_CONTENT$2);
789
- if (!(related instanceof HTMLElement)) return;
790
- closeAbove(related);
791
- const floatable = state.mapped.get(related);
792
- if (floatable != null) floatable.toggle(false);
793
- }
794
- function stop(floatable) {
795
- if (floatable.frame != null) cancelAnimationFrame(floatable.frame);
796
- floatable.frame = void 0;
797
- }
798
- function toggle$1(anchor) {
799
- const floatable = getState()?.mapped.get(anchor);
800
- if (floatable == null) {
801
- closeAll();
802
- return;
803
- }
804
- const active = Boolean(floatable.active);
805
- const content = findAncestor(floatable.options.anchor, SELECTOR_CONTENT$2);
806
- if (content == null) closeAll();
807
- else closeAbove(content);
808
- floatable.toggle(!active);
809
- }
810
- function updatePosition(floatable) {
811
- let position = floatable.options.anchor.getAttribute(floatable.options.positionAttribute)?.trim() ?? floatable.options.defaultPosition;
812
- if (!POSITIONS.has(position)) position = floatable.options.defaultPosition;
813
- let previousAnchor;
814
- let previousContent;
815
- let calculated = false;
816
- let runOnAfter = false;
817
- function run() {
818
- const anchor = floatable.options.anchor.getBoundingClientRect();
819
- const content = floatable.options.content.getBoundingClientRect();
820
- if (calculated) {
821
- if (previousAnchor != null && previousContent != null) {
822
- if (PROPERTIES.every((property) => anchor[property] === previousAnchor[property]) && PROPERTIES.every((property) => content[property] === previousContent[property])) {
823
- floatable.frame = requestAnimationFrame(run);
824
- return;
825
- }
826
- }
827
- } else calculated = true;
828
- update(anchor, content);
829
- }
830
- function update(anchor, content) {
831
- previousAnchor = anchor;
832
- previousContent = content;
833
- const left = getX(anchor, content, position);
834
- const top = getY(anchor, content, position, floatable.options.preferAbove);
835
- if (top + content.height > window.innerHeight) floatable.options.content.style.height = `${window.innerHeight - top}px`;
836
- else floatable.options.content.style.height = "";
837
- if (left + content.width > window.innerWidth) floatable.options.content.style.width = `${window.innerWidth - left}px`;
838
- else floatable.options.content.style.width = "";
839
- floatable.options.content.style.transform = `translate3d(${left}px, ${top}px, 0)`;
840
- floatable.frame = requestAnimationFrame(run);
841
- if (!runOnAfter) {
842
- runOnAfter = true;
843
- floatable.options.onAfter?.(true);
844
- }
845
- }
846
- floatable.frame = requestAnimationFrame(run);
847
- }
848
- const ATTRIBUTE_ANCHOR = "oui-floatable-anchor";
849
- const ATTRIBUTE_CONTENT$1 = "oui-floatable-content";
850
- const INSERT_AFTEREND = "afterend";
851
- const POSITION_ABOVE = "above";
852
- const POSITION_BELOW = "below";
853
- const POSITION_BOTTOM = "bottom";
854
- const POSITION_END = "end";
855
- const POSITION_HORIZONTAL = "horizontal";
856
- const POSITION_START = "start";
857
- const POSITION_SUFFIX_END = "-end";
858
- const POSITION_SUFFIX_START = "-start";
859
- const POSITION_TOP = "top";
860
- const POSITION_VERTICAL = "vertical";
861
- const POSITIONS = new Set([
862
- "above",
863
- "above-end",
864
- "above-start",
865
- "below",
866
- "below-end",
867
- "below-start",
868
- "end",
869
- "end-bottom",
870
- "end-top",
871
- "horizontal",
872
- "horizontal-bottom",
873
- "horizontal-top",
874
- "start",
875
- "start-bottom",
876
- "start-top",
877
- "vertical",
878
- "vertical-end",
879
- "vertical-start"
880
- ]);
881
- const PROPERTIES = [
882
- "bottom",
883
- "left",
884
- "right",
885
- "top"
886
- ];
887
- const SELECTOR_ALL = `[${ATTRIBUTE_ANCHOR}], [${ATTRIBUTE_CONTENT$1}]`;
888
- const SELECTOR_CONTENT$2 = `[${ATTRIBUTE_CONTENT$1}]`;
889
- if (window._oscarpalmer_oui_floatable == null) {
890
- Object.defineProperty(window, "_oscarpalmer_oui_floatable", {
891
- enumerable: false,
892
- value: {
893
- active: /* @__PURE__ */ new Set(),
894
- mapped: /* @__PURE__ */ new Map(),
895
- order: []
896
- },
897
- writable: false
898
- });
899
- on(document, "keydown", (event) => {
900
- onKeyDown(event);
901
- });
902
- on(document, "click", (event) => {
903
- onClick$1(event);
904
- });
905
- }
906
- let index$2 = 0;
907
- var OuiPopoverElement = class extends HTMLElement {
908
- #floatable;
909
- #focusTrap;
910
- constructor() {
911
- super();
912
- const content = this.querySelector(SELECTOR_CONTENT$1);
913
- const toggle$2 = this.querySelector(SELECTOR_TOGGLE);
914
- if (!(content instanceof HTMLElement)) throw new Error("A oui-popover must have a direct child element with the [oui-popover-content]-attribute");
915
- if (!(toggle$2 instanceof HTMLButtonElement)) throw new Error("A oui-popover must have a direct child element with the [oui-popover-toggle]-attribute and be a button");
916
- content.hidden = true;
917
- content.setAttribute("role", "dialog");
918
- content.setAttribute("aria-modal", "true");
919
- if (isNullableOrWhitespace(content.id)) content.setAttribute("id", `${ATTRIBUTE_ID_PREFIX}_${++index$2}`);
920
- toggle$2.setAttribute("aria-controls", content.id);
921
- toggle$2.setAttribute("aria-haspopup", "dialog");
922
- this.#floatable = new Floatable({
923
- content,
924
- anchor: toggle$2,
925
- defaultPosition: "below-start",
926
- interactive: true,
927
- positionAttribute: "position",
928
- preferAbove: false,
929
- onAfter: (active) => {
930
- if (active) focus(content);
931
- else if (!this.#floatable.ignoreFocus) toggle$2.focus();
932
- }
933
- });
934
- this.#focusTrap = createFocusTrap(content, { noescape: true });
935
- POPOVERS.set(toggle$2, this.#floatable);
936
- POPOVERS.set(content, this.#floatable);
937
- }
938
- close() {
939
- this.hidePopover();
940
- }
941
- connectedCallback() {
942
- this.#floatable.enable();
943
- this.#focusTrap.connect();
944
- }
945
- disconnectedCallback() {
946
- this.#floatable.disable();
947
- this.#focusTrap.disconnect();
948
- }
949
- hidePopover() {
950
- if (this.#floatable.active && this.isConnected) this.#floatable.toggle(false);
951
- }
952
- open() {
953
- this.showPopover();
954
- }
955
- showPopover() {
956
- if (!this.#floatable.active && this.isConnected) this.#floatable.toggle(true);
957
- }
958
- toggle() {
959
- this.togglePopover();
960
- }
961
- togglePopover(options) {
962
- if (typeof options === "boolean") {
963
- if (options === true) this.showPopover();
964
- else this.hidePopover();
965
- return options;
966
- }
967
- if (this.#floatable.active) {
968
- this.hidePopover();
969
- return false;
970
- }
971
- this.showPopover();
972
- return true;
973
- }
974
- };
975
- function focus(content) {
976
- let target = getFocusable(content)[0];
977
- if (!(target instanceof HTMLElement)) target = content;
978
- requestAnimationFrame(() => {
979
- target.focus();
980
- });
981
- }
982
- const ATTRIBUTE_ID_PREFIX = "oui_popover_content_";
983
- const POPOVERS = /* @__PURE__ */ new Map();
984
- const SELECTOR$2 = "oui-popover";
985
- const SELECTOR_CONTENT$1 = `:scope > [${SELECTOR$2}-content]`;
986
- const SELECTOR_TOGGLE = `:scope > [${SELECTOR$2}-toggle]`;
987
- customElements.define(SELECTOR$2, OuiPopoverElement);
988
- function round(value, decimals) {
989
- if (typeof value !== "number") return NaN;
990
- if (typeof decimals !== "number" || decimals < 1) return Math.round(value);
991
- const mod = 10 ** decimals;
992
- return Math.round((value + Number.EPSILON) * mod) / mod;
993
- }
994
- new Set([
995
- Node.ELEMENT_NODE,
996
- Node.TEXT_NODE,
997
- Node.PROCESSING_INSTRUCTION_NODE,
998
- Node.COMMENT_NODE,
999
- Node.DOCUMENT_TYPE_NODE
1000
- ]);
1001
- Object.freeze([
1002
- "async",
1003
- "autofocus",
1004
- "autoplay",
1005
- "checked",
1006
- "controls",
1007
- "default",
1008
- "defer",
1009
- "disabled",
1010
- "formnovalidate",
1011
- "hidden",
1012
- "inert",
1013
- "ismap",
1014
- "itemscope",
1015
- "loop",
1016
- "multiple",
1017
- "muted",
1018
- "nomodule",
1019
- "novalidate",
1020
- "open",
1021
- "playsinline",
1022
- "readonly",
1023
- "required",
1024
- "reversed",
1025
- "selected"
1026
- ]);
1027
- document.createElement("form");
1028
- function setElementValues(element, first, second, third, callback) {
1029
- if (!isHTMLOrSVGElement(element)) return;
1030
- if (typeof first === "string") {
1031
- callback(element, first, second, third);
1032
- return;
1033
- }
1034
- const isArray = Array.isArray(first);
1035
- if (!isArray && !(typeof first === "object" && first !== null)) return;
1036
- const entries = isArray ? first : Object.entries(first).map(([name, value]) => ({
1037
- name,
1038
- value
1039
- }));
1040
- const { length } = entries;
1041
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
1042
- const entry = entries[index$3];
1043
- if (typeof entry === "object" && typeof entry?.name === "string") callback(element, entry.name, entry.value, third);
1044
- }
1045
- }
1046
- function updateElementValue(element, key, value, set, remove, isBoolean, json) {
1047
- if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
1048
- else set.call(element, key, json ? JSON.stringify(value) : String(value));
1049
- }
1050
- function getStyles(element, properties, computed) {
1051
- const styles = {};
1052
- if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
1053
- const { length } = properties;
1054
- for (let index$3 = 0; index$3 < length; index$3 += 1) {
1055
- const property = properties[index$3];
1056
- if (typeof property === "string") styles[property] = getStyleValue(element, property, computed === true);
1057
- }
1058
- return styles;
1059
- }
1060
- function setStyles(element, styles) {
1061
- setElementValues(element, styles, null, null, updateStyleProperty);
1062
- }
1063
- function toggleStyles(element, styles) {
1064
- function toggle$2(set) {
1065
- hasSet = set;
1066
- let next;
1067
- if (set) {
1068
- values = getStyles(element, keys);
1069
- next = styles;
1070
- } else {
1071
- next = { ...values };
1072
- values = {};
1073
- for (const key of keys) values[key] = void 0;
1074
- }
1075
- setStyles(element, next);
1076
- }
1077
- const keys = Object.keys(styles);
1078
- let hasSet = false;
1079
- let values = {};
1080
- return {
1081
- set() {
1082
- if (!hasSet) toggle$2(true);
1083
- },
1084
- remove() {
1085
- if (hasSet) toggle$2(false);
1086
- }
1087
- };
1088
- }
1089
- function updateStyleProperty(element, key, value) {
1090
- updateElementValue(element, key, value, function(property, style) {
1091
- this.style[property] = style;
1092
- }, function(property) {
1093
- this.style[property] = "";
1094
- }, false, false);
1095
- }
1096
- function getSupport() {
1097
- if (window == null || navigator == null) return false;
1098
- if ("matchMedia" in window) {
1099
- const media = matchMedia?.("(pointer: coarse)");
1100
- if (typeof media?.matches === "boolean" && media.matches) return true;
1101
- }
1102
- if ("ontouchstart" in window) return true;
1103
- if (typeof navigator.maxTouchPoints === "number" && navigator.maxTouchPoints > 0) return true;
1104
- if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
1105
- return false;
1106
- }
1107
- var touch_default = (() => {
1108
- let support = getSupport();
1109
- const instance = Object.create({
1110
- get() {
1111
- return support;
1112
- },
1113
- update() {
1114
- support = getSupport();
1115
- return support;
1116
- }
1117
- });
1118
- Object.defineProperty(instance, "value", { get() {
1119
- return support;
1120
- } });
1121
- return instance;
1122
- })();
1123
- var OuiSplitterElement = class extends HTMLElement {
1124
- static observedAttributes = [
1125
- "max",
1126
- "min",
1127
- "size",
1128
- "type"
1129
- ];
1130
- #splitter;
1131
- get max() {
1132
- return this.#splitter.values.max;
1133
- }
1134
- set max(value) {
1135
- this.setAttribute("max", String(value));
1136
- }
1137
- get min() {
1138
- return this.#splitter.values.min;
1139
- }
1140
- set min(value) {
1141
- this.setAttribute("min", String(value));
1142
- }
1143
- get size() {
1144
- return this.#splitter.values.now.current;
1145
- }
1146
- set size(value) {
1147
- this.setAttribute("size", String(value));
1148
- }
1149
- get type() {
1150
- return this.getAttribute("type") ?? "vertical";
1151
- }
1152
- set type(value) {
1153
- this.setAttribute("type", value);
1154
- }
1155
- constructor() {
1156
- super();
1157
- const panels = [...this.children].filter((child) => child instanceof HTMLElement);
1158
- if (panels.length !== 2) throw new Error(`${SELECTOR$1} must have exactly two panels.`);
1159
- this.#splitter = new Splitter(this, panels);
1160
- }
1161
- connectedCallback() {
1162
- this.#splitter.updateConnections(1);
1163
- }
1164
- disconnectedCallback() {
1165
- this.#splitter.updateConnections(0);
1166
- }
1167
- attributeChangedCallback(name) {
1168
- switch (name) {
1169
- case "max":
1170
- case "min":
1171
- case "size":
1172
- this.#splitter.updateValues();
1173
- break;
1174
- case "type":
1175
- this.#splitter.updateOrientation();
1176
- break;
1177
- default: break;
1178
- }
1179
- }
1180
- };
1181
- let index$1 = 0;
1182
- var Splitter = class {
1183
- element;
1184
- handle;
1185
- panels;
1186
- rectangle;
1187
- separator;
1188
- types;
1189
- values;
1190
- constructor(element, panels) {
1191
- this.element = element;
1192
- this.panels = panels;
1193
- if (isNullableOrWhitespace(element.id)) element.id = `oui_splitter_${++index$1}`;
1194
- this.values = getValues(element);
1195
- this.handle = createHandle();
1196
- this.rectangle = element.getBoundingClientRect();
1197
- this.separator = createSeparator(this);
1198
- this.separator.append(this.handle);
1199
- panels[0].insertAdjacentElement("afterend", this.separator);
1200
- this.updateOrientation();
1201
- this.updateValues();
1202
- }
1203
- updateConnections(add) {
1204
- const method = METHODS_CONNECT[add];
1205
- MAPPED_ELEMENTS[method](this.element, this);
1206
- MAPPED_ELEMENTS[method](this.handle, this);
1207
- MAPPED_ELEMENTS[method](this.separator, this);
1208
- if (this.types.auto) RESIZE_OBSERVER[METHODS_OBSERVE[add]](this.element);
1209
- }
1210
- updateOrientation() {
1211
- this.types = getTypes(this);
1212
- if (this.types.auto) RESIZE_OBSERVER.observe(this.element);
1213
- else RESIZE_OBSERVER.unobserve(this.element);
1214
- if (this.types.horizontal) this.element.setAttribute(ATTRIBUTE_HORIZONTAL, "");
1215
- else this.element.removeAttribute(ATTRIBUTE_HORIZONTAL);
1216
- setAriaOrientation(this);
1217
- }
1218
- updateValues() {
1219
- this.values = getValues(this.element);
1220
- requestAnimationFrame(() => {
1221
- setSize(this, this.values.now.current);
1222
- setAriaValue(this);
1223
- });
1224
- }
1225
- };
1226
- function createHandle() {
1227
- const handle = document.createElement("span");
1228
- handle.setAttribute("aria-hidden", "true");
1229
- handle.setAttribute(ATTRIBUTE_HANDLE, "");
1230
- return handle;
1231
- }
1232
- function createSeparator(splitter$1) {
1233
- const separator = document.createElement("div");
1234
- separator.role = "separator";
1235
- separator.tabIndex = 0;
1236
- separator.setAttribute("aria-controls", splitter$1.element.id);
1237
- separator.setAttribute("aria-label", "Resize panels");
1238
- separator.setAttribute(ATTRIBUTE_SEPARATOR, "");
1239
- return separator;
1240
- }
1241
- function getContained(min, value, max) {
1242
- return round(clamp(value, min, max), VALUE_DECIMALS);
1243
- }
1244
- function getSize(splitter$1, value) {
1245
- const { height, left, top, width } = splitter$1.rectangle;
1246
- const fraction = (value - (splitter$1.types.horizontal ? top : left)) / (splitter$1.types.horizontal ? height : width);
1247
- return getContained(splitter$1.values.min, fraction, splitter$1.values.max);
1248
- }
1249
- function getTypes(splitter$1, width, height) {
1250
- const type = splitter$1.element.getAttribute("type")?.trim() ?? "";
1251
- if (type === "horizontal") return {
1252
- auto: false,
1253
- horizontal: true
1254
- };
1255
- if (type === "auto") return {
1256
- auto: true,
1257
- horizontal: (height ?? splitter$1.rectangle.height) > (width ?? splitter$1.rectangle.width)
1258
- };
1259
- return {
1260
- auto: false,
1261
- horizontal: false
1262
- };
1263
- }
1264
- function getValue(element, name, defaultValue) {
1265
- const value = element.getAttribute(name);
1266
- if (isNullableOrWhitespace(value)) return defaultValue;
1267
- const parsed = Number.parseFloat(value);
1268
- if (Number.isNaN(parsed)) return defaultValue;
1269
- if (parsed < 0) return defaultValue;
1270
- return parsed > 1 ? parsed / NAVIGATION_MAXIMUM_TOTAL : parsed;
1271
- }
1272
- function getValues(element) {
1273
- const values = {
1274
- max: getValue(element, "max", NAVIGATION_MAXIMUM_PERCENTAGE),
1275
- min: getValue(element, "min", NAVIGATION_MINIMUM_PERCENTAGE),
1276
- now: {
1277
- current: .5,
1278
- previous: .5
1279
- }
1280
- };
1281
- const value = getContained(values.min, getValue(element, "size", values.now.current), values.max);
1282
- values.now.current = value;
1283
- values.now.previous = value;
1284
- return values;
1285
- }
1286
- function onEnd(reset$1) {
1287
- if (splitter == null) return;
1288
- splitter.handle.removeAttribute(ATTRIBUTE_ACTIVE);
1289
- splitter.separator.removeAttribute(ATTRIBUTE_ACTIVE);
1290
- if (reset$1) setSize(splitter, splitter.values.now.previous);
1291
- else splitter.values.now.previous = splitter.values.now.current;
1292
- splitter = void 0;
1293
- STYLING_TOGGLER.remove();
1294
- }
1295
- function onKeydown(event) {
1296
- switch (true) {
1297
- case KEYS_ALL.has(event.key):
1298
- onNavigate(event);
1299
- break;
1300
- case event.key === "Escape":
1301
- onEnd(true);
1302
- break;
1303
- default: break;
1304
- }
1305
- }
1306
- function onNavigate(event) {
1307
- const splitter$1 = MAPPED_ELEMENTS.get(findAncestor(event.target, "[oui-splitter-separator]"));
1308
- if (splitter$1 == null) return;
1309
- const { types, values } = splitter$1;
1310
- if (KEYS_ABSOLUTE.has(event.key)) {
1311
- setSize(splitter$1, event.key === "End" ? values.max : values.min, true);
1312
- return;
1313
- }
1314
- if (types.horizontal && !KEYS_HORIZONTAL.has(event.key) || !(types.horizontal || KEYS_VERTICAL.has(event.key))) return;
1315
- const offset = KEYS_NEGATIVE.has(event.key) ? -1 : 1;
1316
- setSize(splitter$1, getContained(values.min, values.now.current + offset * NAVIGATION_MODIFIER, values.max), true);
1317
- }
1318
- function onObservation(entries) {
1319
- if (frame != null) cancelAnimationFrame(frame);
1320
- frame = requestAnimationFrame(() => {
1321
- for (const entry of entries) {
1322
- const splitter$1 = MAPPED_ELEMENTS.get(entry.target);
1323
- if (splitter$1 == null) return;
1324
- splitter$1.types = getTypes(splitter$1, entry.contentRect.width, entry.contentRect.height);
1325
- if (splitter$1.types.horizontal) splitter$1.element.setAttribute(ATTRIBUTE_HORIZONTAL, "");
1326
- else splitter$1.element.removeAttribute(ATTRIBUTE_HORIZONTAL);
1327
- setAriaOrientation(splitter$1);
1328
- }
1329
- frame = void 0;
1330
- });
1331
- }
1332
- function onPointerdown(event) {
1333
- if (event.type === "mousedown" && touch_default.value || event.type === "touchstart" && !touch_default.value) return;
1334
- splitter = MAPPED_ELEMENTS.get(findAncestor(event.target, SELECTOR_HANDLE));
1335
- if (splitter == null) return;
1336
- if (touch_default.value) event.preventDefault();
1337
- splitter.handle.setAttribute(ATTRIBUTE_ACTIVE, "");
1338
- splitter.separator.setAttribute(ATTRIBUTE_ACTIVE, "");
1339
- splitter.rectangle = splitter.element.getBoundingClientRect();
1340
- STYLING_TOGGLER.set();
1341
- }
1342
- function onPointermove(event) {
1343
- if (splitter == null) return;
1344
- const position = getPosition(event);
1345
- if (position != null) {
1346
- splitter.values.now.current = getSize(splitter, splitter.types.horizontal ? position.y : position.x);
1347
- setSize(splitter, splitter.values.now.current);
1348
- }
1349
- }
1350
- function onPointerup() {
1351
- if (splitter != null) onEnd(false);
1352
- }
1353
- function setAriaOrientation(splitter$1) {
1354
- splitter$1.separator.setAttribute("aria-orientation", splitter$1.types.horizontal ? "horizontal" : "vertical");
1355
- }
1356
- function setAriaValue(splitter$1) {
1357
- splitter$1.separator.setAttribute("aria-valuemax", String(splitter$1.values.max));
1358
- splitter$1.separator.setAttribute("aria-valuemin", String(splitter$1.values.min));
1359
- splitter$1.separator.setAttribute("aria-valuenow", String(splitter$1.values.now.current));
1360
- }
1361
- function setSize(splitter$1, size, previous) {
1362
- splitter$1.values.now.current = size;
1363
- if (previous) splitter$1.values.now.previous = size;
1364
- splitter$1.element.style.setProperty("--oui-splitter-size", `${size}`);
1365
- setAriaValue(splitter$1);
1366
- }
1367
- const SELECTOR$1 = "oui-splitter";
1368
- const ATTRIBUTE_ACTIVE = `${SELECTOR$1}-active`;
1369
- const ATTRIBUTE_HANDLE = `${SELECTOR$1}-handle`;
1370
- const ATTRIBUTE_HORIZONTAL = `${SELECTOR$1}-horizontal`;
1371
- const ATTRIBUTE_SEPARATOR = `${SELECTOR$1}-separator`;
1372
- const KEYS_ABSOLUTE = new Set(["End", "Home"]);
1373
- const KEYS_HORIZONTAL = new Set(["ArrowDown", "ArrowUp"]);
1374
- const KEYS_NEGATIVE = new Set(["ArrowLeft", "ArrowUp"]);
1375
- const KEYS_VERTICAL = new Set(["ArrowLeft", "ArrowRight"]);
1376
- const KEYS_ALL = new Set([
1377
- ...KEYS_ABSOLUTE,
1378
- ...KEYS_HORIZONTAL,
1379
- ...KEYS_VERTICAL
1380
- ]);
1381
- const MAPPED_ELEMENTS = /* @__PURE__ */ new WeakMap();
1382
- const METHODS_CONNECT = ["delete", "set"];
1383
- const METHODS_OBSERVE = ["unobserve", "observe"];
1384
- const NAVIGATION_MAXIMUM_PERCENTAGE = .9;
1385
- const NAVIGATION_MAXIMUM_TOTAL = 100;
1386
- const NAVIGATION_MINIMUM_PERCENTAGE = .1;
1387
- const NAVIGATION_MODIFIER = .05;
1388
- const RESIZE_OBSERVER = new ResizeObserver(onObservation);
1389
- const SELECTOR_HANDLE = `[${ATTRIBUTE_HANDLE}]`;
1390
- const STYLING_TOGGLER = toggleStyles(document.body, {
1391
- touchAction: "none",
1392
- userSelect: "none",
1393
- webkitUserSelect: "none"
1394
- });
1395
- const VALUE_DECIMALS = 6;
1396
- let frame;
1397
- let splitter;
1398
- customElements.define(SELECTOR$1, OuiSplitterElement);
1399
- on(document, "keydown", onKeydown);
1400
- on(document, "mousedown", onPointerdown);
1401
- on(document, "pointermove", onPointermove);
1402
- on(document, "pointerup", onPointerup);
1403
- on(document, "touchcancel", onPointerup, { passive: false });
1404
- on(document, "touchstart", onPointerdown, { passive: false });
1405
- var Tooltip = class {
1406
- attributes;
1407
- floatable;
1408
- timer;
1409
- constructor(anchor, content) {
1410
- this.attributes = content.attributes;
1411
- this.floatable = new Floatable({
1412
- anchor,
1413
- content: content.element,
1414
- defaultPosition: "vertical",
1415
- interactive: false,
1416
- preferAbove: true,
1417
- positionAttribute: ATTRIBUTE_POSITION
1418
- });
1419
- anchor.insertAdjacentElement("afterend", content.element);
1420
- TOOLTIPS_ALL.set(content.element, this);
1421
- }
1422
- destroy() {
1423
- const { attributes, floatable } = this;
1424
- TOOLTIPS_ACTIVE.delete(this);
1425
- TOOLTIPS_ALL.delete(floatable.options.anchor);
1426
- TOOLTIPS_ALL.delete(floatable.options.content);
1427
- reset(floatable.options.anchor, attributes);
1428
- floatable.options.content.remove();
1429
- floatable.destroy();
1430
- this.attributes = void 0;
1431
- this.floatable = void 0;
1432
- }
1433
- };
1434
- function addTooltip(anchor) {
1435
- if (TOOLTIPS_ALL.has(anchor)) return;
1436
- const content = getContent(anchor);
1437
- if (content != null) TOOLTIPS_ALL.set(anchor, new Tooltip(anchor, content));
1438
- }
1439
- function closeTooltips(next) {
1440
- const tooltips = [...TOOLTIPS_ACTIVE];
1441
- for (const active of tooltips) {
1442
- if (active === next) continue;
1443
- if (active.timer != null) clearTimeout(active.timer);
1444
- active.floatable.options.content.removeAttribute("oui-tooltip-content-active");
1445
- requestAnimationFrame(() => {
1446
- active.timer = setTimeout(() => {
1447
- TOOLTIPS_ACTIVE.delete(active);
1448
- active.floatable.toggle(false);
1449
- }, delay);
1450
- });
1451
- }
1452
- }
1453
- function getContent(anchor) {
1454
- const attributes = {
1455
- ariaDescribedby: anchor.getAttribute("aria-describedby"),
1456
- ariaLabelledBy: anchor.getAttribute("aria-labelledby")
1457
- };
1458
- const wrapper = getWrapper(anchor);
1459
- const labelledElements = getElements(attributes.ariaLabelledBy);
1460
- if (labelledElements.length > 0) {
1461
- anchor.setAttribute("aria-labelledby", wrapper.id);
1462
- for (const element of labelledElements) wrapper.append(element);
1463
- return {
1464
- attributes,
1465
- element: wrapper
1466
- };
1467
- }
1468
- const describedElements = getElements(attributes.ariaDescribedby);
1469
- if (describedElements.length > 0) {
1470
- anchor.setAttribute("aria-describedby", wrapper.id);
1471
- for (const element of describedElements) wrapper.append(element);
1472
- return {
1473
- attributes,
1474
- element: wrapper
1475
- };
1476
- }
1477
- let content = anchor.getAttribute("aria-label");
1478
- if (isNullableOrWhitespace(content)) content = anchor.getAttribute("aria-description");
1479
- if (isNullableOrWhitespace(content)) return;
1480
- const paragraph = document.createElement("p");
1481
- paragraph.textContent = content;
1482
- wrapper.append(paragraph);
1483
- return {
1484
- attributes,
1485
- element: wrapper
1486
- };
1487
- }
1488
- function getElements(attribute) {
1489
- const ids = attribute?.split(EXPRESSION_WHITESPACE) ?? [];
1490
- const elements = [];
1491
- for (const id of ids) {
1492
- if (isNullableOrWhitespace(id)) continue;
1493
- const element = document.querySelector(`#${id}`);
1494
- if (element instanceof HTMLElement) {
1495
- const cloned = element.cloneNode(true);
1496
- cloned.hidden = false;
1497
- elements.push(cloned);
1498
- }
1499
- }
1500
- return elements;
1501
- }
1502
- function getWrapper(anchor) {
1503
- const wrapper = document.createElement("div");
1504
- wrapper.setAttribute(ATTRIBUTE_CONTENT, "");
1505
- wrapper.className = anchor.getAttribute(ATTRIBUTE_CLASS) ?? "";
1506
- wrapper.hidden = true;
1507
- wrapper.id = `${SELECTOR}-${++index}`;
1508
- wrapper.role = "tooltip";
1509
- wrapper.tabIndex = -1;
1510
- return wrapper;
1511
- }
1512
- function onActivate(event) {
1513
- onToggle(event, true);
1514
- }
1515
- function onClick(event) {
1516
- if (findAncestor(event.target, SELECTOR_CONTENT) != null) event.stopPropagation();
1517
- }
1518
- function onDeactivate(event) {
1519
- onToggle(event, false);
1520
- }
1521
- function onToggle(event, activate$1) {
1522
- if (toggle != null) cancelAnimationFrame(toggle);
1523
- toggle = requestAnimationFrame(() => {
1524
- toggle = void 0;
1525
- const element = findAncestor(event.target, SELECTOR_FULL);
1526
- const tooltip = TOOLTIPS_ALL.get(element);
1527
- if (TOOLTIPS_ACTIVE.size > 0) closeTooltips(tooltip);
1528
- if (tooltip == null || tooltip.floatable.options.content.hasAttribute("oui-tooltip-content-active") === activate$1) return;
1529
- if (activate$1) {
1530
- if (tooltip.timer != null) clearTimeout(tooltip.timer);
1531
- TOOLTIPS_ACTIVE.add(tooltip);
1532
- tooltip.floatable.toggle(true);
1533
- requestAnimationFrame(() => {
1534
- tooltip.floatable.options.content.setAttribute("oui-tooltip-content-active", "");
1535
- });
1536
- return;
1537
- }
1538
- tooltip.floatable.options.content.removeAttribute("oui-tooltip-content-active");
1539
- tooltip.timer ??= setTimeout(() => {
1540
- TOOLTIPS_ACTIVE.delete(tooltip);
1541
- tooltip.floatable.toggle(false);
1542
- }, delay);
1543
- });
1544
- }
1545
- function removeTooltip(element) {
1546
- if (!element.hasAttribute(ATTRIBUTE_CONTENT)) TOOLTIPS_ALL.get(element)?.destroy();
1547
- }
1548
- function reset(anchor, attributes) {
1549
- if (attributes.ariaDescribedby == null) anchor.removeAttribute("aria-describedby");
1550
- else anchor.setAttribute("aria-describedby", attributes.ariaDescribedby);
1551
- }
1552
- function setDelay(value) {
1553
- delay = typeof value === "number" && value >= 0 ? value : delay;
1554
- }
1555
- const SELECTOR = "oui-tooltip";
1556
- const ATTRIBUTE_CLASS = `${SELECTOR}-class`;
1557
- const ATTRIBUTE_CONTENT = `${SELECTOR}-content`;
1558
- const ATTRIBUTE_POSITION = `${SELECTOR}-position`;
1559
- const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
1560
- const SELECTOR_FULL = `[${SELECTOR}], [${ATTRIBUTE_CONTENT}]`;
1561
- const EXPRESSION_WHITESPACE = /\s+/;
1562
- const TOOLTIPS_ACTIVE = /* @__PURE__ */ new Set();
1563
- const TOOLTIPS_ALL = /* @__PURE__ */ new WeakMap();
1564
- let delay = 250;
1565
- let index = 0;
1566
- let toggle;
1567
- attributable(SELECTOR, addTooltip, removeTooltip);
1568
- on(document, "click", onClick, { capture: true });
1569
- on(document, "focusin", onActivate);
1570
- on(document, "focusout", onDeactivate);
1571
- on(document, "mousemove", onActivate);
1572
- on(document, "touchstart", onActivate);
1573
- export { OuiPopoverElement, OuiSplitterElement, setDelay };