@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.
- package/dist/attribute/{get.d.mts → get.attribute.d.mts} +3 -2
- package/dist/attribute/{get.mjs → get.attribute.mjs} +4 -3
- package/dist/attribute/index.d.mts +3 -16
- package/dist/attribute/index.mjs +4 -7
- package/dist/attribute/{set.d.mts → set.attribute.d.mts} +4 -4
- package/dist/attribute/{set.mjs → set.attribute.mjs} +2 -2
- package/dist/create.d.mts +25 -0
- package/dist/create.mjs +17 -0
- package/dist/data.d.mts +1 -1
- package/dist/data.mjs +7 -7
- package/dist/event/delegation.mjs +8 -1
- package/dist/html/index.d.mts +23 -26
- package/dist/html/index.mjs +85 -18
- package/dist/html/sanitize.mjs +6 -5
- package/dist/index.d.mts +114 -53
- package/dist/index.mjs +553 -561
- package/dist/internal/attribute.d.mts +4 -3
- package/dist/internal/attribute.mjs +13 -23
- package/dist/internal/element-value.d.mts +2 -2
- package/dist/internal/element-value.mjs +4 -2
- package/dist/internal/get-value.mjs +1 -1
- package/dist/internal/property.d.mts +4 -0
- package/dist/internal/property.mjs +21 -0
- package/dist/property/get.property.d.mts +20 -0
- package/dist/property/get.property.mjs +35 -0
- package/dist/property/index.d.mts +3 -0
- package/dist/property/index.mjs +3 -0
- package/dist/property/set.property.d.mts +32 -0
- package/dist/property/set.property.mjs +34 -0
- package/dist/style.d.mts +12 -7
- package/dist/style.mjs +14 -18
- package/package.json +12 -5
- package/src/attribute/{get.ts → get.attribute.ts} +14 -3
- package/src/attribute/index.ts +10 -22
- package/src/attribute/{set.ts → set.attribute.ts} +9 -5
- package/src/create.ts +81 -0
- package/src/data.ts +17 -9
- package/src/event/delegation.ts +24 -3
- package/src/event/index.ts +9 -3
- package/src/find/index.ts +12 -4
- package/src/find/relative.ts +4 -0
- package/src/focusable.ts +10 -2
- package/src/html/index.ts +166 -58
- package/src/html/sanitize.ts +14 -11
- package/src/index.ts +2 -1
- package/src/internal/attribute.ts +23 -42
- package/src/internal/element-value.ts +11 -4
- package/src/internal/get-value.ts +8 -0
- package/src/internal/is.ts +4 -0
- package/src/internal/property.ts +42 -0
- package/src/is.ts +10 -2
- package/src/property/get.property.ts +73 -0
- package/src/property/index.ts +2 -0
- package/src/property/set.property.ts +102 -0
- package/src/style.ts +52 -27
- package/src/touch.ts +14 -2
package/src/index.ts
CHANGED
|
@@ -6,11 +6,11 @@ export {
|
|
|
6
6
|
getAttributes,
|
|
7
7
|
isBadAttribute,
|
|
8
8
|
isBooleanAttribute,
|
|
9
|
-
isEmptyNonBooleanAttribute,
|
|
10
9
|
isInvalidBooleanAttribute,
|
|
11
10
|
setAttribute,
|
|
12
11
|
setAttributes,
|
|
13
12
|
} from './attribute/index';
|
|
13
|
+
export * from './create';
|
|
14
14
|
export * from './data';
|
|
15
15
|
export * from './event/index';
|
|
16
16
|
export * from './find/index';
|
|
@@ -18,6 +18,7 @@ export * from './focusable';
|
|
|
18
18
|
export * from './html/index';
|
|
19
19
|
export * from './is';
|
|
20
20
|
export * from './models';
|
|
21
|
+
export * from './property/index';
|
|
21
22
|
export * from './style';
|
|
22
23
|
|
|
23
24
|
export {supportsTouch};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type {PlainObject} from '@oscarpalmer/atoms';
|
|
2
1
|
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {kebabCase} from '@oscarpalmer/atoms/string/case';
|
|
3
4
|
import type {Attribute} from '../models';
|
|
4
5
|
import {updateElementValue} from './element-value';
|
|
6
|
+
import {updateProperty} from './property';
|
|
7
|
+
|
|
8
|
+
// #region Functions
|
|
5
9
|
|
|
6
10
|
function badAttributeHandler(name?: string, value?: string): boolean {
|
|
7
11
|
if (typeof name !== 'string' || name.trim().length === 0 || typeof value !== 'string') {
|
|
@@ -67,6 +71,10 @@ function handleAttribute(
|
|
|
67
71
|
value = second;
|
|
68
72
|
}
|
|
69
73
|
|
|
74
|
+
if (name != null) {
|
|
75
|
+
name = kebabCase(name);
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
if (decode && value != null) {
|
|
71
79
|
value = decodeAttribute(value);
|
|
72
80
|
}
|
|
@@ -96,20 +104,6 @@ export function _isBooleanAttribute(first: unknown, decode: boolean): boolean {
|
|
|
96
104
|
);
|
|
97
105
|
}
|
|
98
106
|
|
|
99
|
-
export function _isEmptyNonBooleanAttribute(
|
|
100
|
-
first: unknown,
|
|
101
|
-
second: unknown,
|
|
102
|
-
decode: boolean,
|
|
103
|
-
): boolean {
|
|
104
|
-
return handleAttribute(
|
|
105
|
-
(name, value) =>
|
|
106
|
-
name != null && value != null && !booleanAttributesSet.has(name) && value.trim().length === 0,
|
|
107
|
-
decode,
|
|
108
|
-
first,
|
|
109
|
-
second,
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
107
|
export function _isInvalidBooleanAttribute(
|
|
114
108
|
first: unknown,
|
|
115
109
|
second: unknown,
|
|
@@ -126,49 +120,39 @@ export function updateAttribute(
|
|
|
126
120
|
element: Element,
|
|
127
121
|
name: string,
|
|
128
122
|
value: unknown,
|
|
129
|
-
dispatch
|
|
123
|
+
dispatch: boolean,
|
|
130
124
|
): void {
|
|
131
|
-
const
|
|
125
|
+
const lowerCaseName = name.toLowerCase();
|
|
132
126
|
|
|
133
|
-
const isBoolean = booleanAttributesSet.has(
|
|
127
|
+
const isBoolean = booleanAttributesSet.has(lowerCaseName);
|
|
134
128
|
|
|
135
129
|
const next = isBoolean
|
|
136
130
|
? value === true ||
|
|
137
|
-
(typeof value === 'string' && (value === '' || value.toLowerCase() ===
|
|
131
|
+
(typeof value === 'string' && (value === '' || value.toLowerCase() === lowerCaseName))
|
|
138
132
|
: value == null
|
|
139
133
|
? ''
|
|
140
134
|
: value;
|
|
141
135
|
|
|
142
|
-
if (
|
|
143
|
-
updateProperty(element,
|
|
136
|
+
if (isBoolean || dispatchedAttributes.has(name)) {
|
|
137
|
+
updateProperty(element, name, next, dispatch);
|
|
144
138
|
}
|
|
145
139
|
|
|
146
140
|
updateElementValue(
|
|
147
141
|
element,
|
|
148
142
|
name,
|
|
149
143
|
isBoolean ? (next ? '' : null) : value,
|
|
144
|
+
// oxlint-disable-next-line typescript/unbound-method: using `.call` in `updateElementValue`
|
|
150
145
|
element.setAttribute,
|
|
146
|
+
// oxlint-disable-next-line typescript/unbound-method: using `.call` in `updateElementValue`
|
|
151
147
|
element.removeAttribute,
|
|
152
148
|
isBoolean,
|
|
153
149
|
false,
|
|
154
150
|
);
|
|
155
151
|
}
|
|
156
152
|
|
|
157
|
-
|
|
158
|
-
if (Object.is((element as unknown as PlainObject)[name], value)) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
(element as unknown as PlainObject)[name] = value;
|
|
153
|
+
// #endregion
|
|
163
154
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (typeof event === 'string') {
|
|
167
|
-
element.dispatchEvent(new Event(event, {bubbles: true}));
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
//
|
|
155
|
+
// #region Variables
|
|
172
156
|
|
|
173
157
|
const EXPRESSION_CLOBBERED_NAME = /^(id|name)$/i;
|
|
174
158
|
|
|
@@ -220,15 +204,12 @@ export const booleanAttributes: readonly string[] = Object.freeze([
|
|
|
220
204
|
'selected',
|
|
221
205
|
]);
|
|
222
206
|
|
|
223
|
-
const booleanAttributesSet = new Set(booleanAttributes);
|
|
207
|
+
export const booleanAttributesSet = new Set(booleanAttributes);
|
|
224
208
|
|
|
225
|
-
const
|
|
226
|
-
DETAILS: {open: 'toggle'},
|
|
227
|
-
INPUT: {checked: 'change', value: 'input'},
|
|
228
|
-
SELECT: {value: 'change'},
|
|
229
|
-
TEXTAREA: {value: 'input'},
|
|
230
|
-
};
|
|
209
|
+
export const dispatchedAttributes = new Set(['checked', 'open', 'value']);
|
|
231
210
|
|
|
232
211
|
const formElement = document.createElement('form');
|
|
233
212
|
|
|
234
213
|
let textArea: HTMLTextAreaElement;
|
|
214
|
+
|
|
215
|
+
// #endregion
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import {kebabCase} from '@oscarpalmer/atoms/string/case';
|
|
2
3
|
import {isHTMLOrSVGElement} from '../is';
|
|
3
4
|
import {isAttribute} from './attribute';
|
|
4
5
|
|
|
6
|
+
// #region Functions
|
|
7
|
+
|
|
5
8
|
export function setElementValue(
|
|
6
9
|
element: Element,
|
|
7
10
|
first: unknown,
|
|
8
11
|
second: unknown,
|
|
9
12
|
third: unknown,
|
|
10
|
-
callback: (element: Element, key: string, value: unknown) => void,
|
|
13
|
+
callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void,
|
|
11
14
|
): void {
|
|
12
15
|
if (!isHTMLOrSVGElement(element)) {
|
|
13
16
|
return;
|
|
@@ -25,14 +28,16 @@ export function setElementValues(
|
|
|
25
28
|
first: unknown,
|
|
26
29
|
second: unknown,
|
|
27
30
|
third: unknown,
|
|
28
|
-
callback: (element: Element, key: string, value: unknown, dispatch
|
|
31
|
+
callback: (element: Element, key: string, value: unknown, dispatch: boolean) => void,
|
|
29
32
|
): void {
|
|
30
33
|
if (!isHTMLOrSVGElement(element)) {
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
const dispatch = third !== false;
|
|
38
|
+
|
|
34
39
|
if (typeof first === 'string') {
|
|
35
|
-
callback(element, first, second,
|
|
40
|
+
callback(element, kebabCase(first), second, dispatch);
|
|
36
41
|
|
|
37
42
|
return;
|
|
38
43
|
}
|
|
@@ -50,7 +55,7 @@ export function setElementValues(
|
|
|
50
55
|
const entry = entries[index];
|
|
51
56
|
|
|
52
57
|
if (typeof entry === 'object' && typeof entry?.name === 'string') {
|
|
53
|
-
callback(element, entry.name, entry.value,
|
|
58
|
+
callback(element, kebabCase(entry.name), entry.value, dispatch);
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
}
|
|
@@ -70,3 +75,5 @@ export function updateElementValue(
|
|
|
70
75
|
set.call(element, key, json ? JSON.stringify(value) : String(value));
|
|
71
76
|
}
|
|
72
77
|
}
|
|
78
|
+
|
|
79
|
+
// #endregion Functions
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {parse} from '@oscarpalmer/atoms/string';
|
|
2
2
|
import {camelCase, kebabCase} from '@oscarpalmer/atoms/string/case';
|
|
3
3
|
|
|
4
|
+
// #region Functions
|
|
5
|
+
|
|
4
6
|
export function getBoolean(value: unknown, defaultValue?: boolean): boolean {
|
|
5
7
|
return typeof value === 'boolean' ? value : (defaultValue ?? false);
|
|
6
8
|
}
|
|
@@ -27,4 +29,10 @@ export function getStyleValue(
|
|
|
27
29
|
: (element as HTMLElement).style[name as never];
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
// #endregion
|
|
33
|
+
|
|
34
|
+
// #region Variables
|
|
35
|
+
|
|
30
36
|
export const EXPRESSION_DATA_PREFIX = /^data-/i;
|
|
37
|
+
|
|
38
|
+
// #endregion
|
package/src/internal/is.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// #region Functions
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Is the value an event target?
|
|
3
5
|
* @param value Value to check
|
|
@@ -21,3 +23,5 @@ export function isEventTarget(value: unknown): value is EventTarget {
|
|
|
21
23
|
export function isHTMLOrSVGElement(value: unknown): value is HTMLElement | SVGElement {
|
|
22
24
|
return value instanceof HTMLElement || value instanceof SVGElement;
|
|
23
25
|
}
|
|
26
|
+
|
|
27
|
+
// #endregion
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type {PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {camelCase} from '@oscarpalmer/atoms/string/case';
|
|
3
|
+
|
|
4
|
+
// #region Functions
|
|
5
|
+
|
|
6
|
+
export function updateProperty(
|
|
7
|
+
element: Element,
|
|
8
|
+
name: string,
|
|
9
|
+
value: unknown,
|
|
10
|
+
dispatch: boolean,
|
|
11
|
+
): void {
|
|
12
|
+
let property = name;
|
|
13
|
+
|
|
14
|
+
if (!(property in element)) {
|
|
15
|
+
property = camelCase(name);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!(property in element) || Object.is((element as unknown as PlainObject)[property], value)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
(element as unknown as PlainObject)[property] = value;
|
|
23
|
+
|
|
24
|
+
const event = dispatch && elementEvents[element.tagName]?.[property];
|
|
25
|
+
|
|
26
|
+
if (typeof event === 'string') {
|
|
27
|
+
element.dispatchEvent(new Event(event, {bubbles: true}));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// #endregion
|
|
32
|
+
|
|
33
|
+
// #region Variables
|
|
34
|
+
|
|
35
|
+
const elementEvents: Record<string, Record<string, string>> = {
|
|
36
|
+
DETAILS: {open: 'toggle'},
|
|
37
|
+
INPUT: {checked: 'change', value: 'input'},
|
|
38
|
+
SELECT: {value: 'change'},
|
|
39
|
+
TEXTAREA: {value: 'input'},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// #endregion
|
package/src/is.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// #region Functions
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Is the value a child node?
|
|
3
5
|
* @param value Value to check
|
|
@@ -36,7 +38,9 @@ export function isInDocument(node: Node, doc?: Document): boolean {
|
|
|
36
38
|
: node.ownerDocument === doc && doc.contains(node);
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
//
|
|
41
|
+
// #endregion
|
|
42
|
+
|
|
43
|
+
// #region Variables
|
|
40
44
|
|
|
41
45
|
const CHILD_NODE_TYPES: Set<number> = new Set([
|
|
42
46
|
Node.ELEMENT_NODE,
|
|
@@ -46,6 +50,10 @@ const CHILD_NODE_TYPES: Set<number> = new Set([
|
|
|
46
50
|
Node.DOCUMENT_TYPE_NODE,
|
|
47
51
|
]);
|
|
48
52
|
|
|
49
|
-
//
|
|
53
|
+
// #endregion
|
|
54
|
+
|
|
55
|
+
// #region Exports
|
|
50
56
|
|
|
51
57
|
export {isEventTarget, isHTMLOrSVGElement} from './internal/is';
|
|
58
|
+
|
|
59
|
+
// #endregion
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type {Primitive} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {camelCase} from '@oscarpalmer/atoms/string/case';
|
|
3
|
+
import {isHTMLOrSVGElement} from '../internal/is';
|
|
4
|
+
|
|
5
|
+
// #region Types
|
|
6
|
+
|
|
7
|
+
type GetProperties<Target extends Element> = {
|
|
8
|
+
[Property in keyof Target as Target[Property] extends Primitive
|
|
9
|
+
? Property
|
|
10
|
+
: never]?: Target[Property];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// #endregion
|
|
14
|
+
|
|
15
|
+
// #region Functions
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get the values of one or more properties on an element
|
|
19
|
+
* @param target Target element
|
|
20
|
+
* @param properties Properties to get
|
|
21
|
+
* @returns Property values
|
|
22
|
+
*/
|
|
23
|
+
export function getProperties<Target extends Element, Property extends keyof GetProperties<Target>>(
|
|
24
|
+
target: Target,
|
|
25
|
+
properties: Property[],
|
|
26
|
+
): Pick<GetProperties<Target>, Property> {
|
|
27
|
+
const values: Partial<GetProperties<Target>> = {};
|
|
28
|
+
|
|
29
|
+
if (!isHTMLOrSVGElement(target) || !Array.isArray(properties)) {
|
|
30
|
+
return values as Pick<GetProperties<Target>, Property>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const {length} = properties;
|
|
34
|
+
|
|
35
|
+
for (let index = 0; index < length; index += 1) {
|
|
36
|
+
const property = properties[index];
|
|
37
|
+
|
|
38
|
+
if (typeof property === 'string') {
|
|
39
|
+
values[property] = getPropertyValue(target, property) as GetProperties<Target>[Property];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return values as Pick<GetProperties<Target>, Property>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get the value of a property on an element
|
|
48
|
+
* @param target Target element
|
|
49
|
+
* @param property Property to get
|
|
50
|
+
* @returns Property value
|
|
51
|
+
*/
|
|
52
|
+
export function getProperty<Target extends Element, Property extends keyof GetProperties<Target>>(
|
|
53
|
+
target: Target,
|
|
54
|
+
property: Property,
|
|
55
|
+
): GetProperties<Target>[Property] {
|
|
56
|
+
if (isHTMLOrSVGElement(target) && typeof property === 'string') {
|
|
57
|
+
return getPropertyValue(target, property) as GetProperties<Target>[Property];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getPropertyValue(element: HTMLElement, property: string): unknown {
|
|
62
|
+
let actual = property;
|
|
63
|
+
|
|
64
|
+
if (!(actual in element)) {
|
|
65
|
+
actual = camelCase(actual);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (actual in element) {
|
|
69
|
+
return element[actual as keyof HTMLElement];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// #endregion
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {PlainObject, Primitive} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {setAttribute} from '../attribute';
|
|
4
|
+
import type {DispatchedAttributeName} from '../attribute/set.attribute';
|
|
5
|
+
import {booleanAttributesSet, dispatchedAttributes} from '../internal/attribute';
|
|
6
|
+
import {updateProperty} from '../internal/property';
|
|
7
|
+
import {isHTMLOrSVGElement} from '../is';
|
|
8
|
+
|
|
9
|
+
// #region Types
|
|
10
|
+
|
|
11
|
+
type DispatchedPropertyValue<
|
|
12
|
+
Target extends Element,
|
|
13
|
+
Property extends DispatchedAttributeName,
|
|
14
|
+
> = Property extends keyof SetProperties<Target> ? SetProperties<Target>[Property] : never;
|
|
15
|
+
|
|
16
|
+
type SetProperties<Target extends Element> = {
|
|
17
|
+
[Property in keyof Target as Target[Property] extends Primitive
|
|
18
|
+
? Property
|
|
19
|
+
: never]?: Target[Property];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// #endregion
|
|
23
|
+
|
|
24
|
+
// #region Functions
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Set the values of one or more properties on an element
|
|
28
|
+
*
|
|
29
|
+
* Also updates attributes for boolean/dispatchable properties, and if `dispatch` is `true`, will dispatch events for dispatchable properties
|
|
30
|
+
* @param target Target element
|
|
31
|
+
* @param properties Properties to set
|
|
32
|
+
* @param dispatch Dispatch events for properties? _(defaults to `true`)_
|
|
33
|
+
*/
|
|
34
|
+
export function setProperties<Target extends Element>(
|
|
35
|
+
target: Target,
|
|
36
|
+
properties: SetProperties<Target>,
|
|
37
|
+
dispatch?: boolean,
|
|
38
|
+
): void {
|
|
39
|
+
if (!isHTMLOrSVGElement(target) || !isPlainObject(properties)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const shouldDispatch = dispatch !== false;
|
|
44
|
+
|
|
45
|
+
const keys = Object.keys(properties);
|
|
46
|
+
const {length} = keys;
|
|
47
|
+
|
|
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
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Set the value for a dispatchable property on an element
|
|
61
|
+
* @param target Target element
|
|
62
|
+
* @param property Property to set
|
|
63
|
+
* @param value Value to set
|
|
64
|
+
* @param dispatch Dispatch event for property? _(defaults to `true`)_
|
|
65
|
+
*/
|
|
66
|
+
export function setProperty<Target extends Element, Property extends DispatchedAttributeName>(
|
|
67
|
+
target: Target,
|
|
68
|
+
property: Property,
|
|
69
|
+
value: DispatchedPropertyValue<Target, Property>,
|
|
70
|
+
dispatch?: boolean,
|
|
71
|
+
): void;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set the value for a property on an element
|
|
75
|
+
* @param target Target element
|
|
76
|
+
* @param property Property to set
|
|
77
|
+
* @param value Value to set
|
|
78
|
+
*/
|
|
79
|
+
export function setProperty<Target extends Element, Property extends keyof SetProperties<Target>>(
|
|
80
|
+
target: Target,
|
|
81
|
+
property: Property,
|
|
82
|
+
value: SetProperties<Target>[Property],
|
|
83
|
+
): void;
|
|
84
|
+
|
|
85
|
+
export function setProperty<Target extends Element, Property extends keyof SetProperties<Target>>(
|
|
86
|
+
target: Target,
|
|
87
|
+
property: Property,
|
|
88
|
+
value: SetProperties<Target>[Property],
|
|
89
|
+
dispatch?: boolean,
|
|
90
|
+
): void {
|
|
91
|
+
if (!isHTMLOrSVGElement(target) || typeof property !== 'string') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (booleanAttributesSet.has(property.toLowerCase()) || dispatchedAttributes.has(property)) {
|
|
96
|
+
setAttribute(target, property as never, value, dispatch !== false);
|
|
97
|
+
} else {
|
|
98
|
+
updateProperty(target, property, value, dispatch !== false);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// #endregion
|
package/src/style.ts
CHANGED
|
@@ -3,6 +3,8 @@ import {getStyleValue} from './internal/get-value';
|
|
|
3
3
|
import {isHTMLOrSVGElement} from './internal/is';
|
|
4
4
|
import type {TextDirection} from './models';
|
|
5
5
|
|
|
6
|
+
// #region Types
|
|
7
|
+
|
|
6
8
|
export type StyleToggler = {
|
|
7
9
|
/**
|
|
8
10
|
* Set the provided styles on the element
|
|
@@ -14,6 +16,12 @@ export type StyleToggler = {
|
|
|
14
16
|
remove(): void;
|
|
15
17
|
};
|
|
16
18
|
|
|
19
|
+
type Styles = Partial<Record<keyof CSSStyleDeclaration, unknown>>;
|
|
20
|
+
|
|
21
|
+
// #endregion
|
|
22
|
+
|
|
23
|
+
// #region Functions
|
|
24
|
+
|
|
17
25
|
/**
|
|
18
26
|
* Get a style from an element
|
|
19
27
|
* @param element Element to get the style from
|
|
@@ -26,11 +34,9 @@ export function getStyle(
|
|
|
26
34
|
property: keyof CSSStyleDeclaration,
|
|
27
35
|
computed?: boolean,
|
|
28
36
|
): string | undefined {
|
|
29
|
-
if (
|
|
30
|
-
return
|
|
37
|
+
if (isHTMLOrSVGElement(element) && typeof property === 'string') {
|
|
38
|
+
return getStyleValue(element, property, computed === true);
|
|
31
39
|
}
|
|
32
|
-
|
|
33
|
-
return getStyleValue(element, property, computed === true);
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
/**
|
|
@@ -65,25 +71,37 @@ export function getStyles<Property extends keyof CSSStyleDeclaration>(
|
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
/**
|
|
68
|
-
* Get the text direction of
|
|
69
|
-
* @param element
|
|
70
|
-
* @param computed Get the computed text direction? _(defaults to `false`)_
|
|
74
|
+
* Get the text direction of a node or element _(or document, if element is invalid)_
|
|
75
|
+
* @param node Node or element to get the text direction from
|
|
71
76
|
* @returns Text direction
|
|
72
77
|
*/
|
|
73
|
-
export function getTextDirection(
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
export function getTextDirection(node: Element | Node): TextDirection;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the text direction of the document
|
|
82
|
+
* @returns Text direction
|
|
83
|
+
*/
|
|
84
|
+
export function getTextDirection(): TextDirection;
|
|
85
|
+
|
|
86
|
+
export function getTextDirection(node?: Element | Node): TextDirection {
|
|
87
|
+
let target: HTMLElement | SVGElement;
|
|
88
|
+
|
|
89
|
+
if (isHTMLOrSVGElement(node)) {
|
|
90
|
+
target = node;
|
|
91
|
+
} else {
|
|
92
|
+
target =
|
|
93
|
+
node instanceof Node
|
|
94
|
+
? (node.ownerDocument?.documentElement ?? document.documentElement)
|
|
95
|
+
: document.documentElement;
|
|
76
96
|
}
|
|
77
97
|
|
|
78
|
-
|
|
98
|
+
let {direction} = target.style;
|
|
79
99
|
|
|
80
|
-
if (direction
|
|
81
|
-
|
|
100
|
+
if (direction === '') {
|
|
101
|
+
direction = getStyleValue(target, PROPETY_DIRECTION, true)!;
|
|
82
102
|
}
|
|
83
103
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return value === 'rtl' ? value : 'ltr';
|
|
104
|
+
return direction === DIRECTION_RTL ? DIRECTION_RTL : DIRECTION_LTR;
|
|
87
105
|
}
|
|
88
106
|
|
|
89
107
|
/**
|
|
@@ -95,7 +113,7 @@ export function getTextDirection(element: Element, computed?: boolean): TextDire
|
|
|
95
113
|
export function setStyle(
|
|
96
114
|
element: Element,
|
|
97
115
|
property: keyof CSSStyleDeclaration,
|
|
98
|
-
value?:
|
|
116
|
+
value?: unknown,
|
|
99
117
|
): void {
|
|
100
118
|
setElementValues(element, property as string, value, null, updateStyleProperty);
|
|
101
119
|
}
|
|
@@ -105,7 +123,7 @@ export function setStyle(
|
|
|
105
123
|
* @param element Element to set the styles on
|
|
106
124
|
* @param styles Styles to set
|
|
107
125
|
*/
|
|
108
|
-
export function setStyles(element: Element, styles:
|
|
126
|
+
export function setStyles(element: Element, styles: Styles): void {
|
|
109
127
|
setElementValues(element, styles as never, null, null, updateStyleProperty);
|
|
110
128
|
}
|
|
111
129
|
|
|
@@ -115,11 +133,11 @@ export function setStyles(element: Element, styles: Partial<CSSStyleDeclaration>
|
|
|
115
133
|
* @param styles Styles to be set or removed
|
|
116
134
|
* @returns Style toggler
|
|
117
135
|
*/
|
|
118
|
-
export function toggleStyles(element: Element, styles:
|
|
136
|
+
export function toggleStyles(element: Element, styles: Styles): StyleToggler {
|
|
119
137
|
function toggle(set: boolean): void {
|
|
120
138
|
hasSet = set;
|
|
121
139
|
|
|
122
|
-
let next:
|
|
140
|
+
let next: Styles;
|
|
123
141
|
|
|
124
142
|
if (set) {
|
|
125
143
|
values = getStyles(element, keys);
|
|
@@ -130,8 +148,8 @@ export function toggleStyles(element: Element, styles: Partial<CSSStyleDeclarati
|
|
|
130
148
|
|
|
131
149
|
values = {};
|
|
132
150
|
|
|
133
|
-
for (
|
|
134
|
-
values[
|
|
151
|
+
for (let index = 0; index < length; index += 1) {
|
|
152
|
+
values[keys[index] as never] = undefined;
|
|
135
153
|
}
|
|
136
154
|
}
|
|
137
155
|
|
|
@@ -139,6 +157,7 @@ export function toggleStyles(element: Element, styles: Partial<CSSStyleDeclarati
|
|
|
139
157
|
}
|
|
140
158
|
|
|
141
159
|
const keys = Object.keys(styles) as (keyof CSSStyleDeclaration)[];
|
|
160
|
+
const {length} = keys;
|
|
142
161
|
|
|
143
162
|
let hasSet = false;
|
|
144
163
|
let values: Record<string, string | undefined> = {};
|
|
@@ -162,8 +181,8 @@ function updateStyleProperty(element: Element, key: string, value: unknown): voi
|
|
|
162
181
|
element,
|
|
163
182
|
key,
|
|
164
183
|
value,
|
|
165
|
-
function (this: Element, property: string, style:
|
|
166
|
-
(this as HTMLElement).style[property as never] = style;
|
|
184
|
+
function (this: Element, property: string, style: unknown) {
|
|
185
|
+
(this as HTMLElement).style[property as never] = String(style);
|
|
167
186
|
},
|
|
168
187
|
function (this: Element, property: string) {
|
|
169
188
|
(this as HTMLElement).style[property as never] = '';
|
|
@@ -173,8 +192,14 @@ function updateStyleProperty(element: Element, key: string, value: unknown): voi
|
|
|
173
192
|
);
|
|
174
193
|
}
|
|
175
194
|
|
|
176
|
-
//
|
|
195
|
+
// #endregion
|
|
196
|
+
|
|
197
|
+
// #region Variables
|
|
198
|
+
|
|
199
|
+
const DIRECTION_LTR = 'ltr';
|
|
200
|
+
|
|
201
|
+
const DIRECTION_RTL = 'rtl';
|
|
177
202
|
|
|
178
|
-
const
|
|
203
|
+
const PROPETY_DIRECTION = 'direction';
|
|
179
204
|
|
|
180
|
-
|
|
205
|
+
// #endregion
|
package/src/touch.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// #region Types
|
|
2
|
+
|
|
1
3
|
type NavigatorWithMsMaxTouchPoints = Navigator & {
|
|
2
4
|
msMaxTouchPoints: number;
|
|
3
5
|
};
|
|
@@ -17,7 +19,9 @@ type SupporsTouch = {
|
|
|
17
19
|
update(): boolean;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
|
-
//
|
|
22
|
+
// #endregion
|
|
23
|
+
|
|
24
|
+
// #region Functions
|
|
21
25
|
|
|
22
26
|
function getSupport(): boolean {
|
|
23
27
|
if (window == null || navigator == null) {
|
|
@@ -50,7 +54,9 @@ function getSupport(): boolean {
|
|
|
50
54
|
return false;
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
//
|
|
57
|
+
// #endregion
|
|
58
|
+
|
|
59
|
+
// #region Variables
|
|
54
60
|
|
|
55
61
|
/**
|
|
56
62
|
* Does the device support touch events?
|
|
@@ -78,4 +84,10 @@ const supportsTouch: SupporsTouch = (() => {
|
|
|
78
84
|
return instance;
|
|
79
85
|
})();
|
|
80
86
|
|
|
87
|
+
// #endregion
|
|
88
|
+
|
|
89
|
+
// #region Exports
|
|
90
|
+
|
|
81
91
|
export default supportsTouch;
|
|
92
|
+
|
|
93
|
+
// #endregion
|