@zcomponent/core 0.0.13 → 0.0.15

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.
@@ -29,15 +29,12 @@ export interface ZComponentData {
29
29
  nodes: NodeByID;
30
30
  root: string;
31
31
  props: Props;
32
+ constructorProps?: Props;
32
33
  entityProps: PropsByID;
33
34
  entityConstructorProps: PropsByID;
34
35
  preview: Import;
35
- propEntityOverrides?: {
36
- [propName: string]: {
37
- [entityID: string]: {
38
- [propName: string]: boolean;
39
- };
40
- };
36
+ entityPropOverrides?: {
37
+ [id: string]: EntityPropOverride;
41
38
  };
42
39
  behaviors: BehaviorByID;
43
40
  animation?: Animation;
@@ -70,3 +67,30 @@ export interface BehaviorData {
70
67
  order: string;
71
68
  };
72
69
  }
70
+ export type EntityPropOverride = PropEntityPropOverride | ImportEntityPropOverride | ContextValueEntityPropOverride;
71
+ export declare enum EntityPropOverrideType {
72
+ ComponentProp = "componentprop",
73
+ Import = "import",
74
+ ContextValue = "contextvalue"
75
+ }
76
+ export interface BaseEntityPropOverride {
77
+ id: string;
78
+ entityID: string;
79
+ entityPropPath: (string | number)[];
80
+ entityPropIsConstructor: boolean;
81
+ type: EntityPropOverrideType;
82
+ }
83
+ export interface PropEntityPropOverride extends BaseEntityPropOverride {
84
+ propName: string;
85
+ isConstructorProp: boolean;
86
+ type: EntityPropOverrideType.ComponentProp;
87
+ }
88
+ export interface ImportEntityPropOverride extends BaseEntityPropOverride {
89
+ imp: string;
90
+ type: EntityPropOverrideType.Import;
91
+ }
92
+ export interface ContextValueEntityPropOverride extends BaseEntityPropOverride {
93
+ imp: string;
94
+ val: string;
95
+ type: EntityPropOverrideType.ContextValue;
96
+ }
package/lib/interfaces.js CHANGED
@@ -1 +1,6 @@
1
- export {};
1
+ export var EntityPropOverrideType;
2
+ (function (EntityPropOverrideType) {
3
+ EntityPropOverrideType["ComponentProp"] = "componentprop";
4
+ EntityPropOverrideType["Import"] = "import";
5
+ EntityPropOverrideType["ContextValue"] = "contextvalue";
6
+ })(EntityPropOverrideType || (EntityPropOverrideType = {}));
@@ -1,3 +1,4 @@
1
+ import { Emitter } from "./emitter";
1
2
  type Resolved<T, M> = [T] extends [never] ? M : T;
2
3
  /**
3
4
  * A class that holds a value and watches it for changes (deeply by default).
@@ -31,14 +32,11 @@ type Resolved<T, M> = [T] extends [never] ? M : T;
31
32
  * @typeParam Type - The type of the contained value
32
33
  * @typeParam TypeInternal - An internal type used to improve automatic type detection
33
34
  */
34
- export declare class Observable<Type = never, TypeInternal extends any[] | [] | never = never> {
35
+ export declare class Observable<Type = never, TypeInternal extends any[] | [] | never = never> extends Emitter<[Resolved<Type, TypeInternal>]> {
35
36
  private _default;
36
37
  private _deep;
37
38
  private _proxies;
38
39
  private _value;
39
- private _nextToken;
40
- private _handlersByToken;
41
- private _tokenByHandler;
42
40
  /**
43
41
  * Constructs a new Observable
44
42
  *
@@ -56,8 +54,7 @@ export declare class Observable<Type = never, TypeInternal extends any[] | [] |
56
54
  get value(): Resolved<Type, TypeInternal>;
57
55
  private _wrap;
58
56
  set value(v: Resolved<Type, TypeInternal> | undefined);
59
- withValue(fn: (v: Resolved<Type, TypeInternal>) => void): number;
60
- removeWithValue(fnOrToken: number | ((v: Resolved<Type, TypeInternal>) => void)): void;
57
+ addListener(fn: (v: Resolved<Type, TypeInternal>) => void, priority?: number): void;
61
58
  private _emitValue;
62
59
  }
63
60
  export {};
package/lib/observable.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { Emitter } from "./emitter";
1
2
  /**
2
3
  * A class that holds a value and watches it for changes (deeply by default).
3
4
  *
@@ -30,14 +31,12 @@
30
31
  * @typeParam Type - The type of the contained value
31
32
  * @typeParam TypeInternal - An internal type used to improve automatic type detection
32
33
  */
33
- export class Observable {
34
+ export class Observable extends Emitter {
34
35
  constructor(_default, withHandler, _deep = true) {
36
+ super();
35
37
  this._default = _default;
36
38
  this._deep = _deep;
37
39
  this._proxies = new WeakMap();
38
- this._nextToken = 0;
39
- this._handlersByToken = new Map();
40
- this._tokenByHandler = new Map();
41
40
  let initial = this._default;
42
41
  if (Array.isArray(this._default) && this._deep) {
43
42
  initial = this._default.slice();
@@ -49,7 +48,7 @@ export class Observable {
49
48
  }
50
49
  this._value = this._wrap(initial);
51
50
  if (withHandler)
52
- this.withValue(withHandler);
51
+ this.addListener(withHandler);
53
52
  }
54
53
  /**
55
54
  * Access the current value for this Observable. Changing this value (or, unless deep inspection is disabled, its recursive elements and keys) will trigger any registered handlers to be called with the new value.
@@ -117,40 +116,16 @@ export class Observable {
117
116
  this._value = this._wrap(v);
118
117
  this._emitValue();
119
118
  }
120
- withValue(fn) {
121
- const token = this._nextToken++;
122
- this._handlersByToken.set(token, fn);
123
- this._tokenByHandler.set(fn, token);
119
+ addListener(fn, priority = 0) {
120
+ this.addListener(fn);
124
121
  try {
125
122
  fn(this._value.proxy);
126
123
  }
127
124
  catch (err) {
128
125
  console.error(err);
129
126
  }
130
- return token;
131
- }
132
- removeWithValue(fnOrToken) {
133
- if (typeof fnOrToken === 'number') {
134
- const handler = this._handlersByToken.get(fnOrToken);
135
- if (handler !== undefined)
136
- this._tokenByHandler.delete(handler);
137
- this._handlersByToken.delete(fnOrToken);
138
- }
139
- else {
140
- const token = this._tokenByHandler.get(fnOrToken);
141
- if (token !== undefined)
142
- this._handlersByToken.delete(token);
143
- this._tokenByHandler.delete(fnOrToken);
144
- }
145
127
  }
146
128
  _emitValue() {
147
- for (let [key, h] of this._handlersByToken) {
148
- try {
149
- h(this._value.proxy);
150
- }
151
- catch (err) {
152
- console.error(err);
153
- }
154
- }
129
+ this._emit(this._value.proxy);
155
130
  }
156
131
  }
@@ -1,4 +1,4 @@
1
- import { Import, NodeByID, ParsedImport, Props } from './interfaces';
1
+ import { EntityPropOverride, Import, NodeByID, ParsedImport, Props } from './interfaces';
2
2
  export declare function parseImport(i: Import): ParsedImport;
3
3
  export declare function constructImport(from: string, destFile: string, imp: string): string;
4
4
  export declare function getScriptName(n: string, requireUniqueIn: {
@@ -6,8 +6,20 @@ export declare function getScriptName(n: string, requireUniqueIn: {
6
6
  }): string;
7
7
  export declare function isValidVariableName(n: string): boolean;
8
8
  export declare function variableNameFromImport(imp: ParsedImport): string;
9
- export declare const typeDefinitionForComponent: (nodes: NodeByID, props: Props, scriptNames: {
9
+ export type EntityPropOverrideByEntityPropPath = {
10
+ [entityID: string]: {
11
+ [propName: string]: {
12
+ [path: string]: EntityPropOverride;
13
+ };
14
+ };
15
+ };
16
+ export declare function entityPropOverrideByEntityAndProp(entityPropOverrides: {
17
+ [id: string]: EntityPropOverride;
18
+ }): EntityPropOverrideByEntityPropPath;
19
+ export declare function summaryForEntityPropOverrideDestination(o: EntityPropOverride): string;
20
+ export declare const typeDefinitionForComponent: (nodes: NodeByID, props: Props, constructorProps: Props | undefined, scriptNames: {
10
21
  [id: string]: {
11
22
  [id: string]: boolean;
12
23
  };
13
- }, url: string) => string;
24
+ } | undefined, url: string) => string;
25
+ export declare function getSafeKeyName(n: string): string;
package/lib/selectors.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { EntityPropOverrideType } from './interfaces';
1
2
  import * as path from 'path';
2
3
  import { outputForType } from './types';
3
4
  export function parseImport(i) {
@@ -117,11 +118,52 @@ export function variableNameFromImport(imp) {
117
118
  return imp[1];
118
119
  return 'unknown';
119
120
  }
120
- export const typeDefinitionForComponent = (nodes, props, scriptNames, url) => {
121
+ export function entityPropOverrideByEntityAndProp(entityPropOverrides) {
122
+ const ret = Object.create(null);
123
+ for (const val of Object.values(entityPropOverrides)) {
124
+ if (!Array.isArray(val.entityPropPath) || val.entityPropPath.length < 1)
125
+ continue;
126
+ const obj = ret[val.entityID] || Object.create(null);
127
+ ret[val.entityID] = obj;
128
+ const propName = val.entityPropPath[0];
129
+ const arr = obj[propName] || Object.create(null);
130
+ obj[propName] = arr;
131
+ arr[val.entityPropPath.join('.')] = val;
132
+ }
133
+ return ret;
134
+ }
135
+ export function summaryForEntityPropOverrideDestination(o) {
136
+ switch (o.type) {
137
+ case EntityPropOverrideType.ComponentProp:
138
+ return 'Component Prop: ' + o.propName;
139
+ case EntityPropOverrideType.ContextValue: {
140
+ const imp = parseImport(o.imp);
141
+ if (imp[1] === 'default' && typeof imp[0] === 'string') {
142
+ const parts = imp[0].split(path.sep);
143
+ return parts[parts.length - 1] + '.' + o.val;
144
+ }
145
+ if (typeof imp[1] === 'string')
146
+ return imp[1] + '.' + o.val;
147
+ return `?.` + o.val;
148
+ }
149
+ case EntityPropOverrideType.Import: {
150
+ return o.imp;
151
+ // const imp = parseImport(o.imp);
152
+ // if (imp[1] === 'default' && typeof imp[0] === 'string') {
153
+ // const parts = imp[0].split(path.sep);
154
+ // return parts[parts.length - 1];
155
+ // }
156
+ // if (typeof imp[1] === 'string') return imp[1];
157
+ // return '?';
158
+ }
159
+ }
160
+ return '?';
161
+ }
162
+ export const typeDefinitionForComponent = (nodes, props, constructorProps, scriptNames, url) => {
121
163
  const importMapping = new Map();
122
164
  let indx = 0;
123
165
  let importStrings = [];
124
- for (const scriptNameNodes of Object.values(scriptNames)) {
166
+ for (const scriptNameNodes of Object.values(scriptNames ?? {})) {
125
167
  for (const nodeID of Object.keys(scriptNameNodes)) {
126
168
  const node = nodes[nodeID];
127
169
  if (!node)
@@ -139,15 +181,20 @@ export const typeDefinitionForComponent = (nodes, props, scriptNames, url) => {
139
181
 
140
182
  ${importStrings.join('\n')}
141
183
 
184
+ interface ConstructorProps {
185
+ ${Object.values(constructorProps ?? {}).map(typeOutputForConstructorProp).join('\n\n')}
186
+ }
187
+
142
188
  /**
143
189
  * @zcomponent
190
+ * @zicon zcomponent
144
191
  */
145
192
  declare class Comp extends ZComponent {
146
193
 
147
- constructor(contextManager: ContextManager, constructorProps: {});
194
+ constructor(contextManager: ContextManager, constructorProps: ConstructorProps);
148
195
 
149
196
  nodes: {
150
- ${Object.entries(scriptNames).map(entry => {
197
+ ${Object.entries(scriptNames ?? {}).map(entry => {
151
198
  const values = Object.keys(entry[1]);
152
199
  if (values.length > 1) {
153
200
  return `\t\t${entry[0]}: {${values.map(e => `${JSON.stringify(e)}: ${importMapping.get(nodes[e].type)}`).join(', ')}},`;
@@ -158,16 +205,40 @@ ${Object.entries(scriptNames).map(entry => {
158
205
  }).join("\n")}
159
206
  };
160
207
 
161
- ${Object.values(props).map(typeOutputForProp).join('\n')}
208
+ ${Object.values(props).map(typeOutputForProp).join('\n\n')}
162
209
  }
163
210
 
164
211
  export default Comp;
165
212
  `;
166
213
  };
214
+ function makeCommentSafe(c) {
215
+ return c.replaceAll('*/', '').split('\n').join('\n\t* ');
216
+ }
167
217
  function typeOutputForProp(prop) {
168
- return ` /**
218
+ const comments = (prop.comments && prop.comments.length > 0) ? '\n\t* ' + prop.comments.map(makeCommentSafe).join('\n\t*\n\t* ') + '\n\t* ' : '';
219
+ return ` /**${comments}
169
220
  * @zprop
170
- * ${prop.default && `@zdefault ${JSON.stringify(prop.default)}`}
221
+ * ${prop.default !== undefined ? `@zdefault ${JSON.stringify(prop.default)}` : ''}
171
222
  */
172
223
  public ${prop.name}: Observable<${outputForType(prop.type, true)}>;`;
173
224
  }
225
+ function typeOutputForConstructorProp(prop) {
226
+ const comments = (prop.comments && prop.comments.length > 0) ? '\n\t* ' + prop.comments.map(makeCommentSafe).join('\n\t*\n\t* ') + '\n\t* ' : '';
227
+ return ` /**${comments}
228
+ * @zprop
229
+ * ${prop.default !== undefined && `@zdefault ${JSON.stringify(prop.default)}`}
230
+ */
231
+ ${prop.name}: ${outputForType(prop.type, true)};`;
232
+ }
233
+ export function getSafeKeyName(n) {
234
+ if (n.length === 0)
235
+ return '_';
236
+ let scriptname = n.replace(' ', '_');
237
+ scriptname = scriptname.replace('-', '_');
238
+ scriptname = scriptname.replace('.', '_');
239
+ scriptname = scriptname.replace(/[^a-zA-Z0-9_]/g, '');
240
+ if (scriptname.match(/^[0-9]/)) {
241
+ scriptname = 'n' + scriptname;
242
+ }
243
+ return scriptname;
244
+ }
package/lib/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { EntityPropOverride } from "./interfaces";
1
2
  export interface BaseType {
2
3
  comments?: string[];
3
4
  typeHint?: TypeHint;
@@ -69,10 +70,18 @@ export interface Prop {
69
70
  groupPriority?: number;
70
71
  values?: Values[];
71
72
  }
73
+ export interface DefaultChild {
74
+ label: string;
75
+ type: string;
76
+ initialProps: {
77
+ [id: string]: any;
78
+ };
79
+ }
80
+ export type ComponentInfoType = "component" | "behavior" | "context";
72
81
  export interface ComponentInfo {
73
82
  name: string;
74
83
  file: string;
75
- type: "component" | "behavior";
84
+ type: ComponentInfoType;
76
85
  isDefault?: boolean;
77
86
  constructorProps: {
78
87
  [id: string]: Prop;
@@ -86,10 +95,23 @@ export interface ComponentInfo {
86
95
  tags: string[];
87
96
  allowedChildren: string[];
88
97
  allowedParents?: string[];
98
+ defaultChildren?: DefaultChild[];
99
+ }
100
+ export interface ValueInfo {
101
+ name: string;
102
+ file: string;
103
+ isDefault?: boolean;
104
+ type: Type;
105
+ comments?: string[];
106
+ }
107
+ export interface SourceFileTypeInfo {
108
+ components: {
109
+ [id: string]: ComponentInfo;
110
+ };
111
+ values: {
112
+ [id: string]: ValueInfo;
113
+ };
89
114
  }
90
- export type SourceFileTypeInfo = {
91
- [id: string]: ComponentInfo;
92
- };
93
115
  export type TypeInfoByFileName = {
94
116
  [id: string]: SourceFileTypeInfo;
95
117
  };
@@ -105,3 +127,8 @@ export interface TemplateInfo {
105
127
  export declare function symbolPathFromFilename(f: string): string;
106
128
  export declare function isValidValueForType(def: any, t: Type, allowUndefined?: boolean): boolean;
107
129
  export declare function outputForType(t: Type, alwaysBasic?: boolean): string;
130
+ export declare function overridesAreCompatible(a: {
131
+ [path: string]: EntityPropOverride;
132
+ }, b: {
133
+ [path: string]: EntityPropOverride;
134
+ }): boolean;
package/lib/types.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { EntityPropOverrideType } from "./interfaces";
2
+ import { getSafeKeyName } from "./selectors";
1
3
  export var TypeHint;
2
4
  (function (TypeHint) {
3
5
  TypeHint["proportion"] = "proportion";
@@ -291,6 +293,9 @@ function getBasicType(t) {
291
293
  case 'array':
292
294
  return outputForType(t.child) + '[]';
293
295
  case 'tuple':
296
+ if (Array.isArray(t.names) && t.names.length === t.children.length) {
297
+ return `[${t.children.map((c, indx) => `${getSafeKeyName(t.names[indx])}: ${outputForType(c)}`).join(', ')}]`;
298
+ }
294
299
  return `[${t.children.map(c => outputForType(c)).join(', ')}]`;
295
300
  case 'unknown':
296
301
  return 'any';
@@ -310,3 +315,59 @@ function getBasicType(t) {
310
315
  return 'Event';
311
316
  }
312
317
  }
318
+ export function overridesAreCompatible(a, b) {
319
+ const bkeys = new Set(Object.keys(b));
320
+ for (const [p, obj] of Object.entries(a)) {
321
+ if (!b[p])
322
+ return false;
323
+ if (!overrideAreCompatible(obj, b[p]))
324
+ return false;
325
+ bkeys.delete(p);
326
+ }
327
+ if (bkeys.size > 0)
328
+ return false;
329
+ return true;
330
+ }
331
+ function overrideAreCompatible(a, b) {
332
+ if (a && b) {
333
+ if (a.type !== b.type)
334
+ return false;
335
+ if (a.entityPropPath.length !== b.entityPropPath.length)
336
+ return false;
337
+ if (a.entityPropIsConstructor !== b.entityPropIsConstructor)
338
+ return false;
339
+ for (let i = 0; i < a.entityPropPath.length; i++) {
340
+ if (a.entityPropPath[i] !== b.entityPropPath[i])
341
+ return false;
342
+ }
343
+ switch (a.type) {
344
+ case EntityPropOverrideType.ComponentProp: {
345
+ const bt = b;
346
+ if (a.isConstructorProp !== bt.isConstructorProp)
347
+ return false;
348
+ if (a.propName !== bt.propName)
349
+ return false;
350
+ return true;
351
+ }
352
+ case EntityPropOverrideType.ContextValue: {
353
+ const bt = b;
354
+ if (a.imp !== bt.imp)
355
+ return false;
356
+ if (a.val !== bt.val)
357
+ return false;
358
+ return true;
359
+ }
360
+ case EntityPropOverrideType.Import: {
361
+ const bt = b;
362
+ if (a.imp !== bt.imp)
363
+ return false;
364
+ return true;
365
+ }
366
+ }
367
+ }
368
+ if (!a && b)
369
+ return false;
370
+ if (a && !b)
371
+ return false;
372
+ return true;
373
+ }
@@ -1,5 +1,6 @@
1
1
  import { Component, ComponentChildren, ConstructorProps } from './component';
2
2
  import { ContextManager, Context } from './context';
3
+ import { Entity } from './entity';
3
4
  import { ZComponentData } from './interfaces';
4
5
  export interface ZComponentOptions {
5
6
  data: ZComponentData;
@@ -35,21 +36,26 @@ export declare class ZComponent<RootType = any> extends Component<RootType> {
35
36
  nodes: {
36
37
  [id: string]: Component | Component[];
37
38
  };
38
- entityByID: Map<string, any>;
39
- entityByLabel: Map<string, any>;
39
+ entityByID: Map<string, Entity>;
40
+ entityByLabel: Map<string, Entity>;
41
+ nodeByLabel: Map<string, Component<any, ConstructorProps>>;
40
42
  private _constructedResolve;
41
43
  constructed: Promise<void>;
42
44
  isConstructed: boolean;
43
45
  private _nodesById;
44
46
  private _behaviorsToInitialize;
47
+ private _constructorPropOverridesByEntityID;
45
48
  constructor(contextManager: ContextManager, constructorProps: ConstructorProps, _opts: ZComponentOptions);
46
49
  private _constructorForNode;
47
50
  private _constructorForBehavior;
48
51
  private _inflateBehaviors;
49
52
  private _wrapBehaviors;
50
53
  notifyPropsChanged(entries: Map<string, Set<string>>): void;
54
+ private _initializeOverrides;
55
+ private _initializeConstructorPropOverrides;
51
56
  private _initializeComponentProps;
52
57
  private _setEntityProp;
58
+ private _setEntityPropPath;
53
59
  _getNodeById(id: string): Component | undefined;
54
60
  dispose(): never;
55
61
  }
package/lib/zcomponent.js CHANGED
@@ -4,6 +4,7 @@ import { Context } from './context';
4
4
  import { isDesignTime } from './contexts/environmentcontext';
5
5
  import { TagContext } from './contexts/tagcontext';
6
6
  import { computeBehaviorHierarchy, computeNodeHierarchy } from './data';
7
+ import { EntityPropOverrideType } from './interfaces';
7
8
  import { Observable } from './observable';
8
9
  import { setCurrentZComponentConstruction } from './zcomponentconstruction';
9
10
  export class ZComponentContext extends Context {
@@ -22,12 +23,15 @@ export class ZComponent extends Component {
22
23
  this.nodes = {};
23
24
  this.entityByID = new Map();
24
25
  this.entityByLabel = new Map();
26
+ this.nodeByLabel = new Map();
25
27
  this.constructed = new Promise(resolve => this._constructedResolve = resolve);
26
28
  this.isConstructed = false;
27
29
  this._nodesById = new Map();
28
30
  this._behaviorsToInitialize = [];
31
+ this._constructorPropOverridesByEntityID = new Map();
29
32
  const contextManagerForChildren = contextManager.forkMultiple([ZComponentContext, { zcomponent: this }], [TagContext, {}])[0];
30
33
  this.id = this._opts.data.id;
34
+ this._initializeConstructorPropOverrides();
31
35
  const rootConstructor = this._constructorForNode(this._opts.data.root);
32
36
  if (rootConstructor) {
33
37
  this.constructChildren([
@@ -36,6 +40,7 @@ export class ZComponent extends Component {
36
40
  }
37
41
  this._inflateBehaviors();
38
42
  this._initializeComponentProps();
43
+ this._initializeOverrides();
39
44
  this.isConstructed = true;
40
45
  this._constructedResolve();
41
46
  }
@@ -65,13 +70,16 @@ export class ZComponent extends Component {
65
70
  ...constructorProps,
66
71
  ...(that._opts.data.entityConstructorProps?.[nodeId] ?? {}),
67
72
  ...(that._opts.constructorPropReplacement?.[nodeId] ?? {}),
73
+ ...(that._constructorPropOverridesByEntityID.get(nodeId) ?? {}),
68
74
  children
69
75
  };
70
76
  setCurrentZComponentConstruction(that);
71
77
  super(contextManager, constructorProps);
72
78
  that.entityByID.set(nodeId, this);
73
- if (node?.label)
79
+ if (node?.label) {
74
80
  that.entityByLabel.set(node.label, this);
81
+ that.nodeByLabel.set(node.label, this);
82
+ }
75
83
  that._nodesById.set(nodeId, this);
76
84
  for (const element of this.elementsResolved) {
77
85
  that.idByElement.set(element, nodeId);
@@ -145,6 +153,7 @@ export class ZComponent extends Component {
145
153
  ...constructorProps,
146
154
  ...(that._opts.data.entityConstructorProps?.[behaviorId] ?? {}),
147
155
  ...(that._opts.constructorPropReplacement?.[behaviorId] ?? {}),
156
+ ...(that._constructorPropOverridesByEntityID.get(behaviorId) ?? {}),
148
157
  };
149
158
  setCurrentZComponentConstruction(that);
150
159
  super(contextManager, instance, constructorProps);
@@ -205,26 +214,84 @@ export class ZComponent extends Component {
205
214
  }
206
215
  }
207
216
  }
208
- _initializeComponentProps() {
209
- const componentProps = this._opts.data.propEntityOverrides ?? {};
210
- for (const [prop, entry] of Object.entries(componentProps)) {
211
- const propInfo = this._opts.data.props[prop];
212
- const entries = Object.entries(entry).map(e => [e[0], Object.keys(e[1])]);
213
- this[prop] = new Observable(propInfo?.default, v => {
214
- for (const e of entries) {
215
- const entity = this.entityByID.get(e[0]);
216
- if (!entity)
217
- continue;
218
- for (const overriddenProp of e[1]) {
219
- try {
220
- this._setEntityProp(entity, overriddenProp, v);
221
- }
222
- catch (err) {
223
- console.log('Warning - unable to set prop', overriddenProp, v);
217
+ _initializeOverrides() {
218
+ const overrides = this._opts.data.entityPropOverrides ?? {};
219
+ for (const override of Object.values(overrides)) {
220
+ const entity = this.entityByID.get(override.entityID);
221
+ if (!entity)
222
+ continue;
223
+ try {
224
+ switch (override.type) {
225
+ case EntityPropOverrideType.Import: {
226
+ const v = this._opts.importMapping[override.imp]?.();
227
+ if (!v)
228
+ continue;
229
+ if (v instanceof Observable)
230
+ this.register(v, val => this._setEntityPropPath(entity, override.entityPropPath, val), { bindWhenDisabled: true });
231
+ else
232
+ this._setEntityPropPath(entity, override.entityPropPath, v);
233
+ break;
234
+ }
235
+ case EntityPropOverrideType.ContextValue: {
236
+ const ctx = this._opts.importMapping[override.imp]?.();
237
+ const ctxInstance = entity.contextManager.getOrThrow(ctx);
238
+ const v = ctxInstance[override.val];
239
+ if (!v)
240
+ continue;
241
+ if (v instanceof Observable)
242
+ this.register(v, val => this._setEntityPropPath(entity, override.entityPropPath, val), { bindWhenDisabled: true });
243
+ else
244
+ this._setEntityPropPath(entity, override.entityPropPath, v);
245
+ break;
246
+ }
247
+ case EntityPropOverrideType.ComponentProp: {
248
+ if (override.isConstructorProp) {
249
+ const prop = this._opts.data.constructorProps?.[override.propName];
250
+ if (!prop)
251
+ break;
252
+ const val = this.constructorProps[override.propName] ?? prop.default;
253
+ if (val !== undefined)
254
+ this._setEntityPropPath(entity, override.entityPropPath, val);
255
+ break;
224
256
  }
257
+ const v = this[override.propName];
258
+ if (!v)
259
+ continue;
260
+ if (v instanceof Observable)
261
+ this.register(v, val => this._setEntityPropPath(entity, override.entityPropPath, val), { bindWhenDisabled: true });
262
+ else
263
+ this._setEntityPropPath(entity, override.entityPropPath, v);
264
+ break;
225
265
  }
226
266
  }
227
- });
267
+ }
268
+ catch (err) {
269
+ console.log('Unable to set entity prop override', err);
270
+ }
271
+ }
272
+ }
273
+ _initializeConstructorPropOverrides() {
274
+ for (const entry of Object.values(this._opts.data.entityPropOverrides ?? {})) {
275
+ if (entry.type !== EntityPropOverrideType.ComponentProp)
276
+ continue;
277
+ if (!entry.isConstructorProp)
278
+ continue;
279
+ if (entry.entityPropPath.length !== 1)
280
+ continue;
281
+ const obj = this._constructorPropOverridesByEntityID.get(entry.entityID) ?? Object.create(null);
282
+ this._constructorPropOverridesByEntityID.set(entry.entityID, obj);
283
+ const prop = this._opts.data.constructorProps?.[entry.propName];
284
+ if (!prop)
285
+ continue;
286
+ const val = this.constructorProps[entry.propName] ?? prop.default;
287
+ if (val !== undefined)
288
+ obj[entry.entityPropPath[0]] = val;
289
+ }
290
+ }
291
+ _initializeComponentProps() {
292
+ const componentProps = this._opts.data.props ?? {};
293
+ for (const prop of Object.values(componentProps)) {
294
+ this[prop.name] = new Observable(prop.default);
228
295
  }
229
296
  }
230
297
  _setEntityProp(entity, prop, v) {
@@ -233,6 +300,22 @@ export class ZComponent extends Component {
233
300
  else
234
301
  entity[prop] = v;
235
302
  }
303
+ _setEntityPropPath(entity, propPath, v) {
304
+ if (propPath.length < 1)
305
+ return;
306
+ const prop = propPath[0];
307
+ let parent = entity;
308
+ let currentKey = prop;
309
+ if (entity[prop] instanceof Observable) {
310
+ parent = entity[prop];
311
+ currentKey = 'value';
312
+ }
313
+ for (let i = 1; i < propPath.length; i++) {
314
+ parent = parent[currentKey];
315
+ currentKey = propPath[i];
316
+ }
317
+ parent[currentKey] = v;
318
+ }
236
319
  _getNodeById(id) {
237
320
  return this._nodesById.get(id);
238
321
  }