@oscarpalmer/toretto 0.30.1 → 0.32.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 (42) hide show
  1. package/dist/attribute/index.js +5 -5
  2. package/dist/event/delegation.js +21 -28
  3. package/dist/event/index.js +1 -1
  4. package/dist/find/index.js +3 -3
  5. package/dist/find/relative.js +22 -22
  6. package/dist/html/index.js +11 -8
  7. package/dist/html/sanitize.js +29 -14
  8. package/dist/index.js +2 -2
  9. package/dist/internal/attribute.js +5 -5
  10. package/dist/is.js +3 -3
  11. package/dist/style.js +2 -2
  12. package/dist/toretto.full.js +125 -264
  13. package/package.json +6 -6
  14. package/src/attribute/get.ts +4 -12
  15. package/src/attribute/index.ts +5 -5
  16. package/src/attribute/set.ts +13 -13
  17. package/src/data.ts +7 -16
  18. package/src/event/delegation.ts +24 -52
  19. package/src/event/index.ts +1 -7
  20. package/src/find/index.ts +2 -2
  21. package/src/find/relative.ts +43 -49
  22. package/src/html/index.ts +13 -12
  23. package/src/html/sanitize.ts +58 -31
  24. package/src/internal/attribute.ts +9 -9
  25. package/src/internal/element-value.ts +3 -4
  26. package/src/internal/get-value.ts +5 -8
  27. package/src/internal/is.ts +1 -3
  28. package/src/is.ts +4 -4
  29. package/src/models.ts +0 -5
  30. package/src/style.ts +12 -15
  31. package/types/attribute/get.d.ts +3 -3
  32. package/types/attribute/set.d.ts +9 -9
  33. package/types/data.d.ts +4 -5
  34. package/types/event/delegation.d.ts +1 -1
  35. package/types/find/index.d.ts +1 -1
  36. package/types/find/relative.d.ts +8 -2
  37. package/types/internal/attribute.d.ts +7 -7
  38. package/types/internal/element-value.d.ts +2 -3
  39. package/types/internal/get-value.d.ts +2 -3
  40. package/types/internal/is.d.ts +1 -2
  41. package/types/models.d.ts +0 -4
  42. package/types/style.d.ts +7 -7
@@ -9,10 +9,7 @@ function getSupport() {
9
9
  if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
10
10
  return false;
11
11
  }
12
- /**
13
- * Does the device support touch events?
14
- */
15
- const supportsTouch = (() => {
12
+ var touch_default = (() => {
16
13
  let support = getSupport();
17
14
  const instance = Object.create({
18
15
  get() {
@@ -28,15 +25,13 @@ const supportsTouch = (() => {
28
25
  } });
29
26
  return instance;
30
27
  })();
31
- var touch_default = supportsTouch;
32
-
33
28
  function isPlainObject(value) {
34
29
  if (value === null || typeof value !== "object") return false;
35
30
  if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
36
31
  const prototype = Object.getPrototypeOf(value);
37
32
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
38
33
  }
39
- var TYPED_ARRAYS = new Set([
34
+ new Set([
40
35
  Int8Array,
41
36
  Uint8Array,
42
37
  Uint8ClampedArray,
@@ -49,7 +44,6 @@ var TYPED_ARRAYS = new Set([
49
44
  BigInt64Array,
50
45
  BigUint64Array
51
46
  ]);
52
-
53
47
  function compact(array, strict) {
54
48
  if (!Array.isArray(array)) return [];
55
49
  const { length } = array;
@@ -61,7 +55,6 @@ function compact(array, strict) {
61
55
  }
62
56
  return compacted;
63
57
  }
64
-
65
58
  function getString(value) {
66
59
  if (typeof value === "string") return value;
67
60
  if (value == null) return "";
@@ -77,12 +70,10 @@ function words(value) {
77
70
  return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
78
71
  }
79
72
  var EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
80
-
81
73
  function isNullableOrWhitespace(value) {
82
74
  return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
83
75
  }
84
76
  var EXPRESSION_WHITESPACE$1 = /^\s*$/;
85
-
86
77
  function camelCase(value) {
87
78
  return toCase(value, "", true, false);
88
79
  }
@@ -117,7 +108,6 @@ function toCase(value, delimiter, capitalizeAny, capitalizeFirst) {
117
108
  }
118
109
  var EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
119
110
  var EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
120
-
121
111
  function parse(value, reviver) {
122
112
  try {
123
113
  return JSON.parse(value, reviver);
@@ -125,24 +115,12 @@ function parse(value, reviver) {
125
115
  return;
126
116
  }
127
117
  }
128
-
129
- /**
130
- * Is the value an event target?
131
- * @param value Value to check
132
- * @returns `true` if it's an event target, otherwise `false`
133
- */
134
118
  function isEventTarget(value) {
135
119
  return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
136
120
  }
137
- /**
138
- * Is the value an HTML or SVG element?
139
- * @param value Value to check
140
- * @returns `true` if it's an HTML or SVG element, otherwise `false`
141
- */
142
121
  function isHTMLOrSVGElement(value) {
143
122
  return value instanceof HTMLElement || value instanceof SVGElement;
144
123
  }
145
-
146
124
  function badAttributeHandler(name, value) {
147
125
  if (name == null || value == null) return true;
148
126
  if (EXPRESSION_CLOBBERED_NAME.test(name) && (value in document || value in formElement) || EXPRESSION_EVENT_NAME.test(name)) return true;
@@ -176,21 +154,39 @@ function handleAttribute(callback, decode, first, second) {
176
154
  function isAttribute(value) {
177
155
  return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && typeof value.value === "string";
178
156
  }
179
- function isBadAttribute$1(first, second, decode) {
157
+ function _isBadAttribute(first, second, decode) {
180
158
  return handleAttribute(badAttributeHandler, decode, first, second);
181
159
  }
182
- function isBooleanAttribute$1(first, decode) {
160
+ function _isBooleanAttribute(first, decode) {
183
161
  return handleAttribute((name) => booleanAttributesSet.has(name?.toLowerCase()), decode, first, "");
184
162
  }
185
- function isEmptyNonBooleanAttribute$1(first, second, decode) {
163
+ function _isEmptyNonBooleanAttribute(first, second, decode) {
186
164
  return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
187
165
  }
188
- function isInvalidBooleanAttribute$1(first, second, decode) {
166
+ function _isInvalidBooleanAttribute(first, second, decode) {
189
167
  return handleAttribute(booleanAttributeHandler, decode, first, second);
190
168
  }
169
+ function isProperty(value) {
170
+ return isPlainObject(value) && typeof value.name === "string";
171
+ }
191
172
  function isValidSourceAttribute(name, value) {
192
173
  return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
193
174
  }
175
+ function updateAttribute(element, name, value) {
176
+ const isBoolean = booleanAttributesSet.has(name.toLowerCase());
177
+ if (isBoolean) updateProperty(element, name, value);
178
+ if (isBoolean ? value !== true : value == null) element.removeAttribute(name);
179
+ else element.setAttribute(name, isBoolean ? "" : getString(value));
180
+ }
181
+ function updateProperty(element, name, value) {
182
+ const actual = name.toLowerCase();
183
+ element[actual] = value === "" || typeof value === "string" && value.toLowerCase() === actual || value === true;
184
+ }
185
+ function updateValue(element, first, second) {
186
+ if (!isHTMLOrSVGElement(element)) return;
187
+ if (isProperty(first)) updateAttribute(element, first.name, first.value);
188
+ else if (typeof first === "string") updateAttribute(element, first, second);
189
+ }
194
190
  const EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
195
191
  const EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
196
192
  const EXPRESSION_EVENT_NAME = /^on/i;
@@ -199,9 +195,6 @@ const EXPRESSION_SOURCE_NAME = /^src$/i;
199
195
  const EXPRESSION_SOURCE_VALUE = /^data:/i;
200
196
  const EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
201
197
  const EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
202
- /**
203
- * List of boolean attributes
204
- */
205
198
  const booleanAttributes = Object.freeze([
206
199
  "async",
207
200
  "autofocus",
@@ -231,7 +224,6 @@ const booleanAttributes = Object.freeze([
231
224
  const booleanAttributesSet = new Set(booleanAttributes);
232
225
  const formElement = document.createElement("form");
233
226
  let textArea;
234
-
235
227
  function getBoolean(value, defaultValue) {
236
228
  return typeof value === "boolean" ? value : defaultValue ?? false;
237
229
  }
@@ -240,32 +232,28 @@ function getStyleValue(element, property, computed) {
240
232
  return computed ? getComputedStyle(element)[name] : element.style[name];
241
233
  }
242
234
  const EXPRESSION_DATA_PREFIX = /^data-/i;
243
-
235
+ function setAttribute(element, first, second) {
236
+ updateValue(element, first, second);
237
+ }
244
238
  function isBadAttribute(first, second) {
245
- return isBadAttribute$1(first, second, true);
239
+ return _isBadAttribute(first, second, true);
246
240
  }
247
241
  function isBooleanAttribute(first) {
248
- return isBooleanAttribute$1(first, true);
242
+ return _isBooleanAttribute(first, true);
249
243
  }
250
244
  function isEmptyNonBooleanAttribute(first, second) {
251
- return isEmptyNonBooleanAttribute$1(first, second, true);
245
+ return _isEmptyNonBooleanAttribute(first, second, true);
252
246
  }
253
247
  function isInvalidBooleanAttribute(first, second) {
254
- return isInvalidBooleanAttribute$1(first, second, true);
255
- }
256
-
257
- /**
258
- * Is the value a child node?
259
- * @param value Value to check
260
- * @returns `true` if it's a child node, otherwise `false`
261
- */
248
+ return _isInvalidBooleanAttribute(first, second, true);
249
+ }
262
250
  function isChildNode(value) {
263
251
  return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
264
252
  }
265
- function isInDocument(node, document$1) {
253
+ function isInDocument(node, doc) {
266
254
  if (!(node instanceof Node)) return false;
267
- if (!(document$1 instanceof Document)) return node.ownerDocument?.contains(node) ?? true;
268
- return node.ownerDocument == null ? node === document$1 : node.ownerDocument === document$1 && document$1.contains(node);
255
+ if (!(doc instanceof Document)) return node.ownerDocument?.contains(node) ?? true;
256
+ return node.ownerDocument == null ? node === doc : node.ownerDocument === doc && doc.contains(node);
269
257
  }
270
258
  const CHILD_NODE_TYPES = new Set([
271
259
  Node.ELEMENT_NODE,
@@ -274,7 +262,6 @@ const CHILD_NODE_TYPES = new Set([
274
262
  Node.COMMENT_NODE,
275
263
  Node.DOCUMENT_TYPE_NODE
276
264
  ]);
277
-
278
265
  function setElementValues(element, first, second, callback) {
279
266
  if (!isHTMLOrSVGElement(element)) return;
280
267
  if (isPlainObject(first)) {
@@ -290,7 +277,6 @@ function updateElementValue(element, key, value, set, remove, json) {
290
277
  if (isNullableOrWhitespace(value)) remove.call(element, key);
291
278
  else set.call(element, key, json ? JSON.stringify(value) : String(value));
292
279
  }
293
-
294
280
  function getData(element, keys, parseValues) {
295
281
  if (!isHTMLOrSVGElement(element)) return;
296
282
  const shouldParse = parseValues !== false;
@@ -319,7 +305,7 @@ function updateDataAttribute(element, key, value) {
319
305
  updateElementValue(element, getName(key), value, element.setAttribute, element.removeAttribute, true);
320
306
  }
321
307
  const ATTRIBUTE_DATA_PREFIX = "data-";
322
-
308
+ function noop() {}
323
309
  function calculate() {
324
310
  return new Promise((resolve) => {
325
311
  const values = [];
@@ -327,53 +313,51 @@ function calculate() {
327
313
  function step(now) {
328
314
  if (last != null) values.push(now - last);
329
315
  last = now;
330
- if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM));
316
+ if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(CALCULATION_TRIM_PART, -CALCULATION_TRIM_PART).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM_TOTAL));
331
317
  else requestAnimationFrame(step);
332
318
  }
333
319
  requestAnimationFrame(step);
334
320
  });
335
321
  }
336
- function noop() {}
337
322
  var CALCULATION_TOTAL = 10;
338
- var CALCULATION_TRIM = 4;
339
- let milliseconds = 1e3 / 60;
340
- calculate().then((value) => {
341
- milliseconds = value;
342
- });
343
-
344
- function addDelegatedHandler(document$1, type, name, passive) {
345
- const count = `${name}${COUNT_SUFFIX}`;
346
- if (document$1[count] != null) {
347
- document$1[count] += 1;
348
- return;
349
- }
350
- document$1[count] = 1;
351
- document$1.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
323
+ var CALCULATION_TRIM_PART = 2;
324
+ var CALCULATION_TRIM_TOTAL = 4;
325
+ calculate().then((value) => {});
326
+ function addDelegatedHandler(doc, type, name, passive) {
327
+ if (DELEGATED.has(name)) return;
328
+ DELEGATED.add(name);
329
+ doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
352
330
  }
353
331
  function addDelegatedListener(target, type, name, listener, passive) {
354
332
  target[name] ??= /* @__PURE__ */ new Set();
355
- target[name]?.add(listener);
333
+ target[name].add(listener);
356
334
  addDelegatedHandler(document, type, name, passive);
357
335
  return () => {
358
- removeDelegatedListener(target, type, name, listener, passive);
336
+ removeDelegatedListener(target, name, listener);
359
337
  };
360
338
  }
361
339
  function delegatedEventHandler(event) {
362
340
  const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
363
341
  const items = event.composedPath();
364
342
  const { length } = items;
365
- Object.defineProperty(event, "target", {
366
- configurable: true,
367
- value: items[0]
343
+ let target = items[0];
344
+ Object.defineProperties(event, {
345
+ currentTarget: {
346
+ configurable: true,
347
+ get() {
348
+ return target;
349
+ }
350
+ },
351
+ target: {
352
+ configurable: true,
353
+ value: target
354
+ }
368
355
  });
369
356
  for (let index = 0; index < length; index += 1) {
370
357
  const item = items[index];
371
358
  const listeners = item[key];
372
359
  if (item.disabled || listeners == null) continue;
373
- Object.defineProperty(event, "currentTarget", {
374
- configurable: true,
375
- value: item
376
- });
360
+ target = item;
377
361
  for (const listener of listeners) {
378
362
  listener.call(item, event);
379
363
  if (event.cancelBubble) return;
@@ -383,23 +367,14 @@ function delegatedEventHandler(event) {
383
367
  function getDelegatedName(target, type, options) {
384
368
  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}`;
385
369
  }
386
- function removeDelegatedHandler(document$1, type, name, passive) {
387
- const count = `${name}${COUNT_SUFFIX}`;
388
- document$1[count] -= 1;
389
- if (document$1[count] < 1) {
390
- document$1[count] = void 0;
391
- document$1.removeEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE);
392
- }
393
- }
394
- function removeDelegatedListener(target, type, name, listener, passive) {
370
+ function removeDelegatedListener(target, name, listener) {
395
371
  const handlers = target[name];
396
372
  if (handlers == null || !handlers.has(listener)) return false;
397
373
  handlers.delete(listener);
398
374
  if (handlers.size === 0) target[name] = void 0;
399
- removeDelegatedHandler(document, type, name, passive);
400
375
  return true;
401
376
  }
402
- const COUNT_SUFFIX = ".count";
377
+ const DELEGATED = /* @__PURE__ */ new Set();
403
378
  const EVENT_PREFIX = "@";
404
379
  const EVENT_SUFFIX_ACTIVE = ":active";
405
380
  const EVENT_SUFFIX_PASSIVE = ":passive";
@@ -429,7 +404,6 @@ const EVENT_TYPES = new Set([
429
404
  ]);
430
405
  const HANDLER_ACTIVE = delegatedEventHandler.bind(false);
431
406
  const HANDLER_PASSIVE = delegatedEventHandler.bind(true);
432
-
433
407
  function createDispatchOptions(options) {
434
408
  return {
435
409
  bubbles: getBoolean(options?.bubbles, true),
@@ -456,11 +430,6 @@ function createEventOptions(options) {
456
430
  function dispatch(target, type, options) {
457
431
  if (isEventTarget(target) && typeof type === "string") target.dispatchEvent(createEvent(type, options));
458
432
  }
459
- /**
460
- * Get the X- and Y-coordinates from a pointer event
461
- * @param event Pointer event
462
- * @returns X- and Y-coordinates
463
- */
464
433
  function getPosition(event) {
465
434
  let x;
466
435
  let y;
@@ -476,18 +445,11 @@ function getPosition(event) {
476
445
  y
477
446
  } : void 0;
478
447
  }
479
- /**
480
- * Remove an event listener
481
- * @param target Event target
482
- * @param type Type of event
483
- * @param listener Event listener
484
- * @param options Options for event
485
- */
486
448
  function off(target, type, listener, options) {
487
449
  if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return;
488
450
  const extended = createEventOptions(options);
489
451
  const delegated = getDelegatedName(target, type, extended);
490
- if (delegated == null || !removeDelegatedListener(target, type, delegated, listener, extended.passive)) target.removeEventListener(type, listener, extended);
452
+ if (delegated == null || !removeDelegatedListener(target, delegated, listener)) target.removeEventListener(type, listener, extended);
491
453
  }
492
454
  function on(target, type, listener, options) {
493
455
  if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
@@ -501,28 +463,6 @@ function on(target, type, listener, options) {
501
463
  };
502
464
  }
503
465
  const PROPERTY_DETAIL = "detail";
504
-
505
- /**
506
- * - Get the distance between two elements _(i.e., the amount of nodes of between them)_
507
- * - If the distance cannot be calculated, `-1` is returned
508
- */
509
- function getDistanceBetweenElements(origin, target) {
510
- if (origin === target || origin.parentElement === target) return 0;
511
- const comparison = origin.compareDocumentPosition(target);
512
- const children = [...origin.parentElement?.children ?? []];
513
- if (children.includes(target)) return Math.abs(children.indexOf(origin) - children.indexOf(target));
514
- const beforeOrInside = !!(comparison & 2 || comparison & 8);
515
- if (beforeOrInside || !!(comparison & 4 || comparison & 16)) return traverse(beforeOrInside ? origin : target, beforeOrInside ? target : origin) ?? -1;
516
- }
517
- /**
518
- * Find the closest ancestor element that matches the selector _(string or callback)_
519
- *
520
- * - If no match is found, `null` is returned
521
- * - _(If you want to search upwards, downwards, and sideways, use {@link findRelatives})_
522
- * @param origin Element to start from
523
- * @param selector Selector to match
524
- * @returns Found ancestor or `null`
525
- */
526
466
  function findAncestor(origin, selector) {
527
467
  if (!(origin instanceof Element) || selector == null) return null;
528
468
  if (typeof selector === "string") {
@@ -538,29 +478,17 @@ function findAncestor(origin, selector) {
538
478
  }
539
479
  return parent;
540
480
  }
541
- /**
542
- * Finds the closest elements to the origin element that matches the selector
543
- *
544
- * - Traverses up, down, and sideways in the _DOM_-tree
545
- * - _(If you only want to traverse up, use {@link findAncestor})_
546
- * @param origin Element to start from
547
- * @param selector Selector to match
548
- * @param context Context to search within
549
- * @returns Found elements
550
- */
551
481
  function findRelatives(origin, selector, context) {
552
482
  if (!(origin instanceof Element) || typeof selector !== "string") return [];
553
- if (origin.matches(selector)) return [origin];
554
483
  const elements = [...(context instanceof Document || context instanceof Element ? context : document).querySelectorAll(selector)];
555
484
  const { length } = elements;
556
- if (length === 0) return [];
557
- if (length === 1) return [elements[0]];
485
+ if (length < 2) return elements.filter((element) => element !== origin);
558
486
  const distances = [];
559
487
  let minimum;
560
488
  for (let index = 0; index < length; index += 1) {
561
489
  const element = elements[index];
562
- const distance = getDistanceBetweenElements(origin, element) ?? -1;
563
- if (distance > -1) {
490
+ const distance = getDistance(origin, element);
491
+ if (distance > 0) {
564
492
  if (minimum == null || distance < minimum) minimum = distance;
565
493
  distances.push({
566
494
  distance,
@@ -568,35 +496,38 @@ function findRelatives(origin, selector, context) {
568
496
  });
569
497
  }
570
498
  }
571
- return minimum == null ? [] : distances.filter((found) => found.distance === minimum).map((found) => found.element);
499
+ return distances.filter((found) => found.distance === minimum).map((found) => found.element);
500
+ }
501
+ function getDistance(origin, target) {
502
+ if (origin === target) return 0;
503
+ if (origin.parentElement === target || target.parentElement === origin) return 1;
504
+ if (origin.parentElement != null && origin.parentElement === target.parentElement) {
505
+ const children = [...origin.parentElement.children];
506
+ return Math.abs(children.indexOf(origin) - children.indexOf(target));
507
+ }
508
+ const comparison = origin.compareDocumentPosition(target);
509
+ if (comparison & Node.DOCUMENT_POSITION_DISCONNECTED) return -1;
510
+ const preceding = comparison & Node.DOCUMENT_POSITION_PRECEDING;
511
+ return traverse(preceding ? origin : target, preceding ? target : origin) ?? -1;
572
512
  }
573
513
  function traverse(from, to) {
574
- let index = [...to.children].indexOf(from);
575
- if (index > -1) return index + 1;
576
514
  let current = from;
577
515
  let distance = 0;
578
516
  let parent = from.parentElement;
579
517
  while (parent != null) {
580
518
  if (parent === to) return distance + 1;
581
- const children = [...parent.children ?? []];
582
- if (children.includes(to)) return distance + Math.abs(children.indexOf(current) - children.indexOf(to));
583
- index = children.findIndex((child) => child.contains(to));
519
+ const children = [...parent.children];
520
+ if (to.parentElement === parent) return distance + Math.abs(children.indexOf(current) - children.indexOf(to));
521
+ const index = children.findIndex((child) => child.contains(to));
584
522
  if (index > -1) {
585
- const traversed = traverse(current, children[index]) ?? -1;
586
- return traversed === -1 ? -1 : distance + Math.abs(index - children.indexOf(current)) + traversed;
523
+ const traversed = traverse(current, children[index]);
524
+ return traversed == null || traversed === -1 ? -1 : distance + Math.abs(index - children.indexOf(current)) + traversed;
587
525
  }
588
526
  current = parent;
589
527
  distance += 1;
590
528
  parent = parent.parentElement;
591
529
  }
592
530
  }
593
-
594
- /**
595
- * Find the first element that matches the selector
596
- * @param selector Selector to find element for
597
- * @param context Context to search within _(defaults to `document`)_
598
- * @returns Found element or `null`
599
- */
600
531
  function findElement(selector, context) {
601
532
  return findElementOrElements(selector, context, true);
602
533
  }
@@ -631,27 +562,13 @@ function findElementOrElementsFromNodes(array, context, contexts) {
631
562
  let element;
632
563
  if (node instanceof Document) element = node.body;
633
564
  else element = node instanceof Element ? node : void 0;
634
- if (element != null && (context == null || contexts.length === 0 || contexts.some((context$1) => context$1 === element || context$1.contains(element))) && !result.includes(element)) result.push(element);
565
+ if (element != null && (context == null || contexts.length === 0 || contexts.some((ctx) => ctx === element || ctx.contains(element))) && !result.includes(element)) result.push(element);
635
566
  }
636
567
  return result;
637
568
  }
638
- /**
639
- * Find elements that match the selector
640
- * @param selector Selector to find elements for
641
- * @param context Context to search within _(defaults to `document`)_
642
- * @returns Found elements
643
- */
644
569
  function findElements(selector, context) {
645
570
  return findElementOrElements(selector, context, false);
646
571
  }
647
- /**
648
- * Get the most specific element under the pointer
649
- *
650
- * - Ignores elements with `pointer-events: none` and `visibility: hidden`
651
- * - _(If `skipIgnore` is `true`, no elements are ignored)_
652
- * @param skipIgnore Skip ignored elements?
653
- * @returns Found element or `null`
654
- */
655
572
  function getElementUnderPointer(skipIgnore) {
656
573
  const elements = [...document.querySelectorAll(SUFFIX_HOVER)];
657
574
  const { length } = elements;
@@ -673,12 +590,6 @@ const STYLE_HIDDEN$1 = "hidden";
673
590
  const STYLE_NONE$1 = "none";
674
591
  const SUFFIX_HOVER = ":hover";
675
592
  const TAG_HEAD = "HEAD";
676
-
677
- /**
678
- * Get a list of focusable elements within a parent element
679
- * @param parent Parent element
680
- * @returns Focusable elements
681
- */
682
593
  function getFocusable(parent) {
683
594
  return getValidElements(parent, FILTERS_FOCUSABLE, false);
684
595
  }
@@ -688,11 +599,6 @@ function getItem(element, tabbable) {
688
599
  tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
689
600
  };
690
601
  }
691
- /**
692
- * Get a list of tabbable elements within a parent element
693
- * @param parent Parent element
694
- * @returns Tabbable elements
695
- */
696
602
  function getTabbable(parent) {
697
603
  return getValidElements(parent, FILTERS_TABBABLE, true);
698
604
  }
@@ -747,11 +653,6 @@ function isDisabledFromFieldset(element) {
747
653
  function isEditable(element) {
748
654
  return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
749
655
  }
750
- /**
751
- * Is the element focusable?
752
- * @param element Element to check
753
- * @returns `true` if focusable, otherwise `false`
754
- */
755
656
  function isFocusable(element) {
756
657
  return element instanceof Element ? isValidElement(element, FILTERS_FOCUSABLE, false) : false;
757
658
  }
@@ -782,11 +683,6 @@ function isNotTabbableRadio(item) {
782
683
  function isSummarised(item) {
783
684
  return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
784
685
  }
785
- /**
786
- * Is the element tabbable?
787
- * @param element Element to check
788
- * @returns `true` if tabbable, otherwise `false`
789
- */
790
686
  function isTabbable(element) {
791
687
  return element instanceof Element ? isValidElement(element, FILTERS_TABBABLE, true) : false;
792
688
  }
@@ -835,33 +731,25 @@ const STYLE_NONE = "none";
835
731
  const TABINDEX_BASE = 0;
836
732
  const TABINDEX_DEFAULT = -1;
837
733
  const TYPE_RADIO = "radio";
838
-
839
734
  function handleElement(element, depth) {
840
- if (isClobbered(element)) {
841
- element.remove();
842
- return true;
843
- }
844
735
  if (depth === 0) {
845
- const scripts = element.querySelectorAll("script");
846
- for (const script of scripts) script.remove();
736
+ const removable = element.querySelectorAll(REMOVE_SELECTOR);
737
+ for (const item of removable) item.remove();
847
738
  }
848
739
  sanitizeAttributes(element, [...element.attributes]);
849
- return false;
850
740
  }
851
- /**
852
- * Is the element clobbered?
853
- *
854
- * Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
855
- */
856
- function isClobbered(element) {
857
- return element instanceof HTMLFormElement && (typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function");
741
+ function isClobbered(value) {
742
+ return value instanceof HTMLFormElement && (typeof value.nodeName !== "string" || typeof value.textContent !== "string" || typeof value.removeChild !== "function" || !(value.attributes instanceof NamedNodeMap) || typeof value.removeAttribute !== "function" || typeof value.setAttribute !== "function" || typeof value.namespaceURI !== "string" || typeof value.insertBefore !== "function" || typeof value.hasChildNodes !== "function");
743
+ }
744
+ function removeNode(node) {
745
+ if (typeof node.remove === "function") node.remove();
858
746
  }
859
747
  function sanitizeAttributes(element, attributes) {
860
748
  const { length } = attributes;
861
749
  for (let index = 0; index < length; index += 1) {
862
750
  const { name, value } = attributes[index];
863
- if (isBadAttribute$1(name, value, false) || isEmptyNonBooleanAttribute$1(name, value, false)) element.removeAttribute(name);
864
- else if (isInvalidBooleanAttribute$1(name, value, false)) element.setAttribute(name, "");
751
+ if (_isBadAttribute(name, value, false) || _isEmptyNonBooleanAttribute(name, value, false)) element.removeAttribute(name);
752
+ else if (_isInvalidBooleanAttribute(name, value, false)) setAttribute(element, name, true);
865
753
  }
866
754
  }
867
755
  function sanitizeNodes(nodes, depth) {
@@ -869,22 +757,37 @@ function sanitizeNodes(nodes, depth) {
869
757
  let { length } = nodes;
870
758
  for (let index = 0; index < length; index += 1) {
871
759
  const node = actual[index];
872
- if (node instanceof Element && handleElement(node, depth)) {
760
+ let remove = isClobbered(node);
761
+ if (!remove) switch (node.nodeType) {
762
+ case Node.ELEMENT_NODE:
763
+ handleElement(node, depth);
764
+ break;
765
+ case Node.COMMENT_NODE:
766
+ remove = COMMENT_HARMFUL.test(node.data);
767
+ break;
768
+ case Node.DOCUMENT_TYPE_NODE:
769
+ case Node.PROCESSING_INSTRUCTION_NODE:
770
+ remove = true;
771
+ break;
772
+ }
773
+ if (remove) {
774
+ removeNode(node);
873
775
  actual.splice(index, 1);
874
- length -= 1;
875
776
  index -= 1;
777
+ length -= 1;
876
778
  continue;
877
779
  }
878
780
  if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], depth + 1);
879
781
  }
880
782
  return nodes;
881
783
  }
882
-
784
+ const COMMENT_HARMFUL = /<[/\w]/g;
785
+ const REMOVE_SELECTOR = "script, toretto-temporary";
883
786
  function createHtml(value) {
884
- const html$1 = getParser().parseFromString(typeof value === "string" ? value : value.innerHTML, HTML_PARSE_TYPE);
885
- html$1.body.normalize();
886
- sanitizeNodes([html$1.body], 0);
887
- return html$1.body.innerHTML;
787
+ const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
788
+ parsed.body.normalize();
789
+ sanitizeNodes([parsed.body], 0);
790
+ return parsed.body.innerHTML;
888
791
  }
889
792
  function createTemplate(value, options) {
890
793
  const template = document.createElement(TEMPLATE_TAG);
@@ -892,6 +795,9 @@ function createTemplate(value, options) {
892
795
  if (typeof value === "string" && options.cache) templates[value] = template;
893
796
  return template;
894
797
  }
798
+ function getHtml(value) {
799
+ return `${TEMPORARY_ELEMENT}${typeof value === "string" ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
800
+ }
895
801
  function getNodes(value, options) {
896
802
  if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
897
803
  const template = getTemplate(value, options);
@@ -908,12 +814,11 @@ function getParser() {
908
814
  }
909
815
  function getTemplate(value, options) {
910
816
  if (value instanceof HTMLTemplateElement) return createTemplate(value, options);
911
- if (typeof value !== "string" || value.trim().length === 0) return;
817
+ if (value.trim().length === 0) return;
912
818
  let template = templates[value];
913
819
  if (template != null) return template;
914
820
  const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
915
- template = element instanceof HTMLTemplateElement ? element : createTemplate(value, options);
916
- return template;
821
+ return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
917
822
  }
918
823
  const html = ((value, options) => {
919
824
  return getNodes(value, getOptions(options));
@@ -932,39 +837,19 @@ html.remove = (template) => {
932
837
  }
933
838
  templates = updated;
934
839
  };
935
- /**
936
- * Sanitize one or more nodes, recursively
937
- * @param value Node or nodes to sanitize
938
- * @param options Sanitization options
939
- * @returns Sanitized nodes
940
- */
941
840
  function sanitize(value) {
942
841
  return sanitizeNodes(Array.isArray(value) ? value : [value], 0);
943
842
  }
944
843
  const EXPRESSION_ID = /^[a-z][\w-]*$/i;
945
- const HTML_PARSE_TYPE = "text/html";
844
+ const PARSE_TYPE_HTML = "text/html";
946
845
  const TEMPLATE_TAG = "template";
846
+ const TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
947
847
  let parser;
948
848
  let templates = {};
949
-
950
- /**
951
- * Get a style from an element
952
- * @param element Element to get the style from
953
- * @param property Style name
954
- * @param computed Get the computed style? _(defaults to `false`)_
955
- * @returns Style value
956
- */
957
849
  function getStyle(element, property, computed) {
958
850
  if (!isHTMLOrSVGElement(element) || typeof property !== "string") return;
959
851
  return getStyleValue(element, property, computed === true);
960
852
  }
961
- /**
962
- * Get styles from an element
963
- * @param element Element to get the styles from
964
- * @param properties Styles to get
965
- * @param computed Get the computed styles? _(defaults to `false`)_
966
- * @returns Style values
967
- */
968
853
  function getStyles(element, properties, computed) {
969
854
  const styles = {};
970
855
  if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
@@ -975,12 +860,6 @@ function getStyles(element, properties, computed) {
975
860
  }
976
861
  return styles;
977
862
  }
978
- /**
979
- * Get the text direction of an element
980
- * @param element Element to get the text direction from
981
- * @param computed Get the computed text direction? _(defaults to `false`)_
982
- * @returns Text direction
983
- */
984
863
  function getTextDirection(element, computed) {
985
864
  if (!(element instanceof Element)) return;
986
865
  const direction = element.getAttribute(ATTRIBUTE_DIRECTION);
@@ -988,29 +867,12 @@ function getTextDirection(element, computed) {
988
867
  const value = getStyleValue(element, "direction", computed === true);
989
868
  return value === "rtl" ? value : "ltr";
990
869
  }
991
- /**
992
- * Set a style on an element
993
- * @param element Element to set the style on
994
- * @param property Style name
995
- * @param value Style value
996
- */
997
870
  function setStyle(element, property, value) {
998
871
  setElementValues(element, property, value, updateStyleProperty);
999
872
  }
1000
- /**
1001
- * Set styles on an element
1002
- * @param element Element to set the styles on
1003
- * @param styles Styles to set
1004
- */
1005
873
  function setStyles(element, styles) {
1006
874
  setElementValues(element, styles, null, updateStyleProperty);
1007
875
  }
1008
- /**
1009
- * Toggle styles for an element
1010
- * @param element Element to style
1011
- * @param styles Styles to be set or removed
1012
- * @returns Style toggler
1013
- */
1014
876
  function toggleStyles(element, styles) {
1015
877
  function toggle(set) {
1016
878
  hasSet = set;
@@ -1038,13 +900,12 @@ function toggleStyles(element, styles) {
1038
900
  };
1039
901
  }
1040
902
  function updateStyleProperty(element, key, value) {
1041
- updateElementValue(element, key, value, function(property, value$1) {
1042
- this.style[property] = value$1;
903
+ updateElementValue(element, key, value, function(property, style) {
904
+ this.style[property] = style;
1043
905
  }, function(property) {
1044
906
  this.style[property] = "";
1045
907
  }, false);
1046
908
  }
1047
909
  const ATTRIBUTE_DIRECTION = "dir";
1048
910
  const EXPRESSION_DIRECTION = /^(ltr|rtl)$/i;
1049
-
1050
- export { findElement as $, findElement, findElements as $$, findElements, dispatch, findAncestor, findRelatives, getData, getElementUnderPointer, getFocusable, getPosition, getStyle, getStyles, getTabbable, getTextDirection, html, isBadAttribute, isBooleanAttribute, isChildNode, isEmptyNonBooleanAttribute, isEventTarget, isFocusable, isHTMLOrSVGElement, isInDocument, isInvalidBooleanAttribute, isTabbable, off, on, sanitize, setData, setStyle, setStyles, touch_default as supportsTouch, toggleStyles };
911
+ export { findElement as $, findElement, findElements as $$, findElements, dispatch, findAncestor, findRelatives, getData, getDistance, getElementUnderPointer, getFocusable, getPosition, getStyle, getStyles, getTabbable, getTextDirection, html, isBadAttribute, isBooleanAttribute, isChildNode, isEmptyNonBooleanAttribute, isEventTarget, isFocusable, isHTMLOrSVGElement, isInDocument, isInvalidBooleanAttribute, isTabbable, off, on, sanitize, setData, setStyle, setStyles, touch_default as supportsTouch, toggleStyles };