@oscarpalmer/toretto 0.47.3 → 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/dist/aria.d.mts +36 -12
- package/dist/aria.mjs +35 -3
- package/dist/attribute/index.d.mts +0 -1
- package/dist/attribute/set.attribute.d.mts +0 -1
- package/dist/create.d.mts +14 -11
- package/dist/create.mjs +20 -4
- package/dist/data.d.mts +22 -7
- package/dist/event/delegation.d.mts +0 -1
- package/dist/event/index.d.mts +6 -3
- package/dist/event/index.mjs +4 -1
- package/dist/find/index.d.mts +0 -1
- package/dist/index.d.mts +114 -41
- package/dist/index.mjs +104 -56
- package/dist/internal/attribute.d.mts +0 -1
- package/dist/internal/is.d.mts +0 -1
- package/dist/is.d.mts +0 -1
- package/dist/models.d.mts +31 -3
- package/dist/property/get.property.d.mts +1 -2
- package/dist/property/set.property.d.mts +1 -2
- package/dist/style.d.mts +9 -13
- package/dist/style.mjs +18 -18
- package/package.json +3 -3
- package/src/aria.ts +102 -22
- package/src/create.ts +45 -30
- package/src/data.ts +25 -7
- package/src/event/index.ts +18 -8
- package/src/models.ts +57 -2
- package/src/style.ts +30 -40
package/src/aria.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import {setElementValues, updateElementValue} from './internal/element-value';
|
|
2
|
-
import type {
|
|
2
|
+
import type {AnyAriaAttribute, AnyAriaBooleanAttribute, AriaRole} from './models';
|
|
3
3
|
|
|
4
4
|
// #region Types
|
|
5
5
|
|
|
6
|
-
type AnyAriaAttribute =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
name: AnyAriaAttribute;
|
|
10
|
-
value?: string;
|
|
6
|
+
type AriaAttributeItem<Name extends AnyAriaAttribute = AnyAriaAttribute> = {
|
|
7
|
+
name: Name;
|
|
8
|
+
value?: Name extends AnyAriaBooleanAttribute ? boolean | string : string;
|
|
11
9
|
};
|
|
12
10
|
|
|
13
11
|
// #endregion
|
|
@@ -18,10 +16,22 @@ type AriaAttributeItem = {
|
|
|
18
16
|
* Get the value of a specific _ARIA_ attribute from an element
|
|
19
17
|
*
|
|
20
18
|
* @param element Element to get _ARIA_ attribute from
|
|
21
|
-
* @param name _ARIA_ name
|
|
19
|
+
* @param name _ARIA_ attribute name
|
|
20
|
+
* @returns _ARIA_ value _(or `undefined`)_
|
|
21
|
+
*/
|
|
22
|
+
export function getAria(
|
|
23
|
+
element: Element,
|
|
24
|
+
name: AnyAriaBooleanAttribute,
|
|
25
|
+
): boolean | string | undefined;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get the value of a specific _ARIA_ attribute from an element
|
|
29
|
+
*
|
|
30
|
+
* @param element Element to get _ARIA_ attribute from
|
|
31
|
+
* @param name _ARIA_ attribute name
|
|
22
32
|
* @returns _ARIA_ value _(or `undefined`)_
|
|
23
33
|
*/
|
|
24
|
-
export function getAria(element: Element,
|
|
34
|
+
export function getAria(element: Element, name: AnyAriaAttribute): string | undefined;
|
|
25
35
|
|
|
26
36
|
/**
|
|
27
37
|
* Get specific _ARIA_ attributes from an element
|
|
@@ -32,8 +42,12 @@ export function getAria(element: Element, attribute: AnyAriaAttribute): string |
|
|
|
32
42
|
*/
|
|
33
43
|
export function getAria<Attribute extends AnyAriaAttribute>(
|
|
34
44
|
element: Element,
|
|
35
|
-
|
|
36
|
-
):
|
|
45
|
+
names: Attribute[],
|
|
46
|
+
): {
|
|
47
|
+
[Key in Attribute as Key extends `aria-${infer Name}`
|
|
48
|
+
? Name
|
|
49
|
+
: Key]: Key extends AnyAriaBooleanAttribute ? boolean | string | undefined : string | undefined;
|
|
50
|
+
};
|
|
37
51
|
|
|
38
52
|
export function getAria(element: Element, value: string | string[]): unknown {
|
|
39
53
|
if (!(element instanceof Element)) {
|
|
@@ -44,7 +58,7 @@ export function getAria(element: Element, value: string | string[]): unknown {
|
|
|
44
58
|
return typeof value === 'string' ? getAriaValue(element, value) : undefined;
|
|
45
59
|
}
|
|
46
60
|
|
|
47
|
-
const arias = {} as Record<string,
|
|
61
|
+
const arias = {} as Record<string, unknown>;
|
|
48
62
|
|
|
49
63
|
const {length} = value;
|
|
50
64
|
|
|
@@ -59,8 +73,20 @@ export function getAria(element: Element, value: string | string[]): unknown {
|
|
|
59
73
|
return arias;
|
|
60
74
|
}
|
|
61
75
|
|
|
62
|
-
function getAriaValue(element: Element, attribute: string):
|
|
63
|
-
|
|
76
|
+
function getAriaValue(element: Element, attribute: string): unknown {
|
|
77
|
+
const name = getName(attribute);
|
|
78
|
+
|
|
79
|
+
const value = element.getAttribute(name) ?? undefined;
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
ariaBooleanAttributesSet.has(name as never) &&
|
|
83
|
+
typeof value === 'string' &&
|
|
84
|
+
EXPRESSION_BOOLEAN.test(value)
|
|
85
|
+
) {
|
|
86
|
+
return value.toLowerCase() === 'true';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return value;
|
|
64
90
|
}
|
|
65
91
|
|
|
66
92
|
function getName(value: string): string {
|
|
@@ -88,7 +114,22 @@ export function getRole(element: Element): string | undefined {
|
|
|
88
114
|
* @param attribute _ARIA_ attribute to set
|
|
89
115
|
* @param value _ARIA_ attribute value
|
|
90
116
|
*/
|
|
91
|
-
export function setAria(
|
|
117
|
+
export function setAria(
|
|
118
|
+
element: Element,
|
|
119
|
+
attribute: AnyAriaBooleanAttribute,
|
|
120
|
+
value?: boolean | string,
|
|
121
|
+
): void;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Set an _ARIA_ attribute on an element
|
|
125
|
+
*
|
|
126
|
+
* _(Or remove it, if value is `null` or `undefined`)_
|
|
127
|
+
*
|
|
128
|
+
* @param element Element for _ARIA_ attribute
|
|
129
|
+
* @param attribute _ARIA_ attribute to set
|
|
130
|
+
* @param value _ARIA_ attribute value
|
|
131
|
+
*/
|
|
132
|
+
export function setAria(element: Element, attribute: AnyAriaAttribute, value?: string): void;
|
|
92
133
|
|
|
93
134
|
/**
|
|
94
135
|
* Set one or more _ARIA_ attributes on an element
|
|
@@ -110,14 +151,12 @@ export function setAria(element: Element, attributes: AriaAttributeItem[]): void
|
|
|
110
151
|
*/
|
|
111
152
|
export function setAria(
|
|
112
153
|
element: Element,
|
|
113
|
-
attributes:
|
|
154
|
+
attributes: {
|
|
155
|
+
[Key in AnyAriaAttribute]?: Key extends AnyAriaBooleanAttribute ? boolean | string : string;
|
|
156
|
+
},
|
|
114
157
|
): void;
|
|
115
158
|
|
|
116
|
-
export function setAria(
|
|
117
|
-
element: Element,
|
|
118
|
-
first: AnyAriaAttribute | AriaAttributeItem[] | Partial<Record<AnyAriaAttribute, unknown>>,
|
|
119
|
-
second?: unknown,
|
|
120
|
-
): void {
|
|
159
|
+
export function setAria(element: Element, first: unknown, second?: unknown): void {
|
|
121
160
|
setElementValues(element, first, second, null, updateAriaAttribute);
|
|
122
161
|
}
|
|
123
162
|
|
|
@@ -140,10 +179,22 @@ export function setRole(element: Element, role?: AriaRole): void {
|
|
|
140
179
|
}
|
|
141
180
|
|
|
142
181
|
function updateAriaAttribute(element: Element, key: string, value: unknown): void {
|
|
182
|
+
const name = getName(key);
|
|
183
|
+
|
|
184
|
+
let actual = value;
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
ariaBooleanAttributesSet.has(name as never) &&
|
|
188
|
+
typeof value === 'string' &&
|
|
189
|
+
EXPRESSION_BOOLEAN.test(value)
|
|
190
|
+
) {
|
|
191
|
+
actual = value.toLowerCase() === 'true';
|
|
192
|
+
}
|
|
193
|
+
|
|
143
194
|
updateElementValue(
|
|
144
195
|
element,
|
|
145
|
-
|
|
146
|
-
|
|
196
|
+
name,
|
|
197
|
+
actual,
|
|
147
198
|
// Using `.call` in `updateElementValue`
|
|
148
199
|
// oxlint-disable-next-line typescript/unbound-method
|
|
149
200
|
element.setAttribute,
|
|
@@ -163,4 +214,33 @@ const ATTRIBUTE_ARIA_PREFIX = 'aria-';
|
|
|
163
214
|
|
|
164
215
|
const EXPRESSION_ARIA_PREFIX = /^aria-/i;
|
|
165
216
|
|
|
217
|
+
const EXPRESSION_BOOLEAN = /^(true|false)$/i;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* List of _ARIA_ attributes that can be treated as boolean values
|
|
221
|
+
*/
|
|
222
|
+
export const ariaBooleanAttributes: readonly AnyAriaBooleanAttribute[] = Object.freeze([
|
|
223
|
+
'aria-atomic',
|
|
224
|
+
'aria-busy',
|
|
225
|
+
'aria-checked',
|
|
226
|
+
'aria-current',
|
|
227
|
+
'aria-disabled',
|
|
228
|
+
'aria-expanded',
|
|
229
|
+
'aria-haspopup',
|
|
230
|
+
'aria-hidden',
|
|
231
|
+
'aria-invalid',
|
|
232
|
+
'aria-modal',
|
|
233
|
+
'aria-multiline',
|
|
234
|
+
'aria-multiselectable',
|
|
235
|
+
'aria-pressed',
|
|
236
|
+
'aria-readonly',
|
|
237
|
+
'aria-required',
|
|
238
|
+
'aria-selected',
|
|
239
|
+
]);
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Set of _ARIA_ attributes that can be treated as boolean values
|
|
243
|
+
*/
|
|
244
|
+
export const ariaBooleanAttributesSet = new Set(ariaBooleanAttributes);
|
|
245
|
+
|
|
166
246
|
// #endregion
|
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
|
|
9
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
63
|
-
setProperties(element, properties);
|
|
64
|
-
}
|
|
63
|
+
const {aria, attribute, data, property, style} = getElementValues<HTMLElement>(values);
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
71
|
-
|
|
74
|
+
function getElementValues<Target extends Element>(input?: unknown): CreateElementValues<Target> {
|
|
75
|
+
if (!isPlainObject(input)) {
|
|
76
|
+
return {};
|
|
72
77
|
}
|
|
73
78
|
|
|
74
|
-
return
|
|
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
|
|
14
|
+
* @param parse Parse the value?
|
|
15
15
|
* @returns Data value
|
|
16
16
|
*/
|
|
17
|
-
export function getData(element: Element, key: string, parse
|
|
17
|
+
export function getData(element: Element, key: string, parse: false): string | undefined;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Get keyed data
|
|
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?
|
|
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
|
|
31
|
-
): Record<Key,
|
|
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/event/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ function createDispatchOptions(options: EventInit): EventInit {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function createEvent(type: string, options?: CustomEventInit): Event {
|
|
35
|
+
function createEvent(type: string, options?: CustomEventInit): CustomEvent | Event {
|
|
36
36
|
const hasOptions = isPlainObject(options);
|
|
37
37
|
|
|
38
38
|
if (hasOptions && 'detail' in (options as CustomEventInit)) {
|
|
@@ -61,11 +61,11 @@ function createEventOptions(options?: AddEventListenerOptions): EventOptions {
|
|
|
61
61
|
* @param type Type of event
|
|
62
62
|
* @param options Options for event _(bubbles and is cancelable by default)_
|
|
63
63
|
*/
|
|
64
|
-
export function dispatch<Type extends keyof HTMLElementEventMap>(
|
|
64
|
+
export function dispatch<Type extends keyof HTMLElementEventMap, Options extends CustomEventInit>(
|
|
65
65
|
target: EventTarget,
|
|
66
66
|
type: Type,
|
|
67
|
-
options?:
|
|
68
|
-
):
|
|
67
|
+
options?: Options,
|
|
68
|
+
): Options extends {detail: infer Detail} ? CustomEvent<Detail> : Event;
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* Dispatch an event for a target
|
|
@@ -74,16 +74,26 @@ export function dispatch<Type extends keyof HTMLElementEventMap>(
|
|
|
74
74
|
* @param type Type of event
|
|
75
75
|
* @param options Options for event _(bubbles and is cancelable by default)_
|
|
76
76
|
*/
|
|
77
|
-
export function dispatch
|
|
77
|
+
export function dispatch<Options extends CustomEventInit>(
|
|
78
|
+
target: EventTarget,
|
|
79
|
+
type: string,
|
|
80
|
+
options?: Options,
|
|
81
|
+
): Options extends {detail: infer Detail} ? CustomEvent<Detail> : Event;
|
|
78
82
|
|
|
79
83
|
export function dispatch<Type extends keyof HTMLElementEventMap>(
|
|
80
84
|
target: EventTarget,
|
|
81
85
|
type: Type | string,
|
|
82
86
|
options?: CustomEventInit,
|
|
83
|
-
):
|
|
84
|
-
if (isEventTarget(target)
|
|
85
|
-
|
|
87
|
+
): CustomEvent | Event | undefined {
|
|
88
|
+
if (!isEventTarget(target) || typeof type !== 'string') {
|
|
89
|
+
return;
|
|
86
90
|
}
|
|
91
|
+
|
|
92
|
+
const event = createEvent(type, options);
|
|
93
|
+
|
|
94
|
+
target.dispatchEvent(event);
|
|
95
|
+
|
|
96
|
+
return event;
|
|
87
97
|
}
|
|
88
98
|
|
|
89
99
|
/**
|
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]:
|
|
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>]:
|
|
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
|
|
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
|
-
|
|
33
|
+
name: keyof CSSValues,
|
|
44
34
|
computed?: boolean,
|
|
45
35
|
): string | undefined {
|
|
46
|
-
if (element instanceof Element && typeof
|
|
47
|
-
return getStyleValue(element,
|
|
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
|
|
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<
|
|
49
|
+
export function getStyles<Name extends keyof CSSValues>(
|
|
60
50
|
element: Element,
|
|
61
|
-
|
|
51
|
+
names: Name[],
|
|
62
52
|
computed?: boolean,
|
|
63
|
-
): Record<
|
|
64
|
-
const styles = {} as Record<
|
|
53
|
+
): Record<Name, string | undefined> {
|
|
54
|
+
const styles = {} as Record<Name, string | undefined>;
|
|
65
55
|
|
|
66
|
-
if (!(element instanceof Element && Array.isArray(
|
|
56
|
+
if (!(element instanceof Element && Array.isArray(names))) {
|
|
67
57
|
return styles;
|
|
68
58
|
}
|
|
69
59
|
|
|
70
|
-
const {length} =
|
|
60
|
+
const {length} = names;
|
|
71
61
|
|
|
72
62
|
for (let index = 0; index < length; index += 1) {
|
|
73
|
-
const
|
|
63
|
+
const name = names[index];
|
|
74
64
|
|
|
75
|
-
if (typeof
|
|
76
|
-
styles[
|
|
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
|
|
113
|
+
* @param name Style name
|
|
124
114
|
* @param value Style value
|
|
125
115
|
*/
|
|
126
|
-
export function setStyle(element: Element,
|
|
127
|
-
setElementValues(element,
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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,
|
|
196
|
-
if (
|
|
197
|
-
(this as HTMLElement).style.setProperty(
|
|
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[
|
|
189
|
+
(this as HTMLElement).style[name as never] = getString(style);
|
|
200
190
|
}
|
|
201
191
|
},
|
|
202
|
-
function (this: Element,
|
|
203
|
-
if (
|
|
204
|
-
(this as HTMLElement).style.removeProperty(
|
|
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[
|
|
196
|
+
(this as HTMLElement).style[name as never] = '';
|
|
207
197
|
}
|
|
208
198
|
|
|
209
199
|
if ((this as HTMLElement).getAttribute(ATTRIBUTE_STYLE) === '') {
|