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