@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.
- package/dist/css/a11y.css +0 -1
- package/dist/css/form.css +0 -1
- package/dist/css/popover.css +22 -0
- package/dist/css/reset.css +8 -8
- package/dist/css/table.css +1 -1
- package/dist/css/tooltip.css +43 -0
- package/dist/js/attributable.d.mts +4 -0
- package/dist/js/{attributable.full.js → attributable.mjs} +8 -1
- package/dist/js/floatable.d.mts +26 -0
- package/dist/js/{floatable.js → floatable.mjs} +73 -50
- package/dist/js/focus-trap/embedded.d.mts +26 -0
- package/dist/js/focus-trap/{embedded.js → embedded.mjs} +10 -8
- package/dist/js/focus-trap/standalone.d.mts +1 -0
- package/dist/js/focus-trap/{standalone.js → standalone.mjs} +5 -2
- package/dist/js/index.d.mts +4 -0
- package/dist/js/index.mjs +5 -0
- package/dist/js/popover.d.mts +20 -0
- package/dist/js/{popover.js → popover.mjs} +10 -8
- package/dist/js/splitter.d.mts +25 -0
- package/dist/js/{splitter.js → splitter.mjs} +58 -56
- package/dist/js/tooltip.d.mts +4 -0
- package/dist/js/{tooltip.js → tooltip.mjs} +20 -18
- package/package.json +64 -69
- package/src/css/mixins.scss +30 -1
- package/src/css/popover.scss +6 -1
- package/src/css/reset.scss +4 -4
- package/src/css/table.scss +1 -1
- package/src/css/tooltip.scss +55 -1
- package/src/js/attributable.ts +11 -1
- package/src/js/floatable.ts +136 -58
- package/src/js/focus-trap/embedded.ts +4 -10
- package/src/js/splitter.ts +2 -5
- package/src/js/tooltip.ts +5 -5
- package/dist/js/attributable.js +0 -36
- package/dist/js/floatable.full.js +0 -398
- package/dist/js/focus-trap/embedded.full.js +0 -408
- package/dist/js/focus-trap/standalone.full.js +0 -447
- package/dist/js/index.js +0 -5
- package/dist/js/oui.full.js +0 -1573
- package/dist/js/popover.full.js +0 -760
- package/dist/js/splitter.full.js +0 -769
- package/dist/js/tooltip.full.js +0 -613
- package/types/attributable.d.ts +0 -1
- package/types/floatable.d.ts +0 -24
- package/types/focus-trap/embedded.d.ts +0 -24
- package/types/focus-trap/standalone.d.ts +0 -1
- package/types/index.d.ts +0 -4
- package/types/popover.d.ts +0 -17
- package/types/splitter.d.ts +0 -23
- package/types/tooltip.d.ts +0 -2
package/src/js/floatable.ts
CHANGED
|
@@ -91,7 +91,6 @@ export class Floatable {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
type FloatableWindow = Window & {
|
|
94
|
-
// biome-ignore lint/style/useNamingConvention: Non-standard name to avoid conflicts
|
|
95
94
|
_oscarpalmer_oui_floatable: State;
|
|
96
95
|
};
|
|
97
96
|
|
|
@@ -193,78 +192,157 @@ export function deactivate(floatable: Floatable): void {
|
|
|
193
192
|
floatable.options.onAfter?.(false);
|
|
194
193
|
}
|
|
195
194
|
|
|
195
|
+
function getAttribute(
|
|
196
|
+
position: Position,
|
|
197
|
+
anchor: DOMRect,
|
|
198
|
+
top: number,
|
|
199
|
+
left: number,
|
|
200
|
+
): Position | undefined {
|
|
201
|
+
switch (position) {
|
|
202
|
+
case 'horizontal':
|
|
203
|
+
case 'horizontal-bottom':
|
|
204
|
+
case 'horizontal-top':
|
|
205
|
+
return position.replace('horizontal', left >= anchor.right ? 'right' : 'left') as Position;
|
|
206
|
+
|
|
207
|
+
case 'vertical':
|
|
208
|
+
case 'vertical-end':
|
|
209
|
+
case 'vertical-start':
|
|
210
|
+
return position.replace('vertical', top >= anchor.bottom ? 'bottom' : 'top') as Position;
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function getMargin(): number {
|
|
218
|
+
try {
|
|
219
|
+
const fontsize = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
220
|
+
|
|
221
|
+
if (Number.isNaN(fontsize)) {
|
|
222
|
+
return 5;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const margin = fontsize / 2;
|
|
226
|
+
|
|
227
|
+
return margin < 5 ? 5 : margin;
|
|
228
|
+
} catch {
|
|
229
|
+
return 5;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
196
233
|
function getState(): State {
|
|
197
234
|
return (window as unknown as FloatableWindow)._oscarpalmer_oui_floatable;
|
|
198
235
|
}
|
|
199
236
|
|
|
200
|
-
function getX(anchor: DOMRect, content: DOMRect, position: Position): number {
|
|
201
|
-
if (position
|
|
202
|
-
const
|
|
237
|
+
function getX(anchor: DOMRect, content: DOMRect, position: Position, margin: number): number {
|
|
238
|
+
if (position === 'above' || position === 'below' || position === 'vertical') {
|
|
239
|
+
const center = anchor.left + anchor.width / 2;
|
|
240
|
+
const width = content.width / 2;
|
|
203
241
|
|
|
204
|
-
|
|
205
|
-
|
|
242
|
+
if (center + width + margin >= document.body.clientWidth) {
|
|
243
|
+
return document.body.clientWidth - content.width - margin / 2;
|
|
244
|
+
}
|
|
206
245
|
|
|
207
|
-
|
|
208
|
-
|
|
246
|
+
if (center - width - margin <= 0) {
|
|
247
|
+
return margin / 2;
|
|
248
|
+
}
|
|
209
249
|
|
|
210
|
-
return
|
|
250
|
+
return center - width;
|
|
211
251
|
}
|
|
212
252
|
|
|
213
|
-
if (position.startsWith(
|
|
253
|
+
if (position.startsWith('end')) {
|
|
214
254
|
return anchor.right;
|
|
215
255
|
}
|
|
216
256
|
|
|
217
|
-
if (position.startsWith(
|
|
257
|
+
if (position.startsWith('start')) {
|
|
218
258
|
return anchor.left - content.width;
|
|
219
259
|
}
|
|
220
260
|
|
|
221
|
-
if (position.
|
|
222
|
-
|
|
223
|
-
|
|
261
|
+
if (position.endsWith('end')) {
|
|
262
|
+
return anchor.right - content.width - margin <= 0 ? margin / 2 : anchor.right - content.width;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (position.endsWith('start')) {
|
|
266
|
+
if (anchor.left + content.width + margin >= document.body.clientWidth) {
|
|
267
|
+
return document.body.clientWidth - content.width - margin / 2;
|
|
224
268
|
}
|
|
225
269
|
|
|
226
|
-
return anchor.left -
|
|
270
|
+
return anchor.left - margin <= 0 ? margin / 2 : anchor.left;
|
|
227
271
|
}
|
|
228
272
|
|
|
229
|
-
|
|
273
|
+
if (!position.startsWith('horizontal')) {
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (anchor.right + content.width + margin >= document.body.clientWidth) {
|
|
278
|
+
return anchor.left - content.width;
|
|
279
|
+
}
|
|
230
280
|
|
|
231
|
-
return
|
|
281
|
+
return anchor.right;
|
|
232
282
|
}
|
|
233
283
|
|
|
234
|
-
function getY(
|
|
235
|
-
|
|
284
|
+
function getY(
|
|
285
|
+
anchor: DOMRect,
|
|
286
|
+
content: DOMRect,
|
|
287
|
+
position: Position,
|
|
288
|
+
margin: number,
|
|
289
|
+
preferAbove: boolean,
|
|
290
|
+
): number {
|
|
291
|
+
if (position === 'end' || position === 'start' || position === 'horizontal') {
|
|
292
|
+
const center = anchor.top + anchor.height / 2;
|
|
293
|
+
const height = content.height / 2;
|
|
294
|
+
|
|
295
|
+
if (center + height + margin >= document.body.clientHeight) {
|
|
296
|
+
return document.body.clientHeight - content.height - margin / 2;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (center - height - margin <= 0) {
|
|
300
|
+
return margin / 2;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return center - height;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (position.startsWith('above')) {
|
|
236
307
|
return anchor.top - content.height;
|
|
237
308
|
}
|
|
238
309
|
|
|
239
|
-
if (position.startsWith(
|
|
310
|
+
if (position.startsWith('below')) {
|
|
240
311
|
return anchor.bottom;
|
|
241
312
|
}
|
|
242
313
|
|
|
243
|
-
if (position.endsWith(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
314
|
+
if (position.endsWith('bottom')) {
|
|
315
|
+
return anchor.bottom - content.height - margin <= 0
|
|
316
|
+
? margin / 2
|
|
317
|
+
: anchor.bottom - content.height;
|
|
247
318
|
}
|
|
248
319
|
|
|
249
|
-
if (position.endsWith(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
320
|
+
if (position.endsWith('top')) {
|
|
321
|
+
return anchor.top + content.height + margin >= document.body.clientHeight
|
|
322
|
+
? document.body.clientHeight - content.height - margin
|
|
323
|
+
: anchor.top;
|
|
253
324
|
}
|
|
254
325
|
|
|
255
|
-
if (position.startsWith(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
326
|
+
if (!position.startsWith('vertical')) {
|
|
327
|
+
return 0;
|
|
328
|
+
}
|
|
259
329
|
|
|
260
|
-
|
|
330
|
+
if (preferAbove) {
|
|
331
|
+
if (
|
|
332
|
+
anchor.top - content.height - margin <= 0 &&
|
|
333
|
+
anchor.bottom + content.height + margin <= document.body.clientHeight
|
|
334
|
+
) {
|
|
261
335
|
return anchor.bottom;
|
|
262
336
|
}
|
|
263
337
|
|
|
264
338
|
return anchor.top - content.height;
|
|
265
339
|
}
|
|
266
340
|
|
|
267
|
-
|
|
341
|
+
if (anchor.bottom + content.height + margin >= document.body.clientHeight) {
|
|
342
|
+
return anchor.top - content.height;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return anchor.bottom;
|
|
268
346
|
}
|
|
269
347
|
|
|
270
348
|
function initialize(floatable: Floatable): void {
|
|
@@ -294,7 +372,7 @@ function isDisabled(element: HTMLElement): boolean {
|
|
|
294
372
|
}
|
|
295
373
|
|
|
296
374
|
function onClick(event: PointerEvent): void {
|
|
297
|
-
const related = findAncestor(event
|
|
375
|
+
const related = findAncestor(event, SELECTOR_ALL);
|
|
298
376
|
|
|
299
377
|
if (!(related instanceof HTMLElement)) {
|
|
300
378
|
closeAll();
|
|
@@ -318,7 +396,7 @@ function onKeyDown(event: KeyboardEvent): void {
|
|
|
318
396
|
|
|
319
397
|
closeNonInteractive(state);
|
|
320
398
|
|
|
321
|
-
const related = findAncestor(event
|
|
399
|
+
const related = findAncestor(event, SELECTOR_CONTENT);
|
|
322
400
|
|
|
323
401
|
if (!(related instanceof HTMLElement)) {
|
|
324
402
|
return;
|
|
@@ -333,6 +411,22 @@ function onKeyDown(event: KeyboardEvent): void {
|
|
|
333
411
|
}
|
|
334
412
|
}
|
|
335
413
|
|
|
414
|
+
function setAttribute(
|
|
415
|
+
position: Position,
|
|
416
|
+
anchor: DOMRect,
|
|
417
|
+
floater: HTMLElement,
|
|
418
|
+
top: number,
|
|
419
|
+
left: number,
|
|
420
|
+
): void {
|
|
421
|
+
let actual: Position | undefined;
|
|
422
|
+
|
|
423
|
+
if (/^(horizontal|vertical)/.test(position)) {
|
|
424
|
+
actual = getAttribute(position, anchor, top, left);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
floater.setAttribute('position', actual ?? position);
|
|
428
|
+
}
|
|
429
|
+
|
|
336
430
|
function stop(floatable: Floatable): void {
|
|
337
431
|
if (floatable.frame != null) {
|
|
338
432
|
cancelAnimationFrame(floatable.frame);
|
|
@@ -372,6 +466,8 @@ function updatePosition(floatable: Floatable): void {
|
|
|
372
466
|
position = floatable.options.defaultPosition;
|
|
373
467
|
}
|
|
374
468
|
|
|
469
|
+
const margin = getMargin();
|
|
470
|
+
|
|
375
471
|
let previousAnchor: DOMRect;
|
|
376
472
|
let previousContent: DOMRect;
|
|
377
473
|
|
|
@@ -404,8 +500,10 @@ function updatePosition(floatable: Floatable): void {
|
|
|
404
500
|
previousAnchor = anchor;
|
|
405
501
|
previousContent = content;
|
|
406
502
|
|
|
407
|
-
const left = getX(anchor, content, position);
|
|
408
|
-
const top = getY(anchor, content, position, floatable.options.preferAbove);
|
|
503
|
+
const left = getX(anchor, content, position, margin);
|
|
504
|
+
const top = getY(anchor, content, position, margin, floatable.options.preferAbove);
|
|
505
|
+
|
|
506
|
+
setAttribute(position, anchor, floatable.options.content, top, left);
|
|
409
507
|
|
|
410
508
|
if (top + content.height > window.innerHeight) {
|
|
411
509
|
floatable.options.content.style.height = `${window.innerHeight - top}px`;
|
|
@@ -442,26 +540,6 @@ const ATTRIBUTE_CONTENT = 'oui-floatable-content';
|
|
|
442
540
|
|
|
443
541
|
const INSERT_AFTEREND = 'afterend';
|
|
444
542
|
|
|
445
|
-
const POSITION_ABOVE = 'above';
|
|
446
|
-
|
|
447
|
-
const POSITION_BELOW = 'below';
|
|
448
|
-
|
|
449
|
-
const POSITION_BOTTOM = 'bottom';
|
|
450
|
-
|
|
451
|
-
const POSITION_END = 'end';
|
|
452
|
-
|
|
453
|
-
const POSITION_HORIZONTAL = 'horizontal';
|
|
454
|
-
|
|
455
|
-
const POSITION_START = 'start';
|
|
456
|
-
|
|
457
|
-
const POSITION_SUFFIX_END = '-end';
|
|
458
|
-
|
|
459
|
-
const POSITION_SUFFIX_START = '-start';
|
|
460
|
-
|
|
461
|
-
const POSITION_TOP = 'top';
|
|
462
|
-
|
|
463
|
-
const POSITION_VERTICAL = 'vertical';
|
|
464
|
-
|
|
465
543
|
const POSITIONS: Set<Position> = new Set([
|
|
466
544
|
'above',
|
|
467
545
|
'above-end',
|
|
@@ -83,7 +83,7 @@ export function createFocusTrap(element: HTMLElement, options?: Options): FocusT
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
function onEscape(event: KeyboardEvent): void {
|
|
86
|
-
let element = findAncestor(event
|
|
86
|
+
let element = findAncestor(event, ATTRIBUTE_SELECTOR) as HTMLElement;
|
|
87
87
|
|
|
88
88
|
let focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
89
89
|
|
|
@@ -112,9 +112,7 @@ function onEscape(event: KeyboardEvent): void {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
function onFocusIn(event: Event): void {
|
|
115
|
-
const focusTrap = FOCUSTRAPS_ALL.get(
|
|
116
|
-
findAncestor(event.target as HTMLElement, ATTRIBUTE_SELECTOR) as HTMLElement,
|
|
117
|
-
);
|
|
115
|
+
const focusTrap = FOCUSTRAPS_ALL.get(findAncestor(event, ATTRIBUTE_SELECTOR) as HTMLElement);
|
|
118
116
|
|
|
119
117
|
lastTarget = focusTrap == null ? undefined : (event.target as HTMLElement);
|
|
120
118
|
}
|
|
@@ -136,11 +134,7 @@ function onKeydown(event: KeyboardEvent): void {
|
|
|
136
134
|
|
|
137
135
|
function onPointerdown(event: MouseEvent | TouchEvent): void {
|
|
138
136
|
const lastFocusTrap = findAncestor(lastTarget as HTMLElement, ATTRIBUTE_SELECTOR) as HTMLElement;
|
|
139
|
-
|
|
140
|
-
const nextFocusTrap = findAncestor(
|
|
141
|
-
event.target as HTMLElement,
|
|
142
|
-
ATTRIBUTE_SELECTOR,
|
|
143
|
-
) as HTMLElement;
|
|
137
|
+
const nextFocusTrap = findAncestor(event, ATTRIBUTE_SELECTOR) as HTMLElement;
|
|
144
138
|
|
|
145
139
|
if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
|
|
146
140
|
if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
|
|
@@ -162,7 +156,7 @@ function onPointerdown(event: MouseEvent | TouchEvent): void {
|
|
|
162
156
|
}
|
|
163
157
|
|
|
164
158
|
function onTab(event: KeyboardEvent): void {
|
|
165
|
-
const element = findAncestor(event
|
|
159
|
+
const element = findAncestor(event, ATTRIBUTE_SELECTOR) as HTMLElement;
|
|
166
160
|
|
|
167
161
|
const focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
168
162
|
|
package/src/js/splitter.ts
CHANGED
|
@@ -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
|
|
326
|
+
findAncestor(event, '[oui-splitter-separator]') as HTMLSpanElement,
|
|
328
327
|
);
|
|
329
328
|
|
|
330
329
|
if (splitter == null) {
|
|
@@ -391,9 +390,7 @@ function onPointerdown(event: Event): void {
|
|
|
391
390
|
return;
|
|
392
391
|
}
|
|
393
392
|
|
|
394
|
-
splitter = MAPPED_ELEMENTS.get(
|
|
395
|
-
findAncestor(event.target as never, SELECTOR_HANDLE) as HTMLSpanElement,
|
|
396
|
-
);
|
|
393
|
+
splitter = MAPPED_ELEMENTS.get(findAncestor(event, SELECTOR_HANDLE) as HTMLSpanElement);
|
|
397
394
|
|
|
398
395
|
if (splitter == null) {
|
|
399
396
|
return;
|
package/src/js/tooltip.ts
CHANGED
|
@@ -79,12 +79,12 @@ function closeTooltips(next: Tooltip | undefined): void {
|
|
|
79
79
|
clearTimeout(active.timer);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
active.floatable
|
|
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
|
|
87
|
+
active.floatable?.toggle(false);
|
|
88
88
|
}, delay) as never;
|
|
89
89
|
});
|
|
90
90
|
}
|
|
@@ -192,7 +192,7 @@ function onActivate(event: Event): void {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
function onClick(event: Event): void {
|
|
195
|
-
if (findAncestor(event
|
|
195
|
+
if (findAncestor(event, SELECTOR_CONTENT) != null) {
|
|
196
196
|
event.stopPropagation();
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -209,7 +209,7 @@ function onToggle(event: Event, activate: boolean): void {
|
|
|
209
209
|
toggle = requestAnimationFrame(() => {
|
|
210
210
|
toggle = undefined;
|
|
211
211
|
|
|
212
|
-
const element = findAncestor(event
|
|
212
|
+
const element = findAncestor(event, SELECTOR_FULL) as HTMLElement;
|
|
213
213
|
|
|
214
214
|
const tooltip = TOOLTIPS_ALL.get(element);
|
|
215
215
|
|
|
@@ -286,7 +286,7 @@ const TOOLTIPS_ACTIVE: Set<Tooltip> = new Set();
|
|
|
286
286
|
|
|
287
287
|
const TOOLTIPS_ALL: WeakMap<HTMLElement, Tooltip> = new WeakMap();
|
|
288
288
|
|
|
289
|
-
let delay =
|
|
289
|
+
let delay = 500;
|
|
290
290
|
|
|
291
291
|
let index = 0;
|
|
292
292
|
|
package/dist/js/attributable.js
DELETED
|
@@ -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 };
|