@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,408 +0,0 @@
1
- function isNumber(value) {
2
- return typeof value === "number" && !Number.isNaN(value);
3
- }
4
- function clamp(value, minimum, maximum, loop) {
5
- if (![
6
- value,
7
- minimum,
8
- maximum
9
- ].every(isNumber)) return NaN;
10
- if (value < minimum) return loop === true ? maximum : minimum;
11
- return value > maximum ? loop === true ? minimum : maximum : value;
12
- }
13
- function noop() {}
14
- function calculate() {
15
- return new Promise((resolve) => {
16
- const values = [];
17
- let last;
18
- function step(now) {
19
- if (last != null) values.push(now - last);
20
- last = now;
21
- if (values.length >= TOTAL) resolve(values.sort().slice(TRIM_PART, -TRIM_PART).reduce((first, second) => first + second, 0) / (values.length - TRIM_TOTAL));
22
- else requestAnimationFrame(step);
23
- }
24
- requestAnimationFrame(step);
25
- });
26
- }
27
- var TOTAL = 10;
28
- var TRIM_PART = 2;
29
- var TRIM_TOTAL = 4;
30
- await calculate();
31
- function getBoolean(value, defaultValue) {
32
- return typeof value === "boolean" ? value : defaultValue ?? false;
33
- }
34
- function isEventTarget(value) {
35
- return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
36
- }
37
- function addDelegatedHandler(doc, type, name, passive) {
38
- if (DELEGATED.has(name)) return;
39
- DELEGATED.add(name);
40
- doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
41
- }
42
- function addDelegatedListener(target, type, name, listener, passive) {
43
- target[name] ??= /* @__PURE__ */ new Set();
44
- target[name].add(listener);
45
- addDelegatedHandler(document, type, name, passive);
46
- return () => {
47
- removeDelegatedListener(target, name, listener);
48
- };
49
- }
50
- function delegatedEventHandler(event) {
51
- const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
52
- const items = event.composedPath();
53
- const { length } = items;
54
- let target = items[0];
55
- Object.defineProperties(event, {
56
- currentTarget: {
57
- configurable: true,
58
- get() {
59
- return target;
60
- }
61
- },
62
- target: {
63
- configurable: true,
64
- value: target
65
- }
66
- });
67
- for (let index = 0; index < length; index += 1) {
68
- const item = items[index];
69
- const listeners = item[key];
70
- if (item.disabled || listeners == null) continue;
71
- target = item;
72
- for (const listener of listeners) {
73
- listener.call(item, event);
74
- if (event.cancelBubble) return;
75
- }
76
- }
77
- }
78
- function getDelegatedName(target, type, options) {
79
- 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}`;
80
- }
81
- function removeDelegatedListener(target, name, listener) {
82
- const handlers = target[name];
83
- if (handlers == null || !handlers.has(listener)) return false;
84
- handlers.delete(listener);
85
- if (handlers.size === 0) target[name] = void 0;
86
- return true;
87
- }
88
- var DELEGATED = /* @__PURE__ */ new Set();
89
- var EVENT_PREFIX = "@";
90
- var EVENT_SUFFIX_ACTIVE = ":active";
91
- var EVENT_SUFFIX_PASSIVE = ":passive";
92
- var EVENT_TYPES = new Set([
93
- "beforeinput",
94
- "click",
95
- "dblclick",
96
- "contextmenu",
97
- "focusin",
98
- "focusout",
99
- "input",
100
- "keydown",
101
- "keyup",
102
- "mousedown",
103
- "mousemove",
104
- "mouseout",
105
- "mouseover",
106
- "mouseup",
107
- "pointerdown",
108
- "pointermove",
109
- "pointerout",
110
- "pointerover",
111
- "pointerup",
112
- "touchend",
113
- "touchmove",
114
- "touchstart"
115
- ]);
116
- var HANDLER_ACTIVE = delegatedEventHandler.bind(false);
117
- var HANDLER_PASSIVE = delegatedEventHandler.bind(true);
118
- function createEventOptions(options) {
119
- return {
120
- capture: getBoolean(options?.capture),
121
- once: getBoolean(options?.once),
122
- passive: getBoolean(options?.passive, true),
123
- signal: options?.signal instanceof AbortSignal ? options.signal : void 0
124
- };
125
- }
126
- function on(target, type, listener, options) {
127
- if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
128
- const extended = createEventOptions(options);
129
- const delegated = getDelegatedName(target, type, extended);
130
- if (delegated != null) return addDelegatedListener(target, type, delegated, listener, extended.passive);
131
- target.addEventListener(type, listener, extended);
132
- if (extended.once) return noop;
133
- return () => {
134
- target.removeEventListener(type, listener, extended);
135
- };
136
- }
137
- function findAncestor(origin, selector) {
138
- if (!(origin instanceof Element) || selector == null) return null;
139
- if (typeof selector === "string") {
140
- if (origin.matches?.(selector)) return origin;
141
- return origin.closest(selector);
142
- }
143
- if (typeof selector !== "function") return null;
144
- if (selector(origin)) return origin;
145
- let parent = origin.parentElement;
146
- while (parent != null && !selector(parent)) {
147
- if (parent === document.body) return null;
148
- parent = parent.parentElement;
149
- }
150
- return parent;
151
- }
152
- function getFocusable(parent) {
153
- return getValidElements(parent, FILTERS_FOCUSABLE, false);
154
- }
155
- function getItem(element, tabbable) {
156
- return {
157
- element,
158
- tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
159
- };
160
- }
161
- function getTabIndex(element) {
162
- const tabIndex = element?.tabIndex ?? TABINDEX_DEFAULT;
163
- if (tabIndex < TABINDEX_BASE && (EXPRESSION_SPECIAL_TABINDEX.test(element.tagName) || isEditable(element)) && !hasTabIndex(element)) return TABINDEX_BASE;
164
- return tabIndex;
165
- }
166
- function getValidElements(parent, filters, tabbable) {
167
- if (!(parent instanceof Element)) return [];
168
- const elements = [...parent.querySelectorAll(SELECTOR_FULL)];
169
- const items = [];
170
- let { length } = elements;
171
- for (let index = 0; index < length; index += 1) {
172
- const item = getItem(elements[index], tabbable);
173
- if (!filters.some((filter) => filter(item))) items.push(item);
174
- }
175
- if (!tabbable) return items.map((item) => item.element);
176
- const indiced = [];
177
- const zeroed = [];
178
- length = items.length;
179
- for (let index = 0; index < length; index += 1) {
180
- const item = items[index];
181
- if (item.tabIndex === TABINDEX_BASE) zeroed.push(item.element);
182
- else indiced[item.tabIndex] = [...indiced[item.tabIndex] ?? [], item.element];
183
- }
184
- return [...indiced.flat(), ...zeroed];
185
- }
186
- function hasTabIndex(element) {
187
- return !Number.isNaN(Number.parseInt(element.getAttribute(ATTRIBUTE_TABINDEX), 10));
188
- }
189
- function isDisabled(item) {
190
- if (EXPRESSION_DISABLEABLE.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
191
- return item.element.disabled ?? false;
192
- }
193
- function isDisabledFromFieldset(element) {
194
- let parent = element.parentElement;
195
- while (parent != null) {
196
- if (parent instanceof HTMLFieldSetElement && parent.disabled) {
197
- const children = Array.from(parent.children);
198
- const { length } = children;
199
- for (let index = 0; index < length; index += 1) {
200
- const child = children[index];
201
- if (child instanceof HTMLLegendElement) return parent.matches(SELECTOR_FIELDSET_DISABLED) || !child.contains(element);
202
- }
203
- return true;
204
- }
205
- parent = parent.parentElement;
206
- }
207
- return false;
208
- }
209
- function isEditable(element) {
210
- return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
211
- }
212
- function isHidden(item) {
213
- if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === STYLE_HIDDEN) return true;
214
- if ((item.element.matches(SELECTOR_SUMMARY_FIRST) ? item.element.parentElement : item.element)?.matches(SELECTOR_DETAILS_CLOSED_CHILDREN) ?? false) return true;
215
- const style = getComputedStyle(item.element);
216
- if (style.display === STYLE_NONE || style.visibility === STYLE_HIDDEN) return true;
217
- const { height, width } = item.element.getBoundingClientRect();
218
- return height === 0 && width === 0;
219
- }
220
- function isInert(item) {
221
- return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
222
- element: item.element.parentElement,
223
- tabIndex: TABINDEX_DEFAULT
224
- });
225
- }
226
- function isSummarised(item) {
227
- return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
228
- }
229
- var ATTRIBUTE_CONTENTEDITABLE = "contenteditable";
230
- var ATTRIBUTE_INERT = "inert";
231
- var ATTRIBUTE_TABINDEX = "tabindex";
232
- var EXPRESSION_DISABLEABLE = /^(button|input|select|textarea)$/i;
233
- var EXPRESSION_SPECIAL_TABINDEX = /^(audio|details|video)$/i;
234
- var EXPRESSION_SUMMARY = /^summary$/i;
235
- var EXPRESSION_TRUEISH = /^(|true)$/i;
236
- var FILTERS_FOCUSABLE = [
237
- isDisabled,
238
- isInert,
239
- isHidden,
240
- isSummarised
241
- ];
242
- [...FILTERS_FOCUSABLE];
243
- var SELECTOR_DETAILS_CLOSED_CHILDREN = "details:not([open]) *";
244
- var SELECTOR_FIELDSET_DISABLED = "fieldset[disabled] *";
245
- var SELECTOR_SUMMARY_FIRST = "details > summary:first-of-type";
246
- var SELECTOR_FULL = [
247
- "[contenteditable]:not([contenteditable=\"false\"])",
248
- "[tabindex]:not(slot)",
249
- "a[href]",
250
- "audio[controls]",
251
- "button",
252
- "details",
253
- SELECTOR_SUMMARY_FIRST,
254
- "input",
255
- "select",
256
- "textarea",
257
- "video[controls]"
258
- ].map((selector) => `${selector}:not([inert])`).join(",");
259
- var STYLE_HIDDEN = "hidden";
260
- var STYLE_NONE = "none";
261
- var TABINDEX_BASE = 0;
262
- var TABINDEX_DEFAULT = -1;
263
- var FocusTrap = class {
264
- disabled = false;
265
- connected = true;
266
- element;
267
- embedded;
268
- get contain() {
269
- return this.element.hasAttribute(FOCUS_TRAP_CONTAIN);
270
- }
271
- get noescape() {
272
- return this.element.hasAttribute(FOCUS_TRAP_NOESCAPE);
273
- }
274
- constructor(element, options) {
275
- this.element = element;
276
- this.embedded = options != null;
277
- element.setAttribute("tabindex", "-1");
278
- if (options != null) element.setAttribute(FOCUS_TRAP_SELECTOR, "");
279
- if (options?.noescape) element.setAttribute(FOCUS_TRAP_NOESCAPE, "");
280
- }
281
- connect() {
282
- setConnected(this, true);
283
- }
284
- destroy() {
285
- this.element = void 0;
286
- }
287
- disable() {
288
- if (!(this.disabled || this.noescape)) setDisabled(this, true);
289
- }
290
- disconnect() {
291
- setConnected(this, false);
292
- }
293
- enable() {
294
- if (this.disabled) setDisabled(this, false);
295
- }
296
- focus(last) {
297
- tabToTrap(this, getFocusable(this.element), this.element, last ? -1 : 0);
298
- }
299
- };
300
- function createFocusTrap(element, options) {
301
- let focusTrap = FOCUSTRAPS_ALL.get(element);
302
- if (focusTrap == null) {
303
- focusTrap = new FocusTrap(element, options);
304
- FOCUSTRAPS_ALL.set(element, focusTrap);
305
- }
306
- return focusTrap;
307
- }
308
- function onEscape(event) {
309
- let element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
310
- let focusTrap = FOCUSTRAPS_ALL.get(element);
311
- if (element == null || focusTrap == null) return;
312
- while (focusTrap.disabled) {
313
- element = findAncestor(focusTrap.element.parentElement, ATTRIBUTE_SELECTOR);
314
- focusTrap = FOCUSTRAPS_ALL.get(element);
315
- if (element == null || focusTrap == null) return;
316
- if (!focusTrap.disabled) break;
317
- }
318
- focusTrap?.disable();
319
- }
320
- function onFocusIn(event) {
321
- lastTarget = FOCUSTRAPS_ALL.get(findAncestor(event.target, ATTRIBUTE_SELECTOR)) == null ? void 0 : event.target;
322
- }
323
- function onKeydown(event) {
324
- switch (event.key) {
325
- case "Escape":
326
- onEscape(event);
327
- break;
328
- case "Tab":
329
- onTab(event);
330
- break;
331
- default: return;
332
- }
333
- }
334
- function onPointerdown(event) {
335
- const lastFocusTrap = findAncestor(lastTarget, ATTRIBUTE_SELECTOR);
336
- const nextFocusTrap = findAncestor(event.target, ATTRIBUTE_SELECTOR);
337
- if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
338
- if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
339
- event.preventDefault();
340
- lastTarget?.focus();
341
- }
342
- }
343
- if (FOCUSTRAPS_DISABLED.size === 0) return;
344
- for (const focusTrap of FOCUSTRAPS_DISABLED) if (focusTrap.element !== nextFocusTrap) focusTrap.enable();
345
- }
346
- function onTab(event) {
347
- const element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
348
- const focusTrap = FOCUSTRAPS_ALL.get(element);
349
- if (focusTrap == null) return;
350
- if (!focusTrap.disabled) event.preventDefault();
351
- const elements = getFocusable(element);
352
- const index = elements.indexOf(event.target);
353
- if (index === -1 || elements.length === 0) tabToTrap(focusTrap, elements, element);
354
- else tabToElement(focusTrap, elements, index, event.shiftKey ? -1 : 1);
355
- }
356
- function setConnected(focusTrap, value) {
357
- if (!focusTrap.embedded || focusTrap.connected === value) return;
358
- focusTrap.connected = value;
359
- }
360
- function setDisabled(focusTrap, value) {
361
- focusTrap.disabled = value;
362
- if (value) FOCUSTRAPS_DISABLED.add(focusTrap);
363
- else FOCUSTRAPS_DISABLED.delete(focusTrap);
364
- }
365
- function tabToElement(focusTrap, elements, index, modifier) {
366
- const { length } = elements;
367
- const next = clamp(index + modifier, 0, length - 1, true);
368
- if (focusTrap.disabled) {
369
- if (index === length - 1 && next === 0 || index === 0 && next === length - 1) {
370
- lastTarget = void 0;
371
- focusTrap.enable();
372
- }
373
- return;
374
- }
375
- const element = elements[next];
376
- const elementFocusTrap = FOCUSTRAPS_ALL.get(element);
377
- if (elementFocusTrap != null) elementFocusTrap.focus(modifier === -1);
378
- else {
379
- elements[next].focus();
380
- lastTarget = elements[next];
381
- }
382
- }
383
- function tabToTrap(focusTrap, elements, element, index) {
384
- if (focusTrap.disabled) {
385
- lastTarget = void 0;
386
- focusTrap.enable();
387
- } else {
388
- const next = elements.length === 0 ? element : elements.at(index ?? 0);
389
- next.focus();
390
- lastTarget = next;
391
- }
392
- }
393
- const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
394
- const ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
395
- const EVENT_OPTIONS = {
396
- capture: true,
397
- passive: false
398
- };
399
- const FOCUS_TRAP_CONTAIN = `${FOCUS_TRAP_SELECTOR}-contain`;
400
- const FOCUS_TRAP_NOESCAPE = `${FOCUS_TRAP_SELECTOR}-noescape`;
401
- const FOCUSTRAPS_ALL = /* @__PURE__ */ new WeakMap();
402
- const FOCUSTRAPS_DISABLED = /* @__PURE__ */ new Set();
403
- let lastTarget;
404
- on(document, "focusin", onFocusIn, EVENT_OPTIONS);
405
- on(document, "keydown", onKeydown, EVENT_OPTIONS);
406
- on(document, "mousedown", onPointerdown, EVENT_OPTIONS);
407
- on(document, "touchstart", onPointerdown, EVENT_OPTIONS);
408
- export { FOCUSTRAPS_ALL, FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap };