@webtides/element-js 0.7.3 → 1.0.0-alpha.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/README.md +2 -2
- package/dist/index.js +663 -963
- package/dist/index.js.map +4 -4
- package/package.json +16 -20
- package/src/BaseElement.js +2 -43
- package/src/StyledElement.js +1 -9
- package/src/TemplateElement.js +3 -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 +331 -0
- package/src/{renderer/vanilla/util → dom-parts}/directives.js +17 -11
- package/src/dom-parts/html.js +12 -0
- package/src/dom-parts/render.js +10 -0
- package/src/util/AttributeParser.js +8 -8
- package/src/util/DOMHelper.js +213 -0
- package/src/util/Directive.js +22 -0
- 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/html.js +0 -65
- package/src/renderer/vanilla/util/render.js +0 -149
package/CHANGELOG.md
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
|
-
|
|
7
|
-
<!--
|
|
8
|
-
PRs should document their user-visible changes (if any) in the
|
|
9
|
-
Unreleased section, uncommenting the header as necessary.
|
|
10
|
-
-->
|
|
11
|
-
|
|
12
|
-
<!-- ## Unreleased -->
|
|
13
|
-
<!-- ### Added -->
|
|
14
|
-
<!-- ### Changed -->
|
|
15
|
-
<!-- ### Removed -->
|
|
16
|
-
<!-- ### Fixed -->
|
|
17
|
-
|
|
18
|
-
## [0.7.3] - 2023-03-07
|
|
19
|
-
|
|
20
|
-
### Fixed
|
|
21
|
-
* last release was tagged wrong
|
|
22
|
-
|
|
23
|
-
## [0.7.2] - 2023-03-03
|
|
24
|
-
|
|
25
|
-
### Fixed
|
|
26
|
-
* watcher callbacks for injected stores
|
|
27
|
-
|
|
28
|
-
## [0.7.1] - 2023-03-03
|
|
29
|
-
|
|
30
|
-
### Added
|
|
31
|
-
* Elements are now able to watch Stores
|
|
32
|
-
|
|
33
|
-
### Fixed
|
|
34
|
-
* Injection of falsy values
|
|
35
|
-
|
|
36
|
-
## [0.7.0] - 2023-02-13
|
|
37
|
-
|
|
38
|
-
### Added
|
|
39
|
-
* Dependency Injection via Context Protocol 💉
|
|
40
|
-
* Provide reactive Properties or entire Stores via: provideProperties() { return { name : value}}
|
|
41
|
-
* Inject / Request them via injectProperties() { return { name : 'defaultValue'}}
|
|
42
|
-
|
|
43
|
-
### Changed
|
|
44
|
-
* docs structure
|
|
45
|
-
|
|
46
|
-
### Fixed
|
|
47
|
-
* Cannot re-render slotted light dom when using the vanilla renderer https://github.com/webtides/element-js/issues/76
|
|
48
|
-
* adds Vanilla Renderer Tests
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## [0.6.2] - 2022-11-18
|
|
52
|
-
|
|
53
|
-
### FIXED
|
|
54
|
-
* Store always switching to singleProperty Mode if constructed without any arguments.
|
|
55
|
-
|
|
56
|
-
## [0.6.1] - 2022-11-18
|
|
57
|
-
|
|
58
|
-
### ADDED
|
|
59
|
-
* Store watch() map to control internal store state scope
|
|
60
|
-
|
|
61
|
-
## [0.6.0] - 2022-11-17
|
|
62
|
-
|
|
63
|
-
### ADDED
|
|
64
|
-
* StoreProperty for shared application state
|
|
65
|
-
* Directives for Vanilla Renderer
|
|
66
|
-
|
|
67
|
-
## [0.5.0] - 2022-09-13
|
|
68
|
-
|
|
69
|
-
### Changed
|
|
70
|
-
* improved the performance of the vanilla-renderer
|
|
71
|
-
|
|
72
|
-
### Removed
|
|
73
|
-
* setting attributes as properties during dom diffing for the vanilla renderer. This is potentially a **breaking** change if you used attributes with the "." (dot) notation
|
|
74
|
-
|
|
75
|
-
## [0.4.3] - 2022-07-06
|
|
76
|
-
|
|
77
|
-
### ADDED
|
|
78
|
-
* parse option to propertyOptions that can be either a boolean OR a function for custom parsing
|
|
79
|
-
* enhance reflect option in propertyOptions that it can also be a function for custom reflection
|
|
80
|
-
|
|
81
|
-
## [0.4.2] - 2022-02-03
|
|
82
|
-
|
|
83
|
-
### Fixed
|
|
84
|
-
* vanilla-renderer: fixes attribute comparsion
|
|
85
|
-
|
|
86
|
-
## [0.4.1] - 2022-02-01
|
|
87
|
-
|
|
88
|
-
### Fixed
|
|
89
|
-
* refs="id[]" indexing keys not nodes *rolleyes*
|
|
90
|
-
|
|
91
|
-
### Added
|
|
92
|
-
* refs="id[]" aka possibbility to refrence a list of nodes to the $refs map.
|
|
93
|
-
|
|
94
|
-
## [0.4.0] - 2022-01-28
|
|
95
|
-
|
|
96
|
-
### Added
|
|
97
|
-
* a "vanilla" renderer with support for hydration and no dependencies
|
|
98
|
-
|
|
99
|
-
### Changed
|
|
100
|
-
* uses new @web/test-runner isntead of karma (#27)
|
|
101
|
-
|
|
102
|
-
## [0.3.3] - 2021-09-22
|
|
103
|
-
|
|
104
|
-
### Added
|
|
105
|
-
* optional complex event callback notation to support addEventListener options (i.E. for passive Event Listeners )
|
|
106
|
-
* Example: {listener: () => {}, options: { passive: true } }
|
|
107
|
-
* docs
|
|
108
|
-
* tests
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
## [0.3.2] - 2021-03-09
|
|
112
|
-
|
|
113
|
-
### Added
|
|
114
|
-
* bundled version of `element-js` to use from a CDN and be able to prototype in tools like CodePen etc.
|
|
115
|
-
|
|
116
|
-
## [0.3.1] - 2020-12-08
|
|
117
|
-
|
|
118
|
-
### Fixed
|
|
119
|
-
* i18n fallback values
|
|
120
|
-
|
|
121
|
-
### Added
|
|
122
|
-
* i18n tests
|
|
123
|
-
|
|
124
|
-
## [0.3.0] - 2020-07-27
|
|
125
|
-
|
|
126
|
-
### Added
|
|
127
|
-
* first batch/draft of the documentation
|
|
128
|
-
* property/attribute reflection via constructor options (see the [Documentation](/docs/README.md#propertyoptions) for more info)
|
|
129
|
-
* mutationObserverOptions to enable observing subtree mutations (see the [Documentation](/docs/README.md#mutationobserveroptions) for more info)
|
|
130
|
-
|
|
131
|
-
### Removed
|
|
132
|
-
* `childListUpdate` constructor option has been deprecated and will be removed before `1.0`
|
|
133
|
-
|
|
134
|
-
## [0.2.0] - 2020-07-01
|
|
135
|
-
|
|
136
|
-
### Changed
|
|
137
|
-
* uses shady-render instead of render from `lit-html` for rendering templates to be compatible with the shady-css polyfill
|
|
138
|
-
* refactored and simplified `StyledElement`s handling/loading of style sheets
|
|
139
|
-
|
|
140
|
-
## [0.1.0] - 2020-06-26
|
|
141
|
-
|
|
142
|
-
* initial release
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { StyledElement } from '../../StyledElement.js';
|
|
2
|
-
import { html, spreadAttributes, unsafeHTML } from './util/html.js';
|
|
3
|
-
import { render } from './util/render.js';
|
|
4
|
-
export { i18n } from '../../util/i18n.js';
|
|
5
|
-
|
|
6
|
-
class TemplateElement extends StyledElement {
|
|
7
|
-
constructor(options) {
|
|
8
|
-
super({
|
|
9
|
-
deferUpdate: false,
|
|
10
|
-
shadowRender: false,
|
|
11
|
-
styles: [],
|
|
12
|
-
adoptGlobalStyles: true,
|
|
13
|
-
mutationObserverOptions: {
|
|
14
|
-
childList: false,
|
|
15
|
-
},
|
|
16
|
-
...options,
|
|
17
|
-
});
|
|
18
|
-
this._template = this._options.template;
|
|
19
|
-
|
|
20
|
-
if (this._options.shadowRender && !this.shadowRoot) {
|
|
21
|
-
this.attachShadow({ mode: 'open' });
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
template() {
|
|
26
|
-
return html``;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
update(options) {
|
|
30
|
-
this.renderTemplate();
|
|
31
|
-
super.update(options);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
renderTemplate() {
|
|
35
|
-
const template = this._template || this.template();
|
|
36
|
-
|
|
37
|
-
if (typeof template === 'string') {
|
|
38
|
-
// just a plain string literal. no fancy rendering required
|
|
39
|
-
this.getRoot().innerHTML = `${template}`;
|
|
40
|
-
} else {
|
|
41
|
-
render(template, this.getRoot());
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
getRoot() {
|
|
46
|
-
return this.shadowRoot !== null ? this.shadowRoot : this;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export { TemplateElement, html, unsafeHTML, render, spreadAttributes };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { BaseElement } from '../../BaseElement.js';
|
|
2
|
-
import { StyledElement } from '../../StyledElement.js';
|
|
3
|
-
import { TemplateElement, html, unsafeHTML, spreadAttributes } from './TemplateElement.js';
|
|
4
|
-
import { toString } from '../../util/toString.js';
|
|
5
|
-
import { defineElement } from '../../util/defineElement.js';
|
|
6
|
-
import { i18n } from '../../util/i18n.js';
|
|
7
|
-
|
|
8
|
-
export {
|
|
9
|
-
BaseElement,
|
|
10
|
-
StyledElement,
|
|
11
|
-
TemplateElement,
|
|
12
|
-
html,
|
|
13
|
-
unsafeHTML,
|
|
14
|
-
spreadAttributes,
|
|
15
|
-
toString,
|
|
16
|
-
defineElement,
|
|
17
|
-
i18n,
|
|
18
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { encodeAttribute } from '../../../util/AttributeParser.js';
|
|
2
|
-
import { unsafeHTML, spreadAttributes } from './directives.js';
|
|
3
|
-
|
|
4
|
-
class Part {
|
|
5
|
-
constructor(value) {
|
|
6
|
-
this.value = value;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
toString() {
|
|
10
|
-
if (typeof this.value !== 'string') {
|
|
11
|
-
return encodeAttribute(JSON.stringify(this.value));
|
|
12
|
-
}
|
|
13
|
-
return encodeAttribute(this.value);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class TemplatePart extends Part {
|
|
18
|
-
$$templatePart = true;
|
|
19
|
-
|
|
20
|
-
constructor(value) {
|
|
21
|
-
super(value?.$$templatePart ? value.value : value);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
toString() {
|
|
25
|
-
if (this.value === null || this.value === undefined) {
|
|
26
|
-
return '';
|
|
27
|
-
} else if (this.value === '') {
|
|
28
|
-
return '';
|
|
29
|
-
} else if (Array.isArray(this.value)) {
|
|
30
|
-
return this.value.map((row) => new TemplatePart(row).toString()).join('');
|
|
31
|
-
} else if (this.value?.$$templateLiteral) {
|
|
32
|
-
return this.value.toString();
|
|
33
|
-
} else if (typeof this.value === 'function') {
|
|
34
|
-
// A directive
|
|
35
|
-
return this.value(this);
|
|
36
|
-
}
|
|
37
|
-
return super.toString();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
class TemplateLiteral {
|
|
42
|
-
$$templateLiteral = true;
|
|
43
|
-
|
|
44
|
-
constructor(strings, ...values) {
|
|
45
|
-
let result = [];
|
|
46
|
-
for (let i = 0; i < strings.length; i++) {
|
|
47
|
-
result.push(strings[i]);
|
|
48
|
-
|
|
49
|
-
if (i < values.length) {
|
|
50
|
-
result.push(new TemplatePart(values[i]));
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
this.result = result;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
toString() {
|
|
57
|
-
return `${this.result.join('')}`;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const html = function (strings, ...values) {
|
|
62
|
-
return new TemplateLiteral(strings, ...values);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export { Part, TemplatePart, TemplateLiteral, html, unsafeHTML, spreadAttributes };
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { TemplateElement } from '../TemplateElement.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Parses the given template string and returns a real DOM element.
|
|
5
|
-
* @param {string} template
|
|
6
|
-
* @returns {HTMLElement}
|
|
7
|
-
*/
|
|
8
|
-
const convertStringToHTML = (template) => {
|
|
9
|
-
const parser = new DOMParser();
|
|
10
|
-
const document = parser.parseFromString(template.toString(), 'text/html');
|
|
11
|
-
return document.body;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Diff the attributes for a live DOM element against a template DOM element
|
|
16
|
-
* @param {Element} templateElement The new template
|
|
17
|
-
* @param {Element} domElement The existing DOM node
|
|
18
|
-
*/
|
|
19
|
-
const diffAttributes = function (templateElement, domElement) {
|
|
20
|
-
// remove or update previous attributes
|
|
21
|
-
for (/** @type {Attr} */ const attribute of Array.from(domElement.attributes)) {
|
|
22
|
-
if (templateElement.hasAttribute(attribute.name)) {
|
|
23
|
-
const oldValue = attribute.value;
|
|
24
|
-
const newValue = templateElement.getAttribute(attribute.name) || '';
|
|
25
|
-
if (oldValue !== newValue) {
|
|
26
|
-
domElement.setAttribute(attribute.name, newValue);
|
|
27
|
-
}
|
|
28
|
-
} else {
|
|
29
|
-
domElement.removeAttribute(attribute.name);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// set newly added attributes
|
|
34
|
-
for (/** @type {Attr} */ const attribute of Array.from(templateElement.attributes)) {
|
|
35
|
-
if (!domElement.hasAttribute(attribute.name)) {
|
|
36
|
-
domElement.setAttribute(attribute.name, attribute.value);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Checks whether the given element or node is a TemplateElement or not
|
|
43
|
-
* @param {Element|Node} element
|
|
44
|
-
* @returns {boolean}
|
|
45
|
-
*/
|
|
46
|
-
const isTemplateElement = (element) => {
|
|
47
|
-
const tagName = element.tagName?.toLowerCase() ?? false;
|
|
48
|
-
if (!tagName || !tagName.includes('-') || element.shadowRoot) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
return element instanceof TemplateElement;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Diff a live DOM node against a template DOM node
|
|
56
|
-
* @param {Node} templateNode
|
|
57
|
-
* @param {Node} domNode
|
|
58
|
-
*/
|
|
59
|
-
const diffNodes = function (templateNode, domNode) {
|
|
60
|
-
const templateChildNodes = [...templateNode.childNodes];
|
|
61
|
-
const domChildNodes = [...domNode.childNodes];
|
|
62
|
-
|
|
63
|
-
// Diff each node in the child node lists
|
|
64
|
-
const length = Math.max(templateChildNodes.length, domChildNodes.length);
|
|
65
|
-
for (let index = 0; index < length; index++) {
|
|
66
|
-
const templateChildNode = templateChildNodes[index];
|
|
67
|
-
const domChildNode = domChildNodes[index];
|
|
68
|
-
|
|
69
|
-
// If the DOM node doesn't exist, append/copy the template node
|
|
70
|
-
if (!domChildNode) {
|
|
71
|
-
domNode.appendChild(templateChildNode);
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// If the template node doesn't exist, remove the node in the DOM
|
|
76
|
-
if (!templateChildNode) {
|
|
77
|
-
domChildNode.parentNode.removeChild(domChildNode);
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// If DOM node is equal to the template node, don't do anything
|
|
82
|
-
if (domChildNode.isEqualNode(templateChildNode)) {
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// If node types are not the same, replace the DOM node with the template node
|
|
87
|
-
if (templateChildNode.nodeType !== domChildNode.nodeType) {
|
|
88
|
-
domChildNode.parentNode.replaceChild(templateChildNode, domChildNode);
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// If the element tag names are not the same, replace the DOM node with the template node
|
|
93
|
-
if (templateChildNode.nodeType === 1 && templateChildNode.tagName !== domChildNode.tagName) {
|
|
94
|
-
domChildNode.parentNode.replaceChild(templateChildNode, domChildNode);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// If the node is an SVG element, don't even think about diffing it, just replace it
|
|
99
|
-
if (templateChildNode.nodeType === 1 && templateChildNode.tagName === 'SVG') {
|
|
100
|
-
domChildNode.parentNode.replaceChild(templateChildNode, domChildNode);
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// If the node is an Element node, diff the attributes
|
|
105
|
-
if (templateChildNode.nodeType === 1) {
|
|
106
|
-
diffAttributes(templateChildNode, domChildNode);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// If the node is a Text node or a Comment node, update it
|
|
110
|
-
if (domChildNode.nodeType === 3 || domChildNode.nodeType === 8) {
|
|
111
|
-
domChildNode.textContent = templateChildNode.textContent;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// If the DOM node should be empty, remove all child nodes
|
|
116
|
-
if (domChildNode.hasChildNodes() && !templateChildNode.hasChildNodes()) {
|
|
117
|
-
domChildNode.replaceChildren();
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// If the DOM node is empty, but should have children, add child nodes from the template node
|
|
122
|
-
if (!domChildNode.hasChildNodes() && templateChildNode.hasChildNodes()) {
|
|
123
|
-
domChildNode.replaceChildren(...templateChildNode.childNodes);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// If there are child nodes, diff them recursively
|
|
128
|
-
if (templateChildNode.hasChildNodes()) {
|
|
129
|
-
// https://stackoverflow.com/questions/46898739/why-domparser-doesnt-use-the-customelements-registered
|
|
130
|
-
// we have to use the domChildNode here because the templateChildNode is not upgraded because it was not
|
|
131
|
-
// imported into a document yet and therefore instanceOf will not work...
|
|
132
|
-
if (!isTemplateElement(domChildNode)) {
|
|
133
|
-
diffNodes(templateChildNode, domChildNode);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Render a template string into the given DOM node
|
|
141
|
-
* @param {string} template
|
|
142
|
-
* @param {Node} domNode
|
|
143
|
-
*/
|
|
144
|
-
const render = (template, domNode) => {
|
|
145
|
-
const templateNode = convertStringToHTML(template);
|
|
146
|
-
diffNodes(templateNode, domNode);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
export { render };
|