@oscarpalmer/toretto 0.37.1 → 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 +8 -3
- 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 +254 -104
- 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
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
function findAncestor(origin, selector) {
|
|
2
2
|
const element = getElement(origin);
|
|
3
3
|
if (element == null || selector == null) return null;
|
|
4
|
-
console.log(element);
|
|
5
4
|
if (typeof selector === "string") {
|
|
6
|
-
if (
|
|
7
|
-
return
|
|
5
|
+
if (Element.prototype.matches.call(element, selector)) return element;
|
|
6
|
+
return Element.prototype.closest.call(element, selector);
|
|
8
7
|
}
|
|
9
8
|
if (typeof selector !== "function") return null;
|
|
10
9
|
if (selector(element)) return element;
|
|
@@ -35,6 +34,12 @@ function findRelatives(origin, selector, context) {
|
|
|
35
34
|
}
|
|
36
35
|
return distances.filter((found) => found.distance === minimum).map((found) => found.element);
|
|
37
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
|
+
*/
|
|
38
43
|
function getDistance(origin, target) {
|
|
39
44
|
if (origin === target) return 0;
|
|
40
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);
|
|
@@ -658,10 +727,9 @@ const PROPERTY_DETAIL = "detail";
|
|
|
658
727
|
function findAncestor(origin, selector) {
|
|
659
728
|
const element = getElement(origin);
|
|
660
729
|
if (element == null || selector == null) return null;
|
|
661
|
-
console.log(element);
|
|
662
730
|
if (typeof selector === "string") {
|
|
663
|
-
if (
|
|
664
|
-
return
|
|
731
|
+
if (Element.prototype.matches.call(element, selector)) return element;
|
|
732
|
+
return Element.prototype.closest.call(element, selector);
|
|
665
733
|
}
|
|
666
734
|
if (typeof selector !== "function") return null;
|
|
667
735
|
if (selector(element)) return element;
|
|
@@ -692,6 +760,12 @@ function findRelatives(origin, selector, context) {
|
|
|
692
760
|
}
|
|
693
761
|
return distances.filter((found) => found.distance === minimum).map((found) => found.element);
|
|
694
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
|
+
*/
|
|
695
769
|
function getDistance(origin, target) {
|
|
696
770
|
if (origin === target) return 0;
|
|
697
771
|
if (origin.parentElement === target || target.parentElement === origin) return 1;
|
|
@@ -767,6 +841,14 @@ function findElementOrElementsFromNodes(array, context, contexts) {
|
|
|
767
841
|
function findElements(selector, context) {
|
|
768
842
|
return findElementOrElements(selector, context, false);
|
|
769
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
|
+
*/
|
|
770
852
|
function getElementUnderPointer(skipIgnore) {
|
|
771
853
|
const elements = [...document.querySelectorAll(SUFFIX_HOVER)];
|
|
772
854
|
const { length } = elements;
|
|
@@ -788,6 +870,11 @@ const STYLE_HIDDEN$1 = "hidden";
|
|
|
788
870
|
const STYLE_NONE$1 = "none";
|
|
789
871
|
const SUFFIX_HOVER = ":hover";
|
|
790
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
|
+
*/
|
|
791
878
|
function getFocusable(parent) {
|
|
792
879
|
return getValidElements(parent, FILTERS_FOCUSABLE, false);
|
|
793
880
|
}
|
|
@@ -797,6 +884,11 @@ function getItem(element, tabbable) {
|
|
|
797
884
|
tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
|
|
798
885
|
};
|
|
799
886
|
}
|
|
887
|
+
/**
|
|
888
|
+
* Get a list of tabbable elements within a parent element
|
|
889
|
+
* @param parent Parent element
|
|
890
|
+
* @returns Tabbable elements
|
|
891
|
+
*/
|
|
800
892
|
function getTabbable(parent) {
|
|
801
893
|
return getValidElements(parent, FILTERS_TABBABLE, true);
|
|
802
894
|
}
|
|
@@ -851,6 +943,11 @@ function isDisabledFromFieldset(element) {
|
|
|
851
943
|
function isEditable(element) {
|
|
852
944
|
return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
|
|
853
945
|
}
|
|
946
|
+
/**
|
|
947
|
+
* Is the element focusable?
|
|
948
|
+
* @param element Element to check
|
|
949
|
+
* @returns `true` if focusable, otherwise `false`
|
|
950
|
+
*/
|
|
854
951
|
function isFocusable(element) {
|
|
855
952
|
return element instanceof Element ? isValidElement(element, FILTERS_FOCUSABLE, false) : false;
|
|
856
953
|
}
|
|
@@ -881,6 +978,11 @@ function isNotTabbableRadio(item) {
|
|
|
881
978
|
function isSummarised(item) {
|
|
882
979
|
return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
|
|
883
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* Is the element tabbable?
|
|
983
|
+
* @param element Element to check
|
|
984
|
+
* @returns `true` if tabbable, otherwise `false`
|
|
985
|
+
*/
|
|
884
986
|
function isTabbable(element) {
|
|
885
987
|
return element instanceof Element ? isValidElement(element, FILTERS_TABBABLE, true) : false;
|
|
886
988
|
}
|
|
@@ -936,6 +1038,11 @@ function handleElement(element, depth) {
|
|
|
936
1038
|
}
|
|
937
1039
|
sanitizeAttributes(element, [...element.attributes]);
|
|
938
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Is the element clobbered?
|
|
1043
|
+
*
|
|
1044
|
+
* Thanks, DOMPurify _(https://github.com/cure53/DOMPurify)_
|
|
1045
|
+
*/
|
|
939
1046
|
function isClobbered(value) {
|
|
940
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");
|
|
941
1048
|
}
|
|
@@ -1035,6 +1142,12 @@ html.remove = (template) => {
|
|
|
1035
1142
|
}
|
|
1036
1143
|
templates = updated;
|
|
1037
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
|
+
*/
|
|
1038
1151
|
function sanitize(value) {
|
|
1039
1152
|
return sanitizeNodes(Array.isArray(value) ? value : [value], 0);
|
|
1040
1153
|
}
|
|
@@ -1044,10 +1157,24 @@ const TEMPLATE_TAG = "template";
|
|
|
1044
1157
|
const TEMPORARY_ELEMENT = "<toretto-temporary></toretto-temporary>";
|
|
1045
1158
|
let parser;
|
|
1046
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
|
+
*/
|
|
1047
1167
|
function getStyle(element, property, computed) {
|
|
1048
1168
|
if (!isHTMLOrSVGElement(element) || typeof property !== "string") return;
|
|
1049
1169
|
return getStyleValue(element, property, computed === true);
|
|
1050
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
|
+
*/
|
|
1051
1178
|
function getStyles(element, properties, computed) {
|
|
1052
1179
|
const styles = {};
|
|
1053
1180
|
if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
|
|
@@ -1058,6 +1185,12 @@ function getStyles(element, properties, computed) {
|
|
|
1058
1185
|
}
|
|
1059
1186
|
return styles;
|
|
1060
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
|
+
*/
|
|
1061
1194
|
function getTextDirection(element, computed) {
|
|
1062
1195
|
if (!(element instanceof Element)) return;
|
|
1063
1196
|
const direction = element.getAttribute(ATTRIBUTE_DIRECTION);
|
|
@@ -1065,12 +1198,29 @@ function getTextDirection(element, computed) {
|
|
|
1065
1198
|
const value = getStyleValue(element, "direction", computed === true);
|
|
1066
1199
|
return value === "rtl" ? value : "ltr";
|
|
1067
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
|
+
*/
|
|
1068
1207
|
function setStyle(element, property, value) {
|
|
1069
1208
|
setElementValues(element, property, value, null, updateStyleProperty);
|
|
1070
1209
|
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Set styles on an element
|
|
1212
|
+
* @param element Element to set the styles on
|
|
1213
|
+
* @param styles Styles to set
|
|
1214
|
+
*/
|
|
1071
1215
|
function setStyles(element, styles) {
|
|
1072
1216
|
setElementValues(element, styles, null, null, updateStyleProperty);
|
|
1073
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
|
+
*/
|
|
1074
1224
|
function toggleStyles(element, styles) {
|
|
1075
1225
|
function toggle(set) {
|
|
1076
1226
|
hasSet = set;
|
|
@@ -1106,4 +1256,4 @@ function updateStyleProperty(element, key, value) {
|
|
|
1106
1256
|
}
|
|
1107
1257
|
const ATTRIBUTE_DIRECTION = "dir";
|
|
1108
1258
|
const EXPRESSION_DIRECTION = /^(ltr|rtl)$/i;
|
|
1109
|
-
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);
|