@oscarpalmer/toretto 0.37.2 → 0.38.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/get.js +7 -0
- package/dist/data.js +2 -1
- package/dist/event/index.js +12 -0
- package/dist/find/index.js +8 -0
- package/dist/find/relative.js +6 -0
- package/dist/focusable.js +20 -0
- package/dist/html/index.js +6 -0
- package/dist/html/sanitize.js +5 -0
- package/dist/index.js +2 -2
- package/dist/internal/attribute.js +3 -0
- package/dist/internal/get-value.js +2 -1
- package/dist/internal/is.js +10 -0
- package/dist/is.js +5 -0
- package/dist/style.js +37 -0
- package/dist/toretto.full.js +252 -101
- package/dist/touch.js +5 -2
- package/package.json +8 -8
- package/src/data.ts +2 -1
- package/src/find/index.ts +1 -1
- package/src/internal/attribute.ts +1 -1
- package/src/internal/get-value.ts +2 -1
package/dist/attribute/get.js
CHANGED
|
@@ -3,6 +3,13 @@ import { isHTMLOrSVGElement } from "../internal/is.js";
|
|
|
3
3
|
function getAttribute(element, name, parseValues) {
|
|
4
4
|
if (isHTMLOrSVGElement(element) && typeof name === "string") return getAttributeValue(element, name, parseValues !== false);
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* Get specific attributes from an element
|
|
8
|
+
* @param element Element to get attributes from
|
|
9
|
+
* @param names Attribute names
|
|
10
|
+
* @param parseData Parse data values? _(defaults to `true`)_
|
|
11
|
+
* @returns Object of named attributes
|
|
12
|
+
*/
|
|
6
13
|
function getAttributes(element, names, parseData) {
|
|
7
14
|
const attributes = {};
|
|
8
15
|
if (!(isHTMLOrSVGElement(element) && Array.isArray(names))) return attributes;
|
package/dist/data.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { EXPRESSION_DATA_PREFIX } from "./internal/get-value.js";
|
|
2
2
|
import { isHTMLOrSVGElement } from "./internal/is.js";
|
|
3
3
|
import { setElementValues, updateElementValue } from "./internal/element-value.js";
|
|
4
|
-
import {
|
|
4
|
+
import { parse } from "@oscarpalmer/atoms/string";
|
|
5
|
+
import { kebabCase } from "@oscarpalmer/atoms/string/case";
|
|
5
6
|
function getData(element, keys, parseValues) {
|
|
6
7
|
if (!isHTMLOrSVGElement(element)) return;
|
|
7
8
|
const shouldParse = parseValues !== false;
|
package/dist/event/index.js
CHANGED
|
@@ -29,6 +29,11 @@ function createEventOptions(options) {
|
|
|
29
29
|
function dispatch(target, type, options) {
|
|
30
30
|
if (isEventTarget(target) && typeof type === "string") target.dispatchEvent(createEvent(type, options));
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the X- and Y-coordinates from a pointer event
|
|
34
|
+
* @param event Pointer event
|
|
35
|
+
* @returns X- and Y-coordinates
|
|
36
|
+
*/
|
|
32
37
|
function getPosition(event) {
|
|
33
38
|
let x;
|
|
34
39
|
let y;
|
|
@@ -44,6 +49,13 @@ function getPosition(event) {
|
|
|
44
49
|
y
|
|
45
50
|
} : void 0;
|
|
46
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Remove an event listener
|
|
54
|
+
* @param target Event target
|
|
55
|
+
* @param type Type of event
|
|
56
|
+
* @param listener Event listener
|
|
57
|
+
* @param options Options for event
|
|
58
|
+
*/
|
|
47
59
|
function off(target, type, listener, options) {
|
|
48
60
|
if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return;
|
|
49
61
|
const extended = createEventOptions(options);
|
package/dist/find/index.js
CHANGED
|
@@ -40,6 +40,14 @@ function findElementOrElementsFromNodes(array, context, contexts) {
|
|
|
40
40
|
function findElements(selector, context) {
|
|
41
41
|
return findElementOrElements(selector, context, false);
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the most specific element under the pointer
|
|
45
|
+
*
|
|
46
|
+
* - Ignores elements with `pointer-events: none` and `visibility: hidden`
|
|
47
|
+
* - _(If `skipIgnore` is `true`, no elements are ignored)_
|
|
48
|
+
* @param skipIgnore Skip ignored elements?
|
|
49
|
+
* @returns Found element or `null`
|
|
50
|
+
*/
|
|
43
51
|
function getElementUnderPointer(skipIgnore) {
|
|
44
52
|
const elements = [...document.querySelectorAll(SUFFIX_HOVER)];
|
|
45
53
|
const { length } = elements;
|
package/dist/find/relative.js
CHANGED
|
@@ -34,6 +34,12 @@ function findRelatives(origin, selector, context) {
|
|
|
34
34
|
}
|
|
35
35
|
return distances.filter((found) => found.distance === minimum).map((found) => found.element);
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Get the distance between two elements _(i.e., the amount of nodes of between them)_
|
|
39
|
+
* @param origin Origin element
|
|
40
|
+
* @param target Target element
|
|
41
|
+
* @returns Distance between elements, or `-1` if distance cannot be calculated
|
|
42
|
+
*/
|
|
37
43
|
function getDistance(origin, target) {
|
|
38
44
|
if (origin === target) return 0;
|
|
39
45
|
if (origin.parentElement === target || target.parentElement === origin) return 1;
|
package/dist/focusable.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a list of focusable elements within a parent element
|
|
3
|
+
* @param parent Parent element
|
|
4
|
+
* @returns Focusable elements
|
|
5
|
+
*/
|
|
1
6
|
function getFocusable(parent) {
|
|
2
7
|
return getValidElements(parent, FILTERS_FOCUSABLE, false);
|
|
3
8
|
}
|
|
@@ -7,6 +12,11 @@ function getItem(element, tabbable) {
|
|
|
7
12
|
tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
|
|
8
13
|
};
|
|
9
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Get a list of tabbable elements within a parent element
|
|
17
|
+
* @param parent Parent element
|
|
18
|
+
* @returns Tabbable elements
|
|
19
|
+
*/
|
|
10
20
|
function getTabbable(parent) {
|
|
11
21
|
return getValidElements(parent, FILTERS_TABBABLE, true);
|
|
12
22
|
}
|
|
@@ -61,6 +71,11 @@ function isDisabledFromFieldset(element) {
|
|
|
61
71
|
function isEditable(element) {
|
|
62
72
|
return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
|
|
63
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Is the element focusable?
|
|
76
|
+
* @param element Element to check
|
|
77
|
+
* @returns `true` if focusable, otherwise `false`
|
|
78
|
+
*/
|
|
64
79
|
function isFocusable(element) {
|
|
65
80
|
return element instanceof Element ? isValidElement(element, FILTERS_FOCUSABLE, false) : false;
|
|
66
81
|
}
|
|
@@ -91,6 +106,11 @@ function isNotTabbableRadio(item) {
|
|
|
91
106
|
function isSummarised(item) {
|
|
92
107
|
return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
|
|
93
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Is the element tabbable?
|
|
111
|
+
* @param element Element to check
|
|
112
|
+
* @returns `true` if tabbable, otherwise `false`
|
|
113
|
+
*/
|
|
94
114
|
function isTabbable(element) {
|
|
95
115
|
return element instanceof Element ? isValidElement(element, FILTERS_TABBABLE, true) : false;
|
|
96
116
|
}
|
package/dist/html/index.js
CHANGED
|
@@ -54,6 +54,12 @@ html.remove = (template) => {
|
|
|
54
54
|
}
|
|
55
55
|
templates = updated;
|
|
56
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Sanitize one or more nodes, recursively
|
|
59
|
+
* @param value Node or nodes to sanitize
|
|
60
|
+
* @param options Sanitization options
|
|
61
|
+
* @returns Sanitized nodes
|
|
62
|
+
*/
|
|
57
63
|
function sanitize(value) {
|
|
58
64
|
return sanitizeNodes(Array.isArray(value) ? value : [value], 0);
|
|
59
65
|
}
|
package/dist/html/sanitize.js
CHANGED
|
@@ -7,6 +7,11 @@ function handleElement(element, depth) {
|
|
|
7
7
|
}
|
|
8
8
|
sanitizeAttributes(element, [...element.attributes]);
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Is the element clobbered?
|
|
12
|
+
*
|
|
13
|
+
* Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
|
|
14
|
+
*/
|
|
10
15
|
function isClobbered(value) {
|
|
11
16
|
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");
|
|
12
17
|
}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,6 @@ import { findAncestor, findRelatives, getDistance } from "./find/relative.js";
|
|
|
7
7
|
import { $ as findElement, $$ as findElements, getElementUnderPointer } from "./find/index.js";
|
|
8
8
|
import { getFocusable, getTabbable, isFocusable, isTabbable } from "./focusable.js";
|
|
9
9
|
import { html, sanitize } from "./html/index.js";
|
|
10
|
-
import
|
|
10
|
+
import supportsTouch from "./touch.js";
|
|
11
11
|
import { getStyle, getStyles, getTextDirection, setStyle, setStyles, toggleStyles } from "./style.js";
|
|
12
|
-
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,
|
|
12
|
+
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, supportsTouch, toggleStyles };
|
|
@@ -70,6 +70,9 @@ var EXPRESSION_SOURCE_NAME = /^src$/i;
|
|
|
70
70
|
var EXPRESSION_SOURCE_VALUE = /^data:/i;
|
|
71
71
|
var EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
72
72
|
var EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
|
|
73
|
+
/**
|
|
74
|
+
* List of boolean attributes
|
|
75
|
+
*/
|
|
73
76
|
const booleanAttributes = Object.freeze([
|
|
74
77
|
"async",
|
|
75
78
|
"autofocus",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parse } from "@oscarpalmer/atoms/string";
|
|
2
|
+
import { camelCase, kebabCase } from "@oscarpalmer/atoms/string/case";
|
|
2
3
|
function getBoolean(value, defaultValue) {
|
|
3
4
|
return typeof value === "boolean" ? value : defaultValue ?? false;
|
|
4
5
|
}
|
package/dist/internal/is.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is the value an event target?
|
|
3
|
+
* @param value Value to check
|
|
4
|
+
* @returns `true` if it's an event target, otherwise `false`
|
|
5
|
+
*/
|
|
1
6
|
function isEventTarget(value) {
|
|
2
7
|
return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
|
|
3
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* Is the value an HTML or SVG element?
|
|
11
|
+
* @param value Value to check
|
|
12
|
+
* @returns `true` if it's an HTML or SVG element, otherwise `false`
|
|
13
|
+
*/
|
|
4
14
|
function isHTMLOrSVGElement(value) {
|
|
5
15
|
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
6
16
|
}
|
package/dist/is.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { isEventTarget, isHTMLOrSVGElement } from "./internal/is.js";
|
|
2
|
+
/**
|
|
3
|
+
* Is the value a child node?
|
|
4
|
+
* @param value Value to check
|
|
5
|
+
* @returns `true` if it's a child node, otherwise `false`
|
|
6
|
+
*/
|
|
2
7
|
function isChildNode(value) {
|
|
3
8
|
return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
|
|
4
9
|
}
|
package/dist/style.js
CHANGED
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { getStyleValue } from "./internal/get-value.js";
|
|
2
2
|
import { isHTMLOrSVGElement } from "./internal/is.js";
|
|
3
3
|
import { setElementValues, updateElementValue } from "./internal/element-value.js";
|
|
4
|
+
/**
|
|
5
|
+
* Get a style from an element
|
|
6
|
+
* @param element Element to get the style from
|
|
7
|
+
* @param property Style name
|
|
8
|
+
* @param computed Get the computed style? _(defaults to `false`)_
|
|
9
|
+
* @returns Style value
|
|
10
|
+
*/
|
|
4
11
|
function getStyle(element, property, computed) {
|
|
5
12
|
if (!isHTMLOrSVGElement(element) || typeof property !== "string") return;
|
|
6
13
|
return getStyleValue(element, property, computed === true);
|
|
7
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Get styles from an element
|
|
17
|
+
* @param element Element to get the styles from
|
|
18
|
+
* @param properties Styles to get
|
|
19
|
+
* @param computed Get the computed styles? _(defaults to `false`)_
|
|
20
|
+
* @returns Style values
|
|
21
|
+
*/
|
|
8
22
|
function getStyles(element, properties, computed) {
|
|
9
23
|
const styles = {};
|
|
10
24
|
if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
|
|
@@ -15,6 +29,12 @@ function getStyles(element, properties, computed) {
|
|
|
15
29
|
}
|
|
16
30
|
return styles;
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the text direction of an element
|
|
34
|
+
* @param element Element to get the text direction from
|
|
35
|
+
* @param computed Get the computed text direction? _(defaults to `false`)_
|
|
36
|
+
* @returns Text direction
|
|
37
|
+
*/
|
|
18
38
|
function getTextDirection(element, computed) {
|
|
19
39
|
if (!(element instanceof Element)) return;
|
|
20
40
|
const direction = element.getAttribute(ATTRIBUTE_DIRECTION);
|
|
@@ -22,12 +42,29 @@ function getTextDirection(element, computed) {
|
|
|
22
42
|
const value = getStyleValue(element, "direction", computed === true);
|
|
23
43
|
return value === "rtl" ? value : "ltr";
|
|
24
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Set a style on an element
|
|
47
|
+
* @param element Element to set the style on
|
|
48
|
+
* @param property Style name
|
|
49
|
+
* @param value Style value
|
|
50
|
+
*/
|
|
25
51
|
function setStyle(element, property, value) {
|
|
26
52
|
setElementValues(element, property, value, null, updateStyleProperty);
|
|
27
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Set styles on an element
|
|
56
|
+
* @param element Element to set the styles on
|
|
57
|
+
* @param styles Styles to set
|
|
58
|
+
*/
|
|
28
59
|
function setStyles(element, styles) {
|
|
29
60
|
setElementValues(element, styles, null, null, updateStyleProperty);
|
|
30
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Toggle styles for an element
|
|
64
|
+
* @param element Element to style
|
|
65
|
+
* @param styles Styles to be set or removed
|
|
66
|
+
* @returns Style toggler
|
|
67
|
+
*/
|
|
31
68
|
function toggleStyles(element, styles) {
|
|
32
69
|
function toggle(set) {
|
|
33
70
|
hasSet = set;
|
package/dist/toretto.full.js
CHANGED
|
@@ -9,7 +9,10 @@ function getSupport() {
|
|
|
9
9
|
if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Does the device support touch events?
|
|
14
|
+
*/
|
|
15
|
+
const supportsTouch = (() => {
|
|
13
16
|
let support = getSupport();
|
|
14
17
|
const instance = Object.create({
|
|
15
18
|
get() {
|
|
@@ -25,9 +28,19 @@ var touch_default = (() => {
|
|
|
25
28
|
} });
|
|
26
29
|
return instance;
|
|
27
30
|
})();
|
|
31
|
+
/**
|
|
32
|
+
* Is the value a number?
|
|
33
|
+
* @param value Value to check
|
|
34
|
+
* @returns `true` if the value is a `number`, otherwise `false`
|
|
35
|
+
*/
|
|
28
36
|
function isNumber(value) {
|
|
29
37
|
return typeof value === "number" && !Number.isNaN(value);
|
|
30
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Is the value a plain object?
|
|
41
|
+
* @param value Value to check
|
|
42
|
+
* @returns `true` if the value is a plain object, otherwise `false`
|
|
43
|
+
*/
|
|
31
44
|
function isPlainObject(value) {
|
|
32
45
|
if (value === null || typeof value !== "object") return false;
|
|
33
46
|
if (Symbol.toStringTag in value || Symbol.iterator in value) return false;
|
|
@@ -45,6 +58,11 @@ function compact(array, strict) {
|
|
|
45
58
|
}
|
|
46
59
|
return compacted;
|
|
47
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Get the string value from any value
|
|
63
|
+
* @param value Original value
|
|
64
|
+
* @returns String representation of the value
|
|
65
|
+
*/
|
|
48
66
|
function getString(value) {
|
|
49
67
|
if (typeof value === "string") return value;
|
|
50
68
|
if (value == null) return "";
|
|
@@ -53,27 +71,54 @@ function getString(value) {
|
|
|
53
71
|
const asString = String(value.valueOf?.() ?? value);
|
|
54
72
|
return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
|
|
55
73
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Join an array of values into a string
|
|
76
|
+
* @param value Array of values
|
|
77
|
+
* @param delimiter Delimiter to use between values
|
|
78
|
+
* @returns Joined string
|
|
79
|
+
*/
|
|
59
80
|
function join(value, delimiter) {
|
|
60
81
|
return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
|
|
61
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Split a string into words _(and other readable parts)_
|
|
85
|
+
* @param value Original string
|
|
86
|
+
* @returns Array of words found in the string
|
|
87
|
+
*/
|
|
62
88
|
function words(value) {
|
|
63
89
|
return typeof value === "string" ? value.match(EXPRESSION_WORDS) ?? [] : [];
|
|
64
90
|
}
|
|
65
|
-
var EXPRESSION_IGNORED = /(^|\.)(__proto__|constructor|prototype)(\.|$)/i;
|
|
66
91
|
var EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
|
|
92
|
+
/**
|
|
93
|
+
* Is the value `undefined`, `null`, or a whitespace-only string?
|
|
94
|
+
* @param value Value to check
|
|
95
|
+
* @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
|
|
96
|
+
*/
|
|
67
97
|
function isNullableOrWhitespace(value) {
|
|
68
98
|
return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
|
|
69
99
|
}
|
|
70
100
|
var EXPRESSION_WHITESPACE$1 = /^\s*$/;
|
|
101
|
+
/**
|
|
102
|
+
* Is the value an event target?
|
|
103
|
+
* @param value Value to check
|
|
104
|
+
* @returns `true` if it's an event target, otherwise `false`
|
|
105
|
+
*/
|
|
71
106
|
function isEventTarget(value) {
|
|
72
107
|
return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
|
|
73
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Is the value an HTML or SVG element?
|
|
111
|
+
* @param value Value to check
|
|
112
|
+
* @returns `true` if it's an HTML or SVG element, otherwise `false`
|
|
113
|
+
*/
|
|
74
114
|
function isHTMLOrSVGElement(value) {
|
|
75
115
|
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
76
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Is the value a child node?
|
|
119
|
+
* @param value Value to check
|
|
120
|
+
* @returns `true` if it's a child node, otherwise `false`
|
|
121
|
+
*/
|
|
77
122
|
function isChildNode(value) {
|
|
78
123
|
return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
|
|
79
124
|
}
|
|
@@ -186,6 +231,9 @@ const EXPRESSION_SOURCE_NAME = /^src$/i;
|
|
|
186
231
|
const EXPRESSION_SOURCE_VALUE = /^data:/i;
|
|
187
232
|
const EXPRESSION_URI_VALUE = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i;
|
|
188
233
|
const EXPRESSION_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
|
|
234
|
+
/**
|
|
235
|
+
* List of boolean attributes
|
|
236
|
+
*/
|
|
189
237
|
const booleanAttributes = Object.freeze([
|
|
190
238
|
"async",
|
|
191
239
|
"autofocus",
|
|
@@ -224,24 +272,27 @@ const elementEvents = {
|
|
|
224
272
|
};
|
|
225
273
|
const formElement = document.createElement("form");
|
|
226
274
|
let textArea;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
});
|
|
275
|
+
/**
|
|
276
|
+
* Parse a JSON string into its proper value _(or `undefined` if it fails)_
|
|
277
|
+
* @param value JSON string to parse
|
|
278
|
+
* @param reviver Reviver function to transform the parsed values
|
|
279
|
+
* @returns Parsed value or `undefined` if parsing fails
|
|
280
|
+
*/
|
|
281
|
+
function parse(value, reviver) {
|
|
282
|
+
try {
|
|
283
|
+
return JSON.parse(value, reviver);
|
|
284
|
+
} catch {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
240
287
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Clamp a number between a minimum and maximum value
|
|
290
|
+
* @param value Value to clamp
|
|
291
|
+
* @param minimum Minimum value
|
|
292
|
+
* @param maximum Maximum value
|
|
293
|
+
* @param loop If `true`, the value will loop around when smaller than the minimum or larger than the maximum _(defaults to `false`)_
|
|
294
|
+
* @returns Clamped value
|
|
295
|
+
*/
|
|
245
296
|
function clamp(value, minimum, maximum, loop) {
|
|
246
297
|
if (![
|
|
247
298
|
value,
|
|
@@ -251,8 +302,27 @@ function clamp(value, minimum, maximum, loop) {
|
|
|
251
302
|
if (value < minimum) return loop === true ? maximum : minimum;
|
|
252
303
|
return value > maximum ? loop === true ? minimum : maximum : value;
|
|
253
304
|
}
|
|
305
|
+
function getSizedMaximum(first, second) {
|
|
306
|
+
let actual;
|
|
307
|
+
if (typeof first === "number") actual = first;
|
|
308
|
+
else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
|
|
309
|
+
return clamp(actual, 1, MAXIMUM_ABSOLUTE);
|
|
310
|
+
}
|
|
311
|
+
var MAXIMUM_ABSOLUTE = 16777216;
|
|
312
|
+
var MAXIMUM_DEFAULT = 1048576;
|
|
313
|
+
/**
|
|
314
|
+
* A Map with a maximum size
|
|
315
|
+
*
|
|
316
|
+
* Behavior is similar to a _LRU_-cache, where the least recently used entries are removed
|
|
317
|
+
*/
|
|
254
318
|
var SizedMap = class extends Map {
|
|
319
|
+
/**
|
|
320
|
+
* The maximum size of the Map
|
|
321
|
+
*/
|
|
255
322
|
#maximumSize;
|
|
323
|
+
/**
|
|
324
|
+
* Is the Map full?
|
|
325
|
+
*/
|
|
256
326
|
get full() {
|
|
257
327
|
return this.size >= this.#maximumSize;
|
|
258
328
|
}
|
|
@@ -260,7 +330,7 @@ var SizedMap = class extends Map {
|
|
|
260
330
|
return this.#maximumSize;
|
|
261
331
|
}
|
|
262
332
|
constructor(first, second) {
|
|
263
|
-
const maximum =
|
|
333
|
+
const maximum = getSizedMaximum(first, second);
|
|
264
334
|
super();
|
|
265
335
|
this.#maximumSize = maximum;
|
|
266
336
|
if (Array.isArray(first)) {
|
|
@@ -269,30 +339,34 @@ var SizedMap = class extends Map {
|
|
|
269
339
|
else for (let index = 0; index < maximum; index += 1) this.set(...first[length - maximum + index]);
|
|
270
340
|
}
|
|
271
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* @inheritdoc
|
|
344
|
+
*/
|
|
272
345
|
get(key) {
|
|
273
346
|
const value = super.get(key);
|
|
274
347
|
if (value !== void 0 || this.has(key)) this.set(key, value);
|
|
275
348
|
return value;
|
|
276
349
|
}
|
|
350
|
+
/**
|
|
351
|
+
* @inheritdoc
|
|
352
|
+
*/
|
|
277
353
|
set(key, value) {
|
|
278
354
|
if (this.has(key)) this.delete(key);
|
|
279
355
|
else if (this.size >= this.#maximumSize) this.delete(this.keys().next().value);
|
|
280
356
|
return super.set(key, value);
|
|
281
357
|
}
|
|
282
358
|
};
|
|
283
|
-
function getMaximum(first, second) {
|
|
284
|
-
let actual;
|
|
285
|
-
if (typeof first === "number") actual = first;
|
|
286
|
-
else actual = typeof second === "number" ? second : MAXIMUM_DEFAULT;
|
|
287
|
-
return clamp(actual, 1, MAXIMUM_ABSOLUTE);
|
|
288
|
-
}
|
|
289
|
-
var MAXIMUM_ABSOLUTE = 16777216;
|
|
290
|
-
var MAXIMUM_DEFAULT = 1048576;
|
|
291
359
|
var Memoized = class {
|
|
292
360
|
#state;
|
|
361
|
+
/**
|
|
362
|
+
* Maximum cache size
|
|
363
|
+
*/
|
|
293
364
|
get maximum() {
|
|
294
365
|
return this.#state.cache?.maximum ?? NaN;
|
|
295
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Current cache size
|
|
369
|
+
*/
|
|
296
370
|
get size() {
|
|
297
371
|
return this.#state.cache?.size ?? NaN;
|
|
298
372
|
}
|
|
@@ -310,23 +384,49 @@ var Memoized = class {
|
|
|
310
384
|
getter
|
|
311
385
|
};
|
|
312
386
|
}
|
|
387
|
+
/**
|
|
388
|
+
* Clear the cache
|
|
389
|
+
*/
|
|
313
390
|
clear() {
|
|
314
391
|
this.#state.cache?.clear();
|
|
315
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Delete a result from the cache
|
|
395
|
+
* @param key Key to delete
|
|
396
|
+
* @returns `true` if the key existed and was removed, otherwise `false`
|
|
397
|
+
*/
|
|
316
398
|
delete(key) {
|
|
317
399
|
return this.#state.cache?.delete(key) ?? false;
|
|
318
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Destroy the instance _(clearing its cache and removing its callback)_
|
|
403
|
+
*/
|
|
319
404
|
destroy() {
|
|
320
405
|
this.#state.cache?.clear();
|
|
321
406
|
this.#state.cache = void 0;
|
|
322
407
|
this.#state.getter = void 0;
|
|
323
408
|
}
|
|
409
|
+
/**
|
|
410
|
+
* Get a result from the cache
|
|
411
|
+
* @param key Key to get
|
|
412
|
+
* @returns Cached result or `undefined` if it does not exist
|
|
413
|
+
*/
|
|
324
414
|
get(key) {
|
|
325
415
|
return this.#state.cache?.get(key);
|
|
326
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Does the result exist?
|
|
419
|
+
* @param key Key to check
|
|
420
|
+
* @returns `true` if the result exists, otherwise `false`
|
|
421
|
+
*/
|
|
327
422
|
has(key) {
|
|
328
423
|
return this.#state.cache?.has(key) ?? false;
|
|
329
424
|
}
|
|
425
|
+
/**
|
|
426
|
+
* Run the callback with the provided parameters
|
|
427
|
+
* @param parameters Parameters to pass to the callback
|
|
428
|
+
* @returns Cached or computed _(then cached)_ result
|
|
429
|
+
*/
|
|
330
430
|
run(...parameters) {
|
|
331
431
|
if (this.#state.cache == null || this.#state.getter == null) throw new Error("The Memoized instance has been destroyed");
|
|
332
432
|
return this.#state.getter(...parameters);
|
|
@@ -339,18 +439,39 @@ function getMemoizationOptions(input) {
|
|
|
339
439
|
cacheSize: typeof cacheSize === "number" && cacheSize > 0 ? cacheSize : DEFAULT_CACHE_SIZE
|
|
340
440
|
};
|
|
341
441
|
}
|
|
442
|
+
/**
|
|
443
|
+
* Memoize a function, caching and retrieving results based on the first parameter
|
|
444
|
+
* @param callback Callback to memoize
|
|
445
|
+
* @param options Memoization options
|
|
446
|
+
* @returns Memoized instance
|
|
447
|
+
*/
|
|
342
448
|
function memoize(callback, options) {
|
|
343
449
|
return new Memoized(callback, getMemoizationOptions(options));
|
|
344
450
|
}
|
|
345
451
|
var DEFAULT_CACHE_SIZE = 1024;
|
|
452
|
+
/**
|
|
453
|
+
* Convert a string to camel case _(thisIsCamelCase)_
|
|
454
|
+
* @param value String to convert
|
|
455
|
+
* @returns Camel-cased string
|
|
456
|
+
*/
|
|
346
457
|
function camelCase(value) {
|
|
347
458
|
return toCase("camel", value, true, false);
|
|
348
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* Capitalize the first letter of a string _(and lowercase the rest)_
|
|
462
|
+
* @param value String to capitalize
|
|
463
|
+
* @returns Capitalized string
|
|
464
|
+
*/
|
|
349
465
|
function capitalize(value) {
|
|
350
466
|
if (typeof value !== "string" || value.length === 0) return "";
|
|
351
467
|
memoizedCapitalize ??= memoize((v) => v.length === 1 ? v.toLocaleUpperCase() : `${v.charAt(0).toLocaleUpperCase()}${v.slice(1).toLocaleLowerCase()}`);
|
|
352
468
|
return memoizedCapitalize.run(value);
|
|
353
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Convert a string to kebab case _(this-is-kebab-case)_
|
|
472
|
+
* @param value String to convert
|
|
473
|
+
* @returns Kebab-cased string
|
|
474
|
+
*/
|
|
354
475
|
function kebabCase(value) {
|
|
355
476
|
return toCase("kebab", value, false, false);
|
|
356
477
|
}
|
|
@@ -385,6 +506,7 @@ function toCaseCallback(value) {
|
|
|
385
506
|
}
|
|
386
507
|
return join(cased, delimiters[type]);
|
|
387
508
|
}
|
|
509
|
+
var caseMemoizers = {};
|
|
388
510
|
var delimiters = {
|
|
389
511
|
camel: "",
|
|
390
512
|
kebab: "-",
|
|
@@ -393,77 +515,8 @@ var delimiters = {
|
|
|
393
515
|
};
|
|
394
516
|
var EXPRESSION_CAMEL_CASE = /(\p{Ll})(\p{Lu})/gu;
|
|
395
517
|
var EXPRESSION_ACRONYM = /(\p{Lu}*)(\p{Lu})(\p{Ll}+)/gu;
|
|
396
|
-
var caseMemoizers = {};
|
|
397
518
|
var REPLACEMENT_CAMEL_CASE = "$1-$2";
|
|
398
519
|
var memoizedCapitalize;
|
|
399
|
-
function parse(value, reviver) {
|
|
400
|
-
try {
|
|
401
|
-
return JSON.parse(value, reviver);
|
|
402
|
-
} catch {
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
function findKey(needle, haystack) {
|
|
407
|
-
const keys = Object.keys(haystack);
|
|
408
|
-
const index = keys.map((key) => key.toLowerCase()).indexOf(needle.toLowerCase());
|
|
409
|
-
return index > -1 ? keys[index] : needle;
|
|
410
|
-
}
|
|
411
|
-
function getPaths(path, lowercase) {
|
|
412
|
-
const normalized = lowercase ? path.toLowerCase() : path;
|
|
413
|
-
if (!EXPRESSION_NESTED.test(normalized)) return normalized;
|
|
414
|
-
return normalized.replace(EXPRESSION_BRACKET, ".$1").replace(EXPRESSION_DOTS, "").split(".");
|
|
415
|
-
}
|
|
416
|
-
function handleValue(data, path, value, get, ignoreCase) {
|
|
417
|
-
if (typeof data === "object" && data !== null && !ignoreKey(path)) {
|
|
418
|
-
const key = ignoreCase ? findKey(path, data) : path;
|
|
419
|
-
if (get) return data[key];
|
|
420
|
-
data[key] = typeof value === "function" ? value(data[key]) : value;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
var EXPRESSION_BRACKET = /\[(\w+)\]/g;
|
|
424
|
-
var EXPRESSION_DOTS = /^\.|\.$/g;
|
|
425
|
-
var EXPRESSION_NESTED = /\.|\[\w+\]/;
|
|
426
|
-
function getValue(data, path, ignoreCase) {
|
|
427
|
-
if (typeof data !== "object" || data === null || typeof path !== "string" || path.trim().length === 0) return;
|
|
428
|
-
const shouldIgnoreCase = ignoreCase === true;
|
|
429
|
-
const paths = getPaths(path, shouldIgnoreCase);
|
|
430
|
-
if (typeof paths === "string") return handleValue(data, paths, null, true, shouldIgnoreCase);
|
|
431
|
-
const { length } = paths;
|
|
432
|
-
let index = 0;
|
|
433
|
-
let value = data;
|
|
434
|
-
while (index < length && value != null) value = handleValue(value, paths[index++], null, true, shouldIgnoreCase);
|
|
435
|
-
return value;
|
|
436
|
-
}
|
|
437
|
-
function getTemplateOptions(input) {
|
|
438
|
-
const options = isPlainObject(input) ? input : {};
|
|
439
|
-
return {
|
|
440
|
-
ignoreCase: options.ignoreCase === true,
|
|
441
|
-
pattern: options.pattern instanceof RegExp ? options.pattern : EXPRESSION_VARIABLE
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
function handleTemplate(value, pattern, ignoreCase, variables) {
|
|
445
|
-
if (typeof value !== "string") return "";
|
|
446
|
-
if (typeof variables !== "object" || variables === null) return value;
|
|
447
|
-
const values = {};
|
|
448
|
-
return value.replace(pattern, (_, key) => {
|
|
449
|
-
if (values[key] == null) {
|
|
450
|
-
const templateValue = getValue(variables, key, ignoreCase);
|
|
451
|
-
values[key] = templateValue == null ? "" : getString(templateValue);
|
|
452
|
-
}
|
|
453
|
-
return values[key];
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
function template(value, variables, options) {
|
|
457
|
-
const { ignoreCase, pattern } = getTemplateOptions(options);
|
|
458
|
-
return handleTemplate(value, pattern, ignoreCase, variables);
|
|
459
|
-
}
|
|
460
|
-
template.initialize = function(options) {
|
|
461
|
-
const { ignoreCase, pattern } = getTemplateOptions(options);
|
|
462
|
-
return (value, variables) => {
|
|
463
|
-
return handleTemplate(value, pattern, ignoreCase, variables);
|
|
464
|
-
};
|
|
465
|
-
};
|
|
466
|
-
var EXPRESSION_VARIABLE = /{{([\s\S]+?)}}/g;
|
|
467
520
|
function getBoolean(value, defaultValue) {
|
|
468
521
|
return typeof value === "boolean" ? value : defaultValue ?? false;
|
|
469
522
|
}
|
|
@@ -515,6 +568,10 @@ function updateDataAttribute(element, key, value) {
|
|
|
515
568
|
updateElementValue(element, getName(key), value, element.setAttribute, element.removeAttribute, false, true);
|
|
516
569
|
}
|
|
517
570
|
const ATTRIBUTE_DATA_PREFIX = "data-";
|
|
571
|
+
/**
|
|
572
|
+
* A function that does nothing, which can be useful, I guess…
|
|
573
|
+
*/
|
|
574
|
+
function noop() {}
|
|
518
575
|
function addDelegatedHandler(doc, type, name, passive) {
|
|
519
576
|
if (DELEGATED.has(name)) return;
|
|
520
577
|
DELEGATED.add(name);
|
|
@@ -622,6 +679,11 @@ function createEventOptions(options) {
|
|
|
622
679
|
function dispatch(target, type, options) {
|
|
623
680
|
if (isEventTarget(target) && typeof type === "string") target.dispatchEvent(createEvent(type, options));
|
|
624
681
|
}
|
|
682
|
+
/**
|
|
683
|
+
* Get the X- and Y-coordinates from a pointer event
|
|
684
|
+
* @param event Pointer event
|
|
685
|
+
* @returns X- and Y-coordinates
|
|
686
|
+
*/
|
|
625
687
|
function getPosition(event) {
|
|
626
688
|
let x;
|
|
627
689
|
let y;
|
|
@@ -637,6 +699,13 @@ function getPosition(event) {
|
|
|
637
699
|
y
|
|
638
700
|
} : void 0;
|
|
639
701
|
}
|
|
702
|
+
/**
|
|
703
|
+
* Remove an event listener
|
|
704
|
+
* @param target Event target
|
|
705
|
+
* @param type Type of event
|
|
706
|
+
* @param listener Event listener
|
|
707
|
+
* @param options Options for event
|
|
708
|
+
*/
|
|
640
709
|
function off(target, type, listener, options) {
|
|
641
710
|
if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return;
|
|
642
711
|
const extended = createEventOptions(options);
|
|
@@ -691,6 +760,12 @@ function findRelatives(origin, selector, context) {
|
|
|
691
760
|
}
|
|
692
761
|
return distances.filter((found) => found.distance === minimum).map((found) => found.element);
|
|
693
762
|
}
|
|
763
|
+
/**
|
|
764
|
+
* Get the distance between two elements _(i.e., the amount of nodes of between them)_
|
|
765
|
+
* @param origin Origin element
|
|
766
|
+
* @param target Target element
|
|
767
|
+
* @returns Distance between elements, or `-1` if distance cannot be calculated
|
|
768
|
+
*/
|
|
694
769
|
function getDistance(origin, target) {
|
|
695
770
|
if (origin === target) return 0;
|
|
696
771
|
if (origin.parentElement === target || target.parentElement === origin) return 1;
|
|
@@ -766,6 +841,14 @@ function findElementOrElementsFromNodes(array, context, contexts) {
|
|
|
766
841
|
function findElements(selector, context) {
|
|
767
842
|
return findElementOrElements(selector, context, false);
|
|
768
843
|
}
|
|
844
|
+
/**
|
|
845
|
+
* Get the most specific element under the pointer
|
|
846
|
+
*
|
|
847
|
+
* - Ignores elements with `pointer-events: none` and `visibility: hidden`
|
|
848
|
+
* - _(If `skipIgnore` is `true`, no elements are ignored)_
|
|
849
|
+
* @param skipIgnore Skip ignored elements?
|
|
850
|
+
* @returns Found element or `null`
|
|
851
|
+
*/
|
|
769
852
|
function getElementUnderPointer(skipIgnore) {
|
|
770
853
|
const elements = [...document.querySelectorAll(SUFFIX_HOVER)];
|
|
771
854
|
const { length } = elements;
|
|
@@ -787,6 +870,11 @@ const STYLE_HIDDEN$1 = "hidden";
|
|
|
787
870
|
const STYLE_NONE$1 = "none";
|
|
788
871
|
const SUFFIX_HOVER = ":hover";
|
|
789
872
|
const TAG_HEAD = "HEAD";
|
|
873
|
+
/**
|
|
874
|
+
* Get a list of focusable elements within a parent element
|
|
875
|
+
* @param parent Parent element
|
|
876
|
+
* @returns Focusable elements
|
|
877
|
+
*/
|
|
790
878
|
function getFocusable(parent) {
|
|
791
879
|
return getValidElements(parent, FILTERS_FOCUSABLE, false);
|
|
792
880
|
}
|
|
@@ -796,6 +884,11 @@ function getItem(element, tabbable) {
|
|
|
796
884
|
tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
|
|
797
885
|
};
|
|
798
886
|
}
|
|
887
|
+
/**
|
|
888
|
+
* Get a list of tabbable elements within a parent element
|
|
889
|
+
* @param parent Parent element
|
|
890
|
+
* @returns Tabbable elements
|
|
891
|
+
*/
|
|
799
892
|
function getTabbable(parent) {
|
|
800
893
|
return getValidElements(parent, FILTERS_TABBABLE, true);
|
|
801
894
|
}
|
|
@@ -850,6 +943,11 @@ function isDisabledFromFieldset(element) {
|
|
|
850
943
|
function isEditable(element) {
|
|
851
944
|
return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
|
|
852
945
|
}
|
|
946
|
+
/**
|
|
947
|
+
* Is the element focusable?
|
|
948
|
+
* @param element Element to check
|
|
949
|
+
* @returns `true` if focusable, otherwise `false`
|
|
950
|
+
*/
|
|
853
951
|
function isFocusable(element) {
|
|
854
952
|
return element instanceof Element ? isValidElement(element, FILTERS_FOCUSABLE, false) : false;
|
|
855
953
|
}
|
|
@@ -880,6 +978,11 @@ function isNotTabbableRadio(item) {
|
|
|
880
978
|
function isSummarised(item) {
|
|
881
979
|
return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
|
|
882
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* Is the element tabbable?
|
|
983
|
+
* @param element Element to check
|
|
984
|
+
* @returns `true` if tabbable, otherwise `false`
|
|
985
|
+
*/
|
|
883
986
|
function isTabbable(element) {
|
|
884
987
|
return element instanceof Element ? isValidElement(element, FILTERS_TABBABLE, true) : false;
|
|
885
988
|
}
|
|
@@ -935,6 +1038,11 @@ function handleElement(element, depth) {
|
|
|
935
1038
|
}
|
|
936
1039
|
sanitizeAttributes(element, [...element.attributes]);
|
|
937
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Is the element clobbered?
|
|
1043
|
+
*
|
|
1044
|
+
* Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
|
|
1045
|
+
*/
|
|
938
1046
|
function isClobbered(value) {
|
|
939
1047
|
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");
|
|
940
1048
|
}
|
|
@@ -1034,6 +1142,12 @@ html.remove = (template) => {
|
|
|
1034
1142
|
}
|
|
1035
1143
|
templates = updated;
|
|
1036
1144
|
};
|
|
1145
|
+
/**
|
|
1146
|
+
* Sanitize one or more nodes, recursively
|
|
1147
|
+
* @param value Node or nodes to sanitize
|
|
1148
|
+
* @param options Sanitization options
|
|
1149
|
+
* @returns Sanitized nodes
|
|
1150
|
+
*/
|
|
1037
1151
|
function sanitize(value) {
|
|
1038
1152
|
return sanitizeNodes(Array.isArray(value) ? value : [value], 0);
|
|
1039
1153
|
}
|
|
@@ -1043,10 +1157,24 @@ const TEMPLATE_TAG = "template";
|
|
|
1043
1157
|
const TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
|
|
1044
1158
|
let parser;
|
|
1045
1159
|
let templates = {};
|
|
1160
|
+
/**
|
|
1161
|
+
* Get a style from an element
|
|
1162
|
+
* @param element Element to get the style from
|
|
1163
|
+
* @param property Style name
|
|
1164
|
+
* @param computed Get the computed style? _(defaults to `false`)_
|
|
1165
|
+
* @returns Style value
|
|
1166
|
+
*/
|
|
1046
1167
|
function getStyle(element, property, computed) {
|
|
1047
1168
|
if (!isHTMLOrSVGElement(element) || typeof property !== "string") return;
|
|
1048
1169
|
return getStyleValue(element, property, computed === true);
|
|
1049
1170
|
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Get styles from an element
|
|
1173
|
+
* @param element Element to get the styles from
|
|
1174
|
+
* @param properties Styles to get
|
|
1175
|
+
* @param computed Get the computed styles? _(defaults to `false`)_
|
|
1176
|
+
* @returns Style values
|
|
1177
|
+
*/
|
|
1050
1178
|
function getStyles(element, properties, computed) {
|
|
1051
1179
|
const styles = {};
|
|
1052
1180
|
if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
|
|
@@ -1057,6 +1185,12 @@ function getStyles(element, properties, computed) {
|
|
|
1057
1185
|
}
|
|
1058
1186
|
return styles;
|
|
1059
1187
|
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Get the text direction of an element
|
|
1190
|
+
* @param element Element to get the text direction from
|
|
1191
|
+
* @param computed Get the computed text direction? _(defaults to `false`)_
|
|
1192
|
+
* @returns Text direction
|
|
1193
|
+
*/
|
|
1060
1194
|
function getTextDirection(element, computed) {
|
|
1061
1195
|
if (!(element instanceof Element)) return;
|
|
1062
1196
|
const direction = element.getAttribute(ATTRIBUTE_DIRECTION);
|
|
@@ -1064,12 +1198,29 @@ function getTextDirection(element, computed) {
|
|
|
1064
1198
|
const value = getStyleValue(element, "direction", computed === true);
|
|
1065
1199
|
return value === "rtl" ? value : "ltr";
|
|
1066
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Set a style on an element
|
|
1203
|
+
* @param element Element to set the style on
|
|
1204
|
+
* @param property Style name
|
|
1205
|
+
* @param value Style value
|
|
1206
|
+
*/
|
|
1067
1207
|
function setStyle(element, property, value) {
|
|
1068
1208
|
setElementValues(element, property, value, null, updateStyleProperty);
|
|
1069
1209
|
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Set styles on an element
|
|
1212
|
+
* @param element Element to set the styles on
|
|
1213
|
+
* @param styles Styles to set
|
|
1214
|
+
*/
|
|
1070
1215
|
function setStyles(element, styles) {
|
|
1071
1216
|
setElementValues(element, styles, null, null, updateStyleProperty);
|
|
1072
1217
|
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Toggle styles for an element
|
|
1220
|
+
* @param element Element to style
|
|
1221
|
+
* @param styles Styles to be set or removed
|
|
1222
|
+
* @returns Style toggler
|
|
1223
|
+
*/
|
|
1073
1224
|
function toggleStyles(element, styles) {
|
|
1074
1225
|
function toggle(set) {
|
|
1075
1226
|
hasSet = set;
|
|
@@ -1105,4 +1256,4 @@ function updateStyleProperty(element, key, value) {
|
|
|
1105
1256
|
}
|
|
1106
1257
|
const ATTRIBUTE_DIRECTION = "dir";
|
|
1107
1258
|
const EXPRESSION_DIRECTION = /^(ltr|rtl)$/i;
|
|
1108
|
-
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,
|
|
1259
|
+
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, supportsTouch, toggleStyles };
|
package/dist/touch.js
CHANGED
|
@@ -9,7 +9,10 @@ function getSupport() {
|
|
|
9
9
|
if (typeof navigator.msMaxTouchPoints === "number" && navigator.msMaxTouchPoints > 0) return true;
|
|
10
10
|
return false;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Does the device support touch events?
|
|
14
|
+
*/
|
|
15
|
+
var supportsTouch = (() => {
|
|
13
16
|
let support = getSupport();
|
|
14
17
|
const instance = Object.create({
|
|
15
18
|
get() {
|
|
@@ -25,4 +28,4 @@ var touch_default = (() => {
|
|
|
25
28
|
} });
|
|
26
29
|
return instance;
|
|
27
30
|
})();
|
|
28
|
-
export {
|
|
31
|
+
export { supportsTouch as default };
|
package/package.json
CHANGED
|
@@ -4,19 +4,19 @@
|
|
|
4
4
|
"url": "https://oscarpalmer.se"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@oscarpalmer/atoms": "^0.
|
|
7
|
+
"@oscarpalmer/atoms": "^0.157"
|
|
8
8
|
},
|
|
9
9
|
"description": "A collection of badass DOM utilities.",
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@types/node": "^25.
|
|
11
|
+
"@types/node": "^25.3",
|
|
12
12
|
"@vitest/coverage-istanbul": "^4",
|
|
13
|
-
"jsdom": "^
|
|
14
|
-
"oxfmt": "^0.
|
|
15
|
-
"oxlint": "^1.
|
|
16
|
-
"rolldown": "1.0.0-rc.
|
|
13
|
+
"jsdom": "^28.1",
|
|
14
|
+
"oxfmt": "^0.36",
|
|
15
|
+
"oxlint": "^1.51",
|
|
16
|
+
"rolldown": "1.0.0-rc.7",
|
|
17
17
|
"tslib": "^2.8",
|
|
18
18
|
"typescript": "^5.9",
|
|
19
|
-
"vite": "8.0.0-beta.
|
|
19
|
+
"vite": "8.0.0-beta.16",
|
|
20
20
|
"vitest": "^4"
|
|
21
21
|
},
|
|
22
22
|
"exports": {
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
},
|
|
94
94
|
"type": "module",
|
|
95
95
|
"types": "types/index.d.ts",
|
|
96
|
-
"version": "0.
|
|
96
|
+
"version": "0.38.0"
|
|
97
97
|
}
|
package/src/data.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {PlainObject} from '@oscarpalmer/atoms';
|
|
2
|
-
import {
|
|
2
|
+
import {parse} from '@oscarpalmer/atoms/string';
|
|
3
|
+
import {kebabCase} from '@oscarpalmer/atoms/string/case';
|
|
3
4
|
import {setElementValues, updateElementValue} from './internal/element-value';
|
|
4
5
|
import {EXPRESSION_DATA_PREFIX} from './internal/get-value';
|
|
5
6
|
import {isHTMLOrSVGElement} from './internal/is';
|
package/src/find/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {parse} from '@oscarpalmer/atoms/string';
|
|
2
|
+
import {camelCase, kebabCase} from '@oscarpalmer/atoms/string/case';
|
|
2
3
|
|
|
3
4
|
export function getBoolean(value: unknown, defaultValue?: boolean): boolean {
|
|
4
5
|
return typeof value === 'boolean' ? value : (defaultValue ?? false);
|