@webtides/element-js 1.0.0-alpha.1 → 1.0.0-alpha.10

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 (42) hide show
  1. package/docs/README.md +174 -0
  2. package/docs/concepts/classes.md +167 -0
  3. package/docs/concepts/hierarchy.md +61 -0
  4. package/docs/concepts/lifecycle.md +45 -0
  5. package/docs/concepts/reactivity.md +14 -0
  6. package/docs/features/computed-properties.md +28 -0
  7. package/docs/features/dependency-injection-context-protocol.md +132 -0
  8. package/docs/features/events.md +155 -0
  9. package/docs/features/global-styles.md +131 -0
  10. package/docs/features/methods.md +34 -0
  11. package/docs/features/properties.md +56 -0
  12. package/docs/features/refs.md +47 -0
  13. package/docs/features/renderless.md +70 -0
  14. package/docs/features/store.md +143 -0
  15. package/docs/features/styles.md +169 -0
  16. package/docs/features/templates.md +308 -0
  17. package/docs/features/watch.md +54 -0
  18. package/docs/getting-started/upgrade-to-v1.md +243 -0
  19. package/docs/guide/guide.md +112 -0
  20. package/index.js +9 -2
  21. package/package.json +15 -19
  22. package/src/BaseElement.js +201 -42
  23. package/src/StyledElement.js +67 -48
  24. package/src/TemplateElement.js +31 -1
  25. package/src/dom-parts/AttributePart.js +16 -9
  26. package/src/dom-parts/ChildNodePart.js +8 -22
  27. package/src/dom-parts/NodePart.js +1 -0
  28. package/src/dom-parts/TemplatePart.js +19 -25
  29. package/src/dom-parts/TemplateResult.js +46 -35
  30. package/src/dom-parts/directives.js +43 -16
  31. package/src/dom-parts/html.js +1 -1
  32. package/src/util/AttributeParser.js +54 -21
  33. package/src/util/DOMHelper.js +63 -14
  34. package/src/util/Directive.js +21 -1
  35. package/src/util/GlobalStylesStore.js +66 -0
  36. package/src/util/SerializeStateHelper.js +103 -0
  37. package/src/util/Store.js +111 -15
  38. package/src/util/defineElement.js +2 -2
  39. package/src/util/toString.js +2 -2
  40. package/dist/index.js +0 -1330
  41. package/dist/index.js.map +0 -7
  42. package/src/util/i18n.js +0 -20
@@ -0,0 +1,243 @@
1
+ # Upgrade Guide
2
+
3
+ Upgrading from `element-js` v0.x to v1.0
4
+
5
+ ---
6
+
7
+ `element-js` v1.0 is the first major version since it was released in June 2020. The biggest change is a new and custom DOM Parts renderer that allows us to get rid of `lit-html` making it a dependency free library finally.
8
+
9
+ We only have a couple of breaking changes and a few removed deprecations. The deprecations have been logged to the console for a while now and we hope that most of them should not be there anymore. And the breaking changes should be mostly changed import paths. So it should only be a matter of copy and paste.
10
+
11
+ ---
12
+
13
+ ## Install element-js v1.0
14
+
15
+ Update `element-js` using npm:
16
+
17
+ ```
18
+ npm install element-js@latest
19
+ ```
20
+
21
+ ## Support for IE 11 has been dropped
22
+
23
+ Prior to v1.0, we tried our best to make sure features we included in `element-js` worked in IE 11 whenever possible. If you need to support IE 11, we recommend continuing to use `element-js` v0.x until you no longer need to support IE.
24
+
25
+ ## Added `afterUpdate` lifecycle hook upon connecting the elements
26
+
27
+ `element-js` will now also trigger the `afterUpdate` hook right after the `connected` hook. This is to reduce the cases where you had to do the same things in `connected` and `afterUpdate`. You can now remove those duplicate calls from the `connected` hook.
28
+
29
+ ## Change import paths for main exports
30
+
31
+ > This only applies if you used the vanilla renderer. For the default `lit-html` renderer you do not need to change the import paths.
32
+
33
+ Change everything that was imported from:
34
+
35
+ ```javascript
36
+ import { TemplateElement, html } from '@webtides/element-js/src/renderer/vanilla';
37
+ ```
38
+
39
+ to:
40
+
41
+ ```javascript
42
+ import { TemplateElement, html } from '@webtides/element-js';
43
+ ```
44
+
45
+ This must be done for the following classes and functions:
46
+
47
+ - BaseElement
48
+ - StyledElement
49
+ - TemplateElement
50
+ - Store
51
+ - html
52
+ - toString
53
+ - defineElement
54
+ - i18n
55
+
56
+ ## Change import paths for directives
57
+
58
+ If you used any directives you must change their import paths as well.
59
+
60
+ For the vanilla renderer we previously had them here:
61
+
62
+ ```javascript
63
+ import { unsafeHTML } from '@webtides/element-js/src/renderer/vanilla/util/directives.js';
64
+ ```
65
+
66
+ And for the `lit-html` renderer you had to import the directives from `lit`:
67
+
68
+ ```javascript
69
+ import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
70
+ ```
71
+
72
+ In both cases you must now change the imports to our new directives:
73
+
74
+ ```javascript
75
+ import { unsafeHTML } from '@webtides/element-js/src/dom-parts/directives';
76
+ ```
77
+
78
+ ## Removed childListUpdate option from constructor options
79
+
80
+ We removed the deprecated `BaseElement` constructor option `childListUpdate`. Please use the "mutationObserverOptions" dictionary instead.
81
+
82
+ Change:
83
+
84
+ ```javascript
85
+ class MyElement extends BaseElement {
86
+ constructor() {
87
+ super({ childListUpdate: true });
88
+ }
89
+ }
90
+ ```
91
+
92
+ to:
93
+
94
+ ```javascript
95
+ class MyElement extends BaseElement {
96
+ constructor() {
97
+ super({ mutationObserverOptions: { childList: true } });
98
+ }
99
+ }
100
+ ```
101
+
102
+ For more information on how to configure `mutationObserverOptions` see the docs.
103
+
104
+ ## Removed the `hooks` map
105
+
106
+ We removed the `hooks` map in the `BaseElement`. Using the hooks() map for lifecycle hooks is not possible anymore! Please overwrite the existing lifecycle hook functions. See the docs for more info.
107
+
108
+ Change:
109
+
110
+ ```javascript
111
+ class MyElement extends BaseElement {
112
+ hooks() {
113
+ return {
114
+ connected: () => {},
115
+ beforeUpdate: () => {},
116
+ afterUpdate: () => {}
117
+ };
118
+ }
119
+ }
120
+ ```
121
+
122
+ to:
123
+
124
+ ```javascript
125
+ class MyElement extends BaseElement {
126
+ connected() {}
127
+ beforeUpdate() {}
128
+ afterUpdate() {}
129
+ }
130
+ ```
131
+
132
+ ## Removed the `computed` map
133
+
134
+ We removed the `computed` map in the `BaseElement`. Using the computed() map for computed properties is is not possible anymore! Please use regular JS getters and return the computed value. See the docs for more info.
135
+
136
+ Change:
137
+
138
+ ```javascript
139
+ class MyElement extends BaseElement {
140
+ firstName = 'John';
141
+ lastName = 'Doe';
142
+
143
+ computed() {
144
+ return {
145
+ name: () => `${this.firstName} ${this.lastName}`
146
+ };
147
+ }
148
+ }
149
+ ```
150
+
151
+ to:
152
+
153
+ ```javascript
154
+ class MyElement extends BaseElement {
155
+ firstName = 'John';
156
+ lastName = 'Doe';
157
+
158
+ get name() {
159
+ return `${this.firstName} ${this.lastName}`;
160
+ }
161
+ }
162
+ ```
163
+
164
+ ## Removed the `i18n` helper function
165
+
166
+ We removed the `i18n` helper function. It was a very simple and naive implementation for translating strings in templates. We would recommend to use a more sophisticated i18n solution.
167
+
168
+ If you still need the same functionality, you can simply add the following function to your code and change the imports accordingly:
169
+
170
+ ```javascript
171
+ /**
172
+ * Retrieves a translated key from a dictionary on the window object
173
+ * Example: ${i18n('CustomElement.buttonLabel', 'Label')}
174
+ * @param {string} key - to be translated
175
+ * @param {string} fallback - to be used if key is not defined
176
+ * @return {string} - String of the translated key or fallback or original key
177
+ */
178
+ export function i18n(key, fallback) {
179
+ try {
180
+ const translations = window.elementjs.i18n();
181
+ if (translations[key] === undefined) {
182
+ throw 'Translation Missing';
183
+ }
184
+
185
+ return translations[key];
186
+ } catch (err) {
187
+ if (fallback) return fallback;
188
+ else return key;
189
+ }
190
+ }
191
+ ```
192
+
193
+ ## Changed default options for the `dispatch` helper function
194
+
195
+ We changed the default options when using the `dispatch` helper function. `bubbles`, `cancelable` and `composed` will now be `true` by default.
196
+
197
+ Also, we changed the parameter signature. Instead of expecting the tree boolean values as parameters after the data value, we now expect an `options` object that is in line with the `CustomEventInit` options for the `CustomEvent` class. This is not a breaking change, and we will still evaluate the old parameter list for now. It will finally be removed in v2.0.
198
+
199
+ We would recommend that you start using the new syntax. Change this:
200
+
201
+ ```javascript
202
+ this.dispatch('custom-event', 'foo', true, true, true);
203
+ ```
204
+
205
+ to (if you wanted every parameter to be `true` before):
206
+
207
+ ```javascript
208
+ this.dispatch('custom-event', 'foo');
209
+ ```
210
+
211
+ or this (if you had different option values):
212
+
213
+ ```javascript
214
+ this.dispatch('custom-event', 'foo', {
215
+ bubbles: true,
216
+ cancelable: false,
217
+ composed: true
218
+ });
219
+ ```
220
+
221
+ ## Changed adoptGlobalStyles
222
+
223
+ We changed adopting global styles to include ALL global styles now. Previously only one inline <style> with the ID of '#globalStyles' would be adopted. For more information see the docs. We think that this is the behaviour that one would actually want.
224
+
225
+ If you still need it to be the way it was before, please change the `adoptGlobalStyles` option value from:
226
+
227
+ ```javascript
228
+ export class ShadowElement extends TemplateElement {
229
+ constructor() {
230
+ super({ adoptGlobalStyles: true });
231
+ }
232
+ }
233
+ ```
234
+
235
+ to:
236
+
237
+ ```javascript
238
+ export class ShadowElement extends TemplateElement {
239
+ constructor() {
240
+ super({ adoptGlobalStyles: '#globalStyles' });
241
+ }
242
+ }
243
+ ```
@@ -0,0 +1,112 @@
1
+
2
+ ## Guides/Tooling
3
+
4
+ ### Frontend Stack
5
+
6
+ ### Bundling/Publishing
7
+
8
+ ### Design System
9
+
10
+ ### Style Guide / Best Practices
11
+
12
+ This is an element style guide created and enforced for the purpose of standardizing elements and file structures.
13
+
14
+ #### File structure
15
+
16
+ - One element per file.
17
+ - One element per directory. Though it may make sense to group similar elements into the same directory, we've found it'
18
+ s easier to consume and document elements when each one has its own directory.
19
+ - Implementation (.js) and styles (.css) of an element should live in the same directory.
20
+
21
+ Example:
22
+
23
+ ```
24
+ ├── card-element
25
+ │ ├── card-element.css
26
+ │ ├── card-element.js
27
+ │ └── test
28
+ │ ├── card-element.e2e.js
29
+ │ └── card-element.spec.js
30
+ ├── card-content
31
+ │ ├── card-content.css
32
+ │ └── card-content.js
33
+ ├── card-title
34
+ │ ├── card-title.css
35
+ │ └── card-title.js
36
+ ```
37
+
38
+ #### Naming
39
+
40
+ ##### Name
41
+
42
+ Elements are not actions, they are conceptually "things". It is better to use nouns, instead of verbs, such us: "
43
+ animation" instead of "animating". "input", "tab", "nav", "menu" are some examples.
44
+
45
+ ##### -element postfix
46
+
47
+ The naming has a major role when you are creating a collection of elements intended to be used across different
48
+ projects. Web Components are not scoped because they are globally declared within the page, which means a "unique" name
49
+ is needed to prevent collisions.
50
+ Additionally, web components are required to contain a "-" dash within the tag name. When using the first section to
51
+ namespace your components - everything will look the same, and it will be hard to distinguish elements.
52
+
53
+ DO NOT do this:
54
+
55
+ ```
56
+ company-card
57
+ company-card-header
58
+ company-card-title
59
+ company-card-content
60
+ company-card-footer
61
+ ```
62
+
63
+ Instead, use -element for elements with a single noun.
64
+
65
+ ```
66
+ card-element
67
+ card-header
68
+ card-title
69
+ card-content
70
+ card-footer
71
+ ```
72
+
73
+ ##### Modifiers
74
+
75
+ When several elements are related and/or coupled, it is a good idea to share the name, and then add different modifiers,
76
+ for example:
77
+
78
+ ```
79
+ menu-element
80
+ menu-controller
81
+ ```
82
+
83
+ ```
84
+ card-element
85
+ card-header
86
+ card-content
87
+ ```
88
+
89
+ ##### Element (JS class)
90
+
91
+ The name of the ES6 class of the element should reflect the file name, and the html tag name.
92
+
93
+ ```js
94
+ export class ButtonElement extends BaseElement {
95
+ }
96
+
97
+ customElements.define('button-element', ButtonElement);
98
+
99
+ export class MenuElement extends BaseElement {
100
+ }
101
+
102
+ customElements.define('menu-element', MenuElement);
103
+ ```
104
+
105
+ #### Code organization
106
+
107
+ ##### Newspaper Metaphor from The Robert C. Martin's _Clean Code_
108
+
109
+ > The source file should be organized like a newspaper article, with the highest level summary at the top, and more and
110
+ > more details further down. Functions called from the top function come directly below it, and so on down to the lowest
111
+ > level, and most detailed functions at the bottom. This is a good way to organize the source code, even though IDE:s make
112
+ > the location of functions less important, since it is so easy to navigate in and out of them.
package/index.js CHANGED
@@ -3,7 +3,14 @@ import { StyledElement } from './src/StyledElement.js';
3
3
  import { TemplateElement, html } from './src/TemplateElement.js';
4
4
  import { toString } from './src/util/toString.js';
5
5
  import { defineElement } from './src/util/defineElement.js';
6
- import { i18n } from './src/util/i18n.js';
7
6
  import { Store } from './src/util/Store.js';
7
+ import { Directive } from './src/util/Directive.js';
8
8
 
9
- export { BaseElement, StyledElement, TemplateElement, Store, html, toString, defineElement, i18n };
9
+ /**
10
+ * Options object for element-js
11
+ * @typedef {Object} ElementJsConfig
12
+ * @property {boolean} [serializeState] - When set to true all elements and stores will serialize their state on changes to a global JSON object in the document. This is needed when rendering server side, so that elements and stores can hydrate with the correct state.
13
+ * @property {boolean} [observeGlobalStyles] - By default element-js will look for all style elements in the global document and apply them before any custom/element styles inside the shadow DOM. When set to true element-js will also observe the document for any changes regarding styles. This is needed if styles will get added async or late.
14
+ */
15
+
16
+ export { BaseElement, StyledElement, TemplateElement, Store, Directive, html, toString, defineElement };
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@webtides/element-js",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.10",
4
4
  "module": "index.js",
5
- "main": "dist/index.js",
5
+ "main": "index.js",
6
6
  "type": "module",
7
7
  "files": [
8
- "/dist",
8
+ "/docs",
9
9
  "/src",
10
10
  "index.js"
11
11
  ],
12
12
  "exports": {
13
13
  ".": {
14
- "browser": "./dist/index.js",
14
+ "browser": "./index.js",
15
15
  "import": "./index.js",
16
16
  "default": "./index.js"
17
17
  },
@@ -35,21 +35,18 @@
35
35
  ],
36
36
  "dependencies": {},
37
37
  "devDependencies": {
38
- "@babel/eslint-parser": "^7.18.9",
39
- "@open-wc/testing": "^3.1.6",
40
- "@web/dev-server": "^0.1.30",
41
- "@web/test-runner": "^0.14.0",
38
+ "@babel/eslint-parser": "^7.23.3",
39
+ "@open-wc/testing": "^4.0.0",
40
+ "@web/dev-server": "^0.4.1",
41
+ "@web/test-runner": "^0.14.1",
42
42
  "babel-eslint": "^10.1.0",
43
- "babel-plugin-module-resolver": "^5.0.0",
44
- "deepmerge": "^4.2.2",
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"
43
+ "eslint": "8.55.0",
44
+ "eslint-config-prettier": "^9.1.0",
45
+ "eslint-plugin-import": "^2.29.0",
46
+ "eslint-plugin-prettier": "^5.0.1",
47
+ "husky": "^8.0.3",
48
+ "lint-staged": "^15.1.0",
49
+ "prettier": "^3.1.0"
53
50
  },
54
51
  "lint-staged": {
55
52
  "*.{js,json}": [
@@ -59,7 +56,6 @@
59
56
  },
60
57
  "scripts": {
61
58
  "lint": "eslint index.js 'src/**/*.js'",
62
- "prepare": "esbuild index.js --outfile=dist/index.js --bundle --format=esm --sourcemap --target=chrome79,firefox68,safari12,edge79",
63
59
  "test": "web-test-runner test/**/*.test.{html,js} --node-resolve",
64
60
  "test:coverage": "web-test-runner test/**/*.test.{html,js} --node-resolve --coverage",
65
61
  "test:watch": "web-test-runner test/**/*.test.{html,js} --node-resolve --watch",