@oscarpalmer/toretto 0.23.1 → 0.25.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.js CHANGED
@@ -7,7 +7,7 @@ function getAttribute(element, name, parseValues) {
7
7
  }
8
8
  function getAttributes(element, names, parseData) {
9
9
  const attributes = {};
10
- if (!isHTMLOrSVGElement(element) || !Array.isArray(names)) return attributes;
10
+ if (!(isHTMLOrSVGElement(element) && Array.isArray(names))) return attributes;
11
11
  const shouldParse = parseData !== false;
12
12
  const { length } = names;
13
13
  for (let index = 0; index < length; index += 1) {
@@ -20,7 +20,7 @@ function isAttribute(value) {
20
20
  return value instanceof Attr || isPlainObject(value) && typeof value.name === "string" && typeof value.value === "string";
21
21
  }
22
22
  function isBadAttribute(first, second) {
23
- return validateAttribute((attribute) => attribute == null || onPrefix.test(attribute.name) || sourcePrefix.test(attribute.name) && valuePrefix.test(String(attribute.value)), first, second);
23
+ return validateAttribute((attribute) => attribute == null || EXPRESSION_ON_PREFIX.test(attribute.name) || EXPRESSION_SOURCE_PREFIX.test(attribute.name) && EXPRESSION_VALUE_PREFIX.test(String(attribute.value)), first, second);
24
24
  }
25
25
  function isBooleanAttribute(value) {
26
26
  return validateAttribute((attribute) => attribute != null && booleanAttributes.includes(attribute.name.toLowerCase()), value, "");
@@ -86,6 +86,9 @@ function validateAttribute(callback, first, second) {
86
86
  };
87
87
  return callback(attribute);
88
88
  }
89
+ var EXPRESSION_ON_PREFIX = /^on/i;
90
+ var EXPRESSION_SOURCE_PREFIX = /^(href|src|xlink:href)$/i;
91
+ var EXPRESSION_VALUE_PREFIX = /(data:text\/html|javascript:)/i;
89
92
  const booleanAttributes = Object.freeze([
90
93
  "async",
91
94
  "autofocus",
@@ -112,7 +115,4 @@ const booleanAttributes = Object.freeze([
112
115
  "reversed",
113
116
  "selected"
114
117
  ]);
115
- var onPrefix = /^on/i;
116
- var sourcePrefix = /^(href|src|xlink:href)$/i;
117
- var valuePrefix = /(data:text\/html|javascript:)/i;
118
118
  export { booleanAttributes, getAttribute, getAttributes, isBadAttribute, isBooleanAttribute, isEmptyNonBooleanAttribute, isInvalidBooleanAttribute, setAttribute, setAttributes, setProperties, setProperty };
package/dist/data.js CHANGED
@@ -1,24 +1,27 @@
1
1
  import { isHTMLOrSVGElement } from "./is.js";
2
2
  import { setElementValues, updateElementValue } from "./internal/element-value.js";
3
+ import { EXPRESSION_DATA_PREFIX } from "./internal/get-value.js";
3
4
  import { kebabCase, parse } from "@oscarpalmer/atoms/string";
4
5
  function getData(element, keys, parseValues) {
5
6
  if (!isHTMLOrSVGElement(element)) return;
6
7
  const shouldParse = parseValues !== false;
7
8
  if (typeof keys === "string") {
8
9
  const value = element.dataset[keys];
9
- return value == null ? void 0 : shouldParse ? parse(value) : value;
10
+ if (value === void 0) return;
11
+ return shouldParse ? parse(value) : value;
10
12
  }
11
13
  const { length } = keys;
12
14
  const data = {};
13
15
  for (let index = 0; index < length; index += 1) {
14
16
  const key = keys[index];
15
17
  const value = element.dataset[key];
16
- data[key] = value == null ? void 0 : shouldParse ? parse(value) : value;
18
+ if (value == null) data[key] = void 0;
19
+ else data[key] = shouldParse ? parse(value) : value;
17
20
  }
18
21
  return data;
19
22
  }
20
23
  function getName(original) {
21
- return `data-${kebabCase(original).replace(dataPrefix, "")}`;
24
+ return `${ATTRIBUTE_DATA_PREFIX}${kebabCase(original).replace(EXPRESSION_DATA_PREFIX, "")}`;
22
25
  }
23
26
  function setData(element, first, second) {
24
27
  setElementValues(element, first, second, updateDataAttribute);
@@ -26,5 +29,5 @@ function setData(element, first, second) {
26
29
  function updateDataAttribute(element, key, value) {
27
30
  updateElementValue(element, getName(key), value, element.setAttribute, element.removeAttribute, true);
28
31
  }
29
- var dataPrefix = /^data-/i;
32
+ var ATTRIBUTE_DATA_PREFIX = "data-";
30
33
  export { getData, setData };
package/dist/event.js CHANGED
@@ -11,7 +11,7 @@ function createDispatchOptions(options) {
11
11
  }
12
12
  function createEvent(type, options) {
13
13
  const hasOptions = isPlainObject(options);
14
- if (hasOptions && "detail" in options) return new CustomEvent(type, {
14
+ if (hasOptions && PROPERTY_DETAIL in options) return new CustomEvent(type, {
15
15
  ...createDispatchOptions(options),
16
16
  detail: options?.detail
17
17
  });
@@ -54,4 +54,5 @@ function on(target, type, listener, options) {
54
54
  target.removeEventListener(type, listener, extended);
55
55
  };
56
56
  }
57
+ var PROPERTY_DETAIL = "detail";
57
58
  export { dispatch, getPosition, off, on };
package/dist/find.js CHANGED
@@ -25,26 +25,36 @@ function findElement(selector, context) {
25
25
  return findElementOrElements(selector, context, true);
26
26
  }
27
27
  function findElementOrElements(selector, context, single) {
28
- const callback = single ? "querySelector" : "querySelectorAll";
28
+ const callback = single ? QUERY_SELECTOR_SINGLE : QUERY_SELECTOR_ALL;
29
29
  const contexts = context == null ? [document] : findElementOrElements(context, void 0, false).filter(isContext);
30
+ if (typeof selector === "string") return findElementOrElementsForSelector(selector, contexts, callback, single);
31
+ let array;
32
+ if (Array.isArray(selector)) array = selector;
33
+ else array = selector instanceof Node ? [selector] : [...selector];
34
+ return findElementOrElementsFromNodes(array, context, contexts);
35
+ }
36
+ function findElementOrElementsForSelector(selector, contexts, callback, single) {
37
+ const { length } = contexts;
30
38
  const result = [];
31
- if (typeof selector === "string") {
32
- const { length: length$1 } = contexts;
33
- for (let index = 0; index < length$1; index += 1) {
34
- const value = contexts[index][callback](selector);
35
- if (single) {
36
- if (value == null) continue;
37
- return value;
38
- }
39
- result.push(...Array.from(value));
39
+ for (let index = 0; index < length; index += 1) {
40
+ const value = contexts[index][callback](selector);
41
+ if (single) {
42
+ if (value == null) continue;
43
+ return value;
40
44
  }
41
- return single ? null : result.filter((value, index, array) => array.indexOf(value) === index);
45
+ result.push(...Array.from(value));
42
46
  }
43
- const nodes = (Array.isArray(selector) ? selector : selector instanceof Node ? [selector] : [...selector]).filter((node) => node instanceof Node);
47
+ return single ? null : result.filter((value, index, array) => array.indexOf(value) === index);
48
+ }
49
+ function findElementOrElementsFromNodes(array, context, contexts) {
50
+ const result = [];
51
+ const nodes = array.filter((node) => node instanceof Node);
44
52
  const { length } = nodes;
45
53
  for (let index = 0; index < length; index += 1) {
46
54
  const node = nodes[index];
47
- const element = node instanceof Document ? node.body : node instanceof Element ? node : void 0;
55
+ let element;
56
+ if (node instanceof Document) element = node.body;
57
+ else element = node instanceof Element ? node : void 0;
48
58
  if (element != null && (context == null || contexts.length === 0 || contexts.some((context$1) => context$1 === element || context$1.contains(element))) && !result.includes(element)) result.push(element);
49
59
  }
50
60
  return result;
@@ -74,14 +84,14 @@ function findRelatives(origin, selector, context) {
74
84
  return minimum == null ? [] : distances.filter((found) => found.distance === minimum).map((found) => found.element);
75
85
  }
76
86
  function getElementUnderPointer(skipIgnore) {
77
- const elements = [...document.querySelectorAll(":hover")];
87
+ const elements = [...document.querySelectorAll(SUFFIX_HOVER)];
78
88
  const { length } = elements;
79
89
  const returned = [];
80
90
  for (let index = 0; index < length; index += 1) {
81
91
  const element = elements[index];
82
- if (element.tagName === "HEAD") continue;
92
+ if (element.tagName === TAG_HEAD) continue;
83
93
  const style = getComputedStyle(element);
84
- if (skipIgnore === true || style.pointerEvents !== "none" && style.visibility !== "hidden") returned.push(element);
94
+ if (skipIgnore === true || style.pointerEvents !== STYLE_NONE && style.visibility !== STYLE_HIDDEN) returned.push(element);
85
95
  }
86
96
  return returned.at(-1) ?? null;
87
97
  }
@@ -108,4 +118,10 @@ function traverse(from, to) {
108
118
  parent = parent.parentElement;
109
119
  }
110
120
  }
121
+ var QUERY_SELECTOR_ALL = "querySelectorAll";
122
+ var QUERY_SELECTOR_SINGLE = "querySelector";
123
+ var STYLE_HIDDEN = "hidden";
124
+ var STYLE_NONE = "none";
125
+ var SUFFIX_HOVER = ":hover";
126
+ var TAG_HEAD = "HEAD";
111
127
  export { findElement as $, findElement, findElements as $$, findElements, findAncestor, findRelatives, getElementUnderPointer };
package/dist/focusable.js CHANGED
@@ -1,23 +1,23 @@
1
1
  function getFocusable(parent) {
2
- return getValidElements(parent, focusableFilters, false);
2
+ return getValidElements(parent, FILTERS_FOCUSABLE, false);
3
3
  }
4
4
  function getItem(element, tabbable) {
5
5
  return {
6
6
  element,
7
- tabIndex: tabbable ? getTabIndex(element) : -1
7
+ tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
8
8
  };
9
9
  }
10
10
  function getTabbable(parent) {
11
- return getValidElements(parent, tabbableFilters, true);
11
+ return getValidElements(parent, FILTERS_TABBABLE, true);
12
12
  }
13
13
  function getTabIndex(element) {
14
- const tabIndex = element?.tabIndex ?? -1;
15
- if (tabIndex < 0 && (specialTabIndexPattern.test(element.tagName) || isEditable(element)) && !hasTabIndex(element)) return 0;
14
+ const tabIndex = element?.tabIndex ?? TABINDEX_DEFAULT;
15
+ if (tabIndex < TABINDEX_BASE && (EXPRESSION_SPECIAL_TABINDEX.test(element.tagName) || isEditable(element)) && !hasTabIndex(element)) return TABINDEX_BASE;
16
16
  return tabIndex;
17
17
  }
18
18
  function getValidElements(parent, filters, tabbable) {
19
19
  if (!(parent instanceof Element)) return [];
20
- const elements = [...parent.querySelectorAll(selector)];
20
+ const elements = [...parent.querySelectorAll(SELECTOR_FULL)];
21
21
  const items = [];
22
22
  let { length } = elements;
23
23
  for (let index = 0; index < length; index += 1) {
@@ -30,16 +30,16 @@ function getValidElements(parent, filters, tabbable) {
30
30
  length = items.length;
31
31
  for (let index = 0; index < length; index += 1) {
32
32
  const item = items[index];
33
- if (item.tabIndex === 0) zeroed.push(item.element);
33
+ if (item.tabIndex === TABINDEX_BASE) zeroed.push(item.element);
34
34
  else indiced[item.tabIndex] = [...indiced[item.tabIndex] ?? [], item.element];
35
35
  }
36
36
  return [...indiced.flat(), ...zeroed];
37
37
  }
38
38
  function hasTabIndex(element) {
39
- return !Number.isNaN(Number.parseInt(element.getAttribute("tabindex"), 10));
39
+ return !Number.isNaN(Number.parseInt(element.getAttribute(ATTRIBUTE_TABINDEX), 10));
40
40
  }
41
41
  function isDisabled(item) {
42
- if (disableablePattern.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
42
+ if (EXPRESSION_DISABLEABLE.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
43
43
  return item.element.disabled ?? false;
44
44
  }
45
45
  function isDisabledFromFieldset(element) {
@@ -50,7 +50,7 @@ function isDisabledFromFieldset(element) {
50
50
  const { length } = children;
51
51
  for (let index = 0; index < length; index += 1) {
52
52
  const child = children[index];
53
- if (child instanceof HTMLLegendElement) return parent.matches("fieldset[disabled] *") ? true : !child.contains(element);
53
+ if (child instanceof HTMLLegendElement) return parent.matches(SELECTOR_FIELDSET_DISABLED) || !child.contains(element);
54
54
  }
55
55
  return true;
56
56
  }
@@ -59,72 +59,84 @@ function isDisabledFromFieldset(element) {
59
59
  return false;
60
60
  }
61
61
  function isEditable(element) {
62
- return trueishPattern.test(element.getAttribute("contenteditable"));
62
+ return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
63
63
  }
64
64
  function isFocusable(element) {
65
- return element instanceof Element ? isValidElement(element, focusableFilters, false) : false;
65
+ return element instanceof Element ? isValidElement(element, FILTERS_FOCUSABLE, false) : false;
66
66
  }
67
67
  function isHidden(item) {
68
- if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === "hidden") return true;
69
- if ((item.element.matches("details > summary:first-of-type") ? item.element.parentElement : item.element)?.matches("details:not([open]) *") ?? false) return true;
68
+ if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === STYLE_HIDDEN) return true;
69
+ if ((item.element.matches(SELECTOR_SUMMARY_FIRST) ? item.element.parentElement : item.element)?.matches(SELECTOR_DETAILS_CLOSED_CHILDREN) ?? false) return true;
70
70
  const style = getComputedStyle(item.element);
71
- if (style.display === "none" || style.visibility === "hidden") return true;
71
+ if (style.display === STYLE_NONE || style.visibility === STYLE_HIDDEN) return true;
72
72
  const { height, width } = item.element.getBoundingClientRect();
73
73
  return height === 0 && width === 0;
74
74
  }
75
75
  function isInert(item) {
76
- return (item.element.inert ?? false) || trueishPattern.test(item.element.getAttribute("inert")) || item.element.parentElement != null && isInert({
76
+ return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
77
77
  element: item.element.parentElement,
78
- tabIndex: -1
78
+ tabIndex: TABINDEX_DEFAULT
79
79
  });
80
80
  }
81
81
  function isNotTabbable(item) {
82
- return (item.tabIndex ?? -1) < 0;
82
+ return (item.tabIndex ?? TABINDEX_DEFAULT) < TABINDEX_BASE;
83
83
  }
84
84
  function isNotTabbableRadio(item) {
85
- if (!(item.element instanceof HTMLInputElement) || item.element.type !== "radio" || !item.element.name || item.element.checked) return false;
85
+ if (!(item.element instanceof HTMLInputElement) || item.element.type !== TYPE_RADIO || !item.element.name || item.element.checked) return false;
86
86
  const parent = item.element.form ?? item.element.getRootNode?.() ?? item.element.ownerDocument;
87
87
  const realName = CSS?.escape?.(item.element.name) ?? item.element.name;
88
- const checked = [...parent.querySelectorAll(`input[type="radio"][name="${realName}"]`)].find((radio) => radio.checked);
88
+ const checked = [...parent.querySelectorAll(`${SELECTOR_RADIO_PREFIX}${realName}${SELECTOR_RADIO_SUFFIX}`)].find((radio) => radio.checked);
89
89
  return checked != null && checked !== item.element;
90
90
  }
91
91
  function isSummarised(item) {
92
- return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => summaryPattern.test(child.tagName));
92
+ return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
93
93
  }
94
94
  function isTabbable(element) {
95
- return element instanceof Element ? isValidElement(element, tabbableFilters, true) : false;
95
+ return element instanceof Element ? isValidElement(element, FILTERS_TABBABLE, true) : false;
96
96
  }
97
97
  function isValidElement(element, filters, tabbable) {
98
98
  const item = getItem(element, tabbable);
99
99
  return !filters.some((filter) => filter(item));
100
100
  }
101
- var disableablePattern = /^(button|input|select|textarea)$/i;
102
- var firstSummary = "details > summary:first-of-type";
103
- var focusableFilters = [
101
+ var ATTRIBUTE_CONTENTEDITABLE = "contenteditable";
102
+ var ATTRIBUTE_INERT = "inert";
103
+ var ATTRIBUTE_TABINDEX = "tabindex";
104
+ var EXPRESSION_DISABLEABLE = /^(button|input|select|textarea)$/i;
105
+ var EXPRESSION_SPECIAL_TABINDEX = /^(audio|details|video)$/i;
106
+ var EXPRESSION_SUMMARY = /^summary$/i;
107
+ var EXPRESSION_TRUEISH = /^(|true)$/i;
108
+ var FILTERS_FOCUSABLE = [
104
109
  isDisabled,
105
110
  isInert,
106
111
  isHidden,
107
112
  isSummarised
108
113
  ];
109
- var selector = [
114
+ var FILTERS_TABBABLE = [
115
+ isNotTabbable,
116
+ isNotTabbableRadio,
117
+ ...FILTERS_FOCUSABLE
118
+ ];
119
+ var SELECTOR_DETAILS_CLOSED_CHILDREN = "details:not([open]) *";
120
+ var SELECTOR_FIELDSET_DISABLED = "fieldset[disabled] *";
121
+ var SELECTOR_SUMMARY_FIRST = "details > summary:first-of-type";
122
+ var SELECTOR_RADIO_PREFIX = "input[type=\"radio\"][name=\"";
123
+ var SELECTOR_RADIO_SUFFIX = "\"]";
124
+ var SELECTOR_FULL = [
110
125
  "[contenteditable]:not([contenteditable=\"false\"])",
111
126
  "[tabindex]:not(slot)",
112
127
  "a[href]",
113
128
  "audio[controls]",
114
129
  "button",
115
130
  "details",
116
- firstSummary,
131
+ SELECTOR_SUMMARY_FIRST,
117
132
  "input",
118
133
  "select",
119
134
  "textarea",
120
135
  "video[controls]"
121
- ].map((selector$1) => `${selector$1}:not([inert])`).join(",");
122
- var specialTabIndexPattern = /^(audio|details|video)$/i;
123
- var summaryPattern = /^summary$/i;
124
- var tabbableFilters = [
125
- isNotTabbable,
126
- isNotTabbableRadio,
127
- ...focusableFilters
128
- ];
129
- var trueishPattern = /^(|true)$/i;
136
+ ].map((selector) => `${selector}:not([inert])`).join(",");
137
+ var STYLE_HIDDEN = "hidden";
138
+ var STYLE_NONE = "none";
139
+ var TABINDEX_BASE = 0;
140
+ var TABINDEX_DEFAULT = -1;
141
+ var TYPE_RADIO = "radio";
130
142
  export { getFocusable, getTabbable, isFocusable, isTabbable };
package/dist/html.js CHANGED
@@ -1,31 +1,52 @@
1
- import { sanitize } from "./sanitize.js";
1
+ import { sanitizeNodes } from "./internal/sanitize.js";
2
2
  import { isPlainObject } from "@oscarpalmer/atoms/is";
3
- function createTemplate(html$1) {
3
+ function createTemplate(html$1, ignore) {
4
4
  const template = document.createElement("template");
5
5
  template.innerHTML = html$1;
6
- templates[html$1] = template;
6
+ if (!ignore) templates[html$1] = template;
7
7
  return template;
8
8
  }
9
- function getTemplate(value) {
10
- if (typeof value !== "string" || value.trim().length === 0) return;
11
- if (value in templates) return templates[value];
12
- let template;
13
- if (idPattern.test(value)) template = document.querySelector(`#${value}`);
14
- templates[value] = template instanceof HTMLTemplateElement ? template : createTemplate(value);
15
- return templates[value];
16
- }
17
- function html(value, sanitization) {
9
+ function getHtml(value, options) {
18
10
  if (typeof value !== "string" && !(value instanceof HTMLTemplateElement)) return [];
19
- const options = sanitization == null || sanitization === true ? {} : isPlainObject(sanitization) ? { ...sanitization } : null;
20
- const template = value instanceof HTMLTemplateElement ? value : getTemplate(value);
11
+ const template = value instanceof HTMLTemplateElement ? value : getTemplate(value, options.ignoreCache);
21
12
  if (template == null) return [];
22
13
  const cloned = template.content.cloneNode(true);
23
14
  const scripts = cloned.querySelectorAll("script");
24
- const { length } = scripts;
25
- for (let index = 0; index < length; index += 1) scripts[index].remove();
15
+ for (const script of scripts) script.remove();
26
16
  cloned.normalize();
27
- return options != null ? sanitize([...cloned.childNodes], options) : [...cloned.childNodes];
17
+ return sanitizeNodes([...cloned.childNodes], options);
18
+ }
19
+ function getOptions(input) {
20
+ const options = isPlainObject(input) ? input : {};
21
+ options.ignoreCache = typeof options.ignoreCache === "boolean" ? options.ignoreCache : false;
22
+ options.sanitizeBooleanAttributes = typeof options.sanitizeBooleanAttributes === "boolean" ? options.sanitizeBooleanAttributes : true;
23
+ return options;
24
+ }
25
+ function getTemplate(value, ignore) {
26
+ if (typeof value !== "string" || value.trim().length === 0) return;
27
+ let template = templates[value];
28
+ if (template != null) return template;
29
+ const element = EXPRESSION_ID.test(value) ? document.querySelector(`#${value}`) : null;
30
+ template = element instanceof HTMLTemplateElement ? element : createTemplate(value, ignore);
31
+ return template;
28
32
  }
29
- var idPattern = /^[a-z][\w-]*$/i;
33
+ var html = ((value, options) => {
34
+ return getHtml(value, getOptions(options));
35
+ });
36
+ html.clear = () => {
37
+ templates = {};
38
+ };
39
+ html.remove = (template) => {
40
+ if (typeof template !== "string" || templates[template] == null) return;
41
+ const keys = Object.keys(templates);
42
+ const { length } = keys;
43
+ const updated = {};
44
+ for (let index = 0; index < length; index += 1) {
45
+ const key = keys[index];
46
+ if (key !== template) updated[key] = templates[key];
47
+ }
48
+ templates = updated;
49
+ };
50
+ var EXPRESSION_ID = /^[a-z][\w-]*$/i;
30
51
  var templates = {};
31
52
  export { html };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import touch_default from "./touch.js";
2
2
  import { isChildNode, isEventTarget, isHTMLOrSVGElement, isInDocument } from "./is.js";
3
- import { getStyle, getStyles, getTextDirection, setStyle, setStyles } from "./style.js";
3
+ import { getStyle, getStyles, getTextDirection, setStyle, setStyles, toggleStyles } from "./style.js";
4
4
  import { booleanAttributes, getAttribute, getAttributes, isBadAttribute, isBooleanAttribute, isEmptyNonBooleanAttribute, isInvalidBooleanAttribute, setAttribute, setAttributes, setProperties, setProperty } from "./attribute.js";
5
5
  import { sanitize } from "./sanitize.js";
6
6
  import { getData, setData } from "./data.js";
@@ -8,4 +8,4 @@ import { dispatch, getPosition, off, on } from "./event.js";
8
8
  import { $ as findElement, $$ as findElements, findAncestor, findRelatives, getElementUnderPointer } from "./find.js";
9
9
  import { getFocusable, getTabbable, isFocusable, isTabbable } from "./focusable.js";
10
10
  import { html } from "./html.js";
11
- export { findElement as $, findElement, findElements as $$, findElements, booleanAttributes, dispatch, findAncestor, findRelatives, getAttribute, getAttributes, getData, getElementUnderPointer, getFocusable, getPosition, getStyle, getStyles, getTabbable, getTextDirection, html, isBadAttribute, isBooleanAttribute, isChildNode, isEmptyNonBooleanAttribute, isEventTarget, isFocusable, isHTMLOrSVGElement, isInDocument, isInvalidBooleanAttribute, isTabbable, off, on, sanitize, setAttribute, setAttributes, setData, setProperties, setProperty, setStyle, setStyles, touch_default as supportsTouch };
11
+ export { findElement as $, findElement, findElements as $$, findElements, booleanAttributes, dispatch, findAncestor, findRelatives, getAttribute, getAttributes, getData, getElementUnderPointer, getFocusable, getPosition, getStyle, getStyles, getTabbable, getTextDirection, html, isBadAttribute, isBooleanAttribute, isChildNode, isEmptyNonBooleanAttribute, isEventTarget, isFocusable, isHTMLOrSVGElement, isInDocument, isInvalidBooleanAttribute, isTabbable, off, on, sanitize, setAttribute, setAttributes, setData, setProperties, setProperty, setStyle, setStyles, touch_default as supportsTouch, toggleStyles };
@@ -6,11 +6,11 @@ function getAttributeValue(element, name, parseValue) {
6
6
  const normalized = kebabCase(name);
7
7
  const attribute = element.attributes[normalized];
8
8
  const value = attribute instanceof Attr ? attribute.value : void 0;
9
- return dataPrefix.test(normalized) && typeof value === "string" && parseValue ? parse(value) ?? value : value;
9
+ return EXPRESSION_DATA_PREFIX.test(normalized) && typeof value === "string" && parseValue ? parse(value) ?? value : value;
10
10
  }
11
11
  function getStyleValue(element, property, computed) {
12
12
  const name = camelCase(property);
13
13
  return computed ? getComputedStyle(element)[name] : element.style[name];
14
14
  }
15
- var dataPrefix = /^data-/i;
16
- export { getAttributeValue, getBoolean, getStyleValue };
15
+ const EXPRESSION_DATA_PREFIX = /^data-/i;
16
+ export { EXPRESSION_DATA_PREFIX, getAttributeValue, getBoolean, getStyleValue };
@@ -0,0 +1,30 @@
1
+ import { isBadAttribute, isEmptyNonBooleanAttribute, isInvalidBooleanAttribute } from "../attribute.js";
2
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
3
+ function getSanitizeOptions(input) {
4
+ const options = isPlainObject(input) ? input : {};
5
+ options.sanitizeBooleanAttributes = typeof options.sanitizeBooleanAttributes === "boolean" ? options.sanitizeBooleanAttributes : true;
6
+ return options;
7
+ }
8
+ function sanitizeAttributes(element, attributes, options) {
9
+ const { length } = attributes;
10
+ for (let index = 0; index < length; index += 1) {
11
+ const attribute = attributes[index];
12
+ if (isBadAttribute(attribute) || isEmptyNonBooleanAttribute(attribute)) element.removeAttribute(attribute.name);
13
+ else if (options.sanitizeBooleanAttributes && isInvalidBooleanAttribute(attribute)) element.setAttribute(attribute.name, "");
14
+ }
15
+ }
16
+ function sanitizeNodes(nodes, options) {
17
+ const actual = nodes.filter((node) => node instanceof Node);
18
+ const { length } = nodes;
19
+ for (let index = 0; index < length; index += 1) {
20
+ const node = actual[index];
21
+ if (node instanceof Element) {
22
+ const scripts = node.querySelectorAll("script");
23
+ for (const script of scripts) script.remove();
24
+ sanitizeAttributes(node, [...node.attributes], options);
25
+ }
26
+ if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], options);
27
+ }
28
+ return nodes;
29
+ }
30
+ export { getSanitizeOptions, sanitizeAttributes, sanitizeNodes };
package/dist/is.js CHANGED
@@ -1,5 +1,5 @@
1
1
  function isChildNode(value) {
2
- return value instanceof Node && childNodeTypes.has(value.nodeType);
2
+ return value instanceof Node && CHILD_NODE_TYPES.has(value.nodeType);
3
3
  }
4
4
  function isEventTarget(value) {
5
5
  return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
@@ -8,13 +8,15 @@ function isHTMLOrSVGElement(value) {
8
8
  return value instanceof HTMLElement || value instanceof SVGElement;
9
9
  }
10
10
  function isInDocument(node, document) {
11
- return node instanceof Node ? document instanceof Document ? node.ownerDocument == null ? node === document : node.ownerDocument === document && document.contains(node) : node.ownerDocument?.contains(node) ?? true : false;
11
+ if (!(node instanceof Node)) return false;
12
+ if (!(document instanceof Document)) return node.ownerDocument?.contains(node) ?? true;
13
+ return node.ownerDocument == null ? node === document : node.ownerDocument === document && document.contains(node);
12
14
  }
13
- var childNodeTypes = new Set([
14
- 1,
15
- 3,
16
- 7,
17
- 8,
18
- 10
15
+ var CHILD_NODE_TYPES = new Set([
16
+ Node.ELEMENT_NODE,
17
+ Node.TEXT_NODE,
18
+ Node.PROCESSING_INSTRUCTION_NODE,
19
+ Node.COMMENT_NODE,
20
+ Node.DOCUMENT_TYPE_NODE
19
21
  ]);
20
22
  export { isChildNode, isEventTarget, isHTMLOrSVGElement, isInDocument };
package/dist/sanitize.js CHANGED
@@ -1,29 +1,5 @@
1
- import { isBadAttribute, isEmptyNonBooleanAttribute, isInvalidBooleanAttribute } from "./attribute.js";
2
- import { isPlainObject } from "@oscarpalmer/atoms/is";
3
- function getOptions(input) {
4
- const options = isPlainObject(input) ? input : {};
5
- options.sanitizeBooleanAttributes = typeof options.sanitizeBooleanAttributes === "boolean" ? options.sanitizeBooleanAttributes : true;
6
- return options;
7
- }
1
+ import { getSanitizeOptions, sanitizeNodes } from "./internal/sanitize.js";
8
2
  function sanitize(value, options) {
9
- return sanitizeNodes(Array.isArray(value) ? value : [value], getOptions(options));
10
- }
11
- function sanitizeAttributes(element, attributes, options) {
12
- const { length } = attributes;
13
- for (let index = 0; index < length; index += 1) {
14
- const attribute = attributes[index];
15
- if (isBadAttribute(attribute) || isEmptyNonBooleanAttribute(attribute)) element.removeAttribute(attribute.name);
16
- else if (options.sanitizeBooleanAttributes && isInvalidBooleanAttribute(attribute)) element.setAttribute(attribute.name, "");
17
- }
18
- }
19
- function sanitizeNodes(nodes, options) {
20
- const actual = nodes.filter((node) => node instanceof Node);
21
- const { length } = nodes;
22
- for (let index = 0; index < length; index += 1) {
23
- const node = actual[index];
24
- if (node instanceof Element) sanitizeAttributes(node, [...node.attributes], options);
25
- if (node.hasChildNodes()) sanitizeNodes([...node.childNodes], options);
26
- }
27
- return nodes;
3
+ return sanitizeNodes(Array.isArray(value) ? value : [value], getSanitizeOptions(options));
28
4
  }
29
5
  export { sanitize };
package/dist/style.js CHANGED
@@ -7,7 +7,7 @@ function getStyle(element, property, computed) {
7
7
  }
8
8
  function getStyles(element, properties, computed) {
9
9
  const styles = {};
10
- if (!isHTMLOrSVGElement(element) || !Array.isArray(properties)) return styles;
10
+ if (!(isHTMLOrSVGElement(element) && Array.isArray(properties))) return styles;
11
11
  const { length } = properties;
12
12
  for (let index = 0; index < length; index += 1) {
13
13
  const property = properties[index];
@@ -17,9 +17,10 @@ function getStyles(element, properties, computed) {
17
17
  }
18
18
  function getTextDirection(element, computed) {
19
19
  if (!(element instanceof Element)) return;
20
- const direction = element.getAttribute("dir");
21
- if (direction != null && /^(ltr|rtl)$/i.test(direction)) return direction.toLowerCase();
22
- return getStyleValue(element, "direction", computed === true) === "rtl" ? "rtl" : "ltr";
20
+ const direction = element.getAttribute(ATTRIBUTE_DIRECTION);
21
+ if (direction != null && EXPRESSION_DIRECTION.test(direction)) return direction.toLowerCase();
22
+ const value = getStyleValue(element, "direction", computed === true);
23
+ return value === "rtl" ? value : "ltr";
23
24
  }
24
25
  function setStyle(element, property, value) {
25
26
  setElementValues(element, property, value, updateStyleProperty);
@@ -27,6 +28,32 @@ function setStyle(element, property, value) {
27
28
  function setStyles(element, styles) {
28
29
  setElementValues(element, styles, null, updateStyleProperty);
29
30
  }
31
+ function toggleStyles(element, styles) {
32
+ function toggle(set) {
33
+ hasSet = set;
34
+ let next;
35
+ if (set) {
36
+ values = getStyles(element, keys);
37
+ next = styles;
38
+ } else {
39
+ next = { ...values };
40
+ values = {};
41
+ for (const key of keys) values[key] = void 0;
42
+ }
43
+ setStyles(element, next);
44
+ }
45
+ const keys = Object.keys(styles);
46
+ let hasSet = false;
47
+ let values = {};
48
+ return {
49
+ set() {
50
+ if (!hasSet) toggle(true);
51
+ },
52
+ remove() {
53
+ if (hasSet) toggle(false);
54
+ }
55
+ };
56
+ }
30
57
  function updateStyleProperty(element, key, value) {
31
58
  updateElementValue(element, key, value, function(property, value$1) {
32
59
  this.style[property] = value$1;
@@ -34,4 +61,6 @@ function updateStyleProperty(element, key, value) {
34
61
  this.style[property] = "";
35
62
  }, false);
36
63
  }
37
- export { getStyle, getStyles, getTextDirection, setStyle, setStyles };
64
+ var ATTRIBUTE_DIRECTION = "dir";
65
+ var EXPRESSION_DIRECTION = /^(ltr|rtl)$/i;
66
+ export { getStyle, getStyles, getTextDirection, setStyle, setStyles, toggleStyles };