valyrian.js 7.2.1 → 7.2.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.
@@ -1,29 +1,64 @@
1
- import { VnodeWithDom, current, update, updateVnode, v } from "valyrian.js";
1
+ import { VnodeWithDom, current, onUnmount, updateVnode, v } from "valyrian.js";
2
2
 
3
- export function Signal(initialValue) {
3
+ interface GetterInterface {
4
+ (): any;
5
+ }
6
+
7
+ interface SetterInterface {
8
+ (value: any): void;
9
+ }
10
+
11
+ interface SubscribeInterface {
12
+ (callback: Function): void;
13
+ }
14
+
15
+ interface SubscriptionsInterface extends Array<Function> {}
16
+
17
+ export interface SignalInterface extends Array<any> {
18
+ 0: GetterInterface;
19
+ 1: SetterInterface;
20
+ 2: SubscribeInterface;
21
+ 3: SubscriptionsInterface;
22
+ }
23
+
24
+ // eslint-disable-next-line sonarjs/cognitive-complexity
25
+ export function Signal(initialValue): SignalInterface {
4
26
  // Create a copy of the current context object
5
- const context = { ...current };
27
+ const { vnode, component } = { ...current };
6
28
 
7
29
  // Check if the context object has a vnode property
8
- if (context.vnode) {
30
+ if (vnode) {
9
31
  // Is first call
10
- if (!context.vnode.signals) {
11
- // Set the signals property to the signals property of the oldVnode object, or an empty array if that doesn't exist
12
- context.vnode.signals = context.oldVnode?.signals || [];
13
- // Set the calls property to -1
14
- context.vnode.calls = -1;
15
- // Set the subscribers property to the subscribers property of the oldVnode object, or an empty array if that doesn't exist
16
- context.vnode.subscribers = context.oldVnode?.subscribers || [];
32
+ if (!vnode.components) {
33
+ // Set the components property to an empty array
34
+ vnode.components = [];
35
+ }
17
36
 
18
- // Set the initialChildren property of the vnode object to a copy of the children array of the vnode object
19
- context.vnode.initialChildren = [...context.vnode.children];
37
+ // Check if the components array of the vnode object does not contain the component object
38
+ if (vnode.components.indexOf(component) === -1) {
39
+ // Set the calls property to -1
40
+ vnode.signal_calls = -1;
41
+ // Add the component to the components array
42
+ vnode.components.push(component);
43
+
44
+ // Check if the component object has a signals property
45
+ if (!component.signals) {
46
+ // Set the signals property of the component object to an empty array
47
+ component.signals = [];
48
+ // Add a function to the cleanup stack that removes the signals property from the component object
49
+ onUnmount(() => Reflect.deleteProperty(component, "signals"));
50
+ }
20
51
  }
21
52
 
22
53
  // Assign the signal variable to the signal stored at the index of the vnode object's calls property in the vnode's signals array
23
- let signal = context.vnode.signals[++context.vnode.calls];
54
+ let signal: SignalInterface = component.signals[++vnode.signal_calls];
24
55
 
25
56
  // If a signal has already been assigned to the signal variable, return it
26
57
  if (signal) {
58
+ // Remove all subscriptions because we come from a new render
59
+ signal[3].length = 0;
60
+
61
+ // Return the signal
27
62
  return signal;
28
63
  }
29
64
  }
@@ -32,69 +67,93 @@ export function Signal(initialValue) {
32
67
  let value = initialValue;
33
68
 
34
69
  // Create an array to store functions that have subscribed to changes to the Signal's value
35
- const subscribers = [];
70
+ const subscriptions: SubscriptionsInterface = [];
36
71
 
37
72
  // Define a function that allows other parts of the code to subscribe to changes to the Signal's value
38
73
  const subscribe = (callback) => {
39
- // Add the callback function to the subscribers array
40
- if (subscribers.indexOf(callback) === -1) {
41
- subscribers.push(callback);
74
+ // Add the callback function to the subscriptions array if it is not already in the array
75
+ if (subscriptions.indexOf(callback) === -1) {
76
+ subscriptions.push(callback);
77
+ }
78
+ };
79
+
80
+ // Set the vnodes to update when the Signal's value changes
81
+ let vnodesToUpdate: Array<VnodeWithDom> = [];
82
+
83
+ // This is the function that will be called when the Signal's value changes
84
+ const updateVnodes = () => {
85
+ // Create a copy of the vnodesToUpdate array and filter out any duplicate vnodes
86
+ let vnodesToUpdateCopy = vnodesToUpdate.filter((vnode, index, self) => {
87
+ return self.findIndex((v) => v.dom === vnode.dom) === index;
88
+ });
89
+
90
+ // Loop through the vnodesToUpdate array
91
+ for (let i = 0, l = vnodesToUpdateCopy.length; i < l; i++) {
92
+ const vnode2 = vnodesToUpdateCopy[i];
93
+ // If it does, create a new vnode object based on the original vnode, its children, and its DOM and SVG properties
94
+ let newVnode = v(vnode2.tag, vnode2.props, ...vnode2.initialChildren) as VnodeWithDom;
95
+ newVnode.dom = vnode2.dom; // Set the new vnode object's DOM property to the old vnode object's DOM property
96
+ newVnode.isSVG = vnode2.isSVG; // Set the new vnode object's isSVG property to the old vnode object's isSVG property
97
+
98
+ // Update the vnode object
99
+ updateVnode(newVnode, vnode2);
42
100
  }
43
101
  };
44
102
 
45
103
  // Define a function that returns the current value of the Signal
46
104
  function get() {
105
+ // Get the current vnode from the context object
106
+ const { vnode: vnode2 } = current;
107
+
108
+ // If we have a current vnode, it means that a get function is being called from within a component
109
+ // so we subscribe the vnode to be updated when the Signal's value changes
110
+ if (vnode2 && vnodesToUpdate.indexOf(vnode2) === -1) {
111
+ // We set the initialChildren to a copy of the vnode's children array
112
+ // This is the case when the vnode is a component that has not been rendered yet and we need the initial children
113
+ // because they could have the components that are using the Signal
114
+ if (!vnode2.initialChildren) {
115
+ vnode2.initialChildren = [...vnode2.children];
116
+ }
117
+
118
+ // Add the vnode to the vnodesToUpdate array
119
+ vnodesToUpdate.push(vnode2);
120
+
121
+ // Subscribe the updateVnodes function to the Signal
122
+ subscribe(updateVnodes);
123
+ }
124
+
125
+ // Return the current value of the Signal
47
126
  return value;
48
127
  }
49
- // Add value, toJSON, valueOf, and toString properties to the get function
50
- get.value = value;
51
- get.toJSON = get.valueOf = get;
52
- get.toString = () => `${value}`;
53
128
 
54
129
  // Define a function that allows the value of the Signal to be updated and notifies any subscribed functions of the change
55
130
  const set = (newValue) => {
56
- // Update the value of the Signal
57
- value = newValue;
58
- // Update the value property of the get function
59
- get.value = value;
60
- // Call each subscribed function with the new value of the Signal as an argument
61
- for (let i = 0, l = subscribers.length; i < l; i++) {
62
- subscribers[i](value);
131
+ // If we have a current event on going, prevent the default action
132
+ if (current.event) {
133
+ current.event.preventDefault();
63
134
  }
64
135
 
65
- // Check if the context object has a vnode property
66
- if (context.vnode) {
67
- // If it does, create a new vnode object based on the original vnode, its children, and its DOM and SVG properties
68
- let newVnode = v(context.vnode.tag, context.vnode.props, ...context.vnode.initialChildren) as VnodeWithDom;
69
- newVnode.dom = context.vnode.dom;
70
- newVnode.isSVG = context.vnode.isSVG;
71
-
72
- // Clear the subscribers array by setting the length property to 0
73
- context.vnode.subscribers.forEach(
74
- (subscribers) =>
75
- // Setting the length property to 0 is faster than clearing the array with a loop
76
- (subscribers.length = 0)
77
- );
78
-
79
- // Clear the subscribers array by setting it to an empty array
80
- context.vnode.subscribers = [];
81
-
82
- // Return the result of updating the original vnode with the new vnode
83
- return updateVnode(newVnode, context.vnode);
136
+ // Just return if the new value is the same as the current value
137
+ if (newValue === value) {
138
+ return;
84
139
  }
85
140
 
86
- // If the context object doesn't have a vnode property, return the result of calling the update function
87
- return update();
141
+ // Update the value of the Signal
142
+ value = newValue;
143
+
144
+ // Call each subscribed function with the new value of the Signal as an argument
145
+ for (let i = 0, l = subscriptions.length; i < l; i++) {
146
+ subscriptions[i](value);
147
+ }
88
148
  };
89
149
 
90
150
  // Assign the signal variable an array containing the get, set, and subscribe functions
91
- let signal = [get, set, subscribe];
151
+ let signal: SignalInterface = [get, set, subscribe, subscriptions];
92
152
 
93
153
  // If the context object has a vnode property, add the signal to the vnode's signals array
94
- // and add the subscribers array to the vnode's subscribers array
95
- if (context.vnode) {
96
- context.vnode.signals.push(signal);
97
- context.vnode.subscribers.push(subscribers);
154
+ // and add the subscriptions array to the vnode's subscriptions array
155
+ if (vnode) {
156
+ component.signals.push(signal);
98
157
  }
99
158
 
100
159
  // Return the signal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "valyrian.js",
3
- "version": "7.2.1",
3
+ "version": "7.2.3",
4
4
  "description": "Lightweight steel to forge PWAs. (Minimal Frontend Framework with server side rendering and other capabilities)",
5
5
  "repository": "git@github.com:Masquerade-Circus/valyrian.js.git",
6
6
  "author": "Masquerade <christian@masquerade-circus.net>",