@oscarpalmer/toretto 0.42.0 → 0.43.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/index.d.mts CHANGED
@@ -530,6 +530,7 @@ declare function setProperty<Target extends Element, Property extends Dispatched
530
530
  declare function setProperty<Target extends Element, Property extends keyof SetProperties<Target>>(target: Target, property: Property, value: SetProperties<Target>[Property]): void;
531
531
  //#endregion
532
532
  //#region src/style.d.ts
533
+ type CSSStyleValues = Variables & CSSStyleDeclaration;
533
534
  type StyleToggler = {
534
535
  /**
535
536
  * Set the provided styles on the element
@@ -540,7 +541,8 @@ type StyleToggler = {
540
541
  */
541
542
  remove(): void;
542
543
  };
543
- type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
544
+ type Styles = Partial<Record<keyof CSSStyleValues, unknown>>;
545
+ type Variables<Value extends Record<string, string | undefined> = Record<string, string | undefined>> = { [property in keyof Value as `--${string & property}`]?: string | undefined };
544
546
  /**
545
547
  * Get a style from an element
546
548
  * @param element Element to get the style from
@@ -548,7 +550,7 @@ type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
548
550
  * @param computed Get the computed style? _(defaults to `false`)_
549
551
  * @returns Style value
550
552
  */
551
- declare function getStyle(element: Element, property: keyof CSSStyleDeclaration, computed?: boolean): string | undefined;
553
+ declare function getStyle(element: Element, property: keyof CSSStyleValues, computed?: boolean): string | undefined;
552
554
  /**
553
555
  * Get styles from an element
554
556
  * @param element Element to get the styles from
@@ -556,7 +558,7 @@ declare function getStyle(element: Element, property: keyof CSSStyleDeclaration,
556
558
  * @param computed Get the computed styles? _(defaults to `false`)_
557
559
  * @returns Style values
558
560
  */
559
- declare function getStyles<Property extends keyof CSSStyleDeclaration>(element: Element, properties: Property[], computed?: boolean): Record<Property, string | undefined>;
561
+ declare function getStyles<Property extends keyof CSSStyleValues>(element: Element, properties: Property[], computed?: boolean): Record<Property, string | undefined>;
560
562
  /**
561
563
  * Get the text direction of a node or element _(or document, if element is invalid)_
562
564
  * @param node Node or element to get the text direction from
@@ -574,7 +576,7 @@ declare function getTextDirection(): TextDirection;
574
576
  * @param property Style name
575
577
  * @param value Style value
576
578
  */
577
- declare function setStyle(element: Element, property: keyof CSSStyleDeclaration, value?: unknown): void;
579
+ declare function setStyle(element: Element, property: keyof CSSStyleValues, value?: unknown): void;
578
580
  /**
579
581
  * Set styles on an element
580
582
  * @param element Element to set the styles on
package/dist/index.mjs CHANGED
@@ -51,19 +51,6 @@ function isPlainObject(value) {
51
51
  return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
52
52
  }
53
53
  //#endregion
54
- //#region node_modules/@oscarpalmer/atoms/dist/internal/array/compact.mjs
55
- function compact(array, strict) {
56
- if (!Array.isArray(array)) return [];
57
- if (strict === true) return array.filter(Boolean);
58
- const { length } = array;
59
- const compacted = [];
60
- for (let index = 0; index < length; index += 1) {
61
- const item = array[index];
62
- if (item != null) compacted.push(item);
63
- }
64
- return compacted;
65
- }
66
- //#endregion
67
54
  //#region node_modules/@oscarpalmer/atoms/dist/internal/string.mjs
68
55
  /**
69
56
  * Get the string value from any value
@@ -79,13 +66,23 @@ function getString(value) {
79
66
  return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
80
67
  }
81
68
  /**
82
- * Join an array of values into a string
83
- * @param value Array of values
69
+ * Join an array of values into a string _(while ignoring empty values)_
70
+ *
71
+ * _(`null`, `undefined`, and any values that become whitespace-only strings are considered empty)_
72
+ * @param array Array of values
84
73
  * @param delimiter Delimiter to use between values
85
74
  * @returns Joined string
86
75
  */
87
- function join(value, delimiter) {
88
- return compact(value).map(getString).join(typeof delimiter === "string" ? delimiter : "");
76
+ function join(array, delimiter) {
77
+ if (!Array.isArray(array)) return "";
78
+ const { length } = array;
79
+ if (length === 0) return "";
80
+ const values = [];
81
+ for (let index = 0; index < length; index += 1) {
82
+ const item = getString(array[index]);
83
+ if (item.trim().length > 0) values.push(item);
84
+ }
85
+ return values.join(typeof delimiter === "string" ? delimiter : "");
89
86
  }
90
87
  /**
91
88
  * Split a string into words _(and other readable parts)_
@@ -99,9 +96,9 @@ const EXPRESSION_WORDS = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
99
96
  //#endregion
100
97
  //#region node_modules/@oscarpalmer/atoms/dist/is.mjs
101
98
  /**
102
- * Is the value `undefined`, `null`, or a whitespace-only string?
99
+ * Is the value `undefined`, `null`, or stringified as a whitespace-only string?
103
100
  * @param value Value to check
104
- * @returns `true` if the value is nullable or a whitespace-only string, otherwise `false`
101
+ * @returns `true` if the value is nullable or matches a whitespace-only string, otherwise `false`
105
102
  */
106
103
  function isNullableOrWhitespace(value) {
107
104
  return value == null || EXPRESSION_WHITESPACE$1.test(getString(value));
@@ -192,6 +189,9 @@ var SizedMap = class extends Map {
192
189
  };
193
190
  //#endregion
194
191
  //#region node_modules/@oscarpalmer/atoms/dist/function/memoize.mjs
192
+ /**
193
+ * A memoized function, caching and retrieving results based on the its parameters _(or a custom cache key)_
194
+ */
195
195
  var Memoized = class {
196
196
  #state;
197
197
  /**
@@ -406,16 +406,19 @@ const CHILD_NODE_TYPES = new Set([
406
406
  ]);
407
407
  //#endregion
408
408
  //#region src/internal/element-value.ts
409
- function setElementValue(element, first, second, third, callback) {
409
+ function normalizeKey(key, style) {
410
+ return style && key.startsWith(CSS_VARIABLE_PREFIX$1) ? key : kebabCase(key);
411
+ }
412
+ function setElementValue(element, first, second, third, callback, style) {
410
413
  if (!isHTMLOrSVGElement(element)) return;
411
- if (typeof first === "string") setElementValues(element, first, second, third, callback);
412
- else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback);
414
+ if (typeof first === "string") setElementValues(element, first, second, third, callback, style);
415
+ else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback, style);
413
416
  }
414
- function setElementValues(element, first, second, third, callback) {
417
+ function setElementValues(element, first, second, third, callback, style) {
415
418
  if (!isHTMLOrSVGElement(element)) return;
416
419
  const dispatch = third !== false;
417
420
  if (typeof first === "string") {
418
- callback(element, kebabCase(first), second, dispatch);
421
+ callback(element, normalizeKey(first, style), second, dispatch);
419
422
  return;
420
423
  }
421
424
  const isArray = Array.isArray(first);
@@ -427,13 +430,14 @@ function setElementValues(element, first, second, third, callback) {
427
430
  const { length } = entries;
428
431
  for (let index = 0; index < length; index += 1) {
429
432
  const entry = entries[index];
430
- if (typeof entry === "object" && typeof entry?.name === "string") callback(element, kebabCase(entry.name), entry.value, dispatch);
433
+ if (typeof entry === "object" && typeof entry?.name === "string") callback(element, normalizeKey(entry.name, style), entry.value, dispatch);
431
434
  }
432
435
  }
433
436
  function updateElementValue(element, key, value, set, remove, isBoolean, json) {
434
437
  if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
435
438
  else set.call(element, key, json ? JSON.stringify(value) : String(value));
436
439
  }
440
+ const CSS_VARIABLE_PREFIX$1 = "--";
437
441
  //#endregion
438
442
  //#region src/internal/property.ts
439
443
  function updateProperty(element, name, value, dispatch) {
@@ -442,7 +446,10 @@ function updateProperty(element, name, value, dispatch) {
442
446
  if (!(property in element) || Object.is(element[property], value)) return;
443
447
  element[property] = value;
444
448
  const event = dispatch && elementEvents[element.tagName]?.[property];
445
- if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
449
+ if (typeof event === "string") element.dispatchEvent(new Event(event, {
450
+ bubbles: true,
451
+ cancelable: true
452
+ }));
446
453
  }
447
454
  const elementEvents = {
448
455
  DETAILS: { open: "toggle" },
@@ -581,10 +588,12 @@ function getAttributeValue(element, name, parseValue) {
581
588
  return EXPRESSION_DATA_PREFIX.test(normalized) && typeof value === "string" && parseValue ? parse(value) ?? value : value;
582
589
  }
583
590
  function getStyleValue(element, property, computed) {
591
+ if (property.startsWith(CSS_VARIABLE_PREFIX)) return element.style.getPropertyValue(property);
584
592
  const name = camelCase(property);
585
593
  return computed ? getComputedStyle(element)[name] : element.style[name];
586
594
  }
587
595
  const EXPRESSION_DATA_PREFIX = /^data-/i;
596
+ const CSS_VARIABLE_PREFIX = "--";
588
597
  //#endregion
589
598
  //#region src/attribute/get.attribute.ts
590
599
  function getAttribute(element, name, parseValues) {
@@ -661,7 +670,7 @@ function getTextDirection(node) {
661
670
  if (isHTMLOrSVGElement(node)) target = node;
662
671
  else target = node instanceof Node ? node.ownerDocument?.documentElement ?? document.documentElement : document.documentElement;
663
672
  let { direction } = target.style;
664
- if (direction === "") direction = getStyleValue(target, PROPETY_DIRECTION, true);
673
+ if (direction === "") direction = getStyleValue(target, PROPERTY_DIRECTION, true);
665
674
  return direction === DIRECTION_RTL ? DIRECTION_RTL : DIRECTION_LTR;
666
675
  }
667
676
  /**
@@ -671,7 +680,7 @@ function getTextDirection(node) {
671
680
  * @param value Style value
672
681
  */
673
682
  function setStyle(element, property, value) {
674
- setElementValues(element, property, value, null, updateStyleProperty);
683
+ setElementValues(element, property, value, null, updateStyleProperty, true);
675
684
  }
676
685
  /**
677
686
  * Set styles on an element
@@ -679,7 +688,7 @@ function setStyle(element, property, value) {
679
688
  * @param styles Styles to set
680
689
  */
681
690
  function setStyles(element, styles) {
682
- setElementValues(element, styles, null, null, updateStyleProperty);
691
+ setElementValues(element, styles, null, null, updateStyleProperty, true);
683
692
  }
684
693
  /**
685
694
  * Toggle styles for an element
@@ -716,14 +725,19 @@ function toggleStyles(element, styles) {
716
725
  }
717
726
  function updateStyleProperty(element, key, value) {
718
727
  updateElementValue(element, key, value, function(property, style) {
719
- this.style[property] = String(style);
728
+ if (property.startsWith(VARIABLE_PREFIX)) this.style.setProperty(property, String(style));
729
+ else this.style[property] = String(style);
720
730
  }, function(property) {
721
- this.style[property] = "";
731
+ if (property.startsWith(VARIABLE_PREFIX)) this.style.removeProperty(property);
732
+ else this.style[property] = "";
733
+ if (this.getAttribute(ATTRIBUTE_STYLE) === "") this.removeAttribute(ATTRIBUTE_STYLE);
722
734
  }, false, false);
723
735
  }
736
+ const ATTRIBUTE_STYLE = "style";
724
737
  const DIRECTION_LTR = "ltr";
725
738
  const DIRECTION_RTL = "rtl";
726
- const PROPETY_DIRECTION = "direction";
739
+ const PROPERTY_DIRECTION = "direction";
740
+ const VARIABLE_PREFIX = "--";
727
741
  //#endregion
728
742
  //#region src/property/get.property.ts
729
743
  /**
@@ -771,16 +785,14 @@ function setProperties(target, properties, dispatch) {
771
785
  const shouldDispatch = dispatch !== false;
772
786
  const keys = Object.keys(properties);
773
787
  const { length } = keys;
774
- for (let index = 0; index < length; index += 1) {
775
- const key = keys[index];
776
- if (booleanAttributesSet.has(key.toLowerCase()) || dispatchedAttributes.has(key)) setAttribute(target, key, properties[key], shouldDispatch);
777
- else updateProperty(target, key, properties[key], shouldDispatch);
778
- }
788
+ for (let index = 0; index < length; index += 1) setPropertyValue(target, keys[index], properties[keys[index]], shouldDispatch);
779
789
  }
780
790
  function setProperty(target, property, value, dispatch) {
781
- if (!isHTMLOrSVGElement(target) || typeof property !== "string") return;
782
- if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) setAttribute(target, property, value, dispatch !== false);
783
- else updateProperty(target, property, value, dispatch !== false);
791
+ if (isHTMLOrSVGElement(target) && typeof property === "string") setPropertyValue(target, property, value, dispatch !== false);
792
+ }
793
+ function setPropertyValue(element, property, value, dispatch) {
794
+ if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) setAttribute(element, property, value, dispatch);
795
+ else updateProperty(element, property, value, dispatch);
784
796
  }
785
797
  //#endregion
786
798
  //#region src/create.ts
@@ -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, 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;
2
+ declare function setElementValue(element: Element, first: unknown, second: unknown, third: unknown, callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void, style?: boolean): void;
3
+ declare function setElementValues(element: Element, first: unknown, second: unknown, third: unknown, callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void, style?: boolean): 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 };
@@ -4,16 +4,19 @@ import { isAttribute } from "./attribute.mjs";
4
4
  import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
5
5
  import { kebabCase } from "@oscarpalmer/atoms/string/case";
6
6
  //#region src/internal/element-value.ts
7
- function setElementValue(element, first, second, third, callback) {
7
+ function normalizeKey(key, style) {
8
+ return style && key.startsWith(CSS_VARIABLE_PREFIX) ? key : kebabCase(key);
9
+ }
10
+ function setElementValue(element, first, second, third, callback, style) {
8
11
  if (!isHTMLOrSVGElement(element)) return;
9
- if (typeof first === "string") setElementValues(element, first, second, third, callback);
10
- else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback);
12
+ if (typeof first === "string") setElementValues(element, first, second, third, callback, style);
13
+ else if (isAttribute(first)) setElementValues(element, first.name, first.value, third, callback, style);
11
14
  }
12
- function setElementValues(element, first, second, third, callback) {
15
+ function setElementValues(element, first, second, third, callback, style) {
13
16
  if (!isHTMLOrSVGElement(element)) return;
14
17
  const dispatch = third !== false;
15
18
  if (typeof first === "string") {
16
- callback(element, kebabCase(first), second, dispatch);
19
+ callback(element, normalizeKey(first, style), second, dispatch);
17
20
  return;
18
21
  }
19
22
  const isArray = Array.isArray(first);
@@ -25,12 +28,13 @@ function setElementValues(element, first, second, third, callback) {
25
28
  const { length } = entries;
26
29
  for (let index = 0; index < length; index += 1) {
27
30
  const entry = entries[index];
28
- if (typeof entry === "object" && typeof entry?.name === "string") callback(element, kebabCase(entry.name), entry.value, dispatch);
31
+ if (typeof entry === "object" && typeof entry?.name === "string") callback(element, normalizeKey(entry.name, style), entry.value, dispatch);
29
32
  }
30
33
  }
31
34
  function updateElementValue(element, key, value, set, remove, isBoolean, json) {
32
35
  if (isBoolean ? value == null : isNullableOrWhitespace(value)) remove.call(element, key);
33
36
  else set.call(element, key, json ? JSON.stringify(value) : String(value));
34
37
  }
38
+ const CSS_VARIABLE_PREFIX = "--";
35
39
  //#endregion
36
40
  export { setElementValue, setElementValues, updateElementValue };
@@ -11,9 +11,11 @@ function getAttributeValue(element, name, parseValue) {
11
11
  return EXPRESSION_DATA_PREFIX.test(normalized) && typeof value === "string" && parseValue ? parse(value) ?? value : value;
12
12
  }
13
13
  function getStyleValue(element, property, computed) {
14
+ if (property.startsWith(CSS_VARIABLE_PREFIX)) return element.style.getPropertyValue(property);
14
15
  const name = camelCase(property);
15
16
  return computed ? getComputedStyle(element)[name] : element.style[name];
16
17
  }
17
18
  const EXPRESSION_DATA_PREFIX = /^data-/i;
19
+ const CSS_VARIABLE_PREFIX = "--";
18
20
  //#endregion
19
21
  export { EXPRESSION_DATA_PREFIX, getAttributeValue, getBoolean, getStyleValue };
@@ -6,7 +6,10 @@ function updateProperty(element, name, value, dispatch) {
6
6
  if (!(property in element) || Object.is(element[property], value)) return;
7
7
  element[property] = value;
8
8
  const event = dispatch && elementEvents[element.tagName]?.[property];
9
- if (typeof event === "string") element.dispatchEvent(new Event(event, { bubbles: true }));
9
+ if (typeof event === "string") element.dispatchEvent(new Event(event, {
10
+ bubbles: true,
11
+ cancelable: true
12
+ }));
10
13
  }
11
14
  const elementEvents = {
12
15
  DETAILS: { open: "toggle" },
@@ -19,16 +19,14 @@ function setProperties(target, properties, dispatch) {
19
19
  const shouldDispatch = dispatch !== false;
20
20
  const keys = Object.keys(properties);
21
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
- }
22
+ for (let index = 0; index < length; index += 1) setPropertyValue(target, keys[index], properties[keys[index]], shouldDispatch);
27
23
  }
28
24
  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);
25
+ if (isHTMLOrSVGElement(target) && typeof property === "string") setPropertyValue(target, property, value, dispatch !== false);
26
+ }
27
+ function setPropertyValue(element, property, value, dispatch) {
28
+ if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) setAttribute(element, property, value, dispatch);
29
+ else updateProperty(element, property, value, dispatch);
32
30
  }
33
31
  //#endregion
34
32
  export { setProperties, setProperty };
package/dist/style.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { TextDirection } from "./models.mjs";
2
2
 
3
3
  //#region src/style.d.ts
4
+ type CSSStyleValues = Variables & CSSStyleDeclaration;
4
5
  type StyleToggler = {
5
6
  /**
6
7
  * Set the provided styles on the element
@@ -11,7 +12,8 @@ type StyleToggler = {
11
12
  */
12
13
  remove(): void;
13
14
  };
14
- type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
15
+ type Styles = Partial<Record<keyof CSSStyleValues, unknown>>;
16
+ type Variables<Value extends Record<string, string | undefined> = Record<string, string | undefined>> = { [property in keyof Value as `--${string & property}`]?: string | undefined };
15
17
  /**
16
18
  * Get a style from an element
17
19
  * @param element Element to get the style from
@@ -19,7 +21,7 @@ type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
19
21
  * @param computed Get the computed style? _(defaults to `false`)_
20
22
  * @returns Style value
21
23
  */
22
- declare function getStyle(element: Element, property: keyof CSSStyleDeclaration, computed?: boolean): string | undefined;
24
+ declare function getStyle(element: Element, property: keyof CSSStyleValues, computed?: boolean): string | undefined;
23
25
  /**
24
26
  * Get styles from an element
25
27
  * @param element Element to get the styles from
@@ -27,7 +29,7 @@ declare function getStyle(element: Element, property: keyof CSSStyleDeclaration,
27
29
  * @param computed Get the computed styles? _(defaults to `false`)_
28
30
  * @returns Style values
29
31
  */
30
- declare function getStyles<Property extends keyof CSSStyleDeclaration>(element: Element, properties: Property[], computed?: boolean): Record<Property, string | undefined>;
32
+ declare function getStyles<Property extends keyof CSSStyleValues>(element: Element, properties: Property[], computed?: boolean): Record<Property, string | undefined>;
31
33
  /**
32
34
  * Get the text direction of a node or element _(or document, if element is invalid)_
33
35
  * @param node Node or element to get the text direction from
@@ -45,7 +47,7 @@ declare function getTextDirection(): TextDirection;
45
47
  * @param property Style name
46
48
  * @param value Style value
47
49
  */
48
- declare function setStyle(element: Element, property: keyof CSSStyleDeclaration, value?: unknown): void;
50
+ declare function setStyle(element: Element, property: keyof CSSStyleValues, value?: unknown): void;
49
51
  /**
50
52
  * Set styles on an element
51
53
  * @param element Element to set the styles on
package/dist/style.mjs CHANGED
@@ -34,7 +34,7 @@ function getTextDirection(node) {
34
34
  if (isHTMLOrSVGElement(node)) target = node;
35
35
  else target = node instanceof Node ? node.ownerDocument?.documentElement ?? document.documentElement : document.documentElement;
36
36
  let { direction } = target.style;
37
- if (direction === "") direction = getStyleValue(target, PROPETY_DIRECTION, true);
37
+ if (direction === "") direction = getStyleValue(target, PROPERTY_DIRECTION, true);
38
38
  return direction === DIRECTION_RTL ? DIRECTION_RTL : DIRECTION_LTR;
39
39
  }
40
40
  /**
@@ -44,7 +44,7 @@ function getTextDirection(node) {
44
44
  * @param value Style value
45
45
  */
46
46
  function setStyle(element, property, value) {
47
- setElementValues(element, property, value, null, updateStyleProperty);
47
+ setElementValues(element, property, value, null, updateStyleProperty, true);
48
48
  }
49
49
  /**
50
50
  * Set styles on an element
@@ -52,7 +52,7 @@ function setStyle(element, property, value) {
52
52
  * @param styles Styles to set
53
53
  */
54
54
  function setStyles(element, styles) {
55
- setElementValues(element, styles, null, null, updateStyleProperty);
55
+ setElementValues(element, styles, null, null, updateStyleProperty, true);
56
56
  }
57
57
  /**
58
58
  * Toggle styles for an element
@@ -89,13 +89,18 @@ function toggleStyles(element, styles) {
89
89
  }
90
90
  function updateStyleProperty(element, key, value) {
91
91
  updateElementValue(element, key, value, function(property, style) {
92
- this.style[property] = String(style);
92
+ if (property.startsWith(VARIABLE_PREFIX)) this.style.setProperty(property, String(style));
93
+ else this.style[property] = String(style);
93
94
  }, function(property) {
94
- this.style[property] = "";
95
+ if (property.startsWith(VARIABLE_PREFIX)) this.style.removeProperty(property);
96
+ else this.style[property] = "";
97
+ if (this.getAttribute(ATTRIBUTE_STYLE) === "") this.removeAttribute(ATTRIBUTE_STYLE);
95
98
  }, false, false);
96
99
  }
100
+ const ATTRIBUTE_STYLE = "style";
97
101
  const DIRECTION_LTR = "ltr";
98
102
  const DIRECTION_RTL = "rtl";
99
- const PROPETY_DIRECTION = "direction";
103
+ const PROPERTY_DIRECTION = "direction";
104
+ const VARIABLE_PREFIX = "--";
100
105
  //#endregion
101
106
  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.42.0",
3
+ "version": "0.43.0",
4
4
  "description": "A collection of badass DOM utilities.",
5
5
  "keywords": [
6
6
  "dom",
@@ -86,12 +86,13 @@
86
86
  "test:leak": "npx vp test run --detect-async-leaks --coverage"
87
87
  },
88
88
  "dependencies": {
89
- "@oscarpalmer/atoms": "^0.172"
89
+ "@oscarpalmer/atoms": "^0.185"
90
90
  },
91
91
  "devDependencies": {
92
- "@types/node": "^25.5",
92
+ "@oxlint/plugins": "^1.62",
93
+ "@types/node": "^25.6",
93
94
  "@vitest/coverage-istanbul": "^4.1",
94
- "jsdom": "^29",
95
+ "jsdom": "^29.1",
95
96
  "tsdown": "^0.21",
96
97
  "typescript": "^5.9",
97
98
  "vite": "npm:@voidzero-dev/vite-plus-core@latest",
@@ -5,21 +5,26 @@ import {isAttribute} from './attribute';
5
5
 
6
6
  // #region Functions
7
7
 
8
+ function normalizeKey(key: string, style?: boolean): string {
9
+ return style && key.startsWith(CSS_VARIABLE_PREFIX) ? key : kebabCase(key);
10
+ }
11
+
8
12
  export function setElementValue(
9
13
  element: Element,
10
14
  first: unknown,
11
15
  second: unknown,
12
16
  third: unknown,
13
17
  callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void,
18
+ style?: boolean,
14
19
  ): void {
15
20
  if (!isHTMLOrSVGElement(element)) {
16
21
  return;
17
22
  }
18
23
 
19
24
  if (typeof first === 'string') {
20
- setElementValues(element, first, second, third, callback);
25
+ setElementValues(element, first, second, third, callback, style);
21
26
  } else if (isAttribute(first)) {
22
- setElementValues(element, first.name, first.value, third, callback);
27
+ setElementValues(element, first.name, first.value, third, callback, style);
23
28
  }
24
29
  }
25
30
 
@@ -29,6 +34,7 @@ export function setElementValues(
29
34
  second: unknown,
30
35
  third: unknown,
31
36
  callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void,
37
+ style?: boolean,
32
38
  ): void {
33
39
  if (!isHTMLOrSVGElement(element)) {
34
40
  return;
@@ -37,7 +43,7 @@ export function setElementValues(
37
43
  const dispatch = third !== false;
38
44
 
39
45
  if (typeof first === 'string') {
40
- callback(element, kebabCase(first), second, dispatch);
46
+ callback(element, normalizeKey(first, style), second, dispatch);
41
47
 
42
48
  return;
43
49
  }
@@ -55,7 +61,7 @@ export function setElementValues(
55
61
  const entry = entries[index];
56
62
 
57
63
  if (typeof entry === 'object' && typeof entry?.name === 'string') {
58
- callback(element, kebabCase(entry.name), entry.value, dispatch);
64
+ callback(element, normalizeKey(entry.name, style), entry.value, dispatch);
59
65
  }
60
66
  }
61
67
  }
@@ -77,3 +83,9 @@ export function updateElementValue(
77
83
  }
78
84
 
79
85
  // #endregion Functions
86
+
87
+ // #region Variables
88
+
89
+ const CSS_VARIABLE_PREFIX = '--';
90
+
91
+ // #endregion
@@ -22,6 +22,10 @@ export function getStyleValue(
22
22
  property: string,
23
23
  computed: boolean,
24
24
  ): string | undefined {
25
+ if (property.startsWith(CSS_VARIABLE_PREFIX)) {
26
+ return (element as HTMLElement).style.getPropertyValue(property);
27
+ }
28
+
25
29
  const name = camelCase(property);
26
30
 
27
31
  return computed
@@ -35,4 +39,6 @@ export function getStyleValue(
35
39
 
36
40
  export const EXPRESSION_DATA_PREFIX = /^data-/i;
37
41
 
42
+ const CSS_VARIABLE_PREFIX = '--';
43
+
38
44
  // #endregion
@@ -24,7 +24,7 @@ export function updateProperty(
24
24
  const event = dispatch && elementEvents[element.tagName]?.[property];
25
25
 
26
26
  if (typeof event === 'string') {
27
- element.dispatchEvent(new Event(event, {bubbles: true}));
27
+ element.dispatchEvent(new Event(event, {bubbles: true, cancelable: true}));
28
28
  }
29
29
  }
30
30
 
@@ -46,13 +46,7 @@ export function setProperties<Target extends Element>(
46
46
  const {length} = keys;
47
47
 
48
48
  for (let index = 0; index < length; index += 1) {
49
- const key = keys[index];
50
-
51
- if (booleanAttributesSet.has(key.toLowerCase()) || dispatchedAttributes.has(key)) {
52
- setAttribute(target, key as never, (properties as PlainObject)[key], shouldDispatch);
53
- } else {
54
- updateProperty(target, key, (properties as PlainObject)[key], shouldDispatch);
55
- }
49
+ setPropertyValue(target, keys[index], (properties as PlainObject)[keys[index]], shouldDispatch);
56
50
  }
57
51
  }
58
52
 
@@ -88,14 +82,21 @@ export function setProperty<Target extends Element, Property extends keyof SetPr
88
82
  value: SetProperties<Target>[Property],
89
83
  dispatch?: boolean,
90
84
  ): void {
91
- if (!isHTMLOrSVGElement(target) || typeof property !== 'string') {
92
- return;
85
+ if (isHTMLOrSVGElement(target) && typeof property === 'string') {
86
+ setPropertyValue(target, property, value, dispatch !== false);
93
87
  }
88
+ }
94
89
 
90
+ function setPropertyValue(
91
+ element: Element,
92
+ property: string,
93
+ value: unknown,
94
+ dispatch: boolean,
95
+ ): void {
95
96
  if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) {
96
- setAttribute(target, property as never, value, dispatch !== false);
97
+ setAttribute(element, property as never, value, dispatch);
97
98
  } else {
98
- updateProperty(target, property, value, dispatch !== false);
99
+ updateProperty(element, property, value, dispatch);
99
100
  }
100
101
  }
101
102
 
package/src/style.ts CHANGED
@@ -5,6 +5,8 @@ import type {TextDirection} from './models';
5
5
 
6
6
  // #region Types
7
7
 
8
+ type CSSStyleValues = Variables & CSSStyleDeclaration;
9
+
8
10
  export type StyleToggler = {
9
11
  /**
10
12
  * Set the provided styles on the element
@@ -16,7 +18,13 @@ export type StyleToggler = {
16
18
  remove(): void;
17
19
  };
18
20
 
19
- type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
21
+ type Styles = Partial<Record<keyof CSSStyleValues, unknown>>;
22
+
23
+ type Variables<
24
+ Value extends Record<string, string | undefined> = Record<string, string | undefined>,
25
+ > = {
26
+ [property in keyof Value as `--${string & property}`]?: string | undefined;
27
+ };
20
28
 
21
29
  // #endregion
22
30
 
@@ -31,7 +39,7 @@ type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
31
39
  */
32
40
  export function getStyle(
33
41
  element: Element,
34
- property: keyof CSSStyleDeclaration,
42
+ property: keyof CSSStyleValues,
35
43
  computed?: boolean,
36
44
  ): string | undefined {
37
45
  if (isHTMLOrSVGElement(element) && typeof property === 'string') {
@@ -46,7 +54,7 @@ export function getStyle(
46
54
  * @param computed Get the computed styles? _(defaults to `false`)_
47
55
  * @returns Style values
48
56
  */
49
- export function getStyles<Property extends keyof CSSStyleDeclaration>(
57
+ export function getStyles<Property extends keyof CSSStyleValues>(
50
58
  element: Element,
51
59
  properties: Property[],
52
60
  computed?: boolean,
@@ -98,7 +106,7 @@ export function getTextDirection(node?: Element | Node): TextDirection {
98
106
  let {direction} = target.style;
99
107
 
100
108
  if (direction === '') {
101
- direction = getStyleValue(target, PROPETY_DIRECTION, true)!;
109
+ direction = getStyleValue(target, PROPERTY_DIRECTION, true)!;
102
110
  }
103
111
 
104
112
  return direction === DIRECTION_RTL ? DIRECTION_RTL : DIRECTION_LTR;
@@ -110,12 +118,8 @@ export function getTextDirection(node?: Element | Node): TextDirection {
110
118
  * @param property Style name
111
119
  * @param value Style value
112
120
  */
113
- export function setStyle(
114
- element: Element,
115
- property: keyof CSSStyleDeclaration,
116
- value?: unknown,
117
- ): void {
118
- setElementValues(element, property as string, value, null, updateStyleProperty);
121
+ export function setStyle(element: Element, property: keyof CSSStyleValues, value?: unknown): void {
122
+ setElementValues(element, property as string, value, null, updateStyleProperty, true);
119
123
  }
120
124
 
121
125
  /**
@@ -124,7 +128,7 @@ export function setStyle(
124
128
  * @param styles Styles to set
125
129
  */
126
130
  export function setStyles(element: Element, styles: Styles): void {
127
- setElementValues(element, styles as never, null, null, updateStyleProperty);
131
+ setElementValues(element, styles as never, null, null, updateStyleProperty, true);
128
132
  }
129
133
 
130
134
  /**
@@ -182,10 +186,22 @@ function updateStyleProperty(element: Element, key: string, value: unknown): voi
182
186
  key,
183
187
  value,
184
188
  function (this: Element, property: string, style: unknown) {
185
- (this as HTMLElement).style[property as never] = String(style);
189
+ if (property.startsWith(VARIABLE_PREFIX)) {
190
+ (this as HTMLElement).style.setProperty(property, String(style));
191
+ } else {
192
+ (this as HTMLElement).style[property as never] = String(style);
193
+ }
186
194
  },
187
195
  function (this: Element, property: string) {
188
- (this as HTMLElement).style[property as never] = '';
196
+ if (property.startsWith(VARIABLE_PREFIX)) {
197
+ (this as HTMLElement).style.removeProperty(property);
198
+ } else {
199
+ (this as HTMLElement).style[property as never] = '';
200
+ }
201
+
202
+ if ((this as HTMLElement).getAttribute(ATTRIBUTE_STYLE) === '') {
203
+ (this as HTMLElement).removeAttribute(ATTRIBUTE_STYLE);
204
+ }
189
205
  },
190
206
  false,
191
207
  false,
@@ -196,10 +212,14 @@ function updateStyleProperty(element: Element, key: string, value: unknown): voi
196
212
 
197
213
  // #region Variables
198
214
 
215
+ const ATTRIBUTE_STYLE = 'style';
216
+
199
217
  const DIRECTION_LTR = 'ltr';
200
218
 
201
219
  const DIRECTION_RTL = 'rtl';
202
220
 
203
- const PROPETY_DIRECTION = 'direction';
221
+ const PROPERTY_DIRECTION = 'direction';
222
+
223
+ const VARIABLE_PREFIX = '--';
204
224
 
205
225
  // #endregion