@oscarpalmer/toretto 0.48.0 → 0.49.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/src/create.ts CHANGED
@@ -1,15 +1,29 @@
1
+ import {isPlainObject} from '@oscarpalmer/atoms/is';
1
2
  import type {Primitive} from '@oscarpalmer/atoms/models';
3
+ import {setAria} from './aria';
2
4
  import {setAttributes} from './attribute';
5
+ import {setData} from './data';
6
+ import type {AnyAriaAttribute, AnyAriaBooleanAttribute, CSSValues} from './models';
3
7
  import {setProperties} from './property';
4
8
  import {setStyles} from './style';
5
9
 
6
10
  // #region Types
7
11
 
8
- type Properties<Target extends Element> = {
9
- [Property in keyof Target]?: Target[Property] extends Primitive ? Target[Property] : never;
12
+ type CreateElementValues<Target extends Element> = {
13
+ aria?: CreateElementValuesAria;
14
+ attribute?: Record<string, unknown>;
15
+ data?: Record<string, unknown>;
16
+ property?: CreateElementValuesProperties<Target>;
17
+ style?: Partial<CSSValues>;
10
18
  };
11
19
 
12
- type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
20
+ type CreateElementValuesAria = {
21
+ [Key in AnyAriaAttribute]?: Key extends AnyAriaBooleanAttribute ? boolean | string : string;
22
+ };
23
+
24
+ type CreateElementValuesProperties<Target extends Element> = {
25
+ [Property in keyof Target]?: Target[Property] extends Primitive ? Target[Property] : never;
26
+ };
13
27
 
14
28
  // #endregion
15
29
 
@@ -19,59 +33,60 @@ type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
19
33
  * Creates an _HTML_ element with the specified tag name together with optional properties, attributes, and styles
20
34
  *
21
35
  * @param tag Tag name
22
- * @param properties Element properties
23
- * @param attributes Element attributes
24
- * @param styles Element styles
36
+ * @param values Element values
25
37
  * @returns Created element
26
38
  */
27
39
  export function createElement<TagName extends keyof HTMLElementTagNameMap>(
28
40
  tag: TagName,
29
- properties?: Properties<HTMLElementTagNameMap[TagName]>,
30
- attributes?: Record<string, unknown>,
31
- styles?: Styles,
41
+ values?: CreateElementValues<HTMLElementTagNameMap[TagName]>,
32
42
  ): HTMLElementTagNameMap[TagName];
33
43
 
34
44
  /**
35
45
  * Creates an _HTML_ element with the specified tag name together with optional properties, attributes, and styles
36
46
  *
37
47
  * @param tag Tag name
38
- * @param properties Element properties
39
- * @param attributes Element attributes
40
- * @param styles Element styles
48
+ * @param values Element values
41
49
  * @returns Created element
42
50
  */
43
51
  export function createElement(
44
52
  tag: string,
45
- properties?: Properties<HTMLElement>,
46
- attributes?: Record<string, unknown>,
47
- styles?: Styles,
53
+ values?: CreateElementValues<HTMLElement>,
48
54
  ): HTMLUnknownElement;
49
55
 
50
- export function createElement(
51
- tag: string,
52
- properties?: Properties<HTMLElement>,
53
- attributes?: Record<string, unknown>,
54
- styles?: Styles,
55
- ): HTMLElement {
56
+ export function createElement(tag: string, values?: CreateElementValues<HTMLElement>): HTMLElement {
56
57
  if (typeof tag !== 'string') {
57
58
  throw new TypeError(MESSAGE);
58
59
  }
59
60
 
60
61
  const element = document.createElement(tag);
61
62
 
62
- if (properties != null) {
63
- setProperties(element, properties);
64
- }
63
+ const {aria, attribute, data, property, style} = getElementValues<HTMLElement>(values);
65
64
 
66
- if (attributes != null) {
67
- setAttributes(element, attributes);
68
- }
65
+ setAria(element, aria ?? {});
66
+ setAttributes(element, attribute ?? {});
67
+ setData(element, data ?? {});
68
+ setProperties(element, property ?? {});
69
+ setStyles(element, style ?? {});
70
+
71
+ return element;
72
+ }
69
73
 
70
- if (styles != null) {
71
- setStyles(element, styles);
74
+ function getElementValues<Target extends Element>(input?: unknown): CreateElementValues<Target> {
75
+ if (!isPlainObject(input)) {
76
+ return {};
72
77
  }
73
78
 
74
- return element;
79
+ return {
80
+ aria: isPlainObject(input.aria) ? input.aria : undefined,
81
+ attribute: isPlainObject(input.attribute)
82
+ ? (input.attribute as Record<string, unknown>)
83
+ : undefined,
84
+ data: isPlainObject(input.data) ? input.data : undefined,
85
+ property: isPlainObject(input.property)
86
+ ? (input.property as CreateElementValuesProperties<Target>)
87
+ : undefined,
88
+ style: isPlainObject(input.style) ? input.style : undefined,
89
+ };
75
90
  }
76
91
 
77
92
  // #endregion
package/src/data.ts CHANGED
@@ -7,28 +7,46 @@ import {EXPRESSION_DATA_PREFIX} from './internal/get-value';
7
7
  // #region Functions
8
8
 
9
9
  /**
10
- * Get a keyed data value from an element
10
+ * Get a keyed data value from an element, without parsing the value
11
11
  *
12
12
  * @param element Element to get data from
13
13
  * @param key Data key
14
- * @param parse Parse values? _(defaults to `true`)_
14
+ * @param parse Parse the value?
15
15
  * @returns Data value
16
16
  */
17
- export function getData(element: Element, key: string, parse?: boolean): unknown;
17
+ export function getData(element: Element, key: string, parse: false): string | undefined;
18
18
 
19
19
  /**
20
- * Get keyed data values from an element
20
+ * Get a keyed data value from an element and parse the value
21
+ *
22
+ * @param element Element to get data from
23
+ * @param key Data key
24
+ * @returns Data value
25
+ */
26
+ export function getData(element: Element, key: string): unknown;
27
+
28
+ /**
29
+ * Get keyed data values from an element, without parsing the values
21
30
  *
22
31
  * @param element Element to get data from
23
32
  * @param keys Keys of the data values to get
24
- * @param parse Parse values? _(defaults to `true`)_
33
+ * @param parse Parse the values?
25
34
  * @returns Keyed data values
26
35
  */
27
36
  export function getData<Key extends string>(
28
37
  element: Element,
29
38
  keys: Key[],
30
- parse?: boolean,
31
- ): Record<Key, unknown>;
39
+ parse: false,
40
+ ): Record<Key, string | undefined>;
41
+
42
+ /**
43
+ * Get keyed data values from an element and parse the values
44
+ *
45
+ * @param element Element to get data from
46
+ * @param keys Keys of the data values to get
47
+ * @returns Keyed data values
48
+ */
49
+ export function getData<Key extends string>(element: Element, keys: Key[]): Record<Key, unknown>;
32
50
 
33
51
  export function getData(element: Element, keys: string | string[], parseValues?: boolean): unknown {
34
52
  if (!(element instanceof Element)) {
package/src/models.ts CHANGED
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Any _ARIA_ attribute for an element _(both prefixed and unprefixed)_
3
+ */
4
+ export type AnyAriaAttribute = AriaAttribute | AriaAttributeUnprefixed;
5
+
6
+ /**
7
+ * Any _ARIA_ attribute for an element that can be set to a boolean value _(both prefixed and unprefixed)_
8
+ */
9
+ export type AnyAriaBooleanAttribute = AriaBooleanAttribute | AriaBooleanAttributeUnprefixed;
10
+
1
11
  /**
2
12
  * _ARIA_ attribute for an element
3
13
  *
@@ -11,11 +21,39 @@ export type AriaAttribute = keyof AriaAttributes;
11
21
  * _(https://www.w3.org/TR/wai-aria-1.3/#aria-attributes)_
12
22
  */
13
23
  export type AriaAttributeUnprefixed = keyof {
14
- [Key in AriaAttribute as Key extends `aria-${infer Name}` ? Name : never]: string | null;
24
+ [Key in AriaAttribute as Key extends `aria-${infer Name}` ? Name : never]: unknown;
15
25
  };
16
26
 
17
27
  type AriaAttributes = {
18
- [Key in keyof ARIAMixin as NormalizedName<Key>]: string | null;
28
+ [Key in keyof ARIAMixin as NormalizedName<Key>]: unknown;
29
+ };
30
+
31
+ /**
32
+ * _ARIA_ attribute for an element that can be set to a boolean value
33
+ */
34
+ export type AriaBooleanAttribute =
35
+ | 'aria-atomic'
36
+ | 'aria-busy'
37
+ | 'aria-checked'
38
+ | 'aria-current'
39
+ | 'aria-disabled'
40
+ | 'aria-expanded'
41
+ | 'aria-haspopup'
42
+ | 'aria-hidden'
43
+ | 'aria-invalid'
44
+ | 'aria-modal'
45
+ | 'aria-multiline'
46
+ | 'aria-multiselectable'
47
+ | 'aria-pressed'
48
+ | 'aria-readonly'
49
+ | 'aria-required'
50
+ | 'aria-selected';
51
+
52
+ /**
53
+ * _ARIA_ attribute for an element that can be set to a boolean value, without the `aria-` prefix
54
+ */
55
+ export type AriaBooleanAttributeUnprefixed = keyof {
56
+ [Key in AriaBooleanAttribute as Key extends `aria-${infer Name}` ? Name : never]: string | null;
19
57
  };
20
58
 
21
59
  type NormalizedName<Key extends string> = Key extends `aria${infer Name}`
@@ -128,6 +166,23 @@ export type Attribute = {
128
166
  value: unknown;
129
167
  };
130
168
 
169
+ /**
170
+ * CSS styles for an element
171
+ */
172
+ export type CSSStyles = Record<keyof CSSStyleDeclaration, unknown>;
173
+
174
+ /**
175
+ * CSSS values for an element _(both styles and variables)_
176
+ */
177
+ export type CSSValues = CSSVariables & CSSStyles;
178
+
179
+ /**
180
+ * CSS variables for an element
181
+ */
182
+ export type CSSVariables<Value extends Record<string, unknown> = Record<string, unknown>> = {
183
+ [Property in keyof Value as `--${string & Property}`]?: unknown;
184
+ };
185
+
131
186
  /**
132
187
  * Event listener for custom events
133
188
  */
package/src/style.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  import {getString} from '@oscarpalmer/atoms/string';
2
2
  import {setElementValues, updateElementValue} from './internal/element-value';
3
3
  import {getStyleValue} from './internal/get-value';
4
- import type {TextDirection} from './models';
4
+ import type {CSSValues, TextDirection} from './models';
5
5
 
6
6
  // #region Types
7
7
 
8
- type CSSStyleValues = Variables & CSSStyleDeclaration;
9
-
10
8
  export type StyleToggler = {
11
9
  /**
12
10
  * Set the provided styles on the element
@@ -18,14 +16,6 @@ export type StyleToggler = {
18
16
  remove(): void;
19
17
  };
20
18
 
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
- };
28
-
29
19
  // #endregion
30
20
 
31
21
  // #region Functions
@@ -34,17 +24,17 @@ type Variables<
34
24
  * Get a style from an element
35
25
  *
36
26
  * @param element Element to get the style from
37
- * @param property Style name
27
+ * @param name Style name
38
28
  * @param computed Get the computed style? _(defaults to `false`)_
39
29
  * @returns Style value
40
30
  */
41
31
  export function getStyle(
42
32
  element: Element,
43
- property: keyof CSSStyleValues,
33
+ name: keyof CSSValues,
44
34
  computed?: boolean,
45
35
  ): string | undefined {
46
- if (element instanceof Element && typeof property === 'string') {
47
- return getStyleValue(element, property, computed === true);
36
+ if (element instanceof Element && typeof name === 'string') {
37
+ return getStyleValue(element, name, computed === true);
48
38
  }
49
39
  }
50
40
 
@@ -52,28 +42,28 @@ export function getStyle(
52
42
  * Get styles from an element
53
43
  *
54
44
  * @param element Element to get the styles from
55
- * @param properties Styles to get
45
+ * @param names Styles to get
56
46
  * @param computed Get the computed styles? _(defaults to `false`)_
57
47
  * @returns Style values
58
48
  */
59
- export function getStyles<Property extends keyof CSSStyleValues>(
49
+ export function getStyles<Name extends keyof CSSValues>(
60
50
  element: Element,
61
- properties: Property[],
51
+ names: Name[],
62
52
  computed?: boolean,
63
- ): Record<Property, string | undefined> {
64
- const styles = {} as Record<Property, string | undefined>;
53
+ ): Record<Name, string | undefined> {
54
+ const styles = {} as Record<Name, string | undefined>;
65
55
 
66
- if (!(element instanceof Element && Array.isArray(properties))) {
56
+ if (!(element instanceof Element && Array.isArray(names))) {
67
57
  return styles;
68
58
  }
69
59
 
70
- const {length} = properties;
60
+ const {length} = names;
71
61
 
72
62
  for (let index = 0; index < length; index += 1) {
73
- const property = properties[index];
63
+ const name = names[index];
74
64
 
75
- if (typeof property === 'string') {
76
- styles[property] = getStyleValue(element, property, computed === true) as never;
65
+ if (typeof name === 'string') {
66
+ styles[name] = getStyleValue(element, name, computed === true) as never;
77
67
  }
78
68
  }
79
69
 
@@ -120,11 +110,11 @@ export function getTextDirection(node?: Element | Node): TextDirection {
120
110
  * Set a style on an element
121
111
  *
122
112
  * @param element Element to set the style on
123
- * @param property Style name
113
+ * @param name Style name
124
114
  * @param value Style value
125
115
  */
126
- export function setStyle(element: Element, property: keyof CSSStyleValues, value?: unknown): void {
127
- setElementValues(element, property as string, value, null, updateStyleProperty, true);
116
+ export function setStyle(element: Element, name: keyof CSSValues, value?: unknown): void {
117
+ setElementValues(element, name as string, value, null, updateStyleProperty, true);
128
118
  }
129
119
 
130
120
  /**
@@ -133,7 +123,7 @@ export function setStyle(element: Element, property: keyof CSSStyleValues, value
133
123
  * @param element Element to set the styles on
134
124
  * @param styles Styles to set
135
125
  */
136
- export function setStyles(element: Element, styles: Styles): void {
126
+ export function setStyles(element: Element, styles: Partial<CSSValues>): void {
137
127
  setElementValues(element, styles as never, null, null, updateStyleProperty, true);
138
128
  }
139
129
 
@@ -144,11 +134,11 @@ export function setStyles(element: Element, styles: Styles): void {
144
134
  * @param styles Styles to be set or removed
145
135
  * @returns Style toggler
146
136
  */
147
- export function toggleStyles(element: Element, styles: Styles): StyleToggler {
137
+ export function toggleStyles(element: Element, styles: Partial<CSSValues>): StyleToggler {
148
138
  function toggle(set: boolean): void {
149
139
  hasSet = set;
150
140
 
151
- let next: Styles;
141
+ let next: Partial<CSSValues>;
152
142
 
153
143
  if (set) {
154
144
  values = getStyles(element, keys);
@@ -171,7 +161,7 @@ export function toggleStyles(element: Element, styles: Styles): StyleToggler {
171
161
  const {length} = keys;
172
162
 
173
163
  let hasSet = false;
174
- let values: Record<string, string | undefined> = {};
164
+ let values: Record<string, unknown> = {};
175
165
 
176
166
  return {
177
167
  set(): void {
@@ -192,18 +182,18 @@ function updateStyleProperty(element: Element, key: string, value: unknown): voi
192
182
  element,
193
183
  key,
194
184
  value,
195
- function (this: Element, property: string, style: unknown) {
196
- if (property.startsWith(VARIABLE_PREFIX)) {
197
- (this as HTMLElement).style.setProperty(property, getString(style));
185
+ function (this: Element, name: string, style: unknown) {
186
+ if (name.startsWith(VARIABLE_PREFIX)) {
187
+ (this as HTMLElement).style.setProperty(name, getString(style));
198
188
  } else {
199
- (this as HTMLElement).style[property as never] = getString(style);
189
+ (this as HTMLElement).style[name as never] = getString(style);
200
190
  }
201
191
  },
202
- function (this: Element, property: string) {
203
- if (property.startsWith(VARIABLE_PREFIX)) {
204
- (this as HTMLElement).style.removeProperty(property);
192
+ function (this: Element, name: string) {
193
+ if (name.startsWith(VARIABLE_PREFIX)) {
194
+ (this as HTMLElement).style.removeProperty(name);
205
195
  } else {
206
- (this as HTMLElement).style[property as never] = '';
196
+ (this as HTMLElement).style[name as never] = '';
207
197
  }
208
198
 
209
199
  if ((this as HTMLElement).getAttribute(ATTRIBUTE_STYLE) === '') {