@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.
- package/dist/attribute/index.js +5 -5
- package/dist/event/delegation.js +21 -28
- package/dist/event/index.js +1 -1
- package/dist/find/index.js +3 -3
- package/dist/find/relative.js +22 -22
- package/dist/html/index.js +11 -8
- package/dist/html/sanitize.js +29 -14
- package/dist/index.js +2 -2
- package/dist/internal/attribute.js +5 -5
- package/dist/is.js +3 -3
- package/dist/style.js +2 -2
- package/dist/toretto.full.js +125 -264
- package/package.json +6 -6
- package/src/attribute/get.ts +4 -12
- package/src/attribute/index.ts +5 -5
- package/src/attribute/set.ts +13 -13
- package/src/data.ts +7 -16
- package/src/event/delegation.ts +24 -52
- package/src/event/index.ts +1 -7
- package/src/find/index.ts +2 -2
- package/src/find/relative.ts +43 -49
- package/src/html/index.ts +13 -12
- package/src/html/sanitize.ts +58 -31
- package/src/internal/attribute.ts +9 -9
- package/src/internal/element-value.ts +3 -4
- package/src/internal/get-value.ts +5 -8
- package/src/internal/is.ts +1 -3
- package/src/is.ts +4 -4
- package/src/models.ts +0 -5
- package/src/style.ts +12 -15
- package/types/attribute/get.d.ts +3 -3
- package/types/attribute/set.d.ts +9 -9
- package/types/data.d.ts +4 -5
- package/types/event/delegation.d.ts +1 -1
- package/types/find/index.d.ts +1 -1
- package/types/find/relative.d.ts +8 -2
- package/types/internal/attribute.d.ts +7 -7
- package/types/internal/element-value.d.ts +2 -3
- package/types/internal/get-value.d.ts +2 -3
- package/types/internal/is.d.ts +1 -2
- package/types/models.d.ts +0 -4
- 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.
|
|
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.
|
|
15
|
-
"oxlint": "^1.
|
|
16
|
-
"rolldown": "1.0.0-beta.
|
|
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.
|
|
96
|
+
"version": "0.32.0"
|
|
97
97
|
}
|
package/src/attribute/get.ts
CHANGED
|
@@ -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:
|
|
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:
|
|
35
|
+
element: Element,
|
|
44
36
|
names: Key[],
|
|
45
37
|
parseData?: boolean,
|
|
46
38
|
): Record<Key, unknown> {
|
package/src/attribute/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
25
|
+
return _isBadAttribute(first, second, true);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
package/src/attribute/set.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {updateValue, updateValues} from '../internal/attribute';
|
|
2
|
-
import type {Attribute,
|
|
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:
|
|
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:
|
|
21
|
+
export function setAttribute(element: Element, attribute: Attr | Attribute): void;
|
|
22
22
|
|
|
23
|
-
export function setAttribute(element:
|
|
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:
|
|
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:
|
|
43
|
+
export function setAttributes(element: Element, attributes: Record<string, unknown>): void;
|
|
44
44
|
|
|
45
45
|
export function setAttributes(
|
|
46
|
-
element:
|
|
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:
|
|
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:
|
|
69
|
+
export function setProperty(element: Element, property: Property): void;
|
|
70
70
|
|
|
71
|
-
export function setProperty(element:
|
|
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:
|
|
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:
|
|
91
|
+
export function setProperties(element: Element, properties: Record<string, unknown>): void;
|
|
92
92
|
|
|
93
93
|
export function setProperties(
|
|
94
|
-
element:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
87
|
+
function updateDataAttribute(element: Element, key: string, value: unknown): void {
|
|
97
88
|
updateElementValue(
|
|
98
89
|
element,
|
|
99
90
|
getName(key),
|
package/src/event/delegation.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
16
|
+
DELEGATED.add(name);
|
|
31
17
|
|
|
32
|
-
|
|
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]
|
|
32
|
+
target[name].add(listener);
|
|
47
33
|
|
|
48
|
-
addDelegatedHandler(document
|
|
34
|
+
addDelegatedHandler(document, type, name, passive);
|
|
49
35
|
|
|
50
36
|
return () => {
|
|
51
|
-
removeDelegatedListener(target,
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
153
|
+
const HANDLER_ACTIVE = delegatedEventHandler.bind(false);
|
|
182
154
|
|
|
183
|
-
const HANDLER_PASSIVE
|
|
155
|
+
const HANDLER_PASSIVE = delegatedEventHandler.bind(true);
|
package/src/event/index.ts
CHANGED
|
@@ -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(
|
|
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';
|
package/src/find/relative.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
|
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 =
|
|
84
|
+
const distance = getDistance(origin, element);
|
|
117
85
|
|
|
118
|
-
if (distance >
|
|
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
|
|
131
|
-
|
|
132
|
-
|
|
98
|
+
return distances
|
|
99
|
+
.filter(found => found.distance === minimum)
|
|
100
|
+
.map(found => found.element);
|
|
133
101
|
}
|
|
134
102
|
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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 = [...
|
|
145
|
+
const children = [...parent.children];
|
|
152
146
|
|
|
153
|
-
if (
|
|
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])
|
|
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
|
|
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
|
-
|
|
49
|
+
parsed.body.normalize();
|
|
53
50
|
|
|
54
|
-
sanitizeNodes([
|
|
51
|
+
sanitizeNodes([parsed.body], 0);
|
|
55
52
|
|
|
56
|
-
return
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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> = {};
|