@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
package/package.json CHANGED
@@ -4,16 +4,16 @@
4
4
  "url": "https://oscarpalmer.se"
5
5
  },
6
6
  "dependencies": {
7
- "@oscarpalmer/atoms": "^0.115"
7
+ "@oscarpalmer/atoms": "^0.117"
8
8
  },
9
9
  "description": "A collection of badass DOM utilities.",
10
10
  "devDependencies": {
11
11
  "@types/node": "^25",
12
12
  "@vitest/coverage-istanbul": "^4",
13
13
  "jsdom": "^27.3",
14
- "oxfmt": "^0.18",
15
- "oxlint": "^1.33",
16
- "rolldown": "1.0.0-beta.55",
14
+ "oxfmt": "^0.19",
15
+ "oxlint": "^1.34",
16
+ "rolldown": "1.0.0-beta.56",
17
17
  "tslib": "^2.8",
18
18
  "typescript": "^5.9",
19
19
  "vite": "8.0.0-beta.2",
@@ -87,11 +87,11 @@
87
87
  "build": "npm run clean && npx vite build && npm run rolldown:build && npx tsc",
88
88
  "clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
89
89
  "rolldown:build": "npx rolldown -c",
90
- "rolldown:watch": "npx rolldown -c --watch",
90
+ "rolldown:watch": "npx rolldown -c ./rolldown.config.js --watch",
91
91
  "test": "npx vitest --coverage",
92
92
  "watch": "npx vite build --watch"
93
93
  },
94
94
  "type": "module",
95
95
  "types": "types/index.d.ts",
96
- "version": "0.30.1"
96
+ "version": "0.32.0"
97
97
  }
@@ -8,11 +8,7 @@ import {isHTMLOrSVGElement} from '../internal/is';
8
8
  * @param parse Parse value? _(defaults to `true`)_
9
9
  * @returns Attribute value _(or `undefined`)_
10
10
  */
11
- export function getAttribute(
12
- element: HTMLOrSVGElement,
13
- name: `data-${string}`,
14
- parse?: boolean,
15
- ): unknown;
11
+ export function getAttribute(element: Element, name: `data-${string}`, parse?: boolean): unknown;
16
12
 
17
13
  /**
18
14
  * Get the value of a specific attribute from an element
@@ -20,13 +16,9 @@ export function getAttribute(
20
16
  * @param name Attribute name
21
17
  * @returns Attribute value _(or `undefined`)_
22
18
  */
23
- export function getAttribute(element: HTMLOrSVGElement, name: string): unknown;
19
+ export function getAttribute(element: Element, name: string): unknown;
24
20
 
25
- export function getAttribute(
26
- element: HTMLOrSVGElement,
27
- name: string,
28
- parseValues?: boolean,
29
- ): unknown {
21
+ export function getAttribute(element: Element, name: string, parseValues?: boolean): unknown {
30
22
  if (isHTMLOrSVGElement(element) && typeof name === 'string') {
31
23
  return getAttributeValue(element, name, parseValues !== false);
32
24
  }
@@ -40,7 +32,7 @@ export function getAttribute(
40
32
  * @returns Object of named attributes
41
33
  */
42
34
  export function getAttributes<Key extends string>(
43
- element: HTMLOrSVGElement,
35
+ element: Element,
44
36
  names: Key[],
45
37
  parseData?: boolean,
46
38
  ): Record<Key, unknown> {
@@ -1,8 +1,8 @@
1
1
  import {
2
- isBadAttribute as internalIsBadAttribute,
3
- isBooleanAttribute as _isBooleanAttribute,
4
- isEmptyNonBooleanAttribute as _isEmptyNonBooleanAttribute,
5
- isInvalidBooleanAttribute as _isInvalidBooleanAttribute,
2
+ _isBadAttribute,
3
+ _isBooleanAttribute,
4
+ _isEmptyNonBooleanAttribute,
5
+ _isInvalidBooleanAttribute,
6
6
  } from '../internal/attribute';
7
7
  import type {Attribute} from '../models';
8
8
 
@@ -22,7 +22,7 @@ export function isBadAttribute(attribute: Attr | Attribute): boolean;
22
22
  export function isBadAttribute(name: string, value: string): boolean;
23
23
 
24
24
  export function isBadAttribute(first: unknown, second?: unknown): boolean {
25
- return internalIsBadAttribute(first, second, true);
25
+ return _isBadAttribute(first, second, true);
26
26
  }
27
27
 
28
28
  /**
@@ -1,5 +1,5 @@
1
1
  import {updateValue, updateValues} from '../internal/attribute';
2
- import type {Attribute, HTMLOrSVGElement, Property} from '../models';
2
+ import type {Attribute, Property} from '../models';
3
3
 
4
4
  /**
5
5
  * Set an attribute on an element
@@ -9,7 +9,7 @@ import type {Attribute, HTMLOrSVGElement, Property} from '../models';
9
9
  * @param name Attribute name
10
10
  * @param value Attribute value
11
11
  */
12
- export function setAttribute(element: HTMLOrSVGElement, name: string, value?: unknown): void;
12
+ export function setAttribute(element: Element, name: string, value?: unknown): void;
13
13
 
14
14
  /**
15
15
  * Set an attribute on an element
@@ -18,9 +18,9 @@ export function setAttribute(element: HTMLOrSVGElement, name: string, value?: un
18
18
  * @param element Element for attribute
19
19
  * @param attribute Attribute to set
20
20
  */
21
- export function setAttribute(element: HTMLOrSVGElement, attribute: Attr | Attribute): void;
21
+ export function setAttribute(element: Element, attribute: Attr | Attribute): void;
22
22
 
23
- export function setAttribute(element: HTMLOrSVGElement, first: unknown, second?: unknown): void {
23
+ export function setAttribute(element: Element, first: unknown, second?: unknown): void {
24
24
  updateValue(element, first, second);
25
25
  }
26
26
 
@@ -31,7 +31,7 @@ export function setAttribute(element: HTMLOrSVGElement, first: unknown, second?:
31
31
  * @param element Element for attributes
32
32
  * @param attributes Attributes to set
33
33
  */
34
- export function setAttributes(element: HTMLOrSVGElement, attributes: Array<Attr | Attribute>): void;
34
+ export function setAttributes(element: Element, attributes: Array<Attr | Attribute>): void;
35
35
 
36
36
  /**
37
37
  * Set one or more attributes on an element
@@ -40,10 +40,10 @@ export function setAttributes(element: HTMLOrSVGElement, attributes: Array<Attr
40
40
  * @param element Element for attributes
41
41
  * @param attributes Attributes to set
42
42
  */
43
- export function setAttributes(element: HTMLOrSVGElement, attributes: Record<string, unknown>): void;
43
+ export function setAttributes(element: Element, attributes: Record<string, unknown>): void;
44
44
 
45
45
  export function setAttributes(
46
- element: HTMLOrSVGElement,
46
+ element: Element,
47
47
  attributes: Attribute[] | Record<string, unknown>,
48
48
  ): void {
49
49
  updateValues(element, attributes);
@@ -57,7 +57,7 @@ export function setAttributes(
57
57
  * @param name Property name
58
58
  * @param value Property value
59
59
  */
60
- export function setProperty(element: HTMLOrSVGElement, name: string, value: boolean | string): void;
60
+ export function setProperty(element: Element, name: string, value: boolean | string): void;
61
61
 
62
62
  /**
63
63
  * Set a property on an element
@@ -66,9 +66,9 @@ export function setProperty(element: HTMLOrSVGElement, name: string, value: bool
66
66
  * @param element Element for property
67
67
  * @param property Property to set
68
68
  */
69
- export function setProperty(element: HTMLOrSVGElement, property: Property): void;
69
+ export function setProperty(element: Element, property: Property): void;
70
70
 
71
- export function setProperty(element: HTMLOrSVGElement, first: unknown, second?: unknown): void {
71
+ export function setProperty(element: Element, first: unknown, second?: unknown): void {
72
72
  updateValue(element, first, second);
73
73
  }
74
74
 
@@ -79,7 +79,7 @@ export function setProperty(element: HTMLOrSVGElement, first: unknown, second?:
79
79
  * @param element Element for properties
80
80
  * @param properties Properties to set
81
81
  */
82
- export function setProperties(element: HTMLOrSVGElement, properties: Property[]): void;
82
+ export function setProperties(element: Element, properties: Property[]): void;
83
83
 
84
84
  /**
85
85
  * Set one or more properties on an element
@@ -88,10 +88,10 @@ export function setProperties(element: HTMLOrSVGElement, properties: Property[])
88
88
  * @param element Element for properties
89
89
  * @param properties Properties to set
90
90
  */
91
- export function setProperties(element: HTMLOrSVGElement, properties: Record<string, unknown>): void;
91
+ export function setProperties(element: Element, properties: Record<string, unknown>): void;
92
92
 
93
93
  export function setProperties(
94
- element: HTMLOrSVGElement,
94
+ element: Element,
95
95
  properties: Property[] | Record<string, unknown>,
96
96
  ): void {
97
97
  updateValues(element, properties);
package/src/data.ts CHANGED
@@ -3,7 +3,6 @@ import {kebabCase, parse} from '@oscarpalmer/atoms/string';
3
3
  import {setElementValues, updateElementValue} from './internal/element-value';
4
4
  import {EXPRESSION_DATA_PREFIX} from './internal/get-value';
5
5
  import {isHTMLOrSVGElement} from './internal/is';
6
- import type {HTMLOrSVGElement} from './models';
7
6
 
8
7
  /**
9
8
  * Get a keyed data value from an element
@@ -12,7 +11,7 @@ import type {HTMLOrSVGElement} from './models';
12
11
  * @param parse Parse values? _(defaults to `true`)_
13
12
  * @returns Data value
14
13
  */
15
- export function getData(element: HTMLOrSVGElement, key: string, parse?: boolean): unknown;
14
+ export function getData(element: Element, key: string, parse?: boolean): unknown;
16
15
 
17
16
  /**
18
17
  * Get keyed data values from an element
@@ -22,16 +21,12 @@ export function getData(element: HTMLOrSVGElement, key: string, parse?: boolean)
22
21
  * @returns Keyed data values
23
22
  */
24
23
  export function getData<Key extends string>(
25
- element: HTMLOrSVGElement,
24
+ element: Element,
26
25
  keys: Key[],
27
26
  parse?: boolean,
28
27
  ): Record<Key, unknown>;
29
28
 
30
- export function getData(
31
- element: HTMLOrSVGElement,
32
- keys: string | string[],
33
- parseValues?: boolean,
34
- ): unknown {
29
+ export function getData(element: Element, keys: string | string[], parseValues?: boolean): unknown {
35
30
  if (!isHTMLOrSVGElement(element)) {
36
31
  return;
37
32
  }
@@ -75,7 +70,7 @@ function getName(original: string): string {
75
70
  * @param element Element to set data on
76
71
  * @param data Data to set
77
72
  */
78
- export function setData(element: HTMLOrSVGElement, data: PlainObject): void;
73
+ export function setData(element: Element, data: PlainObject): void;
79
74
 
80
75
  /**
81
76
  * Set a data value on an element
@@ -83,17 +78,13 @@ export function setData(element: HTMLOrSVGElement, data: PlainObject): void;
83
78
  * @param key Data key
84
79
  * @param value Data value
85
80
  */
86
- export function setData(element: HTMLOrSVGElement, key: string, value: unknown): void;
81
+ export function setData(element: Element, key: string, value: unknown): void;
87
82
 
88
- export function setData(
89
- element: HTMLOrSVGElement,
90
- first: PlainObject | string,
91
- second?: unknown,
92
- ): void {
83
+ export function setData(element: Element, first: PlainObject | string, second?: unknown): void {
93
84
  setElementValues(element, first, second, updateDataAttribute);
94
85
  }
95
86
 
96
- function updateDataAttribute(element: HTMLOrSVGElement, key: string, value: unknown): void {
87
+ function updateDataAttribute(element: Element, key: string, value: unknown): void {
97
88
  updateElementValue(
98
89
  element,
99
90
  getName(key),
@@ -3,33 +3,19 @@ import type {CustomEventListener, RemovableEventListener} from '../models';
3
3
 
4
4
  //
5
5
 
6
- type DocumentWithListenerCounts = Document &
7
- Partial<{
8
- [key: string]: number;
9
- }>;
10
-
11
6
  export type EventTargetWithListeners = EventTarget &
12
7
  Partial<{
13
8
  [key: string]: Set<EventListener | CustomEventListener>;
14
9
  }>;
15
10
 
16
- function addDelegatedHandler(
17
- document: DocumentWithListenerCounts,
18
- type: string,
19
- name: string,
20
- passive: boolean,
21
- ): void {
22
- const count = `${name}${COUNT_SUFFIX}`;
23
-
24
- if (document[count] != null) {
25
- (document[count] as number) += 1;
26
-
11
+ function addDelegatedHandler(doc: Document, type: string, name: string, passive: boolean): void {
12
+ if (DELEGATED.has(name)) {
27
13
  return;
28
14
  }
29
15
 
30
- document[count] = 1;
16
+ DELEGATED.add(name);
31
17
 
32
- document.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, {
18
+ doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, {
33
19
  passive,
34
20
  });
35
21
  }
@@ -43,12 +29,12 @@ export function addDelegatedListener(
43
29
  ): RemovableEventListener {
44
30
  target[name] ??= new Set();
45
31
 
46
- target[name]?.add(listener);
32
+ target[name].add(listener);
47
33
 
48
- addDelegatedHandler(document as DocumentWithListenerCounts, type, name, passive);
34
+ addDelegatedHandler(document, type, name, passive);
49
35
 
50
36
  return () => {
51
- removeDelegatedListener(target, type, name, listener, passive);
37
+ removeDelegatedListener(target, name, listener);
52
38
  };
53
39
  }
54
40
 
@@ -58,9 +44,19 @@ function delegatedEventHandler(this: boolean, event: Event): void {
58
44
  const items = event.composedPath();
59
45
  const {length} = items;
60
46
 
61
- Object.defineProperty(event, 'target', {
62
- configurable: true,
63
- value: items[0],
47
+ let target = items[0];
48
+
49
+ Object.defineProperties(event, {
50
+ currentTarget: {
51
+ configurable: true,
52
+ get() {
53
+ return target;
54
+ },
55
+ },
56
+ target: {
57
+ configurable: true,
58
+ value: target,
59
+ },
64
60
  });
65
61
 
66
62
  for (let index = 0; index < length; index += 1) {
@@ -71,10 +67,7 @@ function delegatedEventHandler(this: boolean, event: Event): void {
71
67
  continue;
72
68
  }
73
69
 
74
- Object.defineProperty(event, 'currentTarget', {
75
- configurable: true,
76
- value: item,
77
- });
70
+ target = item;
78
71
 
79
72
  for (const listener of listeners) {
80
73
  (listener as EventListener).call(item, event);
@@ -102,29 +95,10 @@ export function getDelegatedName(
102
95
  }
103
96
  }
104
97
 
105
- function removeDelegatedHandler(
106
- document: DocumentWithListenerCounts,
107
- type: string,
108
- name: string,
109
- passive: boolean,
110
- ): void {
111
- const count = `${name}${COUNT_SUFFIX}`;
112
-
113
- (document[count] as number) -= 1;
114
-
115
- if ((document[count] as number) < 1) {
116
- document[count] = undefined;
117
-
118
- document.removeEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE);
119
- }
120
- }
121
-
122
98
  export function removeDelegatedListener(
123
99
  target: EventTargetWithListeners,
124
- type: string,
125
100
  name: string,
126
101
  listener: EventListener | CustomEventListener,
127
- passive: boolean,
128
102
  ): boolean {
129
103
  const handlers = target[name];
130
104
 
@@ -138,14 +112,12 @@ export function removeDelegatedListener(
138
112
  target[name] = undefined;
139
113
  }
140
114
 
141
- removeDelegatedHandler(document as DocumentWithListenerCounts, type, name, passive);
142
-
143
115
  return true;
144
116
  }
145
117
 
146
118
  //
147
119
 
148
- const COUNT_SUFFIX = '.count';
120
+ const DELEGATED = new Set<string>();
149
121
 
150
122
  const EVENT_PREFIX = '@';
151
123
 
@@ -178,6 +150,6 @@ const EVENT_TYPES: Set<string> = new Set([
178
150
  'touchstart',
179
151
  ]);
180
152
 
181
- const HANDLER_ACTIVE: EventListener = delegatedEventHandler.bind(false);
153
+ const HANDLER_ACTIVE = delegatedEventHandler.bind(false);
182
154
 
183
- const HANDLER_PASSIVE: EventListener = delegatedEventHandler.bind(true);
155
+ const HANDLER_PASSIVE = delegatedEventHandler.bind(true);
@@ -151,13 +151,7 @@ export function off(
151
151
 
152
152
  if (
153
153
  delegated == null ||
154
- !removeDelegatedListener(
155
- target as EventTargetWithListeners,
156
- type,
157
- delegated,
158
- listener,
159
- extended.passive,
160
- )
154
+ !removeDelegatedListener(target as EventTargetWithListeners, delegated, listener)
161
155
  ) {
162
156
  target.removeEventListener(type, listener as EventListener, extended);
163
157
  }
package/src/find/index.ts CHANGED
@@ -93,7 +93,7 @@ function findElementOrElementsFromNodes(
93
93
  element != null &&
94
94
  (context == null ||
95
95
  contexts.length === 0 ||
96
- contexts.some(context => context === element || context.contains(element))) &&
96
+ contexts.some(ctx => ctx === element || ctx.contains(element))) &&
97
97
  !result.includes(element)
98
98
  ) {
99
99
  result.push(element);
@@ -171,4 +171,4 @@ const TAG_HEAD = 'HEAD';
171
171
  //
172
172
 
173
173
  export {findElement as $, findElements as $$};
174
- export {findAncestor, findRelatives} from './relative';
174
+ export {findAncestor, findRelatives, getDistance} from './relative';
@@ -1,26 +1,3 @@
1
- /**
2
- * - Get the distance between two elements _(i.e., the amount of nodes of between them)_
3
- * - If the distance cannot be calculated, `-1` is returned
4
- */
5
- function getDistanceBetweenElements(origin: Element, target: Element): number | undefined {
6
- if (origin === target || origin.parentElement === target) {
7
- return 0;
8
- }
9
-
10
- const comparison = origin.compareDocumentPosition(target);
11
- const children = [...(origin.parentElement?.children ?? [])];
12
-
13
- if (children.includes(target)) {
14
- return Math.abs(children.indexOf(origin) - children.indexOf(target));
15
- }
16
-
17
- const beforeOrInside = !!(comparison & 2 || comparison & 8);
18
-
19
- if (beforeOrInside || !!(comparison & 4 || comparison & 16)) {
20
- return traverse(beforeOrInside ? origin : target, beforeOrInside ? target : origin) ?? -1;
21
- }
22
- }
23
-
24
1
  /**
25
2
  * Find the closest ancestor element that matches the selector _(string or callback)_
26
3
  *
@@ -70,8 +47,7 @@ export function findAncestor(
70
47
  /**
71
48
  * Finds the closest elements to the origin element that matches the selector
72
49
  *
73
- * - Traverses up, down, and sideways in the _DOM_-tree
74
- * - _(If you only want to traverse up, use {@link findAncestor})_
50
+ * Traverses up, down, and sideways in the _DOM_-tree. _(If you only want to traverse up, use {@link findAncestor})_
75
51
  * @param origin Element to start from
76
52
  * @param selector Selector to match
77
53
  * @param context Context to search within
@@ -86,10 +62,6 @@ export function findRelatives(
86
62
  return [];
87
63
  }
88
64
 
89
- if (origin.matches(selector)) {
90
- return [origin];
91
- }
92
-
93
65
  const elements = [
94
66
  ...(context instanceof Document || context instanceof Element
95
67
  ? context
@@ -99,12 +71,8 @@ export function findRelatives(
99
71
 
100
72
  const {length} = elements;
101
73
 
102
- if (length === 0) {
103
- return [];
104
- }
105
-
106
- if (length === 1) {
107
- return [elements[0]];
74
+ if (length < 2) {
75
+ return elements.filter(element => element !== origin);
108
76
  }
109
77
 
110
78
  const distances = [];
@@ -113,9 +81,9 @@ export function findRelatives(
113
81
 
114
82
  for (let index = 0; index < length; index += 1) {
115
83
  const element = elements[index];
116
- const distance = getDistanceBetweenElements(origin, element) ?? -1;
84
+ const distance = getDistance(origin, element);
117
85
 
118
- if (distance > -1) {
86
+ if (distance > 0) {
119
87
  if (minimum == null || distance < minimum) {
120
88
  minimum = distance;
121
89
  }
@@ -127,18 +95,44 @@ export function findRelatives(
127
95
  }
128
96
  }
129
97
 
130
- return minimum == null
131
- ? []
132
- : distances.filter(found => found.distance === minimum).map(found => found.element);
98
+ return distances
99
+ .filter(found => found.distance === minimum)
100
+ .map(found => found.element);
133
101
  }
134
102
 
135
- function traverse(from: Element, to: Element): number | undefined {
136
- let index = [...to.children].indexOf(from);
103
+ /**
104
+ * Get the distance between two elements _(i.e., the amount of nodes of between them)_
105
+ * @param origin Origin element
106
+ * @param target Target element
107
+ * @returns Distance between elements, or `-1` if distance cannot be calculated
108
+ */
109
+ export function getDistance(origin: Element, target: Element): number {
110
+ if (origin === target) {
111
+ return 0;
112
+ }
113
+
114
+ if (origin.parentElement === target || target.parentElement === origin) {
115
+ return 1;
116
+ }
117
+
118
+ if (origin.parentElement != null && origin.parentElement === target.parentElement) {
119
+ const children = [...origin.parentElement.children];
137
120
 
138
- if (index > -1) {
139
- return index + 1;
121
+ return Math.abs(children.indexOf(origin) - children.indexOf(target));
122
+ }
123
+
124
+ const comparison = origin.compareDocumentPosition(target);
125
+
126
+ if (comparison & Node.DOCUMENT_POSITION_DISCONNECTED) {
127
+ return -1;
140
128
  }
141
129
 
130
+ const preceding = comparison & Node.DOCUMENT_POSITION_PRECEDING;
131
+
132
+ return traverse(preceding ? origin : target, preceding ? target : origin) ?? -1;
133
+ }
134
+
135
+ function traverse(from: Element, to: Element): number | undefined {
142
136
  let current = from;
143
137
  let distance = 0;
144
138
  let parent: Element | null = from.parentElement;
@@ -148,18 +142,18 @@ function traverse(from: Element, to: Element): number | undefined {
148
142
  return distance + 1;
149
143
  }
150
144
 
151
- const children = [...(parent.children ?? [])];
145
+ const children = [...parent.children];
152
146
 
153
- if (children.includes(to)) {
147
+ if (to.parentElement === parent) {
154
148
  return distance + Math.abs(children.indexOf(current) - children.indexOf(to));
155
149
  }
156
150
 
157
- index = children.findIndex(child => child.contains(to));
151
+ const index = children.findIndex(child => child.contains(to));
158
152
 
159
153
  if (index > -1) {
160
- const traversed = traverse(current, children[index]) ?? -1;
154
+ const traversed = traverse(current, children[index]);
161
155
 
162
- return traversed === -1
156
+ return traversed == null || traversed === -1
163
157
  ? -1
164
158
  : distance + Math.abs(index - children.indexOf(current)) + traversed;
165
159
  }
package/src/html/index.ts CHANGED
@@ -44,16 +44,13 @@ type Options = Required<HtmlOptions>;
44
44
  //
45
45
 
46
46
  function createHtml(value: string | HTMLTemplateElement): string {
47
- const html = getParser().parseFromString(
48
- typeof value === 'string' ? value : value.innerHTML,
49
- HTML_PARSE_TYPE,
50
- );
47
+ const parsed = getParser().parseFromString(getHtml(value), PARSE_TYPE_HTML);
51
48
 
52
- html.body.normalize();
49
+ parsed.body.normalize();
53
50
 
54
- sanitizeNodes([html.body], 0);
51
+ sanitizeNodes([parsed.body], 0);
55
52
 
56
- return html.body.innerHTML;
53
+ return parsed.body.innerHTML;
57
54
  }
58
55
 
59
56
  function createTemplate(
@@ -71,6 +68,10 @@ function createTemplate(
71
68
  return template;
72
69
  }
73
70
 
71
+ function getHtml(value: string | HTMLTemplateElement): string {
72
+ return `${TEMPORARY_ELEMENT}${typeof value === 'string' ? value : value.innerHTML}${TEMPORARY_ELEMENT}`;
73
+ }
74
+
74
75
  function getNodes(value: string | HTMLTemplateElement, options: Options): Node[] {
75
76
  if (typeof value !== 'string' && !(value instanceof HTMLTemplateElement)) {
76
77
  return [];
@@ -103,7 +104,7 @@ function getTemplate(
103
104
  return createTemplate(value, options);
104
105
  }
105
106
 
106
- if (typeof value !== 'string' || value.trim().length === 0) {
107
+ if (value.trim().length === 0) {
107
108
  return;
108
109
  }
109
110
 
@@ -115,9 +116,7 @@ function getTemplate(
115
116
 
116
117
  const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
117
118
 
118
- template = element instanceof HTMLTemplateElement ? element : createTemplate(value, options);
119
-
120
- return template;
119
+ return createTemplate(element instanceof HTMLTemplateElement ? element : value, options);
121
120
  }
122
121
 
123
122
  const html = ((value: string | HTMLTemplateElement, options?: Options): Node[] => {
@@ -163,10 +162,12 @@ export function sanitize(value: Node | Node[]): Node[] {
163
162
 
164
163
  const EXPRESSION_ID = /^[a-z][\w-]*$/i;
165
164
 
166
- const HTML_PARSE_TYPE = 'text/html';
165
+ const PARSE_TYPE_HTML = 'text/html';
167
166
 
168
167
  const TEMPLATE_TAG = 'template';
169
168
 
169
+ const TEMPORARY_ELEMENT = '<toretto-temporary></toretto-temporary>';
170
+
170
171
  let parser: DOMParser;
171
172
 
172
173
  let templates: Record<string, HTMLTemplateElement> = {};