@zcomponent/core 0.0.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 +7 -0
- package/css/zcomponent.css +35 -0
- package/index.d.ts +1 -0
- package/index.js +2 -0
- package/lib/actionbehavior.d.ts +20 -0
- package/lib/actionbehavior.js +32 -0
- package/lib/animation.d.ts +129 -0
- package/lib/animation.js +1 -0
- package/lib/behavior.d.ts +26 -0
- package/lib/behavior.js +10 -0
- package/lib/behaviors/LaunchURL.d.ts +12 -0
- package/lib/behaviors/LaunchURL.js +12 -0
- package/lib/behaviors/LogAnalyticsEvent.d.ts +10 -0
- package/lib/behaviors/LogAnalyticsEvent.js +10 -0
- package/lib/behaviors/PlaySound.d.ts +12 -0
- package/lib/behaviors/PlaySound.js +18 -0
- package/lib/component.d.ts +22 -0
- package/lib/component.js +4 -0
- package/lib/components/DefaultLoader.d.ts +55 -0
- package/lib/components/DefaultLoader.js +112 -0
- package/lib/context.d.ts +28 -0
- package/lib/context.js +65 -0
- package/lib/contexts/analyticscontext.d.ts +9 -0
- package/lib/contexts/analyticscontext.js +17 -0
- package/lib/contexts/canvascontext.d.ts +15 -0
- package/lib/contexts/canvascontext.js +45 -0
- package/lib/contexts/cookieconsentcontext.d.ts +38 -0
- package/lib/contexts/cookieconsentcontext.js +63 -0
- package/lib/contexts/environmentcontext.d.ts +9 -0
- package/lib/contexts/environmentcontext.js +14 -0
- package/lib/contexts/loadcontext.d.ts +24 -0
- package/lib/contexts/loadcontext.js +94 -0
- package/lib/contexts/usereventcontext.d.ts +12 -0
- package/lib/contexts/usereventcontext.js +32 -0
- package/lib/data.d.ts +38 -0
- package/lib/data.js +240 -0
- package/lib/event.d.ts +24 -0
- package/lib/event.js +61 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +20 -0
- package/lib/interfaces.d.ts +67 -0
- package/lib/interfaces.js +1 -0
- package/lib/observable.d.ts +16 -0
- package/lib/observable.js +116 -0
- package/lib/props.d.ts +0 -0
- package/lib/props.js +4 -0
- package/lib/selectors.d.ts +13 -0
- package/lib/selectors.js +173 -0
- package/lib/types.d.ts +105 -0
- package/lib/types.js +295 -0
- package/lib/validators.d.ts +8 -0
- package/lib/validators.js +32 -0
- package/lib/zcomponent.d.ts +55 -0
- package/lib/zcomponent.js +226 -0
- package/package.json +40 -0
package/lib/types.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
export var TypeHint;
|
|
2
|
+
(function (TypeHint) {
|
|
3
|
+
TypeHint["proportion"] = "proportion";
|
|
4
|
+
TypeHint["color-norm-rgb"] = "color-norm-rgb";
|
|
5
|
+
TypeHint["color-unnorm-rgb"] = "color-unnorm-rgb";
|
|
6
|
+
TypeHint["color-hex"] = "color-hex";
|
|
7
|
+
})(TypeHint || (TypeHint = {}));
|
|
8
|
+
function valuesCompatible(l, r) {
|
|
9
|
+
if (!l && !r)
|
|
10
|
+
return true;
|
|
11
|
+
if (!l || !r)
|
|
12
|
+
return false;
|
|
13
|
+
for (const [k, v] of Object.entries(l)) {
|
|
14
|
+
if (r[k] !== v)
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
export function areTypesCompatible(a, b) {
|
|
20
|
+
if (a.name !== b.name)
|
|
21
|
+
return false;
|
|
22
|
+
switch (a.name) {
|
|
23
|
+
case 'array':
|
|
24
|
+
return areTypesCompatible(a.child, b.child);
|
|
25
|
+
case 'literal':
|
|
26
|
+
return a.value === b.value;
|
|
27
|
+
case 'enum': {
|
|
28
|
+
const bt = b;
|
|
29
|
+
if (!valuesCompatible(a.values, bt.values))
|
|
30
|
+
return false;
|
|
31
|
+
if (!valuesCompatible(bt.values, a.values))
|
|
32
|
+
return false;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case 'union': {
|
|
36
|
+
const bt = b;
|
|
37
|
+
for (let achild of a.children) {
|
|
38
|
+
let foundCompatible = false;
|
|
39
|
+
for (let bchild of bt.children) {
|
|
40
|
+
if (areTypesCompatible(achild, bchild)) {
|
|
41
|
+
foundCompatible = true;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!foundCompatible)
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
case 'tuple': {
|
|
51
|
+
const bt = b;
|
|
52
|
+
if (a.children.length !== bt.children.length)
|
|
53
|
+
return false;
|
|
54
|
+
for (let i = 0; i < a.children.length; i++) {
|
|
55
|
+
if (!areTypesCompatible(a.children[i], bt.children[i]))
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
case 'function': {
|
|
61
|
+
const bt = b;
|
|
62
|
+
if (a.args.length !== bt.args.length)
|
|
63
|
+
return false;
|
|
64
|
+
for (let i = 0; i < a.args.length; i++) {
|
|
65
|
+
if (!areTypesCompatible(a.args[i].type, bt.args[i].type))
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
if (a.ret && !bt.ret)
|
|
69
|
+
return false;
|
|
70
|
+
if (!a.ret && !bt.ret)
|
|
71
|
+
return false;
|
|
72
|
+
if (a.ret && bt.ret)
|
|
73
|
+
return areTypesCompatible(a.ret, bt.ret);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
export function mergeValues(a, b) {
|
|
79
|
+
if (a === undefined && b === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
a = a ?? [];
|
|
82
|
+
b = b ?? [];
|
|
83
|
+
const fileValues = new Set();
|
|
84
|
+
const ret = [];
|
|
85
|
+
for (const entry of a) {
|
|
86
|
+
if (entry.type === 'files')
|
|
87
|
+
fileValues.add(entry.param);
|
|
88
|
+
ret.push(entry);
|
|
89
|
+
}
|
|
90
|
+
for (const entry of b) {
|
|
91
|
+
if (entry.type === 'files' && fileValues.has(entry.param))
|
|
92
|
+
continue;
|
|
93
|
+
ret.push(entry);
|
|
94
|
+
}
|
|
95
|
+
return ret;
|
|
96
|
+
}
|
|
97
|
+
export function mergeProps(a, b) {
|
|
98
|
+
if (a.name !== b.name)
|
|
99
|
+
return;
|
|
100
|
+
const type = mergeTypes(a.type, b.type);
|
|
101
|
+
if (!type)
|
|
102
|
+
return;
|
|
103
|
+
let def;
|
|
104
|
+
if (a.default !== undefined && b.default !== undefined && JSON.stringify(a.default) === JSON.stringify(b.default))
|
|
105
|
+
def = a.default;
|
|
106
|
+
return {
|
|
107
|
+
name: a.name,
|
|
108
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
109
|
+
type,
|
|
110
|
+
default: def,
|
|
111
|
+
group: a.group === b.group ? a.group : undefined,
|
|
112
|
+
groupPriority: Math.max(a.groupPriority ?? 0, b.groupPriority ?? 0),
|
|
113
|
+
values: mergeValues(a.values, b.values)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function mergeComments(a, b) {
|
|
117
|
+
const s = new Set([...a, ...b]);
|
|
118
|
+
return [...s.values()];
|
|
119
|
+
}
|
|
120
|
+
function mergeValueComments(a, b) {
|
|
121
|
+
const ret = {};
|
|
122
|
+
for (const [k, v] of Object.entries(a)) {
|
|
123
|
+
ret[k] = mergeComments(a[k], b[k]);
|
|
124
|
+
}
|
|
125
|
+
return ret;
|
|
126
|
+
}
|
|
127
|
+
export function mergeTypes(a, b) {
|
|
128
|
+
if (!areTypesCompatible(a, b))
|
|
129
|
+
return;
|
|
130
|
+
const typeHint = a.typeHint === b.typeHint ? a.typeHint : undefined;
|
|
131
|
+
switch (a.name) {
|
|
132
|
+
case 'string':
|
|
133
|
+
return {
|
|
134
|
+
name: a.name,
|
|
135
|
+
typeHint,
|
|
136
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
137
|
+
};
|
|
138
|
+
case 'number':
|
|
139
|
+
return {
|
|
140
|
+
name: a.name,
|
|
141
|
+
typeHint,
|
|
142
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
143
|
+
};
|
|
144
|
+
case 'enum':
|
|
145
|
+
return {
|
|
146
|
+
name: a.name,
|
|
147
|
+
typeHint,
|
|
148
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
149
|
+
values: a.values,
|
|
150
|
+
valueComments: a.valueComments ? mergeValueComments(a.valueComments, b.valueComments) : undefined,
|
|
151
|
+
};
|
|
152
|
+
case 'boolean':
|
|
153
|
+
return {
|
|
154
|
+
name: a.name,
|
|
155
|
+
typeHint,
|
|
156
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
157
|
+
};
|
|
158
|
+
case 'unknown':
|
|
159
|
+
return {
|
|
160
|
+
name: a.name,
|
|
161
|
+
typeHint,
|
|
162
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
163
|
+
};
|
|
164
|
+
case 'literal':
|
|
165
|
+
return {
|
|
166
|
+
name: a.name,
|
|
167
|
+
typeHint,
|
|
168
|
+
value: a.value,
|
|
169
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
170
|
+
};
|
|
171
|
+
case 'array': {
|
|
172
|
+
const child = mergeTypes(a.child, b.child);
|
|
173
|
+
if (!child)
|
|
174
|
+
return undefined;
|
|
175
|
+
return {
|
|
176
|
+
name: a.name,
|
|
177
|
+
typeHint,
|
|
178
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
179
|
+
child,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
case 'tuple': {
|
|
183
|
+
const children = [];
|
|
184
|
+
for (let i = 0; i < a.children.length; i++) {
|
|
185
|
+
const merged = mergeTypes(a.children[i], b.children[i]);
|
|
186
|
+
if (!merged)
|
|
187
|
+
return undefined;
|
|
188
|
+
children.push(merged);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
name: a.name,
|
|
192
|
+
typeHint,
|
|
193
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
194
|
+
children,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
case 'union':
|
|
198
|
+
return {
|
|
199
|
+
name: a.name,
|
|
200
|
+
typeHint,
|
|
201
|
+
children: a.children,
|
|
202
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? [])
|
|
203
|
+
};
|
|
204
|
+
case 'function':
|
|
205
|
+
return {
|
|
206
|
+
name: a.name,
|
|
207
|
+
typeHint,
|
|
208
|
+
args: a.args,
|
|
209
|
+
ret: a.ret,
|
|
210
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? [])
|
|
211
|
+
};
|
|
212
|
+
case 'event':
|
|
213
|
+
return {
|
|
214
|
+
name: a.name,
|
|
215
|
+
typeHint,
|
|
216
|
+
comments: mergeComments(a.comments ?? [], b.comments ?? []),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const regex = new RegExp(/((\.tsx?)|(\.d\.ts)|(\.jsx?))$/, 'i');
|
|
221
|
+
export function symbolPathFromFilename(f) {
|
|
222
|
+
return f.replace(regex, '');
|
|
223
|
+
}
|
|
224
|
+
export function isValidValueForType(def, t, allowUndefined) {
|
|
225
|
+
if (allowUndefined && typeof def === 'undefined')
|
|
226
|
+
return true;
|
|
227
|
+
switch (t.name) {
|
|
228
|
+
case 'boolean': return typeof def === 'boolean';
|
|
229
|
+
case 'number': return typeof def === 'number';
|
|
230
|
+
case 'string': return typeof def === 'string';
|
|
231
|
+
case 'enum': {
|
|
232
|
+
for (const v of Object.values(t.values)) {
|
|
233
|
+
if (v === def)
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
case 'unknown':
|
|
239
|
+
return true;
|
|
240
|
+
case 'array': {
|
|
241
|
+
if (!Array.isArray(def))
|
|
242
|
+
return false;
|
|
243
|
+
for (const entry of def) {
|
|
244
|
+
if (!isValidValueForType(entry, t.child))
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
case 'tuple': {
|
|
250
|
+
if (!Array.isArray(def))
|
|
251
|
+
return false;
|
|
252
|
+
if (def.length !== t.children.length)
|
|
253
|
+
return false;
|
|
254
|
+
for (let i = 0; i < t.children.length; i++) {
|
|
255
|
+
if (!isValidValueForType(def[i], t.children[i]))
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
case 'union': {
|
|
261
|
+
for (const child of t.children) {
|
|
262
|
+
if (isValidValueForType(def, child))
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
case 'literal': return def === t.value;
|
|
268
|
+
case 'function': return false;
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
export function outputForType(t) {
|
|
273
|
+
switch (t.name) {
|
|
274
|
+
case 'array':
|
|
275
|
+
return outputForType(t.child) + '[]';
|
|
276
|
+
case 'tuple':
|
|
277
|
+
return `[${t.children.map(c => outputForType(c)).join(', ')}]`;
|
|
278
|
+
case 'unknown':
|
|
279
|
+
return 'any';
|
|
280
|
+
case 'number':
|
|
281
|
+
case 'enum':
|
|
282
|
+
case 'string':
|
|
283
|
+
case 'boolean':
|
|
284
|
+
return t.name;
|
|
285
|
+
case 'literal': {
|
|
286
|
+
if (t.value === undefined)
|
|
287
|
+
return "undefined";
|
|
288
|
+
return JSON.stringify(t.value);
|
|
289
|
+
}
|
|
290
|
+
case 'union': return t.children.map(val => outputForType(val)).join(' | ');
|
|
291
|
+
case 'function': return `(${t.args.map(entry => `${entry.name}: ${outputForType(entry.type)}`).join(', ')}) => ${t.ret ? outputForType(t.ret) : 'void'}`;
|
|
292
|
+
case 'event':
|
|
293
|
+
return 'Event';
|
|
294
|
+
}
|
|
295
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Import, NodeData, ZComponentData } from './interfaces';
|
|
2
|
+
interface Issue {
|
|
3
|
+
text: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const validateImport: (i: Import) => Issue[];
|
|
6
|
+
export declare const validatorZcomponentTopLevel: (url: string, component: ZComponentData) => Issue[];
|
|
7
|
+
export declare const validatorZcomponentComponent: (node: NodeData, nodeId: string) => Issue[];
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const validateImport = (i) => {
|
|
2
|
+
if (typeof i !== 'string')
|
|
3
|
+
return [{ text: 'Import structure is invalid' }];
|
|
4
|
+
if (i.indexOf('#') < 0)
|
|
5
|
+
return [{ text: 'Import structure is invalid' }];
|
|
6
|
+
return [];
|
|
7
|
+
};
|
|
8
|
+
export const validatorZcomponentTopLevel = (url, component) => {
|
|
9
|
+
if (typeof component !== 'object' ||
|
|
10
|
+
typeof component.nodes !== 'object' ||
|
|
11
|
+
typeof component.entityConstructorProps !== 'object' ||
|
|
12
|
+
typeof component.entityProps !== 'object' ||
|
|
13
|
+
typeof component.behaviors !== 'object' ||
|
|
14
|
+
typeof component.behaviorsByNode !== 'object' ||
|
|
15
|
+
typeof component.id !== 'string' ||
|
|
16
|
+
typeof component.root !== 'string') {
|
|
17
|
+
return [{ text: 'Component structure is invalid' }];
|
|
18
|
+
}
|
|
19
|
+
if (component.id.length === 0)
|
|
20
|
+
return [{ text: 'Component structure ID has zero length' }];
|
|
21
|
+
if (component.nodes[component.root] === undefined)
|
|
22
|
+
return [{ text: 'Component root node does not exist' }];
|
|
23
|
+
return [];
|
|
24
|
+
};
|
|
25
|
+
export const validatorZcomponentComponent = (node, nodeId) => {
|
|
26
|
+
if (typeof node !== 'object' || !Array.isArray(node.children))
|
|
27
|
+
return [{ text: 'Component structure ID has zero length' }];
|
|
28
|
+
if (node.id !== nodeId)
|
|
29
|
+
return [{ text: 'Component ID mismatch' }];
|
|
30
|
+
const issues = validateImport(node.type);
|
|
31
|
+
return issues;
|
|
32
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ComponentInstance, InstanceOfComponent } from './component';
|
|
2
|
+
import { ContextManager } from './context';
|
|
3
|
+
import { ZComponentData } from './interfaces';
|
|
4
|
+
export interface ZComponentOptions {
|
|
5
|
+
data: ZComponentData;
|
|
6
|
+
importMapping: {
|
|
7
|
+
[id: string]: () => any;
|
|
8
|
+
};
|
|
9
|
+
propReplacement: {
|
|
10
|
+
[id: string]: {
|
|
11
|
+
[id: string]: any;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
constructorPropReplacement: {
|
|
15
|
+
[id: string]: {
|
|
16
|
+
[id: string]: any;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
onConstructingNode?: (id: string | undefined) => void;
|
|
20
|
+
}
|
|
21
|
+
export interface ZComponentContext {
|
|
22
|
+
zcomponent: ZComponent;
|
|
23
|
+
}
|
|
24
|
+
export declare const ZComponentContext: import("./context").ContextTypeWithDefault<ZComponentContext, [zcomponent: ZComponent<any>]>;
|
|
25
|
+
export declare function useZComponentInstance<T extends ZComponent, K extends ((props: any, ctx: any) => T)>(ctx: ContextManager, comp?: K): InstanceOfComponent<K>;
|
|
26
|
+
export declare function useConstructed(ctx: ContextManager): Promise<void>;
|
|
27
|
+
export declare class ZComponent<RootType = any> implements ComponentInstance {
|
|
28
|
+
private _opts;
|
|
29
|
+
id: string;
|
|
30
|
+
root: RootType;
|
|
31
|
+
idByRoot: Map<any, string>;
|
|
32
|
+
nodes: {
|
|
33
|
+
[id: string]: InstanceOfComponent<any> | InstanceOfComponent<any>[];
|
|
34
|
+
};
|
|
35
|
+
entityByID: Map<string, any>;
|
|
36
|
+
private _constructedResolve;
|
|
37
|
+
constructed: Promise<void>;
|
|
38
|
+
isConstructed: boolean;
|
|
39
|
+
private _nodesById;
|
|
40
|
+
private _root;
|
|
41
|
+
private _contextManager;
|
|
42
|
+
private _behaviorsToInitialize;
|
|
43
|
+
constructor(constructorProps: {
|
|
44
|
+
[id: string]: any;
|
|
45
|
+
}, ctx: ContextManager, _opts: ZComponentOptions);
|
|
46
|
+
private _inflate;
|
|
47
|
+
private _inflateBehaviors;
|
|
48
|
+
private _wrapBehaviors;
|
|
49
|
+
notifyPropsChanged(entries: Map<string, Set<string>>): void;
|
|
50
|
+
private _initializeComponentProps;
|
|
51
|
+
private _setEntityProp;
|
|
52
|
+
_getNodeById(id: string): ComponentInstance | undefined;
|
|
53
|
+
set _parent(v: any);
|
|
54
|
+
dispose(): void;
|
|
55
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { shouldBehaviorRunAtDesignTime } from './behavior';
|
|
2
|
+
import { defineContextType } from './context';
|
|
3
|
+
import { isDesignTime } from './contexts/environmentcontext';
|
|
4
|
+
import { Observable } from './observable';
|
|
5
|
+
export const ZComponentContext = defineContextType((ctx, zcomponent) => {
|
|
6
|
+
return { zcomponent };
|
|
7
|
+
});
|
|
8
|
+
export function useZComponentInstance(ctx, comp) {
|
|
9
|
+
return ctx.getOrThrow(ZComponentContext)?.zcomponent;
|
|
10
|
+
}
|
|
11
|
+
export function useConstructed(ctx) {
|
|
12
|
+
return ctx.getOrThrow(ZComponentContext)?.zcomponent.constructed;
|
|
13
|
+
}
|
|
14
|
+
export class ZComponent {
|
|
15
|
+
constructor(constructorProps, ctx, _opts) {
|
|
16
|
+
this._opts = _opts;
|
|
17
|
+
this.idByRoot = new Map();
|
|
18
|
+
this.nodes = {};
|
|
19
|
+
this.entityByID = new Map();
|
|
20
|
+
this.constructed = new Promise(resolve => this._constructedResolve = resolve);
|
|
21
|
+
this.isConstructed = false;
|
|
22
|
+
this._nodesById = new Map();
|
|
23
|
+
this._behaviorsToInitialize = [];
|
|
24
|
+
this.id = this._opts.data.id;
|
|
25
|
+
this._initializeComponentProps();
|
|
26
|
+
this._contextManager = ctx.fork(ZComponentContext, this)[0];
|
|
27
|
+
this._root = this._inflate(this._opts.data.root, {}, this._contextManager);
|
|
28
|
+
this.root = this._root?.root;
|
|
29
|
+
this._inflateBehaviors();
|
|
30
|
+
this.isConstructed = true;
|
|
31
|
+
this._constructedResolve();
|
|
32
|
+
}
|
|
33
|
+
_inflate(nodeId, additionalConstructorProps, ctx) {
|
|
34
|
+
const node = this._opts.data.nodes[nodeId];
|
|
35
|
+
if (!node) {
|
|
36
|
+
console.log('Warning - unable to find node with ID', nodeId);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const construct = this._opts.importMapping[node.type]?.();
|
|
40
|
+
if (!construct) {
|
|
41
|
+
console.log('Warning - unable to find constructor for type', node.type);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const children = additionalConstructorProps['children'] ?? [];
|
|
45
|
+
for (const child of node.children) {
|
|
46
|
+
children.push([
|
|
47
|
+
(cp, ctx) => {
|
|
48
|
+
const comp = this._inflate(child.id, cp, ctx);
|
|
49
|
+
return {
|
|
50
|
+
...comp,
|
|
51
|
+
dispose: () => {
|
|
52
|
+
this.entityByID.delete(nodeId);
|
|
53
|
+
this._nodesById.delete(nodeId);
|
|
54
|
+
if (comp && typeof comp.dispose === 'function')
|
|
55
|
+
comp.dispose();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
{}
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
let impl;
|
|
63
|
+
const constructorProps = {
|
|
64
|
+
...(this._opts.data.entityConstructorProps?.[nodeId] ?? {}),
|
|
65
|
+
...(this._opts.constructorPropReplacement?.[nodeId] ?? {}),
|
|
66
|
+
...additionalConstructorProps,
|
|
67
|
+
children,
|
|
68
|
+
};
|
|
69
|
+
this._opts.onConstructingNode?.(nodeId);
|
|
70
|
+
try {
|
|
71
|
+
impl = construct(constructorProps, ctx);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.log('Warning - unable to construct node of type', node.type, err);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this._behaviorsToInitialize.push([nodeId, impl, ctx]);
|
|
78
|
+
if (impl.root)
|
|
79
|
+
this.idByRoot.set(impl.root, nodeId);
|
|
80
|
+
this._nodesById.set(nodeId, impl);
|
|
81
|
+
this.entityByID.set(nodeId, impl);
|
|
82
|
+
if (node.scriptName) {
|
|
83
|
+
const entriesForScriptName = this._opts.data.entitiesByScriptName?.[node.scriptName] ?? {};
|
|
84
|
+
let moreThanOne = false;
|
|
85
|
+
for (const entry in entriesForScriptName) {
|
|
86
|
+
if (entry !== node.id) {
|
|
87
|
+
moreThanOne = true;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (moreThanOne) {
|
|
92
|
+
const current = this.nodes[node.scriptName] ?? {};
|
|
93
|
+
this.nodes[node.scriptName] = current;
|
|
94
|
+
current[node.id] = impl;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.nodes[node.scriptName] = impl;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!impl)
|
|
101
|
+
return impl;
|
|
102
|
+
const props = {
|
|
103
|
+
...(this._opts.data.entityProps?.[nodeId] ?? {}),
|
|
104
|
+
...(this._opts.propReplacement?.[nodeId] ?? {}),
|
|
105
|
+
};
|
|
106
|
+
for (const [key, val] of Object.entries(props)) {
|
|
107
|
+
try {
|
|
108
|
+
this._setEntityProp(impl, key, val);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.log('Warning - unable to set node prop', key, val);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this._opts.onConstructingNode?.(undefined);
|
|
115
|
+
if (this.isConstructed)
|
|
116
|
+
this._inflateBehaviors();
|
|
117
|
+
return impl;
|
|
118
|
+
}
|
|
119
|
+
_inflateBehaviors() {
|
|
120
|
+
for (const [nodeID, impl, ctx] of this._behaviorsToInitialize) {
|
|
121
|
+
this._wrapBehaviors(nodeID, impl, ctx);
|
|
122
|
+
}
|
|
123
|
+
this._behaviorsToInitialize = [];
|
|
124
|
+
}
|
|
125
|
+
_wrapBehaviors(nodeID, impl, ctx) {
|
|
126
|
+
const behaviors = this._opts.data.behaviorsByNode?.[nodeID] ?? [];
|
|
127
|
+
const designTime = isDesignTime(this._contextManager);
|
|
128
|
+
for (const behaviorID of behaviors) {
|
|
129
|
+
const behavior = this._opts.data.behaviors?.[behaviorID];
|
|
130
|
+
if (!behavior)
|
|
131
|
+
continue;
|
|
132
|
+
const constructorProps = {
|
|
133
|
+
...(this._opts.data.entityConstructorProps?.[behaviorID] ?? {}),
|
|
134
|
+
...(this._opts.constructorPropReplacement?.[behaviorID] ?? {}),
|
|
135
|
+
instance: impl
|
|
136
|
+
};
|
|
137
|
+
const constructor = this._opts.importMapping[behavior.type]?.();
|
|
138
|
+
if (!constructor)
|
|
139
|
+
continue;
|
|
140
|
+
if (designTime && !shouldBehaviorRunAtDesignTime(constructor))
|
|
141
|
+
continue;
|
|
142
|
+
const res = constructor(constructorProps, ctx);
|
|
143
|
+
if (!res)
|
|
144
|
+
continue;
|
|
145
|
+
this.entityByID.set(behaviorID, res);
|
|
146
|
+
const props = {
|
|
147
|
+
...(this._opts.data.entityProps?.[behaviorID] ?? {}),
|
|
148
|
+
...(this._opts.propReplacement?.[behaviorID] ?? {}),
|
|
149
|
+
};
|
|
150
|
+
for (const [key, val] of Object.entries(props)) {
|
|
151
|
+
try {
|
|
152
|
+
this._setEntityProp(res, key, val);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
console.log('Warning - unable to set behavior prop', key, val);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return impl;
|
|
160
|
+
}
|
|
161
|
+
notifyPropsChanged(entries) {
|
|
162
|
+
for (const [entityID, propSet] of entries.entries()) {
|
|
163
|
+
const entity = this.entityByID.get(entityID);
|
|
164
|
+
if (!entity)
|
|
165
|
+
continue;
|
|
166
|
+
for (const prop of propSet.values()) {
|
|
167
|
+
try {
|
|
168
|
+
this._setEntityProp(entity, prop, this._opts.data.entityProps[entityID]?.[prop]);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
console.log('Warning - unable to set prop', entityID, prop);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
_initializeComponentProps() {
|
|
177
|
+
const componentProps = this._opts.data.propEntityOverrides ?? {};
|
|
178
|
+
for (const [prop, entry] of Object.entries(componentProps)) {
|
|
179
|
+
let value = undefined;
|
|
180
|
+
Object.defineProperty(this, prop, {
|
|
181
|
+
get: () => value,
|
|
182
|
+
set: v => {
|
|
183
|
+
value = v;
|
|
184
|
+
for (const [entityID, overriddenProps] of Object.entries(entry)) {
|
|
185
|
+
const entity = this.entityByID.get(entityID);
|
|
186
|
+
if (!entity)
|
|
187
|
+
continue;
|
|
188
|
+
for (const overriddenProp of Object.keys(overriddenProps)) {
|
|
189
|
+
try {
|
|
190
|
+
this._setEntityProp(entity, overriddenProp, v);
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.log('Warning - unable to set prop', overriddenProp, v);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
_setEntityProp(entity, prop, v) {
|
|
202
|
+
if (entity[prop] instanceof Observable)
|
|
203
|
+
entity[prop].value = v;
|
|
204
|
+
else
|
|
205
|
+
entity[prop] = v;
|
|
206
|
+
}
|
|
207
|
+
_getNodeById(id) {
|
|
208
|
+
return this._nodesById.get(id);
|
|
209
|
+
}
|
|
210
|
+
set _parent(v) {
|
|
211
|
+
if (this._root)
|
|
212
|
+
this._root.parent = v;
|
|
213
|
+
}
|
|
214
|
+
dispose() {
|
|
215
|
+
for (const entity of this.entityByID.values()) {
|
|
216
|
+
if (entity && typeof entity.dispose === 'function') {
|
|
217
|
+
try {
|
|
218
|
+
entity.dispose();
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
// Ignore
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zcomponent/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=12.0.0",
|
|
9
|
+
"browsers": "defaults"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"directories": {
|
|
13
|
+
"lib": "lib"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"index.js",
|
|
17
|
+
"index.d.ts",
|
|
18
|
+
"lib/**/*",
|
|
19
|
+
"css/**/*"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"test": "PW_EXPERIMENTAL_TS_ESM=1 playwright test",
|
|
24
|
+
"tests": "parcel serve tests/index.html -p 8088"
|
|
25
|
+
},
|
|
26
|
+
"author": "Zappar Limited",
|
|
27
|
+
"license": "Proprietary",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"typescript": "^4.6.3",
|
|
30
|
+
"@playwright/test": "^1.25.0",
|
|
31
|
+
"parcel": "2.6.2",
|
|
32
|
+
"@types/ua-parser-js": "^0.7.36",
|
|
33
|
+
"ua-parser-js": "^1.0.2"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {},
|
|
36
|
+
"zexports": [
|
|
37
|
+
"./lib/components/**/*",
|
|
38
|
+
"./lib/behaviors/**/*"
|
|
39
|
+
]
|
|
40
|
+
}
|