@webtides/element-js 0.7.2 → 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/src/util/Store.js CHANGED
@@ -18,7 +18,6 @@ export class Store {
18
18
  return this._state[key];
19
19
  },
20
20
  set: (newValue) => {
21
- const oldState = structuredClone(this._state);
22
21
  const oldValue = this._state[key];
23
22
  this._state[key] = newValue;
24
23
 
@@ -27,7 +26,7 @@ export class Store {
27
26
  if (watch.hasOwnProperty(key) && typeof watch[key] === 'function') {
28
27
  watch[key](newValue, oldValue);
29
28
  }
30
- this.requestUpdate(oldState);
29
+ this.requestUpdate();
31
30
  }
32
31
  },
33
32
  });
@@ -69,7 +68,7 @@ export class Store {
69
68
  this._observer.delete(observer);
70
69
  }
71
70
 
72
- requestUpdate(oldState) {
71
+ requestUpdate() {
73
72
  this._observer.forEach(async (observer) => {
74
73
  if (observer instanceof BaseElement) {
75
74
  await observer.requestUpdate();
@@ -78,10 +77,10 @@ export class Store {
78
77
  // observer actually has watched properties
79
78
  const properties = observer.properties();
80
79
  Object.keys(observer.watch() ?? {}).forEach((key) => {
81
- if (properties[key] === this) {
80
+ if (observer._state[key] === this) {
82
81
  // observer is actually watching store changes provide new and old values
83
- observer.callPropertyWatcher(key, this._state, oldState);
84
- observer.notifyPropertyChange(key, this._state);
82
+ observer.callPropertyWatcher(key, this, this);
83
+ observer.notifyPropertyChange(key, this);
85
84
  }
86
85
  });
87
86
  }
package/CHANGELOG.md DELETED
@@ -1,137 +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.2] - 2023-03-03
19
-
20
- ### Fixed
21
- * watcher callbacks for injected stores
22
-
23
- ## [0.7.1] - 2023-03-03
24
-
25
- ### Added
26
- * Elements are now able to watch Stores
27
-
28
- ### Fixed
29
- * Injection of falsy values
30
-
31
- ## [0.7.0] - 2023-02-13
32
-
33
- ### Added
34
- * Dependency Injection via Context Protocol 💉
35
- * Provide reactive Properties or entire Stores via: provideProperties() { return { name : value}}
36
- * Inject / Request them via injectProperties() { return { name : 'defaultValue'}}
37
-
38
- ### Changed
39
- * docs structure
40
-
41
- ### Fixed
42
- * Cannot re-render slotted light dom when using the vanilla renderer https://github.com/webtides/element-js/issues/76
43
- * adds Vanilla Renderer Tests
44
-
45
-
46
- ## [0.6.2] - 2022-11-18
47
-
48
- ### FIXED
49
- * Store always switching to singleProperty Mode if constructed without any arguments.
50
-
51
- ## [0.6.1] - 2022-11-18
52
-
53
- ### ADDED
54
- * Store watch() map to control internal store state scope
55
-
56
- ## [0.6.0] - 2022-11-17
57
-
58
- ### ADDED
59
- * StoreProperty for shared application state
60
- * Directives for Vanilla Renderer
61
-
62
- ## [0.5.0] - 2022-09-13
63
-
64
- ### Changed
65
- * improved the performance of the vanilla-renderer
66
-
67
- ### Removed
68
- * 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
69
-
70
- ## [0.4.3] - 2022-07-06
71
-
72
- ### ADDED
73
- * parse option to propertyOptions that can be either a boolean OR a function for custom parsing
74
- * enhance reflect option in propertyOptions that it can also be a function for custom reflection
75
-
76
- ## [0.4.2] - 2022-02-03
77
-
78
- ### Fixed
79
- * vanilla-renderer: fixes attribute comparsion
80
-
81
- ## [0.4.1] - 2022-02-01
82
-
83
- ### Fixed
84
- * refs="id[]" indexing keys not nodes *rolleyes*
85
-
86
- ### Added
87
- * refs="id[]" aka possibbility to refrence a list of nodes to the $refs map.
88
-
89
- ## [0.4.0] - 2022-01-28
90
-
91
- ### Added
92
- * a "vanilla" renderer with support for hydration and no dependencies
93
-
94
- ### Changed
95
- * uses new @web/test-runner isntead of karma (#27)
96
-
97
- ## [0.3.3] - 2021-09-22
98
-
99
- ### Added
100
- * optional complex event callback notation to support addEventListener options (i.E. for passive Event Listeners )
101
- * Example: {listener: () => {}, options: { passive: true } }
102
- * docs
103
- * tests
104
-
105
-
106
- ## [0.3.2] - 2021-03-09
107
-
108
- ### Added
109
- * bundled version of `element-js` to use from a CDN and be able to prototype in tools like CodePen etc.
110
-
111
- ## [0.3.1] - 2020-12-08
112
-
113
- ### Fixed
114
- * i18n fallback values
115
-
116
- ### Added
117
- * i18n tests
118
-
119
- ## [0.3.0] - 2020-07-27
120
-
121
- ### Added
122
- * first batch/draft of the documentation
123
- * property/attribute reflection via constructor options (see the [Documentation](/docs/README.md#propertyoptions) for more info)
124
- * mutationObserverOptions to enable observing subtree mutations (see the [Documentation](/docs/README.md#mutationobserveroptions) for more info)
125
-
126
- ### Removed
127
- * `childListUpdate` constructor option has been deprecated and will be removed before `1.0`
128
-
129
- ## [0.2.0] - 2020-07-01
130
-
131
- ### Changed
132
- * uses shady-render instead of render from `lit-html` for rendering templates to be compatible with the shady-css polyfill
133
- * refactored and simplified `StyledElement`s handling/loading of style sheets
134
-
135
- ## [0.1.0] - 2020-06-26
136
-
137
- * 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 };