@webtides/element-js 1.0.0 → 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.
Files changed (41) hide show
  1. package/CHANGELOG.md +140 -90
  2. package/README.md +3 -3
  3. package/docs/README.md +70 -89
  4. package/docs/concepts/classes.md +37 -66
  5. package/docs/concepts/hierarchy.md +29 -31
  6. package/docs/concepts/lifecycle.md +9 -23
  7. package/docs/concepts/reactivity.md +1 -3
  8. package/docs/features/computed-properties.md +13 -16
  9. package/docs/features/dependency-injection-context-protocol.md +75 -87
  10. package/docs/features/global-styles.md +1 -1
  11. package/docs/features/methods.md +14 -15
  12. package/docs/features/properties.md +21 -33
  13. package/docs/features/refs.md +23 -31
  14. package/docs/features/renderless.md +31 -37
  15. package/docs/features/store.md +63 -78
  16. package/docs/features/templates.md +4 -1
  17. package/docs/features/watch.md +28 -35
  18. package/docs/getting-started/upgrade-to-v1.md +16 -0
  19. package/docs/guide/guide.md +10 -22
  20. package/index.js +29 -2
  21. package/package.json +62 -62
  22. package/src/BaseElement.js +631 -631
  23. package/src/StyledElement.js +104 -104
  24. package/src/TemplateElement.js +53 -53
  25. package/src/dom-parts/AttributePart.js +116 -116
  26. package/src/dom-parts/ChildNodePart.js +288 -288
  27. package/src/dom-parts/NodePart.js +27 -27
  28. package/src/dom-parts/Part.js +6 -6
  29. package/src/dom-parts/TemplatePart.js +119 -119
  30. package/src/dom-parts/TemplateResult.js +270 -270
  31. package/src/dom-parts/directives.js +105 -48
  32. package/src/dom-parts/html.js +1 -1
  33. package/src/dom-parts/render.js +6 -6
  34. package/src/util/AttributeParser.js +47 -47
  35. package/src/util/DOMHelper.js +190 -190
  36. package/src/util/Directive.js +31 -31
  37. package/src/util/GlobalStylesStore.js +56 -53
  38. package/src/util/SerializeStateHelper.js +56 -56
  39. package/src/util/Store.js +174 -174
  40. package/src/util/defineElement.js +5 -5
  41. package/src/util/toString.js +5 -5
@@ -5,34 +5,34 @@ import { isObjectLike } from '../util/AttributeParser.js';
5
5
  * For updating a directive on a node
6
6
  */
7
7
  export class NodePart extends Part {
8
- /** @type {Node} */
9
- node = undefined;
8
+ /** @type {Node} */
9
+ node = undefined;
10
10
 
11
- /** @type {Directive} */
12
- directive = undefined;
11
+ /** @type {Directive} */
12
+ directive = undefined;
13
13
 
14
- /**
15
- * @param {Node} node
16
- * @param {() => {}} initialValue
17
- */
18
- constructor(node, initialValue) {
19
- if (!isObjectLike(initialValue) && !initialValue.directiveClass) {
20
- throw new Error(
21
- 'NodePart: value is not a wrapped directive function. You must wrap you custom directive class with the defineDirective function.',
22
- );
23
- }
24
- super();
25
- node.__part = this; // add Part to comment node for debugging in the browser
26
- this.node = node.nextElementSibling;
27
- const { directiveClass, values } = initialValue;
28
- this.directive = new directiveClass(node.nextElementSibling);
29
- }
14
+ /**
15
+ * @param {Node} node
16
+ * @param {() => {}} initialValue
17
+ */
18
+ constructor(node, initialValue) {
19
+ if (!isObjectLike(initialValue) && !initialValue.directiveClass) {
20
+ throw new Error(
21
+ 'NodePart: value is not a wrapped directive function. You must wrap you custom directive class with the defineDirective function.',
22
+ );
23
+ }
24
+ super();
25
+ node.__part = this; // add Part to comment node for debugging in the browser
26
+ this.node = node.nextElementSibling;
27
+ const { directiveClass, values } = initialValue;
28
+ this.directive = new directiveClass(node.nextElementSibling);
29
+ }
30
30
 
31
- /**
32
- * @param {() => {}} value
33
- */
34
- update(value) {
35
- const { directiveClass, values } = value;
36
- this.directive.update(...values);
37
- }
31
+ /**
32
+ * @param {() => {}} value
33
+ */
34
+ update(value) {
35
+ const { directiveClass, values } = value;
36
+ this.directive.update(...values);
37
+ }
38
38
  }
@@ -2,11 +2,11 @@
2
2
  * @abstract
3
3
  */
4
4
  export class Part {
5
- processor = undefined;
5
+ processor = undefined;
6
6
 
7
- /**
8
- * @abstract
9
- * @param {TemplateResult | any[] | any} value
10
- */
11
- update(value) {}
7
+ /**
8
+ * @abstract
9
+ * @param {TemplateResult | any[] | any} value
10
+ */
11
+ update(value) {}
12
12
  }
@@ -12,123 +12,123 @@ const partsCache = new WeakMap();
12
12
  const fragmentsCache = new WeakMap();
13
13
 
14
14
  export class TemplatePart extends Part {
15
- /** @type {Part[]} */
16
- parts = [];
17
-
18
- /** @type {TemplateStringsArray} */
19
- strings = undefined;
20
-
21
- /** @type {Node[]} */
22
- childNodes = [];
23
-
24
- /**
25
- * @param {Node} startNode - the start comment marker node
26
- * @param {TemplateResult} value
27
- */
28
- constructor(startNode, value) {
29
- if (startNode && startNode?.nodeType !== COMMENT_NODE) {
30
- throw new Error('TemplatePart: startNode is not a comment node');
31
- }
32
-
33
- super();
34
-
35
- let serverSideRendered = false;
36
- if (startNode) {
37
- startNode.__part = this; // add Part to comment node for debugging in the browser
38
-
39
- const placeholder = startNode.data;
40
- const childNodes = [startNode];
41
- let childNode = startNode.nextSibling;
42
- while (childNode && childNode.data !== `/${placeholder}`) {
43
- childNodes.push(childNode);
44
- childNode = childNode.nextSibling;
45
- }
46
-
47
- const endNode = childNode;
48
- childNodes.push(endNode);
49
-
50
- // if not SSRed, childNodes will only ever have two comment nodes, the start and the end marker
51
- if (childNodes.length > 2) {
52
- serverSideRendered = true;
53
- this.childNodes = childNodes;
54
- }
55
- }
56
-
57
- this.parseValue(value);
58
-
59
- if (!serverSideRendered) {
60
- this.updateParts(value.values);
61
- // We need a childNodes list that is NOT live so that we don't loose elements when they get removed from the dom and we can (re)add them back in later.
62
- this.childNodes = [...this.childNodes];
63
- }
64
- }
65
-
66
- /**
67
- * @param {TemplateResult} value
68
- */
69
- update(value) {
70
- this.parseValue(value);
71
- this.updateParts(value.values);
72
- }
73
-
74
- /**
75
- * @param {any[]} values
76
- */
77
- updateParts(values) {
78
- for (let index = 0; index < values.length; index++) {
79
- this.parts[index]?.update(values[index]);
80
- }
81
- }
82
-
83
- /**
84
- * @param {TemplateResult} templateResult
85
- */
86
- parseValue(templateResult) {
87
- if (this.strings !== templateResult.strings) {
88
- if (this.childNodes.length === 0) {
89
- let fragment = fragmentsCache.get(templateResult.strings);
90
- if (!fragment) {
91
- fragment = this.parseFragment(templateResult);
92
- fragmentsCache.set(templateResult.strings, fragment);
93
- }
94
- const importedFragment = globalThis.document?.importNode(fragment, true);
95
- this.childNodes = importedFragment.childNodes;
96
- }
97
-
98
- let parts = partsCache.get(templateResult.strings);
99
- if (!parts) {
100
- parts = templateResult.parseParts(this.childNodes);
101
- partsCache.set(templateResult.strings, parts);
102
- }
103
-
104
- this.parts = parts
105
- .map((part) => {
106
- // We currently need the path because the fragment will be cloned via importNode and therefore the node will be a different one
107
- part.node = part.path.reduceRight(({ childNodes }, i) => childNodes[i], this);
108
- return part;
109
- })
110
- .map((part, index) => {
111
- if (part.type === 'node') {
112
- return new ChildNodePart(part.node, templateResult.values[index]);
113
- }
114
- if (part.type === 'attribute') {
115
- return new AttributePart(part.node, part.name, part.initialValue);
116
- }
117
- if (part.type === 'directive') {
118
- return new NodePart(part.node, templateResult.values[index]);
119
- }
120
- throw `cannot map part: ${part}`;
121
- });
122
- this.strings = templateResult.strings;
123
- }
124
- }
125
-
126
- /**
127
- * @param {TemplateResult} templateResult
128
- * @return {DocumentFragment}
129
- */
130
- parseFragment(templateResult) {
131
- const templateString = templateResult.templateString;
132
- return convertStringToTemplate(templateString);
133
- }
15
+ /** @type {Part[]} */
16
+ parts = [];
17
+
18
+ /** @type {TemplateStringsArray} */
19
+ strings = undefined;
20
+
21
+ /** @type {Node[]} */
22
+ childNodes = [];
23
+
24
+ /**
25
+ * @param {Node} startNode - the start comment marker node
26
+ * @param {TemplateResult} value
27
+ */
28
+ constructor(startNode, value) {
29
+ if (startNode && startNode?.nodeType !== COMMENT_NODE) {
30
+ throw new Error('TemplatePart: startNode is not a comment node');
31
+ }
32
+
33
+ super();
34
+
35
+ let serverSideRendered = false;
36
+ if (startNode) {
37
+ startNode.__part = this; // add Part to comment node for debugging in the browser
38
+
39
+ const placeholder = startNode.data;
40
+ const childNodes = [startNode];
41
+ let childNode = startNode.nextSibling;
42
+ while (childNode && childNode.data !== `/${placeholder}`) {
43
+ childNodes.push(childNode);
44
+ childNode = childNode.nextSibling;
45
+ }
46
+
47
+ const endNode = childNode;
48
+ childNodes.push(endNode);
49
+
50
+ // if not SSRed, childNodes will only ever have two comment nodes, the start and the end marker
51
+ if (childNodes.length > 2) {
52
+ serverSideRendered = true;
53
+ this.childNodes = childNodes;
54
+ }
55
+ }
56
+
57
+ this.parseValue(value);
58
+
59
+ if (!serverSideRendered) {
60
+ this.updateParts(value.values);
61
+ // We need a childNodes list that is NOT live so that we don't loose elements when they get removed from the dom and we can (re)add them back in later.
62
+ this.childNodes = [...this.childNodes];
63
+ }
64
+ }
65
+
66
+ /**
67
+ * @param {TemplateResult} value
68
+ */
69
+ update(value) {
70
+ this.parseValue(value);
71
+ this.updateParts(value.values);
72
+ }
73
+
74
+ /**
75
+ * @param {any[]} values
76
+ */
77
+ updateParts(values) {
78
+ for (let index = 0; index < values.length; index++) {
79
+ this.parts[index]?.update(values[index]);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @param {TemplateResult} templateResult
85
+ */
86
+ parseValue(templateResult) {
87
+ if (this.strings !== templateResult.strings) {
88
+ if (this.childNodes.length === 0) {
89
+ let fragment = fragmentsCache.get(templateResult.strings);
90
+ if (!fragment) {
91
+ fragment = this.parseFragment(templateResult);
92
+ fragmentsCache.set(templateResult.strings, fragment);
93
+ }
94
+ const importedFragment = globalThis.document?.importNode(fragment, true);
95
+ this.childNodes = importedFragment.childNodes;
96
+ }
97
+
98
+ let parts = partsCache.get(templateResult.strings);
99
+ if (!parts) {
100
+ parts = templateResult.parseParts(this.childNodes);
101
+ partsCache.set(templateResult.strings, parts);
102
+ }
103
+
104
+ this.parts = parts
105
+ .map((part) => {
106
+ // We currently need the path because the fragment will be cloned via importNode and therefore the node will be a different one
107
+ part.node = part.path.reduceRight(({ childNodes }, i) => childNodes[i], this);
108
+ return part;
109
+ })
110
+ .map((part, index) => {
111
+ if (part.type === 'node') {
112
+ return new ChildNodePart(part.node, templateResult.values[index]);
113
+ }
114
+ if (part.type === 'attribute') {
115
+ return new AttributePart(part.node, part.name, part.initialValue);
116
+ }
117
+ if (part.type === 'directive') {
118
+ return new NodePart(part.node, templateResult.values[index]);
119
+ }
120
+ throw `cannot map part: ${part}`;
121
+ });
122
+ this.strings = templateResult.strings;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * @param {TemplateResult} templateResult
128
+ * @return {DocumentFragment}
129
+ */
130
+ parseFragment(templateResult) {
131
+ const templateString = templateResult.templateString;
132
+ return convertStringToTemplate(templateString);
133
+ }
134
134
  }