@webtides/element-js 1.0.0-alpha.2 → 1.0.0-alpha.3
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/dist/index.js +279 -76
- package/dist/index.js.map +4 -4
- package/index.js +8 -2
- package/package.json +1 -1
- package/src/BaseElement.js +104 -21
- package/src/StyledElement.js +35 -48
- package/src/TemplateElement.js +0 -1
- package/src/util/DOMHelper.js +20 -0
- package/src/util/GlobalStylesStore.js +70 -0
- package/src/util/SerializeStateHelper.js +103 -0
- package/src/util/Store.js +88 -13
- package/src/util/i18n.js +0 -20
package/src/util/Store.js
CHANGED
|
@@ -1,21 +1,63 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { deepEquals, isObjectLike } from './AttributeParser.js';
|
|
2
|
+
import {
|
|
3
|
+
hasSerializedState,
|
|
4
|
+
serializeState,
|
|
5
|
+
deserializeState,
|
|
6
|
+
serializableObjectsCache,
|
|
7
|
+
} from './SerializeStateHelper.js';
|
|
2
8
|
import { BaseElement } from '../BaseElement.js';
|
|
3
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Options object for the Store
|
|
12
|
+
* @typedef {Object} StoreOptions
|
|
13
|
+
* @property {string} [key] - A unique key so that the store instance can be serialized and deserialized correctly across multiple shared parents/hosts.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @implements {Serializable}
|
|
18
|
+
*/
|
|
4
19
|
export class Store {
|
|
5
|
-
|
|
20
|
+
_serializationKey;
|
|
21
|
+
_observer = new Set([]);
|
|
6
22
|
_singlePropertyMode = false;
|
|
7
23
|
_state = {};
|
|
8
24
|
|
|
9
25
|
/**
|
|
10
|
-
* @param {* | object} value
|
|
26
|
+
* @param {* | object} [value]
|
|
27
|
+
* @param {StoreOptions} [options]
|
|
11
28
|
*/
|
|
12
|
-
constructor(value) {
|
|
13
|
-
|
|
29
|
+
constructor(value, options) {
|
|
30
|
+
if (options?.key && serializableObjectsCache.has(options?.key)) {
|
|
31
|
+
return serializableObjectsCache.get(options?.key);
|
|
32
|
+
}
|
|
33
|
+
|
|
14
34
|
this._singlePropertyMode = arguments.length > 0 && !isObjectLike(value);
|
|
35
|
+
|
|
36
|
+
if (options?.key) {
|
|
37
|
+
this._serializationKey = options?.key;
|
|
38
|
+
} else {
|
|
39
|
+
this._serializationKey = globalThis.crypto.randomUUID();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (options?.serializedState) {
|
|
43
|
+
deserializeState(this, options.serializedState);
|
|
44
|
+
} else if (hasSerializedState(this._serializationKey)) {
|
|
45
|
+
deserializeState(this);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// wrap primitives with a generic "value" field to generate getter and setter
|
|
15
49
|
const specificValues = this._singlePropertyMode ? { value } : value;
|
|
16
|
-
|
|
50
|
+
const properties = { ...(!this._singlePropertyMode && this.properties()), ...specificValues };
|
|
51
|
+
|
|
52
|
+
const serializationKeys = Object.keys(this.serializeState());
|
|
53
|
+
Object.entries(properties).map(([key, value]) => {
|
|
54
|
+
this._state[key] =
|
|
55
|
+
hasSerializedState(this._serializationKey) && serializationKeys.includes(key) ? this[key] : value;
|
|
56
|
+
|
|
57
|
+
if (value instanceof Store) {
|
|
58
|
+
value.subscribe(this);
|
|
59
|
+
}
|
|
17
60
|
|
|
18
|
-
Object.entries(this._state).map(([key, value]) => {
|
|
19
61
|
Object.defineProperty(this, key, {
|
|
20
62
|
get: () => {
|
|
21
63
|
return this._state[key];
|
|
@@ -23,6 +65,11 @@ export class Store {
|
|
|
23
65
|
set: (newValue) => {
|
|
24
66
|
const oldValue = this._state[key];
|
|
25
67
|
this._state[key] = newValue;
|
|
68
|
+
if (value instanceof Store) {
|
|
69
|
+
value.subscribe(this);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
serializeState(this);
|
|
26
73
|
|
|
27
74
|
if (!deepEquals(newValue, oldValue)) {
|
|
28
75
|
const watch = this.watch();
|
|
@@ -34,6 +81,8 @@ export class Store {
|
|
|
34
81
|
},
|
|
35
82
|
});
|
|
36
83
|
});
|
|
84
|
+
|
|
85
|
+
serializableObjectsCache.set(this._serializationKey, this);
|
|
37
86
|
}
|
|
38
87
|
|
|
39
88
|
/**
|
|
@@ -72,7 +121,7 @@ export class Store {
|
|
|
72
121
|
|
|
73
122
|
/**
|
|
74
123
|
* Add an observer
|
|
75
|
-
* @param {BaseElement
|
|
124
|
+
* @param {BaseElement|Function|Store} observer
|
|
76
125
|
*/
|
|
77
126
|
subscribe(observer) {
|
|
78
127
|
this._observer.add(observer);
|
|
@@ -91,17 +140,23 @@ export class Store {
|
|
|
91
140
|
*/
|
|
92
141
|
requestUpdate() {
|
|
93
142
|
this._observer.forEach(async (observer) => {
|
|
94
|
-
if (observer instanceof BaseElement) {
|
|
95
|
-
|
|
143
|
+
if (observer instanceof BaseElement || observer instanceof Store) {
|
|
144
|
+
if (observer?._options?.autoUpdate !== false) {
|
|
145
|
+
await observer.requestUpdate();
|
|
146
|
+
}
|
|
96
147
|
// check if store is watched by an observer
|
|
97
148
|
if (Object.keys(observer.watch() ?? {}).length > 0) {
|
|
98
149
|
// observer actually has watched properties
|
|
99
|
-
const properties = observer.properties();
|
|
100
150
|
Object.keys(observer.watch() ?? {}).forEach((key) => {
|
|
101
151
|
if (observer._state[key] === this) {
|
|
102
152
|
// observer is actually watching store changes provide new and old values
|
|
103
|
-
observer
|
|
104
|
-
|
|
153
|
+
if (observer instanceof Store) {
|
|
154
|
+
// observer is a foreign store / call watcher
|
|
155
|
+
observer.watch?.()[key](this, this);
|
|
156
|
+
} else {
|
|
157
|
+
observer.callPropertyWatcher(key, this, this);
|
|
158
|
+
observer.notifyPropertyChange(key, this);
|
|
159
|
+
}
|
|
105
160
|
}
|
|
106
161
|
});
|
|
107
162
|
}
|
|
@@ -112,4 +167,24 @@ export class Store {
|
|
|
112
167
|
}
|
|
113
168
|
});
|
|
114
169
|
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* This method will be used to serialize this stores state.
|
|
173
|
+
* By default, it will generate an object with all properties from this.properties().
|
|
174
|
+
* You can override this and return a different object with more/less/different properties.
|
|
175
|
+
* @return {{[string: any]: *}}
|
|
176
|
+
*/
|
|
177
|
+
serializeState() {
|
|
178
|
+
const keys = Object.keys(this.properties());
|
|
179
|
+
return Object.fromEntries(keys.map((key) => [key, this[key]]));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* This method will be used to restore properties on the store from a previously serialized state.
|
|
184
|
+
* You can override this and handle the deserialization differently if the default is not enough.
|
|
185
|
+
* @param {{[string: any]: *}} serializedState
|
|
186
|
+
*/
|
|
187
|
+
restoreState(serializedState) {
|
|
188
|
+
Object.assign(this, serializedState);
|
|
189
|
+
}
|
|
115
190
|
}
|
package/src/util/i18n.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Retrieves a translated key from a dictionary on the window object
|
|
3
|
-
* Example: ${i18n('CustomElement.buttonLabel', 'Label')}
|
|
4
|
-
* @param {string} key - to be translated
|
|
5
|
-
* @param {string} fallback - to be used if key is not defined
|
|
6
|
-
* @return {string} - String of the translated key or fallback or original key
|
|
7
|
-
*/
|
|
8
|
-
export function i18n(key, fallback) {
|
|
9
|
-
try {
|
|
10
|
-
const translations = window.elementjs.i18n();
|
|
11
|
-
if (translations[key] === undefined) {
|
|
12
|
-
throw 'Translation Missing';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return translations[key];
|
|
16
|
-
} catch (err) {
|
|
17
|
-
if (fallback) return fallback;
|
|
18
|
-
else return key;
|
|
19
|
-
}
|
|
20
|
-
}
|