@oscarpalmer/oui 0.19.0 → 0.21.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 (63) 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/focus-trap/embedded.d.mts +26 -0
  8. package/dist/js/focus-trap/{embedded.js → embedded.mjs} +11 -9
  9. package/dist/js/focus-trap/standalone.d.mts +1 -0
  10. package/dist/js/focus-trap/{standalone.js → standalone.mjs} +5 -2
  11. package/dist/js/index.d.mts +4 -0
  12. package/dist/js/index.mjs +7 -0
  13. package/dist/js/internal/attributable.d.mts +4 -0
  14. package/dist/js/{attributable.full.js → internal/attributable.mjs} +8 -1
  15. package/dist/js/internal/draggable.d.mts +2 -0
  16. package/dist/js/internal/draggable.mjs +212 -0
  17. package/dist/js/internal/floatable.d.mts +26 -0
  18. package/dist/js/{floatable.js → internal/floatable.mjs} +73 -50
  19. package/dist/js/movable-BEo2LbUI.d.mts +101 -0
  20. package/dist/js/movable.d.mts +2 -0
  21. package/dist/js/movable.mjs +152 -0
  22. package/dist/js/popover.d.mts +20 -0
  23. package/dist/js/{popover.js → popover.mjs} +10 -8
  24. package/dist/js/sortable.d.mts +2 -0
  25. package/dist/js/sortable.mjs +243 -0
  26. package/dist/js/splitter.d.mts +25 -0
  27. package/dist/js/{splitter.js → splitter.mjs} +62 -60
  28. package/dist/js/tooltip.d.mts +4 -0
  29. package/dist/js/{tooltip.js → tooltip.mjs} +22 -20
  30. package/package.json +66 -69
  31. package/src/css/mixins.scss +30 -1
  32. package/src/css/popover.scss +6 -1
  33. package/src/css/reset.scss +4 -4
  34. package/src/css/table.scss +1 -1
  35. package/src/css/tooltip.scss +55 -1
  36. package/src/js/focus-trap/embedded.ts +4 -10
  37. package/src/js/focus-trap/standalone.ts +1 -1
  38. package/src/js/index.ts +3 -1
  39. package/src/js/{attributable.ts → internal/attributable.ts} +11 -1
  40. package/src/js/internal/draggable.ts +515 -0
  41. package/src/js/{floatable.ts → internal/floatable.ts} +141 -63
  42. package/src/js/movable.ts +260 -0
  43. package/src/js/popover.ts +1 -1
  44. package/src/js/sortable.ts +467 -0
  45. package/src/js/splitter.ts +3 -9
  46. package/src/js/tooltip.ts +11 -9
  47. package/dist/js/attributable.js +0 -36
  48. package/dist/js/floatable.full.js +0 -398
  49. package/dist/js/focus-trap/embedded.full.js +0 -408
  50. package/dist/js/focus-trap/standalone.full.js +0 -447
  51. package/dist/js/index.js +0 -5
  52. package/dist/js/oui.full.js +0 -1573
  53. package/dist/js/popover.full.js +0 -760
  54. package/dist/js/splitter.full.js +0 -769
  55. package/dist/js/tooltip.full.js +0 -613
  56. package/types/attributable.d.ts +0 -1
  57. package/types/floatable.d.ts +0 -24
  58. package/types/focus-trap/embedded.d.ts +0 -24
  59. package/types/focus-trap/standalone.d.ts +0 -1
  60. package/types/index.d.ts +0 -4
  61. package/types/popover.d.ts +0 -17
  62. package/types/splitter.d.ts +0 -23
  63. package/types/tooltip.d.ts +0 -2
@@ -0,0 +1,467 @@
1
+ import type {EventPosition, PlainObject} from '@oscarpalmer/atoms/models';
2
+ import {createElement} from '@oscarpalmer/toretto/create';
3
+ import {getPosition} from '@oscarpalmer/toretto/event';
4
+ import {findAncestor, getElementFromPosition} from '@oscarpalmer/toretto/find';
5
+ import {attributable} from './internal/attributable';
6
+ import {
7
+ addDraggable,
8
+ Draggable,
9
+ removeDraggable,
10
+ type DraggableBound,
11
+ type DraggableState,
12
+ type DragMovePosition,
13
+ } from './internal/draggable';
14
+
15
+ // #region Types
16
+
17
+ export class Sortable extends Draggable {
18
+ connections: string | null;
19
+
20
+ origin: HTMLElement | undefined;
21
+
22
+ get dragged(): HTMLElement {
23
+ return getDragPlaceholder();
24
+ }
25
+
26
+ constructor(element: HTMLElement) {
27
+ super('sort', element, {
28
+ container: {
29
+ attribute: ATTRIBUTE_CONTAINER,
30
+ map: CONTAINERS,
31
+ },
32
+ direction: {
33
+ attribute: ATTRIBUTE_DIRECTION,
34
+ },
35
+ drag: {
36
+ onBegin,
37
+ onCancel,
38
+ onEnd,
39
+ onMove,
40
+ },
41
+ position: {
42
+ getOffset: getOffsetPosition,
43
+ getOriginal: getOriginalPosition,
44
+ },
45
+ });
46
+
47
+ this.connections = this.element.getAttribute(ATTRIBUTE_CONNECTIONS);
48
+ }
49
+ }
50
+
51
+ type SortablePlaceholder = {
52
+ drag: SortablePlaceholderDrag;
53
+ position: HTMLElement | undefined;
54
+ };
55
+
56
+ type SortablePlaceholderDrag = {
57
+ custom: HTMLElement | undefined;
58
+ default: HTMLElement | undefined;
59
+ };
60
+
61
+ // #endregion
62
+
63
+ // #region Functions
64
+
65
+ function afterEnd(
66
+ insert: 'append' | 'insert' | 'prepend' | undefined,
67
+ from: Sortable,
68
+ events: CustomEvent[],
69
+ elements: {origin?: HTMLElement; target: HTMLElement},
70
+ position: EventPosition | undefined,
71
+ valid: boolean,
72
+ ): void {
73
+ elements.origin?.removeAttribute(ATTRIBUTE_ORIGIN);
74
+
75
+ from.origin = undefined;
76
+
77
+ resetPlaceholders();
78
+
79
+ if (!valid || events.some(event => event.defaultPrevented)) {
80
+ return;
81
+ }
82
+
83
+ if (insert !== 'insert') {
84
+ elements.target.append(elements.origin!);
85
+
86
+ return;
87
+ }
88
+
89
+ if (position == null) {
90
+ return;
91
+ }
92
+
93
+ const {height, top} = elements.target.getBoundingClientRect();
94
+
95
+ let insertion: 'afterend' | 'beforebegin';
96
+
97
+ if (position.y < top + height / 2) {
98
+ insertion = INSERT_BEFORE;
99
+ } else {
100
+ insertion = INSERT_AFTER;
101
+ }
102
+
103
+ elements.target?.insertAdjacentElement(insertion, elements.origin!);
104
+
105
+ document.body.removeAttribute(ATTRIBUTE_ACTIVE);
106
+ }
107
+
108
+ function getDragPlaceholder(): HTMLElement {
109
+ placeholder.drag.default ??= createElement('div');
110
+
111
+ return placeholder.drag.custom ?? placeholder.drag.default;
112
+ }
113
+
114
+ function getOffsetPosition(
115
+ _: DraggableState,
116
+ draggable: Draggable,
117
+ element: HTMLElement,
118
+ position: EventPosition,
119
+ ): EventPosition {
120
+ const rectangle = element.getBoundingClientRect();
121
+
122
+ return {
123
+ x: draggable.horizontal ? 0 : position.x - rectangle.left,
124
+ y: draggable.vertical ? 0 : position.y - rectangle.top,
125
+ };
126
+ }
127
+
128
+ function getOriginalPosition(
129
+ _: DraggableState,
130
+ __: Draggable,
131
+ position: EventPosition,
132
+ ): EventPosition {
133
+ return position;
134
+ }
135
+
136
+ function getPositionPlaceholder(sortable: Sortable): HTMLElement {
137
+ placeholder.position ??= createElement('div');
138
+
139
+ placeholder.position.setAttribute(ATTRIBUTE_PLACEHOLDER_POSITION, '');
140
+
141
+ if (sortable.origin != null) {
142
+ placeholder.position.style.setProperty(
143
+ '--placeholder-height',
144
+ `${sortable.origin.getBoundingClientRect().height}px`,
145
+ );
146
+ }
147
+
148
+ return placeholder.position;
149
+ }
150
+
151
+ function onBegin(
152
+ _: MouseEvent | TouchEvent,
153
+ state: DraggableState,
154
+ draggable: Draggable,
155
+ element: HTMLElement,
156
+ ): void {
157
+ const sortable = draggable as Sortable;
158
+
159
+ sortable.origin = element;
160
+
161
+ setPlaceholder(state, sortable, element);
162
+
163
+ element.setAttribute(ATTRIBUTE_ORIGIN, '');
164
+
165
+ document.body.setAttribute(ATTRIBUTE_ACTIVE, '');
166
+ }
167
+
168
+ function onCancel(_: DraggableState, draggable: Draggable): void {
169
+ const sortable = draggable as Sortable;
170
+
171
+ const {origin} = sortable;
172
+
173
+ origin?.removeAttribute(ATTRIBUTE_ORIGIN);
174
+
175
+ document.body.removeAttribute(ATTRIBUTE_ACTIVE);
176
+
177
+ resetPlaceholders();
178
+
179
+ sortable.origin = undefined;
180
+ }
181
+
182
+ function onEnd(
183
+ event: MouseEvent | TouchEvent,
184
+ state: DraggableState,
185
+ draggable: Draggable,
186
+ reset: () => void,
187
+ ): void {
188
+ const from = draggable as Sortable;
189
+ const {origin} = from;
190
+
191
+ const position = getPosition(event) ?? {x: 0, y: 0};
192
+
193
+ const target = getElementFromPosition(position)[0];
194
+
195
+ let element = findAncestor(target, SELECTOR_ITEM) as HTMLElement;
196
+
197
+ if (element?.hasAttribute(ATTRIBUTE_PLACEHOLDER_POSITION)) {
198
+ const position = element.getAttribute(ATTRIBUTE_PLACEHOLDER_POSITION);
199
+
200
+ if (position === 'after') {
201
+ element = element.previousElementSibling as HTMLElement;
202
+ } else {
203
+ element = element.nextElementSibling as HTMLElement;
204
+ }
205
+ }
206
+
207
+ let insert: 'append' | 'insert' | 'prepend' | undefined = 'insert';
208
+ let to: Sortable | undefined;
209
+
210
+ if (element == null) {
211
+ element = findAncestor(target, SELECTOR) as HTMLElement;
212
+
213
+ to = state.instances.get(element)?.sortable;
214
+
215
+ insert = element == null ? undefined : element.children.length === 0 ? 'append' : 'prepend';
216
+ } else {
217
+ to = state.instances.get(element.parentElement!)?.sortable;
218
+ }
219
+
220
+ const valid = insert != null && validatePosition(state, from, to, position);
221
+
222
+ const detail = valid
223
+ ? {
224
+ from: {
225
+ element: origin,
226
+ position: {...state.original},
227
+ },
228
+ to: {
229
+ element: element,
230
+ position: {...position},
231
+ },
232
+ }
233
+ : undefined;
234
+
235
+ const options = {
236
+ detail,
237
+ bubbles: false,
238
+ cancelable: true,
239
+ };
240
+
241
+ const fromEvent = new CustomEvent(EVENT_END, options);
242
+ const toEvent = new CustomEvent(EVENT_END, options);
243
+
244
+ from.element.dispatchEvent(fromEvent);
245
+
246
+ if (from !== to) {
247
+ to?.element.dispatchEvent(toEvent);
248
+ }
249
+
250
+ setTimeout(() => {
251
+ afterEnd(insert, from, [fromEvent, toEvent], {origin, target: element}, position, valid);
252
+
253
+ reset();
254
+ });
255
+ }
256
+
257
+ function onMove(
258
+ event: MouseEvent | TouchEvent,
259
+ state: DraggableState,
260
+ draggable: Draggable,
261
+ position: DragMovePosition,
262
+ ): PlainObject | undefined {
263
+ const from = draggable as Sortable;
264
+
265
+ const fromElement = from.origin;
266
+ const toElement = findAncestor(event, SELECTOR_ITEM) as HTMLElement;
267
+
268
+ let to: Sortable | undefined;
269
+
270
+ if (toElement == null) {
271
+ to = state.instances.get(findAncestor(event, SELECTOR) as HTMLElement)?.sortable;
272
+ } else {
273
+ to = state.instances.get(toElement.parentElement!)?.sortable;
274
+ }
275
+
276
+ if (!validatePosition(state, from, to, position.original)) {
277
+ return;
278
+ }
279
+
280
+ const placeholder = getPositionPlaceholder(from);
281
+
282
+ if (toElement != null && toElement !== fromElement) {
283
+ const {height, top} = toElement.getBoundingClientRect();
284
+
285
+ let place: 'after' | 'before';
286
+
287
+ if (position.calculated.y < top + height / 2) {
288
+ place = 'before';
289
+
290
+ toElement.insertAdjacentElement(INSERT_BEFORE, placeholder);
291
+ } else {
292
+ place = 'after';
293
+
294
+ toElement.insertAdjacentElement(INSERT_AFTER, placeholder);
295
+ }
296
+
297
+ placeholder.setAttribute(ATTRIBUTE_PLACEHOLDER_POSITION, place);
298
+ } else {
299
+ placeholder.remove();
300
+ }
301
+
302
+ return {
303
+ from: {
304
+ element: fromElement,
305
+ position: {...state.original},
306
+ },
307
+ to: {
308
+ element: toElement,
309
+ position: {...position.calculated},
310
+ },
311
+ };
312
+ }
313
+
314
+ function resetPlaceholders(): void {
315
+ placeholder.drag.custom?.remove();
316
+ placeholder.drag.default?.remove();
317
+ placeholder.position?.remove();
318
+
319
+ placeholder.drag.custom = undefined;
320
+ }
321
+
322
+ function setPlaceholder(state: DraggableState, sortable: Sortable, origin: HTMLElement): void {
323
+ const element = getDragPlaceholder();
324
+
325
+ placeholder.drag.default!.innerHTML = '';
326
+
327
+ updatePlaceholder(sortable, element);
328
+
329
+ const event = new CustomEvent(EVENT_PLACEHOLDER, {
330
+ cancelable: true,
331
+ detail: {
332
+ origin,
333
+ parent: sortable.element,
334
+ placeholder: element,
335
+ create: (value: unknown) => {
336
+ if (!(value instanceof HTMLElement)) {
337
+ return;
338
+ }
339
+
340
+ placeholder.drag.custom = value;
341
+
342
+ updatePlaceholder(sortable, value);
343
+
344
+ state.element = {
345
+ rectangle: value.getBoundingClientRect(),
346
+ node: value,
347
+ };
348
+ },
349
+ },
350
+ });
351
+
352
+ sortable.element.dispatchEvent(event);
353
+
354
+ setTimeout(() => {
355
+ if (!event.defaultPrevented && placeholder.drag.custom == null) {
356
+ placeholder.drag.default?.append(element.cloneNode(true));
357
+ }
358
+
359
+ document.body.append(placeholder.drag.custom ?? placeholder.drag.default ?? '');
360
+ });
361
+ }
362
+
363
+ function updatePlaceholder(sortable: Sortable, element: HTMLElement): void {
364
+ element.style.position = 'fixed';
365
+
366
+ element.setAttribute(ATTRIBUTE_PLACEHOLDER_DRAG, '');
367
+
368
+ if (sortable.horizontal) {
369
+ element.setAttribute(ATTRIBUTE_HORIZONTAL, '');
370
+ } else {
371
+ element.removeAttribute(ATTRIBUTE_HORIZONTAL);
372
+ }
373
+
374
+ if (sortable.vertical) {
375
+ element.setAttribute(ATTRIBUTE_VERTICAL, '');
376
+ } else {
377
+ element.removeAttribute(ATTRIBUTE_VERTICAL);
378
+ }
379
+ }
380
+
381
+ function validatePosition(
382
+ _: DraggableState,
383
+ from: Sortable,
384
+ to: Sortable | undefined,
385
+ position: EventPosition,
386
+ ): boolean {
387
+ let valid = true;
388
+
389
+ const rectangle = from.origin?.getBoundingClientRect();
390
+
391
+ if (rectangle != null && !from.horizontal) {
392
+ valid = position.x >= rectangle.left && position.x <= rectangle.right;
393
+ }
394
+
395
+ if (valid && rectangle != null && !from.vertical) {
396
+ valid = position.y >= rectangle.top && position.y <= rectangle.bottom;
397
+ }
398
+
399
+ if (valid && from.connections != null) {
400
+ valid = to?.element.matches(from.connections) ?? true;
401
+ }
402
+
403
+ if (valid && to?.connections != null) {
404
+ valid = from.element.matches(to.connections);
405
+ }
406
+
407
+ return valid;
408
+ }
409
+
410
+ // #endregion
411
+
412
+ // #region Variables
413
+
414
+ const ATTRIBUTE = 'oui-sortable';
415
+
416
+ const ATTRIBUTE_ACTIVE = `${ATTRIBUTE}-active`;
417
+
418
+ const ATTRIBUTE_CONNECTIONS = `${ATTRIBUTE}-connections`;
419
+
420
+ const ATTRIBUTE_CONTAINER = `${ATTRIBUTE}-container`;
421
+
422
+ const ATTRIBUTE_DIRECTION = `${ATTRIBUTE}-direction`;
423
+
424
+ const ATTRIBUTE_HORIZONTAL = `${ATTRIBUTE}-horizontal`;
425
+
426
+ const ATTRIBUTE_ORIGIN = `${ATTRIBUTE}-origin`;
427
+
428
+ const ATTRIBUTE_PLACEHOLDER_DRAG = `${ATTRIBUTE}-placeholder-drag`;
429
+
430
+ const ATTRIBUTE_PLACEHOLDER_POSITION = `${ATTRIBUTE}-placeholder-position`;
431
+
432
+ const ATTRIBUTE_VERTICAL = `${ATTRIBUTE}-vertical`;
433
+
434
+ const CONTAINERS = new Map<HTMLElement, Set<Sortable>>();
435
+
436
+ const EVENT_END = 'sort:end';
437
+
438
+ const EVENT_PLACEHOLDER = 'sort:placeholder';
439
+
440
+ const INSERT_AFTER = 'afterend';
441
+
442
+ const INSERT_BEFORE = 'beforebegin';
443
+
444
+ const SELECTOR = `[${ATTRIBUTE}]`;
445
+
446
+ const SELECTOR_ITEM = `[${ATTRIBUTE}] > *`;
447
+
448
+ const bound: DraggableBound = {
449
+ constructor: Sortable,
450
+ property: 'sortable',
451
+ };
452
+
453
+ const placeholder: SortablePlaceholder = {
454
+ drag: {
455
+ custom: undefined,
456
+ default: undefined,
457
+ },
458
+ position: undefined,
459
+ };
460
+
461
+ // #endregion
462
+
463
+ // #region Initialization
464
+
465
+ attributable(ATTRIBUTE, addDraggable.bind(bound), removeDraggable.bind(bound));
466
+
467
+ // #endregion
@@ -7,7 +7,6 @@ import {type StyleToggler, toggleStyles} from '@oscarpalmer/toretto/style';
7
7
  import supportsTouch from '@oscarpalmer/toretto/touch';
8
8
 
9
9
  declare global {
10
- // biome-ignore lint/nursery/useConsistentTypeDefinitions: Extending builtins to allow custom element type help
11
10
  interface HTMLElementTagNameMap {
12
11
  [SELECTOR]: OuiSplitterElement;
13
12
  }
@@ -324,7 +323,7 @@ function onKeydown(event: KeyboardEvent): void {
324
323
 
325
324
  function onNavigate(event: KeyboardEvent): void {
326
325
  const splitter = MAPPED_ELEMENTS.get(
327
- findAncestor(event.target as never, '[oui-splitter-separator]') as HTMLSpanElement,
326
+ findAncestor(event, '[oui-splitter-separator]') as HTMLSpanElement,
328
327
  );
329
328
 
330
329
  if (splitter == null) {
@@ -384,16 +383,11 @@ function onObservation(entries: ResizeObserverEntry[]): void {
384
383
  }
385
384
 
386
385
  function onPointerdown(event: Event): void {
387
- if (
388
- (event.type === 'mousedown' && supportsTouch.value) ||
389
- (event.type === 'touchstart' && !supportsTouch.value)
390
- ) {
386
+ if (supportsTouch.value ? event.type === 'mousedown' : event.type === 'touchstart') {
391
387
  return;
392
388
  }
393
389
 
394
- splitter = MAPPED_ELEMENTS.get(
395
- findAncestor(event.target as never, SELECTOR_HANDLE) as HTMLSpanElement,
396
- );
390
+ splitter = MAPPED_ELEMENTS.get(findAncestor(event, SELECTOR_HANDLE) as HTMLSpanElement);
397
391
 
398
392
  if (splitter == null) {
399
393
  return;
package/src/js/tooltip.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
2
2
  import {on} from '@oscarpalmer/toretto/event';
3
3
  import {findAncestor} from '@oscarpalmer/toretto/find';
4
- import {attributable} from './attributable';
5
- import {Floatable} from './floatable';
4
+ import {attributable} from './internal/attributable';
5
+ import {Floatable} from './internal/floatable';
6
6
 
7
7
  type Attributes = {
8
8
  ariaDescribedby: string | null;
@@ -79,12 +79,13 @@ function closeTooltips(next: Tooltip | undefined): void {
79
79
  clearTimeout(active.timer);
80
80
  }
81
81
 
82
- active.floatable.options.content.removeAttribute('oui-tooltip-content-active');
82
+ active.floatable?.options.content.removeAttribute('oui-tooltip-content-active');
83
83
 
84
84
  requestAnimationFrame(() => {
85
85
  active.timer = setTimeout(() => {
86
86
  TOOLTIPS_ACTIVE.delete(active);
87
- active.floatable.toggle(false);
87
+
88
+ active.floatable?.toggle(false);
88
89
  }, delay) as never;
89
90
  });
90
91
  }
@@ -192,7 +193,7 @@ function onActivate(event: Event): void {
192
193
  }
193
194
 
194
195
  function onClick(event: Event): void {
195
- if (findAncestor(event.target as HTMLElement, SELECTOR_CONTENT) != null) {
196
+ if (findAncestor(event, SELECTOR_CONTENT) != null) {
196
197
  event.stopPropagation();
197
198
  }
198
199
  }
@@ -209,7 +210,7 @@ function onToggle(event: Event, activate: boolean): void {
209
210
  toggle = requestAnimationFrame(() => {
210
211
  toggle = undefined;
211
212
 
212
- const element = findAncestor(event.target as HTMLElement, SELECTOR_FULL) as HTMLElement;
213
+ const element = findAncestor(event, SELECTOR_FULL) as HTMLElement;
213
214
 
214
215
  const tooltip = TOOLTIPS_ALL.get(element);
215
216
 
@@ -243,6 +244,7 @@ function onToggle(event: Event, activate: boolean): void {
243
244
 
244
245
  tooltip.timer ??= setTimeout(() => {
245
246
  TOOLTIPS_ACTIVE.delete(tooltip);
247
+
246
248
  tooltip.floatable.toggle(false);
247
249
  }, delay) as never;
248
250
  });
@@ -262,7 +264,7 @@ function reset(anchor: HTMLElement, attributes: Attributes): void {
262
264
  }
263
265
  }
264
266
 
265
- function setDelay(value: number): void {
267
+ function setTooltipDelay(value: number): void {
266
268
  delay = typeof value === 'number' && value >= 0 ? value : delay;
267
269
  }
268
270
 
@@ -286,7 +288,7 @@ const TOOLTIPS_ACTIVE: Set<Tooltip> = new Set();
286
288
 
287
289
  const TOOLTIPS_ALL: WeakMap<HTMLElement, Tooltip> = new WeakMap();
288
290
 
289
- let delay = 250;
291
+ let delay = 500;
290
292
 
291
293
  let index = 0;
292
294
 
@@ -304,4 +306,4 @@ on(document, 'touchstart', onActivate);
304
306
 
305
307
  //
306
308
 
307
- export {setDelay};
309
+ export {setTooltipDelay};
@@ -1,36 +0,0 @@
1
- function attributable(attribute, add, remove) {
2
- 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) if (entry.target.hasAttribute(attribute)) handleAdded(attribute, [entry.target], add);
7
- else handleRemoved([entry.target], remove);
8
- else if (entry.type === "childList") {
9
- handleAdded(attribute, entry.addedNodes, add);
10
- handleRemoved(entry.removedNodes, remove);
11
- }
12
- }
13
- }).observe(document, {
14
- attributeFilter: [attribute],
15
- attributes: true,
16
- childList: true,
17
- subtree: true
18
- });
19
- requestAnimationFrame(() => {
20
- handleAdded(attribute, document.querySelectorAll(`[${attribute}]`), add);
21
- });
22
- }
23
- function handleAdded(attribute, nodes, add) {
24
- const elements = [...nodes].filter((node) => node instanceof HTMLElement);
25
- const { length } = elements;
26
- for (let index = 0; index < length; index += 1) {
27
- const element = elements[index];
28
- if (element.hasAttribute(attribute)) add(element);
29
- }
30
- }
31
- function handleRemoved(nodes, remove) {
32
- const elements = [...nodes].filter((node) => node instanceof HTMLElement);
33
- const { length } = elements;
34
- for (let index = 0; index < length; index += 1) remove(elements[index]);
35
- }
36
- export { attributable };