@webtides/element-js 1.0.0-alpha.9 → 1.1.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/CHANGELOG.md +369 -0
- 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 +637 -632
- package/src/StyledElement.js +104 -104
- package/src/TemplateElement.js +53 -58
- 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 +274 -267
- package/src/dom-parts/directives.js +105 -48
- package/src/dom-parts/html.js +2 -2
- package/src/dom-parts/render.js +6 -1
- package/src/util/AttributeParser.js +47 -47
- package/src/util/DOMHelper.js +190 -191
- package/src/util/Directive.js +31 -24
- package/src/util/GlobalStylesStore.js +56 -49
- package/src/util/SerializeStateHelper.js +56 -56
- package/src/util/Store.js +174 -174
- package/src/util/defineElement.js +5 -5
- package/src/util/toString.js +5 -5
package/src/util/DOMHelper.js
CHANGED
|
@@ -15,14 +15,14 @@ export const DOCUMENT_FRAGMENT_NODE = 11;
|
|
|
15
15
|
* @return {number[]}
|
|
16
16
|
*/
|
|
17
17
|
export const getNodePath = (node) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const path = [];
|
|
19
|
+
let parentNode = node.parentNode;
|
|
20
|
+
while (parentNode) {
|
|
21
|
+
path.push([...parentNode.childNodes].indexOf(node));
|
|
22
|
+
node = parentNode;
|
|
23
|
+
parentNode = node.parentNode;
|
|
24
|
+
}
|
|
25
|
+
return path;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -31,14 +31,14 @@ export const getNodePath = (node) => {
|
|
|
31
31
|
* @returns {Node[]}
|
|
32
32
|
*/
|
|
33
33
|
export function getAllParentNodes(domNode) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
let node = domNode.parentElement;
|
|
35
|
+
let parents = [];
|
|
36
|
+
while (node) {
|
|
37
|
+
parents.unshift(node); // adds node to the beginning of parents
|
|
38
|
+
node = node.parentElement;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return parents;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -48,16 +48,16 @@ export function getAllParentNodes(domNode) {
|
|
|
48
48
|
* @returns {ShadowRoot | HTMLElement}
|
|
49
49
|
*/
|
|
50
50
|
export function getShadowParentOrBody(element) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
51
|
+
if (element instanceof ShadowRoot) {
|
|
52
|
+
return element;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
while (element.parentNode && (element = element.parentNode)) {
|
|
56
|
+
if (element instanceof ShadowRoot) {
|
|
57
|
+
return element;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return document.body;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// TODO: add function for getClosestParentOfNodeType('custom-element')
|
|
@@ -68,11 +68,11 @@ export function getShadowParentOrBody(element) {
|
|
|
68
68
|
* @returns {Node}
|
|
69
69
|
*/
|
|
70
70
|
export function getClosestParentCustomElementNode(domNode) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
const customElementParents = getAllParentNodes(domNode).filter((node) => {
|
|
72
|
+
return node.localName && node.localName.indexOf('-') !== -1;
|
|
73
|
+
});
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
return customElementParents.pop();
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/**
|
|
@@ -82,17 +82,17 @@ export function getClosestParentCustomElementNode(domNode) {
|
|
|
82
82
|
* @return {Node[]}
|
|
83
83
|
*/
|
|
84
84
|
export function getAllElementChildren(domNode, instanceOfFilter = HTMLElement) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
const nodeIterator = document.createNodeIterator(domNode, NodeFilter.SHOW_ELEMENT, (node) =>
|
|
86
|
+
node.nodeName.includes('-') && node instanceof instanceOfFilter
|
|
87
|
+
? NodeFilter.FILTER_ACCEPT
|
|
88
|
+
: NodeFilter.FILTER_REJECT,
|
|
89
|
+
);
|
|
90
|
+
const customElements = [];
|
|
91
|
+
let currentNode;
|
|
92
|
+
while ((currentNode = nodeIterator.nextNode())) {
|
|
93
|
+
customElements.push(currentNode);
|
|
94
|
+
}
|
|
95
|
+
return customElements;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
@@ -102,9 +102,9 @@ export function getAllElementChildren(domNode, instanceOfFilter = HTMLElement) {
|
|
|
102
102
|
* @returns {boolean}
|
|
103
103
|
*/
|
|
104
104
|
export function isOfSameNodeType(nodeA, nodeB) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
if (!nodeA && !nodeA.localName) return false;
|
|
106
|
+
if (!nodeB && !nodeB.localName) return false;
|
|
107
|
+
return nodeA.localName === nodeB.localName;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
@@ -112,7 +112,7 @@ export function isOfSameNodeType(nodeA, nodeB) {
|
|
|
112
112
|
* @returns {boolean}
|
|
113
113
|
*/
|
|
114
114
|
export const supportsAdoptingStyleSheets = () => {
|
|
115
|
-
|
|
115
|
+
return 'adoptedStyleSheets' in Document.prototype && 'replace' in CSSStyleSheet.prototype;
|
|
116
116
|
};
|
|
117
117
|
|
|
118
118
|
/**
|
|
@@ -121,17 +121,17 @@ export const supportsAdoptingStyleSheets = () => {
|
|
|
121
121
|
* @returns {boolean}
|
|
122
122
|
*/
|
|
123
123
|
export const hasChildNodes = (node) => {
|
|
124
|
-
|
|
124
|
+
const childNodesLength = node.childNodes.length;
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
if (childNodesLength === 0) return false;
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
if (childNodesLength === 1 && node.firstChild.nodeType === 3 && node.firstChild.textContent.trim() === '')
|
|
129
|
+
return false;
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
// children will not contain text nodes...
|
|
132
|
+
if (childNodesLength > 0) return true;
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
// TODO: check if more than 1 child nodes, but all childnodes are whitespace text ndoes?!
|
|
135
135
|
};
|
|
136
136
|
|
|
137
137
|
/**
|
|
@@ -140,9 +140,9 @@ export const hasChildNodes = (node) => {
|
|
|
140
140
|
* @returns {HTMLElement}
|
|
141
141
|
*/
|
|
142
142
|
export const convertStringToHTML = (template) => {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
const parser = new DOMParser();
|
|
144
|
+
const document = parser.parseFromString(template.toString(), 'text/html');
|
|
145
|
+
return document.body;
|
|
146
146
|
};
|
|
147
147
|
|
|
148
148
|
/**
|
|
@@ -152,10 +152,9 @@ export const convertStringToHTML = (template) => {
|
|
|
152
152
|
* @return {DocumentFragment}
|
|
153
153
|
*/
|
|
154
154
|
export const convertStringToTemplate = (string) => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return template.content;
|
|
155
|
+
const template = globalThis.document?.createElement('template');
|
|
156
|
+
template.innerHTML = string;
|
|
157
|
+
return template.content;
|
|
159
158
|
};
|
|
160
159
|
|
|
161
160
|
/**
|
|
@@ -164,25 +163,25 @@ export const convertStringToTemplate = (string) => {
|
|
|
164
163
|
* @param {Element} domElement - The existing DOM node
|
|
165
164
|
*/
|
|
166
165
|
export const diffAttributes = function (templateElement, domElement) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
166
|
+
// remove or update previous attributes
|
|
167
|
+
for (/** @type {Attr} */ const attribute of Array.from(domElement.attributes)) {
|
|
168
|
+
if (templateElement.hasAttribute(attribute.name)) {
|
|
169
|
+
const oldValue = attribute.value;
|
|
170
|
+
const newValue = templateElement.getAttribute(attribute.name) || '';
|
|
171
|
+
if (oldValue !== newValue) {
|
|
172
|
+
domElement.setAttribute(attribute.name, newValue);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
domElement.removeAttribute(attribute.name);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// set newly added attributes
|
|
180
|
+
for (/** @type {Attr} */ const attribute of Array.from(templateElement.attributes)) {
|
|
181
|
+
if (!domElement.hasAttribute(attribute.name)) {
|
|
182
|
+
domElement.setAttribute(attribute.name, attribute.value);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
186
185
|
};
|
|
187
186
|
|
|
188
187
|
/**
|
|
@@ -192,117 +191,117 @@ export const diffAttributes = function (templateElement, domElement) {
|
|
|
192
191
|
* @param {(Node) => Boolean} shouldDiffChildNodes
|
|
193
192
|
*/
|
|
194
193
|
export const diffNodes = function (templateNode, domNode, shouldDiffChildNodes = (templateChildNode) => true) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
194
|
+
// If the DOM node should be empty, remove all child nodes
|
|
195
|
+
if (hasChildNodes(domNode) && !hasChildNodes(templateNode)) {
|
|
196
|
+
domNode.replaceChildren();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// If the DOM node is empty, but should have children, add child nodes from the template node
|
|
201
|
+
if (!hasChildNodes(domNode) && hasChildNodes(templateNode)) {
|
|
202
|
+
domNode.replaceChildren(...templateNode.childNodes);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const templateChildNodes = [...templateNode.childNodes];
|
|
207
|
+
const domChildNodes = [...domNode.childNodes];
|
|
208
|
+
|
|
209
|
+
// Diff each node in the child node lists
|
|
210
|
+
let length = Math.max(templateChildNodes.length, domChildNodes.length);
|
|
211
|
+
for (let index = 0; index < length; index++) {
|
|
212
|
+
const templateChildNode = templateChildNodes[index];
|
|
213
|
+
const domChildNode = domChildNodes[index];
|
|
214
|
+
|
|
215
|
+
// If the DOM node doesn't exist, append/copy the template node
|
|
216
|
+
if (!domChildNode) {
|
|
217
|
+
domNode.appendChild(templateChildNode);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// If the template node doesn't exist, remove the node in the DOM
|
|
222
|
+
if (!templateChildNode) {
|
|
223
|
+
domNode.removeChild(domChildNode);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// If DOM node is equal to the template node, don't do anything
|
|
228
|
+
if (domChildNode.isEqualNode(templateChildNode)) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// the following two checks don't have to be correct, but it could bring as back to the fast path
|
|
233
|
+
// in the worst case we still have to compare and swap all the elements
|
|
234
|
+
// but in the best case we find the one element that should actually be inserted or removed
|
|
235
|
+
// and from there on, every node that comes after should be equal again
|
|
236
|
+
|
|
237
|
+
// fast path for removing DOM nodes - we delete the node now instead of at the end
|
|
238
|
+
if (domNode.childNodes.length > templateNode.childNodes.length) {
|
|
239
|
+
domChildNodes.splice(index, 1);
|
|
240
|
+
domNode.removeChild(domChildNode);
|
|
241
|
+
// because domChildNodes will get shorter by splicing it, everything moves up by one
|
|
242
|
+
// so the (actual) next element will have the same index now as we currently have
|
|
243
|
+
// therefore we have to adjust our counters
|
|
244
|
+
length--;
|
|
245
|
+
index--;
|
|
246
|
+
|
|
247
|
+
// we might have corrected everything and the parent nodes could be equal again
|
|
248
|
+
// if so, we can skip the rest of the child node checks
|
|
249
|
+
if (domNode.childNodes.length === templateNode.childNodes.length && domNode.isEqualNode(templateNode)) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// fast path for adding DOM nodes - we insert the node now instead of at the end
|
|
257
|
+
// but NOT if we already are at the end of the list of child nodes
|
|
258
|
+
if (index !== domNode.childNodes.length - 1 && domNode.childNodes.length < templateNode.childNodes.length) {
|
|
259
|
+
domChildNodes.splice(index, 0, templateChildNode);
|
|
260
|
+
domNode.insertBefore(templateChildNode, domChildNode);
|
|
261
|
+
|
|
262
|
+
// we might have corrected everything and the parent nodes could be equal again
|
|
263
|
+
// if so, we can skip the rest of the child node checks
|
|
264
|
+
if (domNode.childNodes.length === templateNode.childNodes.length && domNode.isEqualNode(templateNode)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// If node types are not the same, replace the DOM node with the template node
|
|
272
|
+
if (templateChildNode.nodeType !== domChildNode.nodeType) {
|
|
273
|
+
domNode.replaceChild(templateChildNode, domChildNode);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// If the node is a Text node or a Comment node, update it
|
|
278
|
+
if (domChildNode.nodeType === TEXT_NODE || domChildNode.nodeType === COMMENT_NODE) {
|
|
279
|
+
domChildNode.textContent = templateChildNode.textContent;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// If the element tag names are not the same, replace the DOM node with the template node
|
|
284
|
+
if (templateChildNode.nodeType === ELEMENT_NODE && templateChildNode.tagName !== domChildNode.tagName) {
|
|
285
|
+
domNode.replaceChild(templateChildNode, domChildNode);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// If the node is an SVG element, don't even think about diffing it, just replace it
|
|
290
|
+
if (templateChildNode.nodeType === ELEMENT_NODE && templateChildNode.tagName === 'SVG') {
|
|
291
|
+
domNode.replaceChild(templateChildNode, domChildNode);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// If the node is an Element node, diff the attributes
|
|
296
|
+
if (templateChildNode.nodeType === ELEMENT_NODE) {
|
|
297
|
+
diffAttributes(templateChildNode, domChildNode);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// If there are child nodes, diff them recursively
|
|
301
|
+
if (templateChildNode.hasChildNodes()) {
|
|
302
|
+
if (shouldDiffChildNodes(templateChildNode)) {
|
|
303
|
+
diffNodes(templateChildNode, domChildNode);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
308
307
|
};
|
package/src/util/Directive.js
CHANGED
|
@@ -1,35 +1,42 @@
|
|
|
1
1
|
export class Directive {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/** @type {Element} */
|
|
3
|
+
node = undefined;
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @param {Node} node
|
|
7
|
+
*/
|
|
8
|
+
constructor(node) {
|
|
9
|
+
this.node = node;
|
|
10
|
+
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
/**
|
|
13
|
+
* @abstract
|
|
14
|
+
*/
|
|
15
|
+
update() {}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
// TODO: this is somewhat custom... maybe we could set the initial values in the constructor and then simply override the default toString() method?!
|
|
18
|
+
/**
|
|
19
|
+
* Implement the stringify method and return a string for rendering the directive in SSR mode
|
|
20
|
+
* @param {...any} values
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
stringify(...values) {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* @param {Class<Directive>} directiveClass
|
|
30
30
|
*/
|
|
31
31
|
export const defineDirective = (directiveClass) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
return (...values) => {
|
|
33
|
+
return {
|
|
34
|
+
directiveClass,
|
|
35
|
+
values,
|
|
36
|
+
toString: () => {
|
|
37
|
+
const directive = new directiveClass();
|
|
38
|
+
return directive.stringify(...values);
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
};
|
|
35
42
|
};
|
|
@@ -4,63 +4,70 @@ import { Store } from './Store.js';
|
|
|
4
4
|
* @property {CSSStyleSheet[]} cssStyleSheets
|
|
5
5
|
*/
|
|
6
6
|
class GlobalStylesStore extends Store {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/** @type {Map<Node, CSSStyleSheet>} */
|
|
8
|
+
globalStyleSheetsCache = new WeakMap();
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
constructor() {
|
|
11
|
+
super();
|
|
12
|
+
if (globalThis.elementJsConfig?.observeGlobalStyles) {
|
|
13
|
+
const mutationObserver = new MutationObserver((mutationRecord) => {
|
|
14
|
+
if (!mutationRecord[0]) return;
|
|
15
|
+
const filteredNodes = Array.from(mutationRecord[0].addedNodes).filter(
|
|
16
|
+
(node) => node.tagName === 'STYLE' || node.tagName === 'LINK',
|
|
17
|
+
);
|
|
18
|
+
if (filteredNodes && filteredNodes[0] && filteredNodes[0].tagName === 'LINK') {
|
|
19
|
+
filteredNodes[0].onload = () => {
|
|
20
|
+
this.requestUpdate();
|
|
21
|
+
};
|
|
22
|
+
} else if (filteredNodes && filteredNodes[0] && filteredNodes[0].tagName === 'STYLE') {
|
|
23
|
+
this.requestUpdate();
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
mutationObserver.observe(globalThis.document, { subtree: true, childList: true });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
getGlobalStyleSheets(selector) {
|
|
31
|
+
/** @type {CSSStyleSheet[]}*/
|
|
32
|
+
const cssStyleSheets = [];
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
if (selector === false) return cssStyleSheets;
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
if (typeof selector === 'string') {
|
|
37
|
+
selector = [selector];
|
|
38
|
+
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
if (selector === true || selector.includes('document')) {
|
|
41
|
+
cssStyleSheets.push(...globalThis.document?.adoptedStyleSheets);
|
|
42
|
+
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
Array.from(globalThis.document?.styleSheets).map((styleSheet) => {
|
|
45
|
+
if (Array.isArray(selector) && !selector.some((cssSelector) => styleSheet.ownerNode.matches(cssSelector))) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
49
|
+
// TODO: this will always be null as we never set anything to the cache...
|
|
50
|
+
let cssStyleSheet = this.globalStyleSheetsCache.get(styleSheet.ownerNode);
|
|
51
|
+
if (!cssStyleSheet) {
|
|
52
|
+
cssStyleSheet = new CSSStyleSheet();
|
|
53
|
+
if (styleSheet.ownerNode.tagName === 'STYLE') {
|
|
54
|
+
cssStyleSheet.replaceSync(styleSheet.ownerNode.textContent);
|
|
55
|
+
} else if (styleSheet.ownerNode.tagName === 'LINK') {
|
|
56
|
+
try {
|
|
57
|
+
Array.from(styleSheet?.cssRules ?? []).map((rule) => cssStyleSheet.insertRule(rule.cssText));
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.error(
|
|
60
|
+
'GlobalStylesStore: cannot read cssRules. Maybe add crossorigin="anonymous" to your style link?',
|
|
61
|
+
e,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
cssStyleSheets.push(cssStyleSheet);
|
|
67
|
+
});
|
|
61
68
|
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
return cssStyleSheets;
|
|
70
|
+
}
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
export const globalStylesStore = new GlobalStylesStore();
|