j-templates 8.0.21 → 8.0.23

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.
@@ -56,6 +56,9 @@ function getHTMLNode(from, current) {
56
56
  return from;
57
57
  }
58
58
  export const DOMNodeConfig = {
59
+ isConnected(target) {
60
+ return target.isConnected;
61
+ },
59
62
  createNode(type, namespace) {
60
63
  return namespace
61
64
  ? document.createElementNS(namespace, type)
@@ -14,6 +14,11 @@ export declare class Component<D = void, T = void, E = {}> {
14
14
  private scope;
15
15
  private templates;
16
16
  private componentEvents;
17
+ /**
18
+ * Return if the component's vNode is connected
19
+ * to a parent document
20
+ */
21
+ get IsConnected(): boolean;
17
22
  /**
18
23
  * Returns the component's virtual node injector.
19
24
  */
@@ -51,6 +56,7 @@ export declare class Component<D = void, T = void, E = {}> {
51
56
  * Override to perform post‑binding initialization.
52
57
  */
53
58
  Bound(): void;
59
+ Connected(): void;
54
60
  /**
55
61
  * Fires a component event.
56
62
  *
@@ -85,6 +91,6 @@ export declare namespace Component {
85
91
  * @param vnode - The virtual node to be attached.
86
92
  * @returns The result of the attachment operation.
87
93
  */
88
- function Attach(node: any, vnode: vNodeType): vNodeType;
94
+ function Attach(node: any, vnode: vElementNode): vElementNode;
89
95
  }
90
96
  export {};
package/Node/component.js CHANGED
@@ -9,6 +9,13 @@ import { ObservableScope } from "../Store";
9
9
  * @template E - Event map type for component events.
10
10
  */
11
11
  export class Component {
12
+ /**
13
+ * Return if the component's vNode is connected
14
+ * to a parent document
15
+ */
16
+ get IsConnected() {
17
+ return this.vNode.connected;
18
+ }
12
19
  /**
13
20
  * Returns the component's virtual node injector.
14
21
  */
@@ -76,6 +83,7 @@ export class Component {
76
83
  Bound() {
77
84
  Bound.All(this);
78
85
  }
86
+ Connected() { }
79
87
  /**
80
88
  * Fires a component event.
81
89
  *
@@ -1,4 +1,5 @@
1
1
  export interface INodeConfig {
2
+ isConnected(node: any): boolean;
2
3
  createNode(type: any, namespace: string): any;
3
4
  createTextNode(value?: string): any;
4
5
  scheduleUpdate(callback: () => void): void;
package/Node/vNode.d.ts CHANGED
@@ -6,5 +6,5 @@ export declare namespace vNode {
6
6
  function Destroy(vnode: vNodeType): void;
7
7
  function DestroyAll(vnodes: vNodeType[]): void;
8
8
  function ToFunction<P = HTMLElement, E = HTMLElementEventMap>(type: string | typeof TEXT_NODE | typeof FRAGMENT_NODE, namespace?: string): <T>(config: vNodeConfig<P, E, T>, children?: vNodeType[] | vNodeChildrenFunction<T>) => vElementNode;
9
- function Attach(node: any, vnode: vNodeType): vNodeType;
9
+ function Attach(node: any, vnode: vElementNode): vElementNode;
10
10
  }
package/Node/vNode.js CHANGED
@@ -13,6 +13,7 @@ export var vNode;
13
13
  return {
14
14
  definition,
15
15
  type: definition.type,
16
+ connected: false,
16
17
  injector: definition.componentFactory
17
18
  ? new Injector()
18
19
  : (Injector.Current() ?? new Injector()),
@@ -71,8 +72,11 @@ export var vNode;
71
72
  if (vnode.type === FRAGMENT_NODE)
72
73
  throw new Error("Cannot attach a fragment directly. A fragment has no DOM node — " +
73
74
  "wrap it in a real element (e.g. div) before attaching.");
75
+ // Must create a node + attach before Init so Connected can run correctly
76
+ // on a possible Component instance
77
+ const childNode = vnode.definition.node = CreateNode(vnode);
78
+ NodeConfig.addChild(node, childNode);
74
79
  Init(vnode);
75
- NodeConfig.addChild(node, vnode.node);
76
80
  return vnode;
77
81
  }
78
82
  vNode.Attach = Attach;
@@ -80,19 +84,22 @@ export var vNode;
80
84
  function ComponentChildren() {
81
85
  return this.Template();
82
86
  }
83
- function InitNode(vnode, parentNode) {
84
- const { type, namespace, props, attrs, on, data, componentFactory, children, childrenArray, } = vnode.definition;
85
- let node = null;
87
+ function CreateNode(vnode) {
86
88
  switch (vnode.type) {
87
89
  case FRAGMENT_NODE:
88
- break;
90
+ return null;
89
91
  case TEXT_NODE:
90
- vnode.node = node = vnode.definition.node ?? NodeConfig.createTextNode();
91
- break;
92
+ return vnode.definition.node ?? NodeConfig.createTextNode();
92
93
  default:
93
- vnode.node = node = vnode.definition.node ?? NodeConfig.createNode(type, namespace);
94
- break;
94
+ return vnode.definition.node ?? NodeConfig.createNode(vnode.definition.type, vnode.definition.namespace);
95
95
  }
96
+ }
97
+ function InitNode(vnode, parentNode) {
98
+ const {
99
+ /* type,
100
+ namespace, */
101
+ props, attrs, on, data, componentFactory, children, childrenArray, } = vnode.definition;
102
+ const node = vnode.node = CreateNode(vnode);
96
103
  vnode.definition = null;
97
104
  vnode.parentNode = parentNode;
98
105
  if (props) {
@@ -130,7 +137,7 @@ function InitNode(vnode, parentNode) {
130
137
  }
131
138
  if (componentFactory) {
132
139
  vnode.component = Injector.Scope(vnode.injector, componentFactory, vnode);
133
- vnode.component.Bound();
140
+ // vnode.component.Bound();
134
141
  Children(vnode, ComponentChildren.bind(vnode.component));
135
142
  }
136
143
  else if (childrenArray) {
@@ -173,7 +180,7 @@ function CreateChildrenScope(vnode, children, data) {
173
180
  return ObservableScope.Create(DynamicChildrenFunction.bind(null, vnode.injector, children, data));
174
181
  }
175
182
  function ToVNodeType(children) {
176
- return typeof children === "string" ? { type: STRING_NODE, node: children } : children;
183
+ return typeof children === "string" ? { type: STRING_NODE, connected: false, node: children } : children;
177
184
  }
178
185
  function GetNextNodes(injector, children, data) {
179
186
  return ToVNodeType(Injector.Scope(injector, children, data));
@@ -236,14 +243,18 @@ function UpdateChildren(vnode, init = false, skipInit = false) {
236
243
  if (vnode.destroyed || children !== vnode.children)
237
244
  return;
238
245
  if (init) {
239
- if (vnode.node !== null)
246
+ if (vnode.node !== null) {
240
247
  NodeConfig.reconcileChildren(vnode.node, CleanupChildrenArray(vnode.children));
248
+ vnode.component?.Bound();
249
+ FireConnected(vnode, true);
250
+ }
241
251
  }
242
252
  else if (!async) {
243
253
  let reconcileNode = vnode;
244
254
  while (reconcileNode.node === null)
245
255
  reconcileNode = reconcileNode.parentNode;
246
256
  NodeConfig.reconcileChildren(reconcileNode.node, CleanupChildrenArray(reconcileNode.children));
257
+ FireConnected(vnode, true);
247
258
  }
248
259
  else {
249
260
  NodeConfig.scheduleUpdate(function () {
@@ -253,11 +264,47 @@ function UpdateChildren(vnode, init = false, skipInit = false) {
253
264
  while (reconcileNode.node === null)
254
265
  reconcileNode = reconcileNode.parentNode;
255
266
  NodeConfig.reconcileChildren(reconcileNode.node, CleanupChildrenArray(reconcileNode.children));
267
+ FireConnected(vnode, true);
256
268
  });
257
269
  }
258
270
  });
259
271
  });
260
272
  }
273
+ function FireConnected(vnode, root = false) {
274
+ if ((!root && vnode.connected) ||
275
+ (vnode.type !== FRAGMENT_NODE && vnode.node === null))
276
+ return;
277
+ switch (vnode.type) {
278
+ case FRAGMENT_NODE:
279
+ break;
280
+ default: {
281
+ if (!vnode.connected) {
282
+ vnode.connected = NodeConfig.isConnected(vnode.node);
283
+ switch (vnode.type) {
284
+ case STRING_NODE:
285
+ case TEXT_NODE:
286
+ break;
287
+ default:
288
+ vnode.connected && vnode.component?.Connected();
289
+ }
290
+ }
291
+ break;
292
+ }
293
+ }
294
+ if (vnode.type !== FRAGMENT_NODE && !vnode.connected)
295
+ return;
296
+ switch (vnode.type) {
297
+ case STRING_NODE:
298
+ case TEXT_NODE:
299
+ break;
300
+ default: {
301
+ const children = vnode.children;
302
+ const count = children?.length;
303
+ for (let x = 0; x < count; x++)
304
+ FireConnected(children[x]);
305
+ }
306
+ }
307
+ }
261
308
  function ScheduledAssignment(assign) {
262
309
  let scheduled = false;
263
310
  return function (scope) {
@@ -27,10 +27,12 @@ export type vNodeConfig<P = HTMLElement, E = HTMLElementEventMap, T = never> = {
27
27
  };
28
28
  export type vStringNode = {
29
29
  type: typeof STRING_NODE;
30
+ connected: boolean;
30
31
  node: string;
31
32
  };
32
33
  export type vElementNode = {
33
34
  type: string | typeof TEXT_NODE | typeof FRAGMENT_NODE;
35
+ connected: boolean;
34
36
  definition: vNodeDefinition<any, any, any>;
35
37
  injector: Injector;
36
38
  parentNode: vElementNode | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "j-templates",
3
- "version": "8.0.21",
3
+ "version": "8.0.23",
4
4
  "description": "j-templates",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/TypesInCode/jTemplates",