@webtides/element-js 0.7.3 → 1.0.0-alpha.2
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/README.md +2 -2
- package/dist/index.js +688 -969
- package/dist/index.js.map +4 -4
- package/index.js +2 -1
- package/package.json +16 -20
- package/src/BaseElement.js +102 -66
- package/src/StyledElement.js +34 -12
- package/src/TemplateElement.js +27 -7
- package/src/dom-parts/AttributePart.js +160 -0
- package/src/dom-parts/ChildNodePart.js +343 -0
- package/src/dom-parts/NodePart.js +37 -0
- package/src/dom-parts/Part.js +12 -0
- package/src/dom-parts/TemplatePart.js +140 -0
- package/src/dom-parts/TemplateResult.js +332 -0
- package/src/dom-parts/directives.js +109 -0
- package/src/dom-parts/html.js +12 -0
- package/src/dom-parts/render.js +10 -0
- package/src/util/AttributeParser.js +62 -29
- package/src/util/DOMHelper.js +247 -5
- package/src/util/Directive.js +35 -0
- package/src/util/Store.js +25 -4
- package/src/util/defineElement.js +2 -2
- package/src/util/i18n.js +3 -3
- package/src/util/toString.js +2 -2
- package/CHANGELOG.md +0 -142
- package/src/renderer/vanilla/TemplateElement.js +0 -50
- package/src/renderer/vanilla/index.js +0 -18
- package/src/renderer/vanilla/util/directives.js +0 -78
- package/src/renderer/vanilla/util/html.js +0 -65
- package/src/renderer/vanilla/util/render.js +0 -149
package/index.js
CHANGED
|
@@ -5,5 +5,6 @@ import { toString } from './src/util/toString.js';
|
|
|
5
5
|
import { defineElement } from './src/util/defineElement.js';
|
|
6
6
|
import { i18n } from './src/util/i18n.js';
|
|
7
7
|
import { Store } from './src/util/Store.js';
|
|
8
|
+
import { Directive } from './src/util/Directive.js';
|
|
8
9
|
|
|
9
|
-
export { BaseElement, StyledElement, TemplateElement, Store, html, toString, defineElement, i18n };
|
|
10
|
+
export { BaseElement, StyledElement, TemplateElement, Store, Directive, html, toString, defineElement, i18n };
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webtides/element-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-alpha.2",
|
|
4
4
|
"module": "index.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"files": [
|
|
7
8
|
"/dist",
|
|
8
9
|
"/src",
|
|
@@ -16,12 +17,7 @@
|
|
|
16
17
|
},
|
|
17
18
|
"./src/*": "./src/*.js",
|
|
18
19
|
"./src/util/*": "./src/util/*.js",
|
|
19
|
-
"./src/
|
|
20
|
-
"./src/renderer/vanilla/TemplateElement": "./src/renderer/vanilla/TemplateElement.js",
|
|
21
|
-
"./src/renderer/vanilla/util/*": "./src/renderer/vanilla/util/*.js",
|
|
22
|
-
"./src/renderer/vanilla/util/directives.js": "./src/renderer/vanilla/util/directives.js",
|
|
23
|
-
"./src/renderer/vanilla/util/html.js": "./src/renderer/vanilla/util/html.js",
|
|
24
|
-
"./src/renderer/vanilla/util/render.js": "./src/renderer/vanilla/util/render.js"
|
|
20
|
+
"./src/dom-parts/*": "./src/dom-parts/*.js"
|
|
25
21
|
},
|
|
26
22
|
"repository": "https://github.com/webtides/element-js.git",
|
|
27
23
|
"author": "@webtides",
|
|
@@ -37,23 +33,23 @@
|
|
|
37
33
|
"element-js",
|
|
38
34
|
"shadow-dom"
|
|
39
35
|
],
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"lit-html": "^1.2.1"
|
|
42
|
-
},
|
|
36
|
+
"dependencies": {},
|
|
43
37
|
"devDependencies": {
|
|
44
|
-
"@
|
|
38
|
+
"@babel/eslint-parser": "^7.18.9",
|
|
39
|
+
"@open-wc/testing": "^3.1.6",
|
|
45
40
|
"@web/dev-server": "^0.1.30",
|
|
46
|
-
"@web/test-runner": "^0.
|
|
41
|
+
"@web/test-runner": "^0.14.0",
|
|
47
42
|
"babel-eslint": "^10.1.0",
|
|
48
43
|
"babel-plugin-module-resolver": "^5.0.0",
|
|
49
44
|
"deepmerge": "^4.2.2",
|
|
50
|
-
"esbuild": "^0.
|
|
51
|
-
"eslint": "
|
|
52
|
-
"eslint-config-prettier": "^
|
|
53
|
-
"eslint-plugin-
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
45
|
+
"esbuild": "^0.15.5",
|
|
46
|
+
"eslint": "8.22.0",
|
|
47
|
+
"eslint-config-prettier": "^7.2.0",
|
|
48
|
+
"eslint-plugin-import": "^2.26.0",
|
|
49
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
50
|
+
"husky": "^8.0.1",
|
|
51
|
+
"lint-staged": "^13.0.3",
|
|
52
|
+
"prettier": "^2.7.1"
|
|
57
53
|
},
|
|
58
54
|
"lint-staged": {
|
|
59
55
|
"*.{js,json}": [
|
|
@@ -62,7 +58,7 @@
|
|
|
62
58
|
]
|
|
63
59
|
},
|
|
64
60
|
"scripts": {
|
|
65
|
-
"lint": "eslint src/**/*.js",
|
|
61
|
+
"lint": "eslint index.js 'src/**/*.js'",
|
|
66
62
|
"prepare": "esbuild index.js --outfile=dist/index.js --bundle --format=esm --sourcemap --target=chrome79,firefox68,safari12,edge79",
|
|
67
63
|
"test": "web-test-runner test/**/*.test.{html,js} --node-resolve",
|
|
68
64
|
"test:coverage": "web-test-runner test/**/*.test.{html,js} --node-resolve --coverage",
|
package/src/BaseElement.js
CHANGED
|
@@ -5,7 +5,44 @@ import { Store } from './util/Store.js';
|
|
|
5
5
|
export { defineElement } from './util/defineElement.js';
|
|
6
6
|
export { toString } from './util/toString.js';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Options object for the BaseElement
|
|
10
|
+
* @typedef {Object} BaseElementOptions
|
|
11
|
+
* @property {boolean} [autoUpdate] - When set to true the element will call the requestUpdate() method on the instance every time a property or attribute was changed. This will re-evaluate everything on the element and trigger a re-render (if a template is provided) and trigger the watchers for the affected properties/attributes. Default is `true`
|
|
12
|
+
* @property {boolean} [deferUpdate] - When set to true the element will not call the requestUpdate() method upon connecting and therefore will not render (if template was provided) initially. Default is `true`
|
|
13
|
+
* @property {MutationObserverOptions} [mutationObserverOptions]
|
|
14
|
+
* @property {PropertyOptions} [propertyOptions]
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Options object for the BaseElement mutationObserverOptions option
|
|
19
|
+
* @typedef {Object} MutationObserverOptions
|
|
20
|
+
* @property {boolean} [childList] - When childList is set to true the element will also call the requestUpdate method for childList modifications (eg. Adding or removing child elements). Default is `true`
|
|
21
|
+
* @property {boolean} [subtree] - Please note that observing subtree mutations might have performance implications and use it only if necessary. Default is `false`
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options object for the BaseElement propertyOptions option
|
|
26
|
+
* @typedef {Object} PropertyOptions
|
|
27
|
+
* @property {undefined | boolean | function} [reflect] - When set to true the element will reflect property changes back to attributes if the attribute was not present when connecting the element. By default, all attributes that are present when connecting the element will be reflected anyway. Default is `undefined`
|
|
28
|
+
* @property {undefined | boolean | function} [parse] - When set to false the element will not automatically try to parse the attributes string value to a complex type (number, array, object). Default is `undefined`
|
|
29
|
+
* @property {undefined | boolean | function} [notify] - When set to true the element will dispatch CustomEvents for every property/attribute change. The event name will be the property name all lowercase and camel to dashes with a postfix of -changed. Default is `undefined`
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options object for updating properties
|
|
34
|
+
* @typedef {Object} PropertyUpdateOptions
|
|
35
|
+
* @property {boolean} [notify] - Whether the update should trigger the lifecycle methods. The default is `true`
|
|
36
|
+
* @property {string} property - The property name
|
|
37
|
+
* @property {any} newValue - The new value for the property
|
|
38
|
+
* @property {string} newValueString - The new value as `string` for the property (for comparison reasons)
|
|
39
|
+
* @property {any} oldValue - The old value for the property
|
|
40
|
+
*/
|
|
41
|
+
|
|
8
42
|
class BaseElement extends HTMLElement {
|
|
43
|
+
/**
|
|
44
|
+
* @param {BaseElementOptions} options
|
|
45
|
+
*/
|
|
9
46
|
constructor(options = {}) {
|
|
10
47
|
super();
|
|
11
48
|
this.$refs = {};
|
|
@@ -26,15 +63,13 @@ class BaseElement extends HTMLElement {
|
|
|
26
63
|
propertyOptions: {},
|
|
27
64
|
...options,
|
|
28
65
|
};
|
|
29
|
-
|
|
30
|
-
if (options.childListUpdate !== undefined && options.childListUpdate !== null) {
|
|
31
|
-
this._options.mutationObserverOptions.childList = options.childListUpdate;
|
|
32
|
-
console.warn(
|
|
33
|
-
`[${this.localName}] Using the "childListUpdate" option is deprecated and will be removed before 1.0! Please use the "mutationObserverOptions" dictionary instead. See the docs for more info`,
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
66
|
}
|
|
37
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Overrides the native `connectedCallback` of the HTMLElement to set up and initialize our element.
|
|
70
|
+
* This will define the attributes and properties as reactive getters and setter,
|
|
71
|
+
* register observers, refs and events.
|
|
72
|
+
*/
|
|
38
73
|
connectedCallback() {
|
|
39
74
|
// define all attributes to "this" as properties
|
|
40
75
|
this.defineAttributesAsProperties();
|
|
@@ -42,9 +77,6 @@ class BaseElement extends HTMLElement {
|
|
|
42
77
|
// define all properties to "this"
|
|
43
78
|
this.defineProperties();
|
|
44
79
|
|
|
45
|
-
// define all computed properties to "this"
|
|
46
|
-
this.defineComputedProperties();
|
|
47
|
-
|
|
48
80
|
// define context
|
|
49
81
|
this.definePropertyInjection();
|
|
50
82
|
|
|
@@ -52,17 +84,21 @@ class BaseElement extends HTMLElement {
|
|
|
52
84
|
this.defineObserver();
|
|
53
85
|
|
|
54
86
|
if (this.hasAttribute('defer-update') || this._options.deferUpdate) {
|
|
55
|
-
// don't
|
|
87
|
+
// don't update/render, but register refs and events
|
|
56
88
|
this.registerEventsAndRefs();
|
|
57
89
|
|
|
58
90
|
this.triggerHook('connected');
|
|
59
91
|
} else {
|
|
60
92
|
this.requestUpdate({ notify: false }).then(() => {
|
|
61
93
|
this.triggerHook('connected');
|
|
94
|
+
this.triggerHook('afterUpdate');
|
|
62
95
|
});
|
|
63
96
|
}
|
|
64
97
|
}
|
|
65
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Define a MutationObserver on the element to get notified on attribute changes and childList updates according to the options specified via the constructor options.
|
|
101
|
+
*/
|
|
66
102
|
defineObserver() {
|
|
67
103
|
// see: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#Example_usage
|
|
68
104
|
this._mutationObserver = new MutationObserver((mutations) => {
|
|
@@ -95,6 +131,9 @@ class BaseElement extends HTMLElement {
|
|
|
95
131
|
});
|
|
96
132
|
}
|
|
97
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Native `disconnectedCallback` of the HTMLElement
|
|
136
|
+
*/
|
|
98
137
|
disconnectedCallback() {
|
|
99
138
|
// remove events for elements in the component
|
|
100
139
|
this.removeEvents();
|
|
@@ -116,6 +155,11 @@ class BaseElement extends HTMLElement {
|
|
|
116
155
|
this.triggerHook('disconnected');
|
|
117
156
|
}
|
|
118
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Request and batch an asynchronous update cycle
|
|
160
|
+
* @param {PropertyUpdateOptions} options
|
|
161
|
+
* @returns {Promise<unknown>}
|
|
162
|
+
*/
|
|
119
163
|
requestUpdate(options = { notify: true }) {
|
|
120
164
|
if (options.notify === true) {
|
|
121
165
|
this.triggerHook('beforeUpdate');
|
|
@@ -145,6 +189,7 @@ class BaseElement extends HTMLElement {
|
|
|
145
189
|
* This should be called by the template component AFTER adding the template to
|
|
146
190
|
* the DOM.
|
|
147
191
|
* Here we will register the events and the refs for the element.
|
|
192
|
+
* @param {PropertyUpdateOptions} options
|
|
148
193
|
*/
|
|
149
194
|
update(options = { notify: true }) {
|
|
150
195
|
this.registerEventsAndRefs();
|
|
@@ -211,6 +256,9 @@ class BaseElement extends HTMLElement {
|
|
|
211
256
|
* Define a property on the element
|
|
212
257
|
* Will trigger watch() function when a property was changed
|
|
213
258
|
* Will trigger update() when a property was changed
|
|
259
|
+
* @param {string} property
|
|
260
|
+
* @param {any} value
|
|
261
|
+
* @param {boolean} reflectAttribute
|
|
214
262
|
*/
|
|
215
263
|
defineProperty(property, value, reflectAttribute = false) {
|
|
216
264
|
if (value instanceof Store) {
|
|
@@ -274,12 +322,10 @@ class BaseElement extends HTMLElement {
|
|
|
274
322
|
}
|
|
275
323
|
|
|
276
324
|
/**
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* @param
|
|
280
|
-
* @param
|
|
281
|
-
* @param newValue
|
|
282
|
-
* @param oldValue
|
|
325
|
+
* Call the watch callbacks on property changes
|
|
326
|
+
* @param {string} property property that changes
|
|
327
|
+
* @param {any} newValue
|
|
328
|
+
* @param {any} oldValue
|
|
283
329
|
*/
|
|
284
330
|
callPropertyWatcher(property, newValue, oldValue) {
|
|
285
331
|
// notify watched properties (after update())
|
|
@@ -288,12 +334,11 @@ class BaseElement extends HTMLElement {
|
|
|
288
334
|
watch[property](newValue, oldValue);
|
|
289
335
|
}
|
|
290
336
|
}
|
|
337
|
+
|
|
291
338
|
/**
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* @param
|
|
295
|
-
* @param property property that changes
|
|
296
|
-
* @param newValue
|
|
339
|
+
* Notify property observer via change event
|
|
340
|
+
* @param {string} property property that changes
|
|
341
|
+
* @param {any} newValue
|
|
297
342
|
*/
|
|
298
343
|
notifyPropertyChange(property, newValue) {
|
|
299
344
|
// dispatch change event
|
|
@@ -305,6 +350,10 @@ class BaseElement extends HTMLElement {
|
|
|
305
350
|
}
|
|
306
351
|
}
|
|
307
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Reflects a property as attribute on the element
|
|
355
|
+
* @param {PropertyUpdateOptions} options
|
|
356
|
+
*/
|
|
308
357
|
reflectProperty(options) {
|
|
309
358
|
const { property, newValue } = options;
|
|
310
359
|
const newValueString = options.newValueString || JSON.stringify(newValue);
|
|
@@ -353,9 +402,8 @@ class BaseElement extends HTMLElement {
|
|
|
353
402
|
|
|
354
403
|
/**
|
|
355
404
|
* Helper Function to initialize the context requests
|
|
356
|
-
*
|
|
357
|
-
* @param
|
|
358
|
-
* @param valueOrCallback
|
|
405
|
+
* @param {string} propertyName
|
|
406
|
+
* @param {any | function} valueOrCallback
|
|
359
407
|
*/
|
|
360
408
|
requestContext(propertyName, valueOrCallback) {
|
|
361
409
|
this.dispatch('request-context', { [propertyName]: valueOrCallback }, true);
|
|
@@ -365,8 +413,7 @@ class BaseElement extends HTMLElement {
|
|
|
365
413
|
* Internal Context Request Handler
|
|
366
414
|
* This will check if the current/receiving instance actually provides a value under the requested name.
|
|
367
415
|
* If there is something to provide it will either assign the value to the requesting element or call the callback.
|
|
368
|
-
*
|
|
369
|
-
* @param event
|
|
416
|
+
* @param {CustomEvent} event
|
|
370
417
|
*/
|
|
371
418
|
onRequestContext(event) {
|
|
372
419
|
const properties = this.properties();
|
|
@@ -388,33 +435,31 @@ class BaseElement extends HTMLElement {
|
|
|
388
435
|
});
|
|
389
436
|
}
|
|
390
437
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Connected lifecycle hook
|
|
438
|
+
/**
|
|
439
|
+
* Connected lifecycle hook
|
|
440
|
+
*/
|
|
397
441
|
connected() {}
|
|
398
442
|
|
|
399
|
-
|
|
443
|
+
/**
|
|
444
|
+
* BeforeUpdate lifecycle hook
|
|
445
|
+
*/
|
|
400
446
|
beforeUpdate() {}
|
|
401
447
|
|
|
402
|
-
|
|
448
|
+
/**
|
|
449
|
+
* AfterUpdate lifecycle hook
|
|
450
|
+
*/
|
|
403
451
|
afterUpdate() {}
|
|
404
452
|
|
|
405
|
-
|
|
453
|
+
/**
|
|
454
|
+
* Disconnected lifecycle hook
|
|
455
|
+
*/
|
|
406
456
|
disconnected() {}
|
|
407
457
|
|
|
408
|
-
|
|
458
|
+
/**
|
|
459
|
+
* Triggers a lifecycle hook based on the name
|
|
460
|
+
* @param {string} name
|
|
461
|
+
*/
|
|
409
462
|
triggerHook(name) {
|
|
410
|
-
if (this.hooks && name in this.hooks()) {
|
|
411
|
-
console.warn(
|
|
412
|
-
`[${this.localName}] Using the hooks() map for lifecycle hooks is deprecated! Please overwrite the existing lifecycle hook functions. See the docs for more info`,
|
|
413
|
-
);
|
|
414
|
-
this.hooks()[name]();
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
463
|
if (name in this) {
|
|
419
464
|
this[name]();
|
|
420
465
|
}
|
|
@@ -431,25 +476,6 @@ class BaseElement extends HTMLElement {
|
|
|
431
476
|
return {};
|
|
432
477
|
}
|
|
433
478
|
|
|
434
|
-
// Deprecated
|
|
435
|
-
computed() {
|
|
436
|
-
return {};
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Deprecated
|
|
440
|
-
defineComputedProperties() {
|
|
441
|
-
Object.keys(this.computed()).forEach((prop) => {
|
|
442
|
-
if (!this.hasOwnProperty(prop)) {
|
|
443
|
-
console.warn(
|
|
444
|
-
`[${this.localName}] Using the computed() map for computed properties is deprecated! Please use regular JS getters and return the computed value. See the docs for more info`,
|
|
445
|
-
);
|
|
446
|
-
Object.defineProperty(this, prop, {
|
|
447
|
-
get: () => this.computed()[prop](),
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
|
|
453
479
|
/**
|
|
454
480
|
* Return a map of events that should be registered on the element.
|
|
455
481
|
* eg. { '.link': {
|
|
@@ -542,7 +568,14 @@ class BaseElement extends HTMLElement {
|
|
|
542
568
|
this.$refs = refsMap;
|
|
543
569
|
}
|
|
544
570
|
|
|
545
|
-
|
|
571
|
+
/**
|
|
572
|
+
* Helper function for dispatching custom events
|
|
573
|
+
* @param {string} name
|
|
574
|
+
* @param {Object} data
|
|
575
|
+
* @param {boolean} bubble
|
|
576
|
+
* @param {boolean} cancelable
|
|
577
|
+
* @param {boolean} composed
|
|
578
|
+
*/
|
|
546
579
|
dispatch(name, data, bubble = false, cancelable = false, composed = false) {
|
|
547
580
|
const event = new CustomEvent(name, {
|
|
548
581
|
bubbles: bubble,
|
|
@@ -553,7 +586,10 @@ class BaseElement extends HTMLElement {
|
|
|
553
586
|
this.dispatchEvent(event);
|
|
554
587
|
}
|
|
555
588
|
|
|
556
|
-
|
|
589
|
+
/**
|
|
590
|
+
* Get the root element
|
|
591
|
+
* @returns {HTMLElement}
|
|
592
|
+
*/
|
|
557
593
|
getRoot() {
|
|
558
594
|
return this;
|
|
559
595
|
}
|
package/src/StyledElement.js
CHANGED
|
@@ -2,13 +2,22 @@ import { BaseElement } from './BaseElement.js';
|
|
|
2
2
|
import { supportsAdoptingStyleSheets, getShadowParentOrBody } from './util/DOMHelper.js';
|
|
3
3
|
export { i18n } from './util/i18n.js';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Options object for the StyledElement
|
|
7
|
+
* @typedef {Object} StyledElementOptions
|
|
8
|
+
* @extends BaseElementOptions
|
|
9
|
+
* @property {boolean} [shadowRender] - When set to true the element will render the template (if provided) in the Shadow DOM and therefore encapsulate the element and styles from the rest of the document. Default is `false`
|
|
10
|
+
* @property {[]} [styles] - Via the styles option you can add multiple styles/stylesheets to your element. Default is `[]`
|
|
11
|
+
* @property {boolean} [adoptGlobalStyles] - When set to true element-js will look for a style element in the global document with an id of "globalStyles" and apply it before any custom/element styles inside the shadow DOM. Default is `true`
|
|
12
|
+
*/
|
|
13
|
+
|
|
5
14
|
class StyledElement extends BaseElement {
|
|
6
15
|
static globalStyles = null;
|
|
7
16
|
|
|
8
17
|
static updateGlobalStyles() {
|
|
9
18
|
// this is a runtime dependency so that every shadow dom can make use of global css
|
|
10
19
|
// we assume these styles to be inlined into the document
|
|
11
|
-
StyledElement.globalStyles = document
|
|
20
|
+
StyledElement.globalStyles = globalThis.document?.getElementById('globalStyles');
|
|
12
21
|
|
|
13
22
|
if (StyledElement.globalStyles && StyledElement['globalStyleSheet']) {
|
|
14
23
|
//updates already adopted global styles
|
|
@@ -16,6 +25,9 @@ class StyledElement extends BaseElement {
|
|
|
16
25
|
}
|
|
17
26
|
}
|
|
18
27
|
|
|
28
|
+
/**
|
|
29
|
+
* @param {StyledElementOptions} options
|
|
30
|
+
*/
|
|
19
31
|
constructor(options) {
|
|
20
32
|
super({
|
|
21
33
|
deferUpdate: false,
|
|
@@ -27,32 +39,36 @@ class StyledElement extends BaseElement {
|
|
|
27
39
|
this._styles = [...this._options.styles, ...this.styles()];
|
|
28
40
|
}
|
|
29
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Overrides the `connectedCallback` to adopt optional styles when the element is connected
|
|
44
|
+
*/
|
|
30
45
|
connectedCallback() {
|
|
31
46
|
super.connectedCallback();
|
|
32
47
|
|
|
33
48
|
if (supportsAdoptingStyleSheets() && this._options.shadowRender) {
|
|
34
49
|
// adopting does only make sense in shadow dom. Fall back to append for light elements
|
|
35
50
|
this.adoptStyleSheets();
|
|
36
|
-
} else if (this._options.shadowRender && window.ShadyCSS !== undefined) {
|
|
37
|
-
// if shadowRoot is polyfilled we use ShadyCSS to copy scoped styles to <head>
|
|
38
|
-
window.ShadyCSS.ScopingShim.prepareAdoptedCssText(this._styles, this.localName);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// if shadowRoot is polyfilled - scope element template
|
|
42
|
-
if (window.ShadyCSS !== undefined) {
|
|
43
|
-
window.ShadyCSS.styleElement(this);
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
|
|
54
|
+
/**
|
|
55
|
+
* The styles method is another way to return a list of styles to be adopted when the element is connected.
|
|
56
|
+
* You can either provide a list in the constructor options or return it here.
|
|
57
|
+
* @returns {string[]}
|
|
58
|
+
*/
|
|
47
59
|
styles() {
|
|
48
60
|
return [];
|
|
49
61
|
}
|
|
50
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Overrides the `update` method to adopt optional styles
|
|
65
|
+
* @param {PropertyUpdateOptions} options
|
|
66
|
+
*/
|
|
51
67
|
update(options) {
|
|
52
68
|
if (!supportsAdoptingStyleSheets() || this._options.shadowRender === false) {
|
|
53
69
|
// append stylesheets to template if not already adopted
|
|
54
70
|
const appendableStyles = [...this._styles];
|
|
55
|
-
if (this._options.shadowRender && this._options.adoptGlobalStyles
|
|
71
|
+
if (this._options.shadowRender && this._options.adoptGlobalStyles) {
|
|
56
72
|
appendableStyles.unshift(StyledElement.globalStyles?.textContent ?? '');
|
|
57
73
|
}
|
|
58
74
|
this.appendStyleSheets(appendableStyles);
|
|
@@ -60,6 +76,9 @@ class StyledElement extends BaseElement {
|
|
|
60
76
|
super.update(options);
|
|
61
77
|
}
|
|
62
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Adopt stylesheets
|
|
81
|
+
*/
|
|
63
82
|
adoptStyleSheets() {
|
|
64
83
|
if (!this.constructor['cssStyleSheets']) {
|
|
65
84
|
this.constructor['cssStyleSheets'] = this._styles.map((style) => {
|
|
@@ -87,7 +106,10 @@ class StyledElement extends BaseElement {
|
|
|
87
106
|
];
|
|
88
107
|
}
|
|
89
108
|
|
|
90
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Custom polyfill for constructable stylesheets by appending styles to the end of an element
|
|
111
|
+
* @param {string[]} styles
|
|
112
|
+
*/
|
|
91
113
|
appendStyleSheets(styles) {
|
|
92
114
|
const parentDocument = getShadowParentOrBody(this.getRoot());
|
|
93
115
|
styles.forEach((style, index) => {
|
|
@@ -95,7 +117,7 @@ class StyledElement extends BaseElement {
|
|
|
95
117
|
|
|
96
118
|
// only append stylesheet if not already appended to shadowRoot or document
|
|
97
119
|
if (!parentDocument.querySelector(`#${identifier}`)) {
|
|
98
|
-
const styleElement = document
|
|
120
|
+
const styleElement = globalThis.document?.createElement('style');
|
|
99
121
|
styleElement.id = identifier;
|
|
100
122
|
styleElement.style.display = 'none';
|
|
101
123
|
styleElement.textContent = style;
|
package/src/TemplateElement.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { StyledElement } from './StyledElement.js';
|
|
2
|
-
import { html } from '
|
|
3
|
-
import { render } from '
|
|
2
|
+
import { html } from './dom-parts/html.js';
|
|
3
|
+
import { render } from './dom-parts/render.js';
|
|
4
4
|
export { i18n } from './util/i18n.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Options object for the TemplateElement
|
|
8
|
+
* @typedef {Object} TemplateElementOptions
|
|
9
|
+
* @extends StyledElementOptions
|
|
10
|
+
*/
|
|
11
|
+
|
|
6
12
|
class TemplateElement extends StyledElement {
|
|
13
|
+
/**
|
|
14
|
+
* @param {TemplateElementOptions} options
|
|
15
|
+
*/
|
|
7
16
|
constructor(options) {
|
|
8
17
|
super({
|
|
9
18
|
deferUpdate: false,
|
|
@@ -20,29 +29,40 @@ class TemplateElement extends StyledElement {
|
|
|
20
29
|
if (this._options.shadowRender) this.attachShadow({ mode: 'open' });
|
|
21
30
|
}
|
|
22
31
|
|
|
32
|
+
/**
|
|
33
|
+
* The template method should be overridden in extending elements and return the template to be rendered to the root
|
|
34
|
+
* @returns {TemplateResult}
|
|
35
|
+
*/
|
|
23
36
|
template() {
|
|
24
37
|
return html``;
|
|
25
38
|
}
|
|
26
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Override update method to render the template to the root
|
|
42
|
+
* @param {PropertyUpdateOptions} options
|
|
43
|
+
*/
|
|
27
44
|
update(options) {
|
|
28
45
|
this.renderTemplate();
|
|
29
46
|
super.update(options);
|
|
30
47
|
}
|
|
31
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Render the template to the root
|
|
51
|
+
*/
|
|
32
52
|
renderTemplate() {
|
|
33
53
|
const template = this._template || this.template();
|
|
34
54
|
if (typeof template === 'string') {
|
|
35
55
|
// just a plain string literal. no lit-html required
|
|
36
56
|
this.getRoot().innerHTML = `${template}`;
|
|
37
57
|
} else {
|
|
38
|
-
|
|
39
|
-
render(html` ${template} `, this.getRoot(), {
|
|
40
|
-
scopeName: this.localName,
|
|
41
|
-
eventContext: this,
|
|
42
|
-
});
|
|
58
|
+
render(template, this.getRoot());
|
|
43
59
|
}
|
|
44
60
|
}
|
|
45
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Get the root element - either the element or the shadow root
|
|
64
|
+
* @returns {ShadowRoot | HTMLElement}
|
|
65
|
+
*/
|
|
46
66
|
getRoot() {
|
|
47
67
|
return this.shadowRoot !== null ? this.shadowRoot : this;
|
|
48
68
|
}
|