@oscarpalmer/oui 0.17.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 (58) 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/reset.css +176 -56
  6. package/dist/css/tooltip.css +8 -0
  7. package/dist/js/attributable.full.js +48 -0
  8. package/dist/js/attributable.js +30 -45
  9. package/dist/js/floatable.full.js +413 -0
  10. package/dist/js/floatable.js +254 -169
  11. package/dist/js/focus-trap/embedded.full.js +351 -0
  12. package/dist/js/focus-trap/embedded.js +131 -131
  13. package/dist/js/focus-trap/standalone.full.js +402 -0
  14. package/dist/js/focus-trap/standalone.js +4 -4
  15. package/dist/js/index.js +4 -5
  16. package/dist/js/oui.full.js +1596 -0
  17. package/dist/js/popover.full.js +822 -0
  18. package/dist/js/popover.js +83 -162
  19. package/dist/js/splitter.full.js +605 -0
  20. package/dist/js/splitter.js +263 -245
  21. package/dist/js/tooltip.full.js +679 -0
  22. package/dist/js/tooltip.js +159 -150
  23. package/package.json +31 -59
  24. package/src/css/content.scss +1 -2
  25. package/src/css/form.scss +12 -4
  26. package/src/css/message.scss +3 -0
  27. package/src/css/mixins.scss +7 -0
  28. package/src/css/reset.scss +180 -54
  29. package/src/css/tooltip.scss +8 -0
  30. package/src/js/floatable.ts +380 -133
  31. package/src/js/focus-trap/embedded.ts +149 -64
  32. package/src/js/focus-trap/standalone.ts +4 -4
  33. package/src/js/index.ts +1 -0
  34. package/src/js/popover.ts +50 -120
  35. package/src/js/splitter.ts +250 -103
  36. package/src/js/tooltip.ts +155 -68
  37. package/types/floatable.d.ts +17 -10
  38. package/types/focus-trap/embedded.d.ts +18 -5
  39. package/types/index.d.ts +1 -0
  40. package/types/popover.d.ts +2 -0
  41. package/types/splitter.d.ts +13 -1
  42. package/types/tooltip.d.ts +2 -1
  43. package/dist/js/attributable.cjs +0 -51
  44. package/dist/js/floatable.cjs +0 -176
  45. package/dist/js/focus-trap/embedded.cjs +0 -150
  46. package/dist/js/focus-trap/standalone.cjs +0 -8
  47. package/dist/js/index.cjs +0 -6
  48. package/dist/js/popover.cjs +0 -166
  49. package/dist/js/splitter.cjs +0 -272
  50. package/dist/js/tooltip.cjs +0 -166
  51. package/types/attributable.d.cts +0 -5
  52. package/types/floatable.d.cts +0 -20
  53. package/types/focus-trap/embedded.d.cts +0 -15
  54. package/types/focus-trap/standalone.d.cts +0 -3
  55. package/types/index.d.cts +0 -14
  56. package/types/popover.d.cts +0 -14
  57. package/types/splitter.d.cts +0 -10
  58. package/types/tooltip.d.cts +0 -3
@@ -0,0 +1,351 @@
1
+ function isNumber(value) {
2
+ return typeof value === "number" && !Number.isNaN(value);
3
+ }
4
+
5
+ function clamp(value, minimum, maximum, loop) {
6
+ if (![
7
+ value,
8
+ minimum,
9
+ maximum
10
+ ].every(isNumber)) return NaN;
11
+ if (value < minimum) return maximum ;
12
+ return value > maximum ? minimum : value;
13
+ }
14
+
15
+ function isEventTarget(value) {
16
+ return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
17
+ }
18
+
19
+ function getBoolean(value, defaultValue) {
20
+ return typeof value === "boolean" ? value : defaultValue ?? false;
21
+ }
22
+
23
+ function calculate() {
24
+ return new Promise((resolve) => {
25
+ const values = [];
26
+ let last;
27
+ function step(now) {
28
+ if (last != null) values.push(now - last);
29
+ last = now;
30
+ if (values.length >= CALCULATION_TOTAL) {
31
+ const median = values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM);
32
+ resolve(median);
33
+ } else requestAnimationFrame(step);
34
+ }
35
+ requestAnimationFrame(step);
36
+ });
37
+ }
38
+ function noop() {}
39
+ var CALCULATION_TOTAL = 10;
40
+ var CALCULATION_TRIM = 4;
41
+ calculate().then((value) => {
42
+ });
43
+
44
+ function createEventOptions(options) {
45
+ return {
46
+ capture: getBoolean(options?.capture),
47
+ once: getBoolean(options?.once),
48
+ passive: getBoolean(options?.passive, true),
49
+ signal: options?.signal
50
+ };
51
+ }
52
+ function on(target, type, listener, options) {
53
+ if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
54
+ const extended = createEventOptions(options);
55
+ target.addEventListener(type, listener, extended);
56
+ return () => {
57
+ target.removeEventListener(type, listener, extended);
58
+ };
59
+ }
60
+
61
+ function findAncestor(origin, selector) {
62
+ if (!(origin instanceof Element) || selector == null) return null;
63
+ if (typeof selector === "string") {
64
+ if (origin.matches?.(selector)) return origin;
65
+ return origin.closest(selector);
66
+ }
67
+ if (typeof selector !== "function") return null;
68
+ if (selector(origin)) return origin;
69
+ let parent = origin.parentElement;
70
+ while (parent != null && !selector(parent)) {
71
+ if (parent === document.body) return null;
72
+ parent = parent.parentElement;
73
+ }
74
+ return parent;
75
+ }
76
+
77
+ function getFocusable(parent) {
78
+ return getValidElements(parent, FILTERS_FOCUSABLE);
79
+ }
80
+ function getItem(element, tabbable) {
81
+ return {
82
+ element,
83
+ tabIndex: TABINDEX_DEFAULT
84
+ };
85
+ }
86
+ function getValidElements(parent, filters, tabbable) {
87
+ if (!(parent instanceof Element)) return [];
88
+ const elements = [...parent.querySelectorAll(SELECTOR_FULL)];
89
+ const items = [];
90
+ let { length } = elements;
91
+ for (let index = 0; index < length; index += 1) {
92
+ const item = getItem(elements[index]);
93
+ if (!filters.some((filter) => filter(item))) items.push(item);
94
+ }
95
+ return items.map((item) => item.element);
96
+ }
97
+ function isDisabled(item) {
98
+ if (EXPRESSION_DISABLEABLE.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
99
+ return item.element.disabled ?? false;
100
+ }
101
+ function isDisabledFromFieldset(element) {
102
+ let parent = element.parentElement;
103
+ while (parent != null) {
104
+ if (parent instanceof HTMLFieldSetElement && parent.disabled) {
105
+ const children = Array.from(parent.children);
106
+ const { length } = children;
107
+ for (let index = 0; index < length; index += 1) {
108
+ const child = children[index];
109
+ if (child instanceof HTMLLegendElement) return parent.matches(SELECTOR_FIELDSET_DISABLED) || !child.contains(element);
110
+ }
111
+ return true;
112
+ }
113
+ parent = parent.parentElement;
114
+ }
115
+ return false;
116
+ }
117
+ function isHidden(item) {
118
+ if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === STYLE_HIDDEN) return true;
119
+ if ((item.element.matches(SELECTOR_SUMMARY_FIRST) ? item.element.parentElement : item.element)?.matches(SELECTOR_DETAILS_CLOSED_CHILDREN) ?? false) return true;
120
+ const style = getComputedStyle(item.element);
121
+ if (style.display === STYLE_NONE || style.visibility === STYLE_HIDDEN) return true;
122
+ const { height, width } = item.element.getBoundingClientRect();
123
+ return height === 0 && width === 0;
124
+ }
125
+ function isInert(item) {
126
+ return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
127
+ element: item.element.parentElement});
128
+ }
129
+ function isSummarised(item) {
130
+ return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
131
+ }
132
+ var ATTRIBUTE_INERT = "inert";
133
+ var EXPRESSION_DISABLEABLE = /^(button|input|select|textarea)$/i;
134
+ var EXPRESSION_SUMMARY = /^summary$/i;
135
+ var EXPRESSION_TRUEISH = /^(|true)$/i;
136
+ var FILTERS_FOCUSABLE = [
137
+ isDisabled,
138
+ isInert,
139
+ isHidden,
140
+ isSummarised
141
+ ];
142
+ var SELECTOR_DETAILS_CLOSED_CHILDREN = "details:not([open]) *";
143
+ var SELECTOR_FIELDSET_DISABLED = "fieldset[disabled] *";
144
+ var SELECTOR_SUMMARY_FIRST = "details > summary:first-of-type";
145
+ var SELECTOR_FULL = [
146
+ "[contenteditable]:not([contenteditable=\"false\"])",
147
+ "[tabindex]:not(slot)",
148
+ "a[href]",
149
+ "audio[controls]",
150
+ "button",
151
+ "details",
152
+ SELECTOR_SUMMARY_FIRST,
153
+ "input",
154
+ "select",
155
+ "textarea",
156
+ "video[controls]"
157
+ ].map((selector) => `${selector}:not([inert])`).join(",");
158
+ var STYLE_HIDDEN = "hidden";
159
+ var STYLE_NONE = "none";
160
+ var TABINDEX_DEFAULT = -1;
161
+
162
+ class FocusTrap {
163
+ disabled = false;
164
+ connected = true;
165
+ element;
166
+ embedded;
167
+ get contain() {
168
+ return this.element.hasAttribute(FOCUS_TRAP_CONTAIN);
169
+ }
170
+ get noescape() {
171
+ return this.element.hasAttribute(FOCUS_TRAP_NOESCAPE);
172
+ }
173
+ constructor(element, options) {
174
+ this.element = element;
175
+ this.embedded = options != null;
176
+ element.setAttribute('tabindex', '-1');
177
+ if (options != null) {
178
+ element.setAttribute(FOCUS_TRAP_SELECTOR, '');
179
+ }
180
+ if (options?.noescape) {
181
+ element.setAttribute(FOCUS_TRAP_NOESCAPE, '');
182
+ }
183
+ }
184
+ connect() {
185
+ setConnected(this, true);
186
+ }
187
+ destroy() {
188
+ this.element = undefined;
189
+ }
190
+ disable() {
191
+ if (!(this.disabled || this.noescape)) {
192
+ setDisabled(this, true);
193
+ }
194
+ }
195
+ disconnect() {
196
+ setConnected(this, false);
197
+ }
198
+ enable() {
199
+ if (this.disabled) {
200
+ setDisabled(this, false);
201
+ }
202
+ }
203
+ focus(last) {
204
+ tabToTrap(this, getFocusable(this.element), this.element, last ? -1 : 0);
205
+ }
206
+ }
207
+ //
208
+ function createFocusTrap(element, options) {
209
+ let focusTrap = FOCUSTRAPS_ALL.get(element);
210
+ if (focusTrap == null) {
211
+ focusTrap = new FocusTrap(element, options);
212
+ FOCUSTRAPS_ALL.set(element, focusTrap);
213
+ }
214
+ return focusTrap;
215
+ }
216
+ function onEscape(event) {
217
+ let element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
218
+ let focusTrap = FOCUSTRAPS_ALL.get(element);
219
+ if (element == null || focusTrap == null) {
220
+ return;
221
+ }
222
+ while (focusTrap.disabled) {
223
+ element = findAncestor(focusTrap.element.parentElement, ATTRIBUTE_SELECTOR);
224
+ focusTrap = FOCUSTRAPS_ALL.get(element);
225
+ if (element == null || focusTrap == null) {
226
+ return;
227
+ }
228
+ if (!focusTrap.disabled) {
229
+ break;
230
+ }
231
+ }
232
+ focusTrap?.disable();
233
+ }
234
+ function onFocusIn(event) {
235
+ const focusTrap = FOCUSTRAPS_ALL.get(findAncestor(event.target, ATTRIBUTE_SELECTOR));
236
+ lastTarget = focusTrap == null ? undefined : event.target;
237
+ }
238
+ function onKeydown(event) {
239
+ switch (event.key) {
240
+ case 'Escape':
241
+ onEscape(event);
242
+ break;
243
+ case 'Tab':
244
+ onTab(event);
245
+ break;
246
+ default:
247
+ return;
248
+ }
249
+ }
250
+ function onPointerdown(event) {
251
+ const lastFocusTrap = findAncestor(lastTarget, ATTRIBUTE_SELECTOR);
252
+ const nextFocusTrap = findAncestor(event.target, ATTRIBUTE_SELECTOR);
253
+ if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
254
+ if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
255
+ event.preventDefault();
256
+ lastTarget?.focus();
257
+ }
258
+ }
259
+ if (FOCUSTRAPS_DISABLED.size === 0) {
260
+ return;
261
+ }
262
+ for (const focusTrap of FOCUSTRAPS_DISABLED) {
263
+ if (focusTrap.element !== nextFocusTrap) {
264
+ focusTrap.enable();
265
+ }
266
+ }
267
+ }
268
+ function onTab(event) {
269
+ const element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
270
+ const focusTrap = FOCUSTRAPS_ALL.get(element);
271
+ if (focusTrap == null) {
272
+ return;
273
+ }
274
+ if (!focusTrap.disabled) {
275
+ event.preventDefault();
276
+ }
277
+ const elements = getFocusable(element);
278
+ const index = elements.indexOf(event.target);
279
+ if (index === -1 || elements.length === 0) {
280
+ tabToTrap(focusTrap, elements, element);
281
+ }
282
+ else {
283
+ tabToElement(focusTrap, elements, index, event.shiftKey ? -1 : 1);
284
+ }
285
+ }
286
+ function setConnected(focusTrap, value) {
287
+ if (!focusTrap.embedded || focusTrap.connected === value) {
288
+ return;
289
+ }
290
+ focusTrap.connected = value;
291
+ }
292
+ function setDisabled(focusTrap, value) {
293
+ focusTrap.disabled = value;
294
+ if (value) {
295
+ FOCUSTRAPS_DISABLED.add(focusTrap);
296
+ }
297
+ else {
298
+ FOCUSTRAPS_DISABLED.delete(focusTrap);
299
+ }
300
+ }
301
+ function tabToElement(focusTrap, elements, index, modifier) {
302
+ const { length } = elements;
303
+ const next = clamp(index + modifier, 0, length - 1);
304
+ if (focusTrap.disabled) {
305
+ if ((index === length - 1 && next === 0) ||
306
+ (index === 0 && next === length - 1)) {
307
+ lastTarget = undefined;
308
+ focusTrap.enable();
309
+ }
310
+ return;
311
+ }
312
+ const element = elements[next];
313
+ const elementFocusTrap = FOCUSTRAPS_ALL.get(element);
314
+ if (elementFocusTrap != null) {
315
+ elementFocusTrap.focus(modifier === -1);
316
+ }
317
+ else {
318
+ elements[next].focus();
319
+ lastTarget = elements[next];
320
+ }
321
+ }
322
+ function tabToTrap(focusTrap, elements, element, index) {
323
+ if (focusTrap.disabled) {
324
+ lastTarget = undefined;
325
+ focusTrap.enable();
326
+ }
327
+ else {
328
+ const next = elements.length === 0 ? element : elements.at(index ?? 0);
329
+ next.focus();
330
+ lastTarget = next;
331
+ }
332
+ }
333
+ //
334
+ const FOCUS_TRAP_SELECTOR = 'oui-focus-trap';
335
+ const ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
336
+ const EVENT_OPTIONS = {
337
+ capture: true,
338
+ passive: false,
339
+ };
340
+ const FOCUS_TRAP_CONTAIN = `${FOCUS_TRAP_SELECTOR}-contain`;
341
+ const FOCUS_TRAP_NOESCAPE = `${FOCUS_TRAP_SELECTOR}-noescape`;
342
+ const FOCUSTRAPS_ALL = new WeakMap();
343
+ const FOCUSTRAPS_DISABLED = new Set();
344
+ let lastTarget;
345
+ //
346
+ on(document, 'focusin', onFocusIn, EVENT_OPTIONS);
347
+ on(document, 'keydown', onKeydown, EVENT_OPTIONS);
348
+ on(document, 'mousedown', onPointerdown, EVENT_OPTIONS);
349
+ on(document, 'touchstart', onPointerdown, EVENT_OPTIONS);
350
+
351
+ export { FOCUSTRAPS_ALL, FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap };
@@ -1,150 +1,150 @@
1
- import { clamp } from "@oscarpalmer/atoms/number";
2
1
  import { on } from "@oscarpalmer/toretto/event";
3
2
  import { findAncestor } from "@oscarpalmer/toretto/find";
3
+ import { clamp } from "@oscarpalmer/atoms/number";
4
4
  import { getFocusable } from "@oscarpalmer/toretto/focusable";
5
- class FocusTrap {
6
- constructor(element) {
7
- this.element = element;
8
- element.setAttribute("aria-modal", "true");
9
- element.setAttribute("tabindex", "-1");
10
- }
11
- active = true;
12
- destroy() {
13
- this.element = void 0;
14
- }
15
- disable() {
16
- if (this.active && !this.element.hasAttribute(`${selector}-noescape`)) {
17
- setDisabled(this, true);
18
- }
19
- }
20
- enable() {
21
- if (!this.active) {
22
- setDisabled(this, false);
23
- }
24
- }
25
- }
26
- function createFocusTrap(element) {
27
- let focusTrap = focusTraps.get(element);
28
- if (focusTrap == null) {
29
- focusTrap = new FocusTrap(element);
30
- focusTraps.set(element, focusTrap);
31
- }
32
- return focusTrap;
5
+ var FocusTrap = class {
6
+ disabled = false;
7
+ connected = true;
8
+ element;
9
+ embedded;
10
+ get contain() {
11
+ return this.element.hasAttribute(FOCUS_TRAP_CONTAIN);
12
+ }
13
+ get noescape() {
14
+ return this.element.hasAttribute(FOCUS_TRAP_NOESCAPE);
15
+ }
16
+ constructor(element, options) {
17
+ this.element = element;
18
+ this.embedded = options != null;
19
+ element.setAttribute("tabindex", "-1");
20
+ if (options != null) element.setAttribute(FOCUS_TRAP_SELECTOR, "");
21
+ if (options?.noescape) element.setAttribute(FOCUS_TRAP_NOESCAPE, "");
22
+ }
23
+ connect() {
24
+ setConnected(this, true);
25
+ }
26
+ destroy() {
27
+ this.element = void 0;
28
+ }
29
+ disable() {
30
+ if (!(this.disabled || this.noescape)) setDisabled(this, true);
31
+ }
32
+ disconnect() {
33
+ setConnected(this, false);
34
+ }
35
+ enable() {
36
+ if (this.disabled) setDisabled(this, false);
37
+ }
38
+ focus(last) {
39
+ tabToTrap(this, getFocusable(this.element), this.element, last ? -1 : 0);
40
+ }
41
+ };
42
+ function createFocusTrap(element, options) {
43
+ let focusTrap = FOCUSTRAPS_ALL.get(element);
44
+ if (focusTrap == null) {
45
+ focusTrap = new FocusTrap(element, options);
46
+ FOCUSTRAPS_ALL.set(element, focusTrap);
47
+ }
48
+ return focusTrap;
33
49
  }
34
50
  function onEscape(event) {
35
- focusTraps.get(
36
- findAncestor(event.target, `[${selector}]`)
37
- )?.disable();
51
+ let element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
52
+ let focusTrap = FOCUSTRAPS_ALL.get(element);
53
+ if (element == null || focusTrap == null) return;
54
+ while (focusTrap.disabled) {
55
+ element = findAncestor(focusTrap.element.parentElement, ATTRIBUTE_SELECTOR);
56
+ focusTrap = FOCUSTRAPS_ALL.get(element);
57
+ if (element == null || focusTrap == null) return;
58
+ if (!focusTrap.disabled) break;
59
+ }
60
+ focusTrap?.disable();
38
61
  }
39
62
  function onFocusIn(event) {
40
- lastTarget = findAncestor(event.target, `[${selector}]`) == null ? void 0 : event.target;
63
+ lastTarget = FOCUSTRAPS_ALL.get(findAncestor(event.target, ATTRIBUTE_SELECTOR)) == null ? void 0 : event.target;
41
64
  }
42
65
  function onKeydown(event) {
43
- switch (event.key) {
44
- case "Escape":
45
- onEscape(event);
46
- break;
47
- case "Tab":
48
- onTab(event);
49
- break;
50
- default:
51
- return;
52
- }
66
+ switch (event.key) {
67
+ case "Escape":
68
+ onEscape(event);
69
+ break;
70
+ case "Tab":
71
+ onTab(event);
72
+ break;
73
+ default: return;
74
+ }
53
75
  }
54
76
  function onPointerdown(event) {
55
- const lastFocusTrap = findAncestor(
56
- lastTarget,
57
- `[${selector}]`
58
- );
59
- const nextFocusTrap = findAncestor(
60
- event.target,
61
- `[${selector}]`
62
- );
63
- if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
64
- event.preventDefault();
65
- lastTarget?.focus();
66
- }
67
- if (disabled.size === 0) {
68
- return;
69
- }
70
- for (const focusTrap of disabled) {
71
- if (focusTrap.element !== nextFocusTrap) {
72
- focusTrap.enable();
73
- return;
74
- }
75
- }
77
+ const lastFocusTrap = findAncestor(lastTarget, ATTRIBUTE_SELECTOR);
78
+ const nextFocusTrap = findAncestor(event.target, ATTRIBUTE_SELECTOR);
79
+ if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
80
+ if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
81
+ event.preventDefault();
82
+ lastTarget?.focus();
83
+ }
84
+ }
85
+ if (FOCUSTRAPS_DISABLED.size === 0) return;
86
+ for (const focusTrap of FOCUSTRAPS_DISABLED) if (focusTrap.element !== nextFocusTrap) focusTrap.enable();
76
87
  }
77
88
  function onTab(event) {
78
- const element = findAncestor(
79
- event.target,
80
- `[${selector}]`
81
- );
82
- const focusTrap = focusTraps.get(element);
83
- if (focusTrap == null) {
84
- return;
85
- }
86
- if (focusTrap.active) {
87
- event.preventDefault();
88
- }
89
- const elements = getFocusable(element);
90
- const index = elements.indexOf(event.target);
91
- if (index === -1 || elements.length === 0) {
92
- tabToTrap(focusTrap, elements, element);
93
- } else {
94
- tabToElement(event, focusTrap, elements, index);
95
- }
89
+ const element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
90
+ const focusTrap = FOCUSTRAPS_ALL.get(element);
91
+ if (focusTrap == null) return;
92
+ if (!focusTrap.disabled) event.preventDefault();
93
+ const elements = getFocusable(element);
94
+ const index = elements.indexOf(event.target);
95
+ if (index === -1 || elements.length === 0) tabToTrap(focusTrap, elements, element);
96
+ else tabToElement(focusTrap, elements, index, event.shiftKey ? -1 : 1);
97
+ }
98
+ function setConnected(focusTrap, value) {
99
+ if (!focusTrap.embedded || focusTrap.connected === value) return;
100
+ focusTrap.connected = value;
96
101
  }
97
102
  function setDisabled(focusTrap, value) {
98
- focusTrap.element.setAttribute("aria-modal", String(!value));
99
- focusTrap.active = !value;
100
- if (value) {
101
- disabled.add(focusTrap);
102
- } else {
103
- disabled.delete(focusTrap);
104
- }
103
+ focusTrap.disabled = value;
104
+ if (value) FOCUSTRAPS_DISABLED.add(focusTrap);
105
+ else FOCUSTRAPS_DISABLED.delete(focusTrap);
105
106
  }
106
- function tabToElement(event, focusTrap, elements, index) {
107
- const next = clamp(
108
- index + (event.shiftKey ? -1 : 1),
109
- 0,
110
- elements.length - 1,
111
- true
112
- );
113
- if (!focusTrap.active) {
114
- if (index === length - 1 && next === 0 || index === 0 && next === length - 1) {
115
- lastTarget = void 0;
116
- focusTrap.enable();
117
- }
118
- return;
119
- }
120
- elements[next].focus();
121
- lastTarget = elements[next];
107
+ function tabToElement(focusTrap, elements, index, modifier) {
108
+ const { length } = elements;
109
+ const next = clamp(index + modifier, 0, length - 1, true);
110
+ if (focusTrap.disabled) {
111
+ if (index === length - 1 && next === 0 || index === 0 && next === length - 1) {
112
+ lastTarget = void 0;
113
+ focusTrap.enable();
114
+ }
115
+ return;
116
+ }
117
+ const element = elements[next];
118
+ const elementFocusTrap = FOCUSTRAPS_ALL.get(element);
119
+ if (elementFocusTrap != null) elementFocusTrap.focus(modifier === -1);
120
+ else {
121
+ elements[next].focus();
122
+ lastTarget = elements[next];
123
+ }
122
124
  }
123
- function tabToTrap(focusTrap, elements, element) {
124
- if (focusTrap.active) {
125
- const next = length === 0 ? element : elements[0];
126
- next.focus();
127
- lastTarget = next;
128
- } else {
129
- lastTarget = void 0;
130
- focusTrap.enable();
131
- }
125
+ function tabToTrap(focusTrap, elements, element, index) {
126
+ if (focusTrap.disabled) {
127
+ lastTarget = void 0;
128
+ focusTrap.enable();
129
+ } else {
130
+ const next = elements.length === 0 ? element : elements.at(index ?? 0);
131
+ next.focus();
132
+ lastTarget = next;
133
+ }
132
134
  }
133
- const disabled = /* @__PURE__ */ new Set();
134
- const eventOptions = {
135
- capture: true,
136
- passive: false
137
- };
138
- const focusTraps = /* @__PURE__ */ new WeakMap();
139
- let lastTarget;
140
- const selector = "oui-focus-trap";
141
- on(document, "focusin", onFocusIn, eventOptions);
142
- on(document, "keydown", onKeydown, eventOptions);
143
- on(document, "mousedown", onPointerdown, eventOptions);
144
- on(document, "touchstart", onPointerdown, eventOptions);
145
- export {
146
- FocusTrap,
147
- createFocusTrap,
148
- focusTraps,
149
- selector
135
+ const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
136
+ var ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
137
+ var EVENT_OPTIONS = {
138
+ capture: true,
139
+ passive: false
150
140
  };
141
+ const FOCUS_TRAP_CONTAIN = `${FOCUS_TRAP_SELECTOR}-contain`;
142
+ const FOCUS_TRAP_NOESCAPE = `${FOCUS_TRAP_SELECTOR}-noescape`;
143
+ const FOCUSTRAPS_ALL = /* @__PURE__ */ new WeakMap();
144
+ var FOCUSTRAPS_DISABLED = /* @__PURE__ */ new Set();
145
+ var lastTarget;
146
+ on(document, "focusin", onFocusIn, EVENT_OPTIONS);
147
+ on(document, "keydown", onKeydown, EVENT_OPTIONS);
148
+ on(document, "mousedown", onPointerdown, EVENT_OPTIONS);
149
+ on(document, "touchstart", onPointerdown, EVENT_OPTIONS);
150
+ export { FOCUSTRAPS_ALL, FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap };