@oscarpalmer/toretto 0.40.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/attribute/{get.d.mts → get.attribute.d.mts} +3 -2
  2. package/dist/attribute/{get.mjs → get.attribute.mjs} +4 -3
  3. package/dist/attribute/index.d.mts +3 -16
  4. package/dist/attribute/index.mjs +4 -7
  5. package/dist/attribute/{set.d.mts → set.attribute.d.mts} +4 -4
  6. package/dist/attribute/{set.mjs → set.attribute.mjs} +2 -2
  7. package/dist/create.d.mts +25 -0
  8. package/dist/create.mjs +17 -0
  9. package/dist/data.d.mts +1 -1
  10. package/dist/data.mjs +7 -7
  11. package/dist/event/delegation.mjs +8 -1
  12. package/dist/html/index.d.mts +23 -26
  13. package/dist/html/index.mjs +85 -18
  14. package/dist/html/sanitize.mjs +6 -5
  15. package/dist/index.d.mts +114 -53
  16. package/dist/index.mjs +553 -561
  17. package/dist/internal/attribute.d.mts +4 -3
  18. package/dist/internal/attribute.mjs +13 -23
  19. package/dist/internal/element-value.d.mts +2 -2
  20. package/dist/internal/element-value.mjs +4 -2
  21. package/dist/internal/get-value.mjs +1 -1
  22. package/dist/internal/property.d.mts +4 -0
  23. package/dist/internal/property.mjs +21 -0
  24. package/dist/property/get.property.d.mts +20 -0
  25. package/dist/property/get.property.mjs +35 -0
  26. package/dist/property/index.d.mts +3 -0
  27. package/dist/property/index.mjs +3 -0
  28. package/dist/property/set.property.d.mts +32 -0
  29. package/dist/property/set.property.mjs +34 -0
  30. package/dist/style.d.mts +12 -7
  31. package/dist/style.mjs +14 -18
  32. package/package.json +12 -5
  33. package/src/attribute/{get.ts → get.attribute.ts} +14 -3
  34. package/src/attribute/index.ts +10 -22
  35. package/src/attribute/{set.ts → set.attribute.ts} +9 -5
  36. package/src/create.ts +81 -0
  37. package/src/data.ts +17 -9
  38. package/src/event/delegation.ts +24 -3
  39. package/src/event/index.ts +9 -3
  40. package/src/find/index.ts +12 -4
  41. package/src/find/relative.ts +4 -0
  42. package/src/focusable.ts +10 -2
  43. package/src/html/index.ts +166 -58
  44. package/src/html/sanitize.ts +14 -11
  45. package/src/index.ts +2 -1
  46. package/src/internal/attribute.ts +23 -42
  47. package/src/internal/element-value.ts +11 -4
  48. package/src/internal/get-value.ts +8 -0
  49. package/src/internal/is.ts +4 -0
  50. package/src/internal/property.ts +42 -0
  51. package/src/is.ts +10 -2
  52. package/src/property/get.property.ts +73 -0
  53. package/src/property/index.ts +2 -0
  54. package/src/property/set.property.ts +102 -0
  55. package/src/style.ts +52 -27
  56. package/src/touch.ts +14 -2
@@ -4,12 +4,13 @@ import { Attribute } from "../models.mjs";
4
4
  declare function isAttribute(value: unknown): value is Attr | Attribute;
5
5
  declare function _isBadAttribute(first: unknown, second: unknown, decode: boolean): boolean;
6
6
  declare function _isBooleanAttribute(first: unknown, decode: boolean): boolean;
7
- declare function _isEmptyNonBooleanAttribute(first: unknown, second: unknown, decode: boolean): boolean;
8
7
  declare function _isInvalidBooleanAttribute(first: unknown, second: unknown, decode: boolean): boolean;
9
- declare function updateAttribute(element: Element, name: string, value: unknown, dispatch?: unknown): void;
8
+ declare function updateAttribute(element: Element, name: string, value: unknown, dispatch: boolean): void;
10
9
  /**
11
10
  * List of boolean attributes
12
11
  */
13
12
  declare const booleanAttributes: readonly string[];
13
+ declare const booleanAttributesSet: Set<string>;
14
+ declare const dispatchedAttributes: Set<string>;
14
15
  //#endregion
15
- export { _isBadAttribute, _isBooleanAttribute, _isEmptyNonBooleanAttribute, _isInvalidBooleanAttribute, booleanAttributes, isAttribute, updateAttribute };
16
+ export { _isBadAttribute, _isBooleanAttribute, _isInvalidBooleanAttribute, booleanAttributes, booleanAttributesSet, dispatchedAttributes, isAttribute, updateAttribute };
@@ -1,5 +1,7 @@
1
1
  import { updateElementValue } from "./element-value.mjs";
2
+ import { updateProperty } from "./property.mjs";
2
3
  import { isPlainObject } from "@oscarpalmer/atoms/is";
4
+ import { kebabCase } from "@oscarpalmer/atoms/string/case";
3
5
  //#region src/internal/attribute.ts
4
6
  function badAttributeHandler(name, value) {
5
7
  if (typeof name !== "string" || name.trim().length === 0 || typeof value !== "string") return true;
@@ -29,6 +31,7 @@ function handleAttribute(callback, decode, first, second) {
29
31
  name = first;
30
32
  value = second;
31
33
  }
34
+ if (name != null) name = kebabCase(name);
32
35
  if (decode && value != null) value = decodeAttribute(value);
33
36
  return callback(name, value?.replace(EXPRESSION_WHITESPACE, ""));
34
37
  }
@@ -41,9 +44,6 @@ function _isBadAttribute(first, second, decode) {
41
44
  function _isBooleanAttribute(first, decode) {
42
45
  return handleAttribute((name) => booleanAttributesSet.has(name?.toLowerCase()), decode, first, "");
43
46
  }
44
- function _isEmptyNonBooleanAttribute(first, second, decode) {
45
- return handleAttribute((name, value) => name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0, decode, first, second);
46
- }
47
47
  function _isInvalidBooleanAttribute(first, second, decode) {
48
48
  return handleAttribute(booleanAttributeHandler, decode, first, second);
49
49
  }
@@ -51,18 +51,12 @@ function isValidSourceAttribute(name, value) {
51
51
  return EXPRESSION_SOURCE_NAME.test(name) && EXPRESSION_SOURCE_VALUE.test(value);
52
52
  }
53
53
  function updateAttribute(element, name, value, dispatch) {
54
- const normalizedName = name.toLowerCase();
55
- const isBoolean = booleanAttributesSet.has(normalizedName);
56
- const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === normalizedName) : value == null ? "" : value;
57
- if (name in element) updateProperty(element, normalizedName, next, dispatch);
54
+ const lowerCaseName = name.toLowerCase();
55
+ const isBoolean = booleanAttributesSet.has(lowerCaseName);
56
+ const next = isBoolean ? value === true || typeof value === "string" && (value === "" || value.toLowerCase() === lowerCaseName) : value == null ? "" : value;
57
+ if (isBoolean || dispatchedAttributes.has(name)) updateProperty(element, name, next, dispatch);
58
58
  updateElementValue(element, name, isBoolean ? next ? "" : null : value, element.setAttribute, element.removeAttribute, isBoolean, false);
59
59
  }
60
- function updateProperty(element, name, value, dispatch) {
61
- if (Object.is(element[name], value)) return;
62
- element[name] = value;
63
- const event = dispatch !== false && elementEvents[element.tagName]?.[name];
64
- if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
65
- }
66
60
  const EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
67
61
  const EXPRESSION_DATA_OR_SCRIPT = /^(?:data|\w+script):/i;
68
62
  const EXPRESSION_EVENT_NAME = /^on/i;
@@ -101,16 +95,12 @@ const booleanAttributes = Object.freeze([
101
95
  "selected"
102
96
  ]);
103
97
  const booleanAttributesSet = new Set(booleanAttributes);
104
- const elementEvents = {
105
- DETAILS: { open: "toggle" },
106
- INPUT: {
107
- checked: "change",
108
- value: "input"
109
- },
110
- SELECT: { value: "change" },
111
- TEXTAREA: { value: "input" }
112
- };
98
+ const dispatchedAttributes = new Set([
99
+ "checked",
100
+ "open",
101
+ "value"
102
+ ]);
113
103
  const formElement = document.createElement("form");
114
104
  let textArea;
115
105
  //#endregion
116
- export { _isBadAttribute, _isBooleanAttribute, _isEmptyNonBooleanAttribute, _isInvalidBooleanAttribute, booleanAttributes, isAttribute, updateAttribute };
106
+ export { _isBadAttribute, _isBooleanAttribute, _isInvalidBooleanAttribute, booleanAttributes, booleanAttributesSet, dispatchedAttributes, isAttribute, updateAttribute };
@@ -1,6 +1,6 @@
1
1
  //#region src/internal/element-value.d.ts
2
- declare function setElementValue(element: Element, first: unknown, second: unknown, third: unknown, callback: (element: Element, key: string, value: unknown) => void): void;
3
- declare function setElementValues(element: Element, first: unknown, second: unknown, third: unknown, callback: (element: Element, key: string, value: unknown, dispatch?: unknown) => void): void;
2
+ declare function setElementValue(element: Element, first: unknown, second: unknown, third: unknown, callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void): void;
3
+ declare function setElementValues(element: Element, first: unknown, second: unknown, third: unknown, callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void): void;
4
4
  declare function updateElementValue(element: Element, key: string, value: unknown, set: (key: string, value: string) => void, remove: (key: string) => void, isBoolean: boolean, json: boolean): void;
5
5
  //#endregion
6
6
  export { setElementValue, setElementValues, updateElementValue };
@@ -2,6 +2,7 @@ import { isHTMLOrSVGElement } from "./is.mjs";
2
2
  import "../is.mjs";
3
3
  import { isAttribute } from "./attribute.mjs";
4
4
  import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
5
+ import { kebabCase } from "@oscarpalmer/atoms/string/case";
5
6
  //#region src/internal/element-value.ts
6
7
  function setElementValue(element, first, second, third, callback) {
7
8
  if (!isHTMLOrSVGElement(element)) return;
@@ -10,8 +11,9 @@ function setElementValue(element, first, second, third, callback) {
10
11
  }
11
12
  function setElementValues(element, first, second, third, callback) {
12
13
  if (!isHTMLOrSVGElement(element)) return;
14
+ const dispatch = third !== false;
13
15
  if (typeof first === "string") {
14
- callback(element, first, second, third);
16
+ callback(element, kebabCase(first), second, dispatch);
15
17
  return;
16
18
  }
17
19
  const isArray = Array.isArray(first);
@@ -23,7 +25,7 @@ function setElementValues(element, first, second, third, callback) {
23
25
  const { length } = entries;
24
26
  for (let index = 0; index < length; index += 1) {
25
27
  const entry = entries[index];
26
- if (typeof entry === "object" && typeof entry?.name === "string") callback(element, entry.name, entry.value, third);
28
+ if (typeof entry === "object" && typeof entry?.name === "string") callback(element, kebabCase(entry.name), entry.value, dispatch);
27
29
  }
28
30
  }
29
31
  function updateElementValue(element, key, value, set, remove, isBoolean, json) {
@@ -1,5 +1,5 @@
1
- import { parse } from "@oscarpalmer/atoms/string";
2
1
  import { camelCase, kebabCase } from "@oscarpalmer/atoms/string/case";
2
+ import { parse } from "@oscarpalmer/atoms/string";
3
3
  //#region src/internal/get-value.ts
4
4
  function getBoolean(value, defaultValue) {
5
5
  return typeof value === "boolean" ? value : defaultValue ?? false;
@@ -0,0 +1,4 @@
1
+ //#region src/internal/property.d.ts
2
+ declare function updateProperty(element: Element, name: string, value: unknown, dispatch: boolean): void;
3
+ //#endregion
4
+ export { updateProperty };
@@ -0,0 +1,21 @@
1
+ import { camelCase } from "@oscarpalmer/atoms/string/case";
2
+ //#region src/internal/property.ts
3
+ function updateProperty(element, name, value, dispatch) {
4
+ let property = name;
5
+ if (!(property in element)) property = camelCase(name);
6
+ if (!(property in element) || Object.is(element[property], value)) return;
7
+ element[property] = value;
8
+ const event = dispatch && elementEvents[element.tagName]?.[property];
9
+ if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
10
+ }
11
+ const elementEvents = {
12
+ DETAILS: { open: "toggle" },
13
+ INPUT: {
14
+ checked: "change",
15
+ value: "input"
16
+ },
17
+ SELECT: { value: "change" },
18
+ TEXTAREA: { value: "input" }
19
+ };
20
+ //#endregion
21
+ export { updateProperty };
@@ -0,0 +1,20 @@
1
+ import { Primitive } from "@oscarpalmer/atoms/models";
2
+
3
+ //#region src/property/get.property.d.ts
4
+ type GetProperties<Target extends Element> = { [Property in keyof Target as Target[Property] extends Primitive ? Property : never]?: Target[Property] };
5
+ /**
6
+ * Get the values of one or more properties on an element
7
+ * @param target Target element
8
+ * @param properties Properties to get
9
+ * @returns Property values
10
+ */
11
+ declare function getProperties<Target extends Element, Property extends keyof GetProperties<Target>>(target: Target, properties: Property[]): Pick<GetProperties<Target>, Property>;
12
+ /**
13
+ * Get the value of a property on an element
14
+ * @param target Target element
15
+ * @param property Property to get
16
+ * @returns Property value
17
+ */
18
+ declare function getProperty<Target extends Element, Property extends keyof GetProperties<Target>>(target: Target, property: Property): GetProperties<Target>[Property];
19
+ //#endregion
20
+ export { getProperties, getProperty };
@@ -0,0 +1,35 @@
1
+ import { isHTMLOrSVGElement } from "../internal/is.mjs";
2
+ import { camelCase } from "@oscarpalmer/atoms/string/case";
3
+ //#region src/property/get.property.ts
4
+ /**
5
+ * Get the values of one or more properties on an element
6
+ * @param target Target element
7
+ * @param properties Properties to get
8
+ * @returns Property values
9
+ */
10
+ function getProperties(target, properties) {
11
+ const values = {};
12
+ if (!isHTMLOrSVGElement(target) || !Array.isArray(properties)) return values;
13
+ const { length } = properties;
14
+ for (let index = 0; index < length; index += 1) {
15
+ const property = properties[index];
16
+ if (typeof property === "string") values[property] = getPropertyValue(target, property);
17
+ }
18
+ return values;
19
+ }
20
+ /**
21
+ * Get the value of a property on an element
22
+ * @param target Target element
23
+ * @param property Property to get
24
+ * @returns Property value
25
+ */
26
+ function getProperty(target, property) {
27
+ if (isHTMLOrSVGElement(target) && typeof property === "string") return getPropertyValue(target, property);
28
+ }
29
+ function getPropertyValue(element, property) {
30
+ let actual = property;
31
+ if (!(actual in element)) actual = camelCase(actual);
32
+ if (actual in element) return element[actual];
33
+ }
34
+ //#endregion
35
+ export { getProperties, getProperty };
@@ -0,0 +1,3 @@
1
+ import { getProperties, getProperty } from "./get.property.mjs";
2
+ import { setProperties, setProperty } from "./set.property.mjs";
3
+ export { getProperties, getProperty, setProperties, setProperty };
@@ -0,0 +1,3 @@
1
+ import { getProperties, getProperty } from "./get.property.mjs";
2
+ import { setProperties, setProperty } from "./set.property.mjs";
3
+ export { getProperties, getProperty, setProperties, setProperty };
@@ -0,0 +1,32 @@
1
+ import { DispatchedAttributeName } from "../attribute/set.attribute.mjs";
2
+ import { Primitive } from "@oscarpalmer/atoms/models";
3
+
4
+ //#region src/property/set.property.d.ts
5
+ type DispatchedPropertyValue<Target extends Element, Property extends DispatchedAttributeName> = Property extends keyof SetProperties<Target> ? SetProperties<Target>[Property] : never;
6
+ type SetProperties<Target extends Element> = { [Property in keyof Target as Target[Property] extends Primitive ? Property : never]?: Target[Property] };
7
+ /**
8
+ * Set the values of one or more properties on an element
9
+ *
10
+ * Also updates attributes for boolean/dispatchable properties, and if `dispatch` is `true`, will dispatch events for dispatchable properties
11
+ * @param target Target element
12
+ * @param properties Properties to set
13
+ * @param dispatch Dispatch events for properties? _(defaults to `true`)_
14
+ */
15
+ declare function setProperties<Target extends Element>(target: Target, properties: SetProperties<Target>, dispatch?: boolean): void;
16
+ /**
17
+ * Set the value for a dispatchable property on an element
18
+ * @param target Target element
19
+ * @param property Property to set
20
+ * @param value Value to set
21
+ * @param dispatch Dispatch event for property? _(defaults to `true`)_
22
+ */
23
+ declare function setProperty<Target extends Element, Property extends DispatchedAttributeName>(target: Target, property: Property, value: DispatchedPropertyValue<Target, Property>, dispatch?: boolean): void;
24
+ /**
25
+ * Set the value for a property on an element
26
+ * @param target Target element
27
+ * @param property Property to set
28
+ * @param value Value to set
29
+ */
30
+ declare function setProperty<Target extends Element, Property extends keyof SetProperties<Target>>(target: Target, property: Property, value: SetProperties<Target>[Property]): void;
31
+ //#endregion
32
+ export { setProperties, setProperty };
@@ -0,0 +1,34 @@
1
+ import { isHTMLOrSVGElement } from "../internal/is.mjs";
2
+ import "../is.mjs";
3
+ import { updateProperty } from "../internal/property.mjs";
4
+ import { booleanAttributesSet, dispatchedAttributes } from "../internal/attribute.mjs";
5
+ import { setAttribute } from "../attribute/set.attribute.mjs";
6
+ import "../attribute/index.mjs";
7
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
8
+ //#region src/property/set.property.ts
9
+ /**
10
+ * Set the values of one or more properties on an element
11
+ *
12
+ * Also updates attributes for boolean/dispatchable properties, and if `dispatch` is `true`, will dispatch events for dispatchable properties
13
+ * @param target Target element
14
+ * @param properties Properties to set
15
+ * @param dispatch Dispatch events for properties? _(defaults to `true`)_
16
+ */
17
+ function setProperties(target, properties, dispatch) {
18
+ if (!isHTMLOrSVGElement(target) || !isPlainObject(properties)) return;
19
+ const shouldDispatch = dispatch !== false;
20
+ const keys = Object.keys(properties);
21
+ const { length } = keys;
22
+ for (let index = 0; index < length; index += 1) {
23
+ const key = keys[index];
24
+ if (booleanAttributesSet.has(key.toLowerCase()) || dispatchedAttributes.has(key)) setAttribute(target, key, properties[key], shouldDispatch);
25
+ else updateProperty(target, key, properties[key], shouldDispatch);
26
+ }
27
+ }
28
+ function setProperty(target, property, value, dispatch) {
29
+ if (!isHTMLOrSVGElement(target) || typeof property !== "string") return;
30
+ if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) setAttribute(target, property, value, dispatch !== false);
31
+ else updateProperty(target, property, value, dispatch !== false);
32
+ }
33
+ //#endregion
34
+ export { setProperties, setProperty };
package/dist/style.d.mts CHANGED
@@ -11,6 +11,7 @@ type StyleToggler = {
11
11
  */
12
12
  remove(): void;
13
13
  };
14
+ type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
14
15
  /**
15
16
  * Get a style from an element
16
17
  * @param element Element to get the style from
@@ -28,31 +29,35 @@ declare function getStyle(element: Element, property: keyof CSSStyleDeclaration,
28
29
  */
29
30
  declare function getStyles<Property extends keyof CSSStyleDeclaration>(element: Element, properties: Property[], computed?: boolean): Record<Property, string | undefined>;
30
31
  /**
31
- * Get the text direction of an element
32
- * @param element Element to get the text direction from
33
- * @param computed Get the computed text direction? _(defaults to `false`)_
32
+ * Get the text direction of a node or element _(or document, if element is invalid)_
33
+ * @param node Node or element to get the text direction from
34
34
  * @returns Text direction
35
35
  */
36
- declare function getTextDirection(element: Element, computed?: boolean): TextDirection;
36
+ declare function getTextDirection(node: Element | Node): TextDirection;
37
+ /**
38
+ * Get the text direction of the document
39
+ * @returns Text direction
40
+ */
41
+ declare function getTextDirection(): TextDirection;
37
42
  /**
38
43
  * Set a style on an element
39
44
  * @param element Element to set the style on
40
45
  * @param property Style name
41
46
  * @param value Style value
42
47
  */
43
- declare function setStyle(element: Element, property: keyof CSSStyleDeclaration, value?: string): void;
48
+ declare function setStyle(element: Element, property: keyof CSSStyleDeclaration, value?: unknown): void;
44
49
  /**
45
50
  * Set styles on an element
46
51
  * @param element Element to set the styles on
47
52
  * @param styles Styles to set
48
53
  */
49
- declare function setStyles(element: Element, styles: Partial<CSSStyleDeclaration>): void;
54
+ declare function setStyles(element: Element, styles: Styles): void;
50
55
  /**
51
56
  * Toggle styles for an element
52
57
  * @param element Element to style
53
58
  * @param styles Styles to be set or removed
54
59
  * @returns Style toggler
55
60
  */
56
- declare function toggleStyles(element: Element, styles: Partial<CSSStyleDeclaration>): StyleToggler;
61
+ declare function toggleStyles(element: Element, styles: Styles): StyleToggler;
57
62
  //#endregion
58
63
  export { StyleToggler, getStyle, getStyles, getTextDirection, setStyle, setStyles, toggleStyles };
package/dist/style.mjs CHANGED
@@ -10,8 +10,7 @@ import { getStyleValue } from "./internal/get-value.mjs";
10
10
  * @returns Style value
11
11
  */
12
12
  function getStyle(element, property, computed) {
13
- if (!isHTMLOrSVGElement(element) || typeof property !== "string") return;
14
- return getStyleValue(element, property, computed === true);
13
+ if (isHTMLOrSVGElement(element) && typeof property === "string") return getStyleValue(element, property, computed === true);
15
14
  }
16
15
  /**
17
16
  * Get styles from an element
@@ -30,18 +29,13 @@ function getStyles(element, properties, computed) {
30
29
  }
31
30
  return styles;
32
31
  }
33
- /**
34
- * Get the text direction of an element
35
- * @param element Element to get the text direction from
36
- * @param computed Get the computed text direction? _(defaults to `false`)_
37
- * @returns Text direction
38
- */
39
- function getTextDirection(element, computed) {
40
- if (!(element instanceof Element)) return;
41
- const direction = element.getAttribute(ATTRIBUTE_DIRECTION);
42
- if (direction != null && EXPRESSION_DIRECTION.test(direction)) return direction.toLowerCase();
43
- const value = getStyleValue(element, "direction", computed === true);
44
- return value === "rtl" ? value : "ltr";
32
+ function getTextDirection(node) {
33
+ let target;
34
+ if (isHTMLOrSVGElement(node)) target = node;
35
+ else target = node instanceof Node ? node.ownerDocument?.documentElement ?? document.documentElement : document.documentElement;
36
+ let { direction } = target.style;
37
+ if (direction === "") direction = getStyleValue(target, PROPETY_DIRECTION, true);
38
+ return direction === DIRECTION_RTL ? DIRECTION_RTL : DIRECTION_LTR;
45
39
  }
46
40
  /**
47
41
  * Set a style on an element
@@ -76,11 +70,12 @@ function toggleStyles(element, styles) {
76
70
  } else {
77
71
  next = { ...values };
78
72
  values = {};
79
- for (const key of keys) values[key] = void 0;
73
+ for (let index = 0; index < length; index += 1) values[keys[index]] = void 0;
80
74
  }
81
75
  setStyles(element, next);
82
76
  }
83
77
  const keys = Object.keys(styles);
78
+ const { length } = keys;
84
79
  let hasSet = false;
85
80
  let values = {};
86
81
  return {
@@ -94,12 +89,13 @@ function toggleStyles(element, styles) {
94
89
  }
95
90
  function updateStyleProperty(element, key, value) {
96
91
  updateElementValue(element, key, value, function(property, style) {
97
- this.style[property] = style;
92
+ this.style[property] = String(style);
98
93
  }, function(property) {
99
94
  this.style[property] = "";
100
95
  }, false, false);
101
96
  }
102
- const ATTRIBUTE_DIRECTION = "dir";
103
- const EXPRESSION_DIRECTION = /^(ltr|rtl)$/i;
97
+ const DIRECTION_LTR = "ltr";
98
+ const DIRECTION_RTL = "rtl";
99
+ const PROPETY_DIRECTION = "direction";
104
100
  //#endregion
105
101
  export { getStyle, getStyles, getTextDirection, setStyle, setStyles, toggleStyles };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/toretto",
3
- "version": "0.40.0",
3
+ "version": "0.42.0",
4
4
  "description": "A collection of badass DOM utilities.",
5
5
  "keywords": [
6
6
  "dom",
@@ -34,6 +34,10 @@
34
34
  "types": "./dist/attribute/index.d.mts",
35
35
  "default": "./dist/attribute/index.mjs"
36
36
  },
37
+ "./create": {
38
+ "types": "./dist/create.d.mts",
39
+ "default": "./dist/create.mjs"
40
+ },
37
41
  "./data": {
38
42
  "types": "./dist/data.d.mts",
39
43
  "default": "./dist/data.mjs"
@@ -61,6 +65,10 @@
61
65
  "./models": {
62
66
  "types": "./dist/models.d.mts"
63
67
  },
68
+ "./property": {
69
+ "types": "./dist/property/index.d.mts",
70
+ "default": "./dist/property/index.mjs"
71
+ },
64
72
  "./style": {
65
73
  "types": "./dist/style.d.mts",
66
74
  "default": "./dist/style.mjs"
@@ -75,16 +83,15 @@
75
83
  "tsdown:build": "npx tsdown -c ./tsdown.config.ts",
76
84
  "tsdown:watch": "npx tsdown -c ./tsdown.config.ts --watch",
77
85
  "test": "npx vp test run --coverage",
78
- "test:leak": "npx vp test run --detect-async-leaks --coverage",
79
- "watch": "npx vite build --watch"
86
+ "test:leak": "npx vp test run --detect-async-leaks --coverage"
80
87
  },
81
88
  "dependencies": {
82
- "@oscarpalmer/atoms": "^0.164"
89
+ "@oscarpalmer/atoms": "^0.172"
83
90
  },
84
91
  "devDependencies": {
85
92
  "@types/node": "^25.5",
86
93
  "@vitest/coverage-istanbul": "^4.1",
87
- "jsdom": "^28.1",
94
+ "jsdom": "^29",
88
95
  "tsdown": "^0.21",
89
96
  "typescript": "^5.9",
90
97
  "vite": "npm:@voidzero-dev/vite-plus-core@latest",
@@ -1,6 +1,15 @@
1
+ import {kebabCase} from '@oscarpalmer/atoms/string/case';
1
2
  import {getAttributeValue} from '../internal/get-value';
2
3
  import {isHTMLOrSVGElement} from '../internal/is';
3
4
 
5
+ // #region Types
6
+
7
+ type DataPrefixedName = `data-${string}`;
8
+
9
+ // #endregion
10
+
11
+ // #region Functions
12
+
4
13
  /**
5
14
  * Get the value of a specific attribute from an element
6
15
  * @param element Element to get attribute from
@@ -8,7 +17,7 @@ import {isHTMLOrSVGElement} from '../internal/is';
8
17
  * @param parse Parse value? _(defaults to `true`)_
9
18
  * @returns Attribute value _(or `undefined`)_
10
19
  */
11
- export function getAttribute(element: Element, name: `data-${string}`, parse?: boolean): unknown;
20
+ export function getAttribute(element: Element, name: DataPrefixedName, parse?: boolean): unknown;
12
21
 
13
22
  /**
14
23
  * Get the value of a specific attribute from an element
@@ -20,7 +29,7 @@ export function getAttribute(element: Element, name: string): unknown;
20
29
 
21
30
  export function getAttribute(element: Element, name: string, parseValues?: boolean): unknown {
22
31
  if (isHTMLOrSVGElement(element) && typeof name === 'string') {
23
- return getAttributeValue(element, name, parseValues !== false);
32
+ return getAttributeValue(element, kebabCase(name), parseValues !== false);
24
33
  }
25
34
  }
26
35
 
@@ -50,9 +59,11 @@ export function getAttributes<Key extends string>(
50
59
  const name = names[index];
51
60
 
52
61
  if (typeof name === 'string') {
53
- attributes[name] = getAttributeValue(element, name, shouldParse);
62
+ attributes[name] = getAttributeValue(element, kebabCase(name), shouldParse);
54
63
  }
55
64
  }
56
65
 
57
66
  return attributes;
58
67
  }
68
+
69
+ // #endregion
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  _isBadAttribute,
3
3
  _isBooleanAttribute,
4
- _isEmptyNonBooleanAttribute,
5
4
  _isInvalidBooleanAttribute,
6
5
  } from '../internal/attribute';
7
6
  import type {Attribute} from '../models';
8
7
 
8
+ // #region Functions
9
+
9
10
  /**
10
11
  * Is the attribute considered bad and potentially harmful?
11
12
  * @param attribute Attribute to check
@@ -43,25 +44,6 @@ export function isBooleanAttribute(first: unknown): boolean {
43
44
  return _isBooleanAttribute(first, true);
44
45
  }
45
46
 
46
- /**
47
- * Is the attribute empty and not a boolean attribute?
48
- * @param attribute Attribute to check
49
- * @returns `true` if attribute is empty and not a boolean attribute
50
- */
51
- export function isEmptyNonBooleanAttribute(attribute: Attr | Attribute): boolean;
52
-
53
- /**
54
- * Is the attribute empty and not a boolean attribute?
55
- * @param name Attribute name
56
- * @param value Attribute value
57
- * @returns `true` if attribute is empty and not a boolean attribute
58
- */
59
- export function isEmptyNonBooleanAttribute(name: string, value: string): boolean;
60
-
61
- export function isEmptyNonBooleanAttribute(first: unknown, second?: unknown): boolean {
62
- return _isEmptyNonBooleanAttribute(first, second, true);
63
- }
64
-
65
47
  /**
66
48
  * Is the attribute an invalid boolean attribute?
67
49
  *
@@ -85,6 +67,12 @@ export function isInvalidBooleanAttribute(first: unknown, second?: unknown): boo
85
67
  return _isInvalidBooleanAttribute(first, second, true);
86
68
  }
87
69
 
70
+ // #endregion
71
+
72
+ // #region Exports
73
+
88
74
  export {booleanAttributes} from '../internal/attribute';
89
- export * from './get';
90
- export * from './set';
75
+ export * from './get.attribute';
76
+ export {setAttribute, setAttributes} from './set.attribute';
77
+
78
+ // #endregion
@@ -2,11 +2,13 @@ import {updateAttribute} from '../internal/attribute';
2
2
  import {setElementValue, setElementValues} from '../internal/element-value';
3
3
  import type {Attribute} from '../models';
4
4
 
5
- //
5
+ // #region Types
6
6
 
7
- type DispatchedAttribute = 'checked' | 'open' | 'value';
7
+ export type DispatchedAttributeName = 'checked' | 'open' | 'value';
8
8
 
9
- //
9
+ // #endregion
10
+
11
+ // #region Functions
10
12
 
11
13
  /**
12
14
  * Set an attribute on an element
@@ -17,9 +19,9 @@ type DispatchedAttribute = 'checked' | 'open' | 'value';
17
19
  * @param value Attribute value
18
20
  * @param dispatch Dispatch event for attribute? _(defaults to `true`)_
19
21
  */
20
- export function setAttribute<Name extends DispatchedAttribute>(
22
+ export function setAttribute(
21
23
  element: Element,
22
- name: Name,
24
+ name: DispatchedAttributeName,
23
25
  value?: unknown,
24
26
  dispatch?: boolean,
25
27
  ): void;
@@ -92,3 +94,5 @@ export function setAttributes(
92
94
  ): void {
93
95
  setElementValues(element, attributes, null, dispatch, updateAttribute);
94
96
  }
97
+
98
+ // #endregion