@webtides/element-js 1.0.0 → 1.1.1
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/CHANGELOG.md +147 -90
- package/README.md +3 -3
- package/docs/README.md +70 -89
- package/docs/concepts/classes.md +37 -66
- package/docs/concepts/hierarchy.md +29 -31
- package/docs/concepts/lifecycle.md +9 -23
- package/docs/concepts/reactivity.md +1 -3
- package/docs/features/computed-properties.md +13 -16
- package/docs/features/dependency-injection-context-protocol.md +75 -87
- package/docs/features/global-styles.md +1 -1
- package/docs/features/methods.md +14 -15
- package/docs/features/properties.md +21 -33
- package/docs/features/refs.md +23 -31
- package/docs/features/renderless.md +31 -37
- package/docs/features/store.md +63 -78
- package/docs/features/templates.md +4 -1
- package/docs/features/watch.md +28 -35
- package/docs/getting-started/upgrade-to-v1.md +16 -0
- package/docs/guide/guide.md +10 -22
- package/index.js +29 -2
- package/package.json +62 -62
- package/src/BaseElement.js +632 -631
- package/src/StyledElement.js +104 -104
- package/src/TemplateElement.js +53 -53
- package/src/dom-parts/AttributePart.js +116 -116
- package/src/dom-parts/ChildNodePart.js +288 -288
- package/src/dom-parts/NodePart.js +27 -27
- package/src/dom-parts/Part.js +6 -6
- package/src/dom-parts/TemplatePart.js +119 -119
- package/src/dom-parts/TemplateResult.js +270 -270
- package/src/dom-parts/directives.js +105 -48
- package/src/dom-parts/html.js +1 -1
- package/src/dom-parts/render.js +6 -6
- package/src/util/AttributeParser.js +47 -47
- package/src/util/DOMHelper.js +190 -190
- package/src/util/Directive.js +31 -31
- package/src/util/GlobalStylesStore.js +63 -53
- package/src/util/SerializeStateHelper.js +56 -56
- package/src/util/Store.js +175 -174
- package/src/util/crypto.js +13 -0
- package/src/util/defineElement.js +5 -5
- package/src/util/toString.js +5 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { camelToDash, decodeAttribute, encodeAttribute } from '../util/AttributeParser.js';
|
|
1
|
+
import { camelToDash, decodeAttribute, encodeAttribute, isNaN } from '../util/AttributeParser.js';
|
|
2
2
|
import { TemplateResult } from './TemplateResult.js';
|
|
3
3
|
import { convertStringToHTML, convertStringToTemplate } from '../util/DOMHelper.js';
|
|
4
4
|
import { defineDirective, Directive } from '../util/Directive.js';
|
|
@@ -10,11 +10,11 @@ import { defineDirective, Directive } from '../util/Directive.js';
|
|
|
10
10
|
* @returns {string} string of classes joined together
|
|
11
11
|
*/
|
|
12
12
|
const classMap = (map) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
const classes = [];
|
|
14
|
+
for (const [key, value] of Object.entries(map)) {
|
|
15
|
+
if (value) classes.push(key);
|
|
16
|
+
}
|
|
17
|
+
return classes.join(' ');
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -24,11 +24,11 @@ const classMap = (map) => {
|
|
|
24
24
|
* @returns {string} string of styles joined together
|
|
25
25
|
*/
|
|
26
26
|
const styleMap = (map) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const styles = [];
|
|
28
|
+
for (const [key, value] of Object.entries(map)) {
|
|
29
|
+
if (value) styles.push(`${key}:${value};`);
|
|
30
|
+
}
|
|
31
|
+
return styles.join(' ');
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -39,7 +39,7 @@ const styleMap = (map) => {
|
|
|
39
39
|
* @returns {TemplateResult | string}
|
|
40
40
|
*/
|
|
41
41
|
const when = (condition, trueCase, falseCase) => {
|
|
42
|
-
|
|
42
|
+
return condition ? trueCase : falseCase;
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -50,7 +50,7 @@ const when = (condition, trueCase, falseCase) => {
|
|
|
50
50
|
* @returns {TemplateResult | string}
|
|
51
51
|
*/
|
|
52
52
|
const choose = (value, cases, defaultCase) => {
|
|
53
|
-
|
|
53
|
+
return cases[value] || defaultCase;
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
/**
|
|
@@ -59,47 +59,88 @@ const choose = (value, cases, defaultCase) => {
|
|
|
59
59
|
* @returns {(function(): Node) | { __unsafeHTML: true, string: string }}
|
|
60
60
|
*/
|
|
61
61
|
const unsafeHTML = (string) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
if (!globalThis.DOMParser) {
|
|
63
|
+
return { __unsafeHTML: true, string };
|
|
64
|
+
}
|
|
65
|
+
const node = convertStringToHTML(string).firstChild;
|
|
66
|
+
const importedNode = globalThis.document?.importNode(node, true);
|
|
67
|
+
return () => importedNode;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* Renders multiple attributes as key="value" pairs from a map of attributes
|
|
72
72
|
*/
|
|
73
73
|
export class SpreadAttributesDirective extends Directive {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
/**
|
|
75
|
+
* @param {Object.<string, any>} attributes
|
|
76
|
+
*/
|
|
77
|
+
update(attributes) {
|
|
78
|
+
for (const name of Object.keys(attributes)) {
|
|
79
|
+
const value = attributes[name];
|
|
80
|
+
if (value === undefined || value === null || isNaN(value)) {
|
|
81
|
+
this.node.removeAttribute(camelToDash(name));
|
|
82
|
+
} else {
|
|
83
|
+
this.node.setAttribute(
|
|
84
|
+
camelToDash(name),
|
|
85
|
+
encodeAttribute(typeof value !== 'string' ? JSON.stringify(value) : value),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
91
|
+
/**
|
|
92
|
+
* @param {Object.<string, any>} attributes
|
|
93
|
+
* @returns {string}
|
|
94
|
+
*/
|
|
95
|
+
stringify(attributes) {
|
|
96
|
+
return Object.keys(attributes)
|
|
97
|
+
.map((name) => {
|
|
98
|
+
let value = attributes[name];
|
|
99
|
+
return `${camelToDash(name)}='${encodeAttribute(
|
|
100
|
+
typeof value !== 'string' ? JSON.stringify(value) : value,
|
|
101
|
+
)}'`;
|
|
102
|
+
})
|
|
103
|
+
.join(' ');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Renders an attribute as key="value" if a condition is truthy
|
|
109
|
+
*/
|
|
110
|
+
export class OptionalAttributeDirective extends Directive {
|
|
111
|
+
/**
|
|
112
|
+
* @param {boolean} condition
|
|
113
|
+
* @param {string} attributeName
|
|
114
|
+
* @param {string|any} attributeValue
|
|
115
|
+
*/
|
|
116
|
+
update(condition, attributeName, attributeValue = '') {
|
|
117
|
+
if (condition) {
|
|
118
|
+
this.node.setAttribute(
|
|
119
|
+
camelToDash(attributeName),
|
|
120
|
+
encodeAttribute(typeof attributeValue !== 'string' ? JSON.stringify(attributeValue) : attributeValue),
|
|
121
|
+
);
|
|
122
|
+
} else {
|
|
123
|
+
this.node.removeAttribute(camelToDash(attributeName));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* @param {boolean} condition
|
|
128
|
+
* @param {string} attributeName
|
|
129
|
+
* @param {string|any} attributeValue
|
|
130
|
+
*/
|
|
131
|
+
stringify(condition, attributeName, attributeValue = '') {
|
|
132
|
+
if (condition) {
|
|
133
|
+
if (attributeValue === '') {
|
|
134
|
+
// empty string toggles boolean attributes
|
|
135
|
+
return `${camelToDash(attributeName)}`;
|
|
136
|
+
}
|
|
137
|
+
return `${camelToDash(attributeName)}='${encodeAttribute(
|
|
138
|
+
typeof attributeValue !== 'string' ? JSON.stringify(attributeValue) : attributeValue,
|
|
139
|
+
)}'`;
|
|
140
|
+
} else {
|
|
141
|
+
return '';
|
|
142
|
+
}
|
|
143
|
+
}
|
|
103
144
|
}
|
|
104
145
|
|
|
105
146
|
/**
|
|
@@ -108,4 +149,20 @@ export class SpreadAttributesDirective extends Directive {
|
|
|
108
149
|
*/
|
|
109
150
|
const spreadAttributes = defineDirective(SpreadAttributesDirective);
|
|
110
151
|
|
|
111
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Renders an optional attribute based on a condition
|
|
154
|
+
* @param {Object.<string, any>} attributes
|
|
155
|
+
*/
|
|
156
|
+
const optionalAttribute = defineDirective(OptionalAttributeDirective);
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
defineDirective,
|
|
160
|
+
Directive,
|
|
161
|
+
classMap,
|
|
162
|
+
styleMap,
|
|
163
|
+
when,
|
|
164
|
+
choose,
|
|
165
|
+
unsafeHTML,
|
|
166
|
+
spreadAttributes,
|
|
167
|
+
optionalAttribute,
|
|
168
|
+
};
|
package/src/dom-parts/html.js
CHANGED
package/src/dom-parts/render.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* @param {Element} domNode
|
|
5
5
|
*/
|
|
6
6
|
const render = (template, domNode) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
if (typeof template === 'string') {
|
|
8
|
+
// just a plain string (or literal)
|
|
9
|
+
domNode.innerHTML = template;
|
|
10
|
+
} else {
|
|
11
|
+
template.renderInto(domNode);
|
|
12
|
+
}
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
export { render };
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @returns {boolean}
|
|
5
5
|
*/
|
|
6
6
|
export function isObjectLike(value) {
|
|
7
|
-
|
|
7
|
+
return typeof value == 'object' && value !== null;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -13,11 +13,11 @@ export function isObjectLike(value) {
|
|
|
13
13
|
* @returns {boolean}
|
|
14
14
|
*/
|
|
15
15
|
export function isJSON(value) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(value) && !!value;
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -26,7 +26,7 @@ export function isJSON(value) {
|
|
|
26
26
|
* @returns {boolean}
|
|
27
27
|
*/
|
|
28
28
|
export function isBoolean(value) {
|
|
29
|
-
|
|
29
|
+
return value === 'true' || value === 'false';
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -35,7 +35,7 @@ export function isBoolean(value) {
|
|
|
35
35
|
* @returns {boolean}
|
|
36
36
|
*/
|
|
37
37
|
export function parseBoolean(value) {
|
|
38
|
-
|
|
38
|
+
return value === 'true';
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
@@ -44,10 +44,10 @@ export function parseBoolean(value) {
|
|
|
44
44
|
* @returns {boolean}
|
|
45
45
|
*/
|
|
46
46
|
export function isString(value) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
return (
|
|
48
|
+
typeof value === 'string' ||
|
|
49
|
+
(!!value && typeof value === 'object' && Object.prototype.toString.call(value) === '[object String]')
|
|
50
|
+
);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -56,7 +56,7 @@ export function isString(value) {
|
|
|
56
56
|
* @returns {boolean}
|
|
57
57
|
*/
|
|
58
58
|
export function isNumber(value) {
|
|
59
|
-
|
|
59
|
+
return new RegExp('^-?(0|0\\.\\d+|[1-9]\\d*(\\.\\d+)?)$').test(value);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
|
@@ -65,7 +65,7 @@ export function isNumber(value) {
|
|
|
65
65
|
* @returns {boolean}
|
|
66
66
|
*/
|
|
67
67
|
export function isNaN(value) {
|
|
68
|
-
|
|
68
|
+
return Number.isNaN(value);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
@@ -75,7 +75,7 @@ export function isNaN(value) {
|
|
|
75
75
|
* @returns {boolean}
|
|
76
76
|
*/
|
|
77
77
|
export function deepEquals(valueA, valueB) {
|
|
78
|
-
|
|
78
|
+
return JSON.stringify(valueA) === JSON.stringify(valueB);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
@@ -85,23 +85,23 @@ export function deepEquals(valueA, valueB) {
|
|
|
85
85
|
* @returns {string | number | boolean | object | array}
|
|
86
86
|
*/
|
|
87
87
|
export function parseAttribute(value, options = {}) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
88
|
+
if (options.parse === false || !isString(value)) {
|
|
89
|
+
// no-op
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
if (typeof options.parse === 'function') {
|
|
93
|
+
// custom parse fn
|
|
94
|
+
return options.parse(value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// default parse
|
|
98
|
+
let parsedValue = value;
|
|
99
|
+
|
|
100
|
+
if (isJSON(value)) parsedValue = JSON.parse(value);
|
|
101
|
+
else if (isBoolean(value)) parsedValue = parseBoolean(value);
|
|
102
|
+
else if (isNumber(value)) parsedValue = parseFloat(value);
|
|
103
|
+
|
|
104
|
+
return parsedValue;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/**
|
|
@@ -110,9 +110,9 @@ export function parseAttribute(value, options = {}) {
|
|
|
110
110
|
* @returns {string}
|
|
111
111
|
*/
|
|
112
112
|
export function dashToCamel(string) {
|
|
113
|
-
|
|
113
|
+
if (string.indexOf('-') === -1) return string;
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
return string.replace(/-[a-z]/g, (matches) => matches[1].toUpperCase());
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/**
|
|
@@ -121,7 +121,7 @@ export function dashToCamel(string) {
|
|
|
121
121
|
* @returns {string}
|
|
122
122
|
*/
|
|
123
123
|
export function camelToDash(string) {
|
|
124
|
-
|
|
124
|
+
return string.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/**
|
|
@@ -130,11 +130,11 @@ export function camelToDash(string) {
|
|
|
130
130
|
* @returns {string}
|
|
131
131
|
*/
|
|
132
132
|
export function decodeAttribute(attribute) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
133
|
+
return `${attribute}`
|
|
134
|
+
.replace(/</g, '<')
|
|
135
|
+
.replace(/>/g, '>')
|
|
136
|
+
.replace(/"/g, '"')
|
|
137
|
+
.replace(/'/g, "'");
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
/**
|
|
@@ -143,11 +143,11 @@ export function decodeAttribute(attribute) {
|
|
|
143
143
|
* @returns {string}
|
|
144
144
|
*/
|
|
145
145
|
export function encodeAttribute(attribute) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
return `${attribute}`
|
|
147
|
+
.replace(/'/g, ''')
|
|
148
|
+
.replace(/"/g, '"')
|
|
149
|
+
.replace(/</g, '<')
|
|
150
|
+
.replace(/>/g, '>')
|
|
151
|
+
.replace(/\r\n/g, '\n')
|
|
152
|
+
.replace(/[\r\n]/g, '\n');
|
|
153
153
|
}
|