valyrian.js 7.2.11 → 8.0.0
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 +6 -6
- package/dist/flux-store/index.d.ts +32 -0
- package/dist/flux-store/index.d.ts.map +1 -0
- package/dist/flux-store/index.js +258 -0
- package/dist/flux-store/index.js.map +7 -0
- package/dist/flux-store/index.min.js +1 -0
- package/dist/flux-store/index.min.js.map +1 -0
- package/dist/flux-store/index.mjs +237 -0
- package/dist/flux-store/index.mjs.map +7 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +42 -75
- package/dist/hooks/index.js.map +2 -2
- package/dist/hooks/index.min.js +1 -0
- package/dist/hooks/index.min.js.map +1 -0
- package/dist/hooks/index.mjs +43 -76
- package/dist/hooks/index.mjs.map +2 -2
- package/dist/index.d.ts +52 -54
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +397 -328
- package/dist/index.js.map +3 -3
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +397 -328
- package/dist/index.mjs.map +3 -3
- package/dist/native-store/index.d.ts +14 -0
- package/dist/native-store/index.d.ts.map +1 -0
- package/dist/native-store/index.js +103 -0
- package/dist/native-store/index.js.map +7 -0
- package/dist/native-store/index.min.js +1 -0
- package/dist/native-store/index.min.js.map +1 -0
- package/dist/native-store/index.mjs +82 -0
- package/dist/native-store/index.mjs.map +7 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +223 -86
- package/dist/node/index.js.map +4 -4
- package/dist/node/index.mjs +223 -86
- package/dist/node/index.mjs.map +4 -4
- package/dist/node/node.sw.js +152 -0
- package/dist/node/utils/inline.d.ts.map +1 -1
- package/dist/node/utils/node.sw.js +152 -0
- package/dist/node/utils/session-storage.d.ts +22 -0
- package/dist/node/utils/session-storage.d.ts.map +1 -0
- package/dist/node/utils/sw.d.ts.map +1 -1
- package/dist/node/utils/tree-adapter.d.ts +9 -0
- package/dist/node/utils/tree-adapter.d.ts.map +1 -1
- package/dist/pulse-store/index.d.ts +13 -0
- package/dist/pulse-store/index.d.ts.map +1 -0
- package/dist/pulse-store/index.js +143 -0
- package/dist/pulse-store/index.js.map +7 -0
- package/dist/pulse-store/index.min.js +1 -0
- package/dist/pulse-store/index.min.js.map +1 -0
- package/dist/pulse-store/index.mjs +122 -0
- package/dist/pulse-store/index.mjs.map +7 -0
- package/dist/request/index.d.ts.map +1 -1
- package/dist/request/index.js +68 -89
- package/dist/request/index.js.map +2 -2
- package/dist/request/index.min.js +1 -0
- package/dist/request/index.min.js.map +1 -0
- package/dist/request/index.mjs +68 -89
- package/dist/request/index.mjs.map +2 -2
- package/dist/router/index.d.ts +32 -31
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +256 -104
- package/dist/router/index.js.map +3 -3
- package/dist/router/index.min.js +1 -0
- package/dist/router/index.min.js.map +1 -0
- package/dist/router/index.mjs +256 -104
- package/dist/router/index.mjs.map +3 -3
- package/dist/signals/index.d.ts +6 -0
- package/dist/signals/index.d.ts.map +1 -0
- package/dist/signals/index.js +92 -0
- package/dist/signals/index.js.map +7 -0
- package/dist/signals/index.min.js +1 -0
- package/dist/signals/index.min.js.map +1 -0
- package/dist/signals/index.mjs +71 -0
- package/dist/signals/index.mjs.map +7 -0
- package/dist/suspense/index.d.ts +6 -0
- package/dist/suspense/index.d.ts.map +1 -0
- package/dist/suspense/index.js +67 -0
- package/dist/suspense/index.js.map +7 -0
- package/dist/suspense/index.min.js +1 -0
- package/dist/suspense/index.min.js.map +1 -0
- package/dist/suspense/index.mjs +46 -0
- package/dist/suspense/index.mjs.map +7 -0
- package/dist/sw/index.min.js +1 -0
- package/dist/sw/index.min.js.map +1 -0
- package/dist/translate/index.d.ts +19 -0
- package/dist/translate/index.d.ts.map +1 -0
- package/dist/translate/index.js +150 -0
- package/dist/translate/index.js.map +7 -0
- package/dist/translate/index.min.js +1 -0
- package/dist/translate/index.min.js.map +1 -0
- package/dist/translate/index.mjs +129 -0
- package/dist/translate/index.mjs.map +7 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/deep-freeze.d.ts +3 -0
- package/dist/utils/deep-freeze.d.ts.map +1 -0
- package/dist/utils/getter-setter.d.ts +3 -0
- package/dist/utils/getter-setter.d.ts.map +1 -0
- package/dist/utils/has-changed.d.ts +2 -0
- package/dist/utils/has-changed.d.ts.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +138 -0
- package/dist/utils/index.js.map +7 -0
- package/dist/utils/index.min.js +1 -0
- package/dist/utils/index.min.js.map +1 -0
- package/dist/utils/index.mjs +115 -0
- package/dist/utils/index.mjs.map +7 -0
- package/lib/flux-store/index.ts +301 -0
- package/lib/hooks/index.ts +52 -101
- package/lib/index.ts +479 -719
- package/lib/native-store/index.ts +106 -0
- package/lib/node/index.ts +5 -3
- package/lib/node/utils/icons.ts +5 -5
- package/lib/node/utils/inline.ts +17 -17
- package/lib/node/utils/node.sw.js +152 -0
- package/lib/node/utils/session-storage.ts +117 -0
- package/lib/node/utils/sw.ts +35 -11
- package/lib/node/utils/tree-adapter.ts +99 -52
- package/lib/pulse-store/index.ts +181 -0
- package/lib/request/index.ts +86 -116
- package/lib/router/index.ts +358 -170
- package/lib/signals/index.ts +98 -0
- package/lib/suspense/index.ts +57 -0
- package/lib/translate/index.ts +156 -0
- package/lib/utils/deep-freeze.ts +54 -0
- package/lib/utils/getter-setter.ts +40 -0
- package/lib/utils/has-changed.ts +43 -0
- package/lib/utils/index.ts +3 -0
- package/package.json +38 -50
- package/tsconfig.json +1 -1
- package/dist/dataset/index.d.ts +0 -24
- package/dist/dataset/index.d.ts.map +0 -1
- package/dist/dataset/index.js +0 -178
- package/dist/dataset/index.js.map +0 -7
- package/dist/dataset/index.mjs +0 -157
- package/dist/dataset/index.mjs.map +0 -7
- package/dist/node/node.sw.tpl +0 -133
- package/dist/node/utils/node.sw.tpl +0 -133
- package/dist/proxy-signal/index.d.ts +0 -23
- package/dist/proxy-signal/index.d.ts.map +0 -1
- package/dist/proxy-signal/index.js +0 -138
- package/dist/proxy-signal/index.js.map +0 -7
- package/dist/proxy-signal/index.mjs +0 -117
- package/dist/proxy-signal/index.mjs.map +0 -7
- package/dist/signal/index.d.ts +0 -20
- package/dist/signal/index.d.ts.map +0 -1
- package/dist/signal/index.js +0 -95
- package/dist/signal/index.js.map +0 -7
- package/dist/signal/index.mjs +0 -74
- package/dist/signal/index.mjs.map +0 -7
- package/dist/store/index.d.ts +0 -16
- package/dist/store/index.d.ts.map +0 -1
- package/dist/store/index.js +0 -93
- package/dist/store/index.js.map +0 -7
- package/dist/store/index.mjs +0 -72
- package/dist/store/index.mjs.map +0 -7
- package/lib/dataset/index.ts +0 -193
- package/lib/index.d.ts +0 -0
- package/lib/interfaces.ts.bak +0 -141
- package/lib/node/utils/node.sw.tpl +0 -133
- package/lib/proxy-signal/index.ts +0 -187
- package/lib/signal/index.ts +0 -161
- package/lib/store/index.ts +0 -101
package/lib/index.ts
CHANGED
|
@@ -1,369 +1,168 @@
|
|
|
1
|
-
/* eslint-disable
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
declare global {
|
|
3
|
+
var document: Document;
|
|
4
|
+
namespace JSX {
|
|
5
|
+
interface IntrinsicElements extends DefaultRecord {}
|
|
6
|
+
}
|
|
7
|
+
}
|
|
5
8
|
|
|
6
9
|
interface DefaultRecord extends Record<string | number | symbol, any> {}
|
|
7
10
|
|
|
8
|
-
// The VnodeProperties interface represents properties that can be passed to a virtual node.
|
|
9
11
|
export interface VnodeProperties extends DefaultRecord {
|
|
10
|
-
// A unique key for the virtual node, which can be a string or a number.
|
|
11
|
-
// This is useful for optimizing updates in a list of nodes.
|
|
12
12
|
key?: string | number;
|
|
13
|
-
// A state object that is associated with the virtual node.
|
|
14
|
-
state?: any;
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
// The DomElement interface extends the Element interface with an index signature.
|
|
18
|
-
// This allows for any additional properties to be added to DOM elements.
|
|
19
15
|
export interface DomElement extends Element, DefaultRecord {}
|
|
20
16
|
|
|
21
|
-
// The VnodeInterface represents a virtual node. It has a number of optional fields,
|
|
22
|
-
// including a tag, props, children, and a DOM element.
|
|
23
|
-
export interface VnodeInterface extends DefaultRecord {
|
|
24
|
-
// The constructor for the virtual node. It takes a tag, props, and children as arguments.
|
|
25
|
-
// The tag can be a string, a component, or a POJO component.
|
|
26
|
-
// eslint-disable-next-line no-unused-vars
|
|
27
|
-
new (tag: string | Component | POJOComponent, props: VnodeProperties, children: Children): VnodeInterface;
|
|
28
|
-
// The tag for the virtual node. It can be a string, a component, or a POJO component.
|
|
29
|
-
tag: string | Component | POJOComponent;
|
|
30
|
-
// The props for the virtual node.
|
|
31
|
-
props: VnodeProperties;
|
|
32
|
-
// The children for the virtual node.
|
|
33
|
-
children: Children;
|
|
34
|
-
// A boolean indicating whether the virtual node is an SVG element.
|
|
35
|
-
isSVG?: boolean;
|
|
36
|
-
// The DOM element that corresponds to the virtual node.
|
|
37
|
-
dom?: DomElement;
|
|
38
|
-
// A boolean indicating whether the virtual node has been processed in the keyed diffing algorithm.
|
|
39
|
-
processed?: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// The VnodeWithDom interface represents a virtual node that has a DOM element associated with it.
|
|
43
|
-
export interface VnodeWithDom extends VnodeInterface {
|
|
44
|
-
dom: DomElement;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// The Component interface represents a function that returns a virtual node or a list of virtual nodes.
|
|
48
|
-
// It can also have additional properties.
|
|
49
17
|
export interface Component extends DefaultRecord {
|
|
50
|
-
|
|
51
|
-
// It can take props and children as arguments.
|
|
52
|
-
// eslint-disable-next-line no-unused-vars
|
|
53
|
-
(props?: VnodeProperties | null, ...children: any[]): VnodeInterface | Children | any;
|
|
18
|
+
(props: VnodeProperties, children: any[]): Vnode | any;
|
|
54
19
|
}
|
|
55
20
|
|
|
56
|
-
// The POJOComponent interface represents a "plain old JavaScript object" (POJO) component.
|
|
57
|
-
// It has a view function that returns a virtual node or a list of virtual nodes,
|
|
58
|
-
// as well as optional props and children.
|
|
59
|
-
// It can be used also to identify class instance components.
|
|
60
21
|
export interface POJOComponent extends DefaultRecord {
|
|
61
|
-
// The view function that returns a virtual node or a list of virtual nodes.
|
|
62
22
|
view: Component;
|
|
63
|
-
// The props for the component.
|
|
64
|
-
props?: VnodeProperties | null;
|
|
65
|
-
// The children for the component.
|
|
66
|
-
children?: any[];
|
|
67
23
|
}
|
|
68
24
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
export interface VnodeComponentInterface extends
|
|
72
|
-
tag:
|
|
73
|
-
props: VnodeProperties;
|
|
74
|
-
children: Children;
|
|
25
|
+
export type ValyrianComponent = Component | POJOComponent;
|
|
26
|
+
|
|
27
|
+
export interface VnodeComponentInterface extends Vnode {
|
|
28
|
+
tag: ValyrianComponent;
|
|
75
29
|
}
|
|
76
30
|
|
|
77
|
-
|
|
78
|
-
export interface Children extends Array<VnodeInterface | VnodeComponentInterface | any> {}
|
|
31
|
+
export interface Children extends Array<Vnode | VnodeComponentInterface | ValyrianComponent | any> {}
|
|
79
32
|
|
|
80
|
-
// The Directive interface represents a function that can be applied to a virtual node.
|
|
81
|
-
// It receives the value, virtual node, and old virtual node as arguments, and can return a boolean value.
|
|
82
|
-
// If only the virtual node is passed, it means its the on create phase for the v-node.
|
|
83
|
-
// If the old virtual node is also passed, it means its the on update phase for the v-node.
|
|
84
33
|
export interface Directive {
|
|
85
|
-
|
|
86
|
-
(value: any, vnode: VnodeWithDom, oldVnode?: VnodeWithDom): void | boolean;
|
|
34
|
+
(value: any, vnode: VnodeWithDom, oldProps: VnodeProperties | null): void | boolean;
|
|
87
35
|
}
|
|
88
36
|
|
|
89
|
-
|
|
90
|
-
export interface Directives extends Record<string, Directive> {}
|
|
91
|
-
|
|
92
|
-
// The ReservedProps interface is a mapping of reserved prop names to the value `true`.
|
|
93
|
-
// These prop names cannot be used as custom prop names.
|
|
94
|
-
export interface ReservedProps extends Record<string, true> {}
|
|
95
|
-
|
|
96
|
-
// The Current interface represents the current component and virtual node that are being processed.
|
|
97
|
-
export interface Current {
|
|
98
|
-
// The current component. It can be a component, a POJO component, or null.
|
|
99
|
-
component: Component | POJOComponent | null;
|
|
100
|
-
// The current virtual node. It must have a DOM element associated with it.
|
|
101
|
-
vnode: VnodeWithDom | null;
|
|
102
|
-
// The old virtual node. It must have a DOM element associated with it.
|
|
103
|
-
oldVnode?: VnodeWithDom | null;
|
|
104
|
-
// The current event. It can be an event or null.
|
|
105
|
-
event: Event | null;
|
|
106
|
-
}
|
|
37
|
+
export const isNodeJs = Boolean(typeof process !== "undefined" && process.versions && process.versions.node);
|
|
107
38
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
fragment(_: any, ...children: Children): Children;
|
|
39
|
+
export class Vnode {
|
|
40
|
+
constructor(
|
|
41
|
+
public tag: string | Component | POJOComponent,
|
|
42
|
+
public props: null | VnodeProperties,
|
|
43
|
+
public children: Children,
|
|
44
|
+
public dom?: DomElement,
|
|
45
|
+
public isSVG?: boolean
|
|
46
|
+
) {}
|
|
117
47
|
}
|
|
118
48
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// It is determined by checking if the 'process' global object is defined and has a 'versions' property.
|
|
124
|
-
export let isNodeJs = Boolean(typeof process !== "undefined" && process.versions && process.versions.node);
|
|
125
|
-
|
|
126
|
-
// 'createDomElement' is a function that creates a new DOM element with the specified tag name.
|
|
127
|
-
// If 'isSVG' is true, it creates an SVG element instead of a regular DOM element.
|
|
128
|
-
export function createDomElement(tag: string, isSVG: boolean = false): DomElement {
|
|
129
|
-
return isSVG ? document.createElementNS("http://www.w3.org/2000/svg", tag) : document.createElement(tag);
|
|
49
|
+
export interface VnodeWithDom extends Vnode {
|
|
50
|
+
tag: string;
|
|
51
|
+
dom: DomElement;
|
|
52
|
+
props: VnodeProperties;
|
|
130
53
|
}
|
|
131
54
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// 'Vnode' is exported as an object with a type of 'VnodeInterface'.
|
|
135
|
-
// The 'as unknown as VnodeInterface' is used to tell TypeScript that the 'Vnode' function has the same type as 'VnodeInterface'.
|
|
136
|
-
export const Vnode = function Vnode(this: VnodeInterface, tag: string, props: VnodeProperties, children: Children) {
|
|
137
|
-
// 'this' refers to the current instance of 'Vnode'.
|
|
138
|
-
this.tag = tag;
|
|
139
|
-
this.props = props;
|
|
140
|
-
this.children = children;
|
|
141
|
-
} as unknown as VnodeInterface;
|
|
142
|
-
|
|
143
|
-
// 'isComponent' is a function that returns true if the given 'component' is a valid component and false otherwise.
|
|
144
|
-
// A component is either a function or an object with a 'view' function.
|
|
145
|
-
export function isComponent(component: unknown): component is Component {
|
|
146
|
-
return Boolean(
|
|
147
|
-
component && (typeof component === "function" || (typeof component === "object" && "view" in component))
|
|
148
|
-
);
|
|
149
|
-
}
|
|
55
|
+
export const isPOJOComponent = (component: unknown): component is POJOComponent =>
|
|
56
|
+
Boolean(component && typeof component === "object" && "view" in component);
|
|
150
57
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
return object instanceof Vnode;
|
|
155
|
-
};
|
|
58
|
+
export const isComponent = (component: unknown): component is Component =>
|
|
59
|
+
Boolean(typeof component === "function" || isPOJOComponent(component));
|
|
60
|
+
export const isVnode = (object?: unknown): object is Vnode => object instanceof Vnode;
|
|
156
61
|
|
|
157
|
-
|
|
158
|
-
// It returns false otherwise.
|
|
159
|
-
export const isVnodeComponent = (object?: unknown | VnodeComponentInterface): object is VnodeComponentInterface => {
|
|
160
|
-
// Check if 'object' is a 'Vnode' instance and its 'tag' property is a valid component.
|
|
62
|
+
export const isVnodeComponent = (object?: unknown): object is VnodeComponentInterface => {
|
|
161
63
|
return isVnode(object) && isComponent(object.tag);
|
|
162
64
|
};
|
|
163
65
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
66
|
+
export function v(tagOrComponent: string | ValyrianComponent, props: VnodeProperties, ...children: Children) {
|
|
67
|
+
return new Vnode(tagOrComponent, props, children);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
v.fragment = (_: VnodeProperties, ...children: Children) => children;
|
|
71
|
+
|
|
72
|
+
export function hidrateDomToVnode(dom: any): VnodeWithDom | void {
|
|
169
73
|
if (dom.nodeType === 3) {
|
|
170
|
-
|
|
171
|
-
vnode.dom = dom;
|
|
172
|
-
return vnode as VnodeWithDom;
|
|
74
|
+
return dom.nodeValue;
|
|
173
75
|
}
|
|
174
76
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
77
|
+
if (dom.nodeType === 1) {
|
|
78
|
+
const tag = dom.nodeName.toLowerCase();
|
|
79
|
+
const props = {} as VnodeProperties;
|
|
80
|
+
const children = [] as Children;
|
|
81
|
+
|
|
82
|
+
for (let i = 0, l = dom.childNodes.length; i < l; i++) {
|
|
83
|
+
const childDom = dom.childNodes[i];
|
|
84
|
+
if (childDom.nodeType === 3) {
|
|
85
|
+
children.push(childDom.nodeValue);
|
|
86
|
+
} else if (childDom.nodeType === 1) {
|
|
87
|
+
const childVnode = hidrateDomToVnode(childDom);
|
|
88
|
+
children.push(childVnode);
|
|
89
|
+
}
|
|
183
90
|
}
|
|
184
|
-
}
|
|
185
91
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
props[attr.nodeName] = attr.nodeValue;
|
|
192
|
-
}
|
|
92
|
+
const attributes = dom.attributes;
|
|
93
|
+
for (let i = 0, l = attributes.length; i < l; i++) {
|
|
94
|
+
const attr = attributes[i];
|
|
95
|
+
props[attr.nodeName] = attr.nodeValue;
|
|
96
|
+
}
|
|
193
97
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return vnode as VnodeWithDom;
|
|
98
|
+
const vnode = new Vnode(tag, props, children);
|
|
99
|
+
vnode.dom = dom;
|
|
100
|
+
vnode.isSVG = tag === "svg";
|
|
101
|
+
return vnode as VnodeWithDom;
|
|
102
|
+
}
|
|
200
103
|
}
|
|
201
104
|
|
|
202
|
-
// This function takes in an HTML string and creates a virtual node representation of it
|
|
203
|
-
// using the `domToVnode` function. It does this by creating a new `div` element, setting
|
|
204
|
-
// its `innerHTML` to the provided HTML string, and then using `map` to iterate over the
|
|
205
|
-
// `childNodes` of the `div` element, passing each one to `domToVnode` to create a virtual
|
|
206
|
-
// node representation of it. The resulting array of virtual nodes is then returned.
|
|
207
105
|
export function trust(htmlString: string) {
|
|
208
|
-
|
|
106
|
+
const div = document.createElement("div");
|
|
209
107
|
div.innerHTML = htmlString.trim();
|
|
210
|
-
|
|
211
|
-
return [].map.call(div.childNodes, (item) => domToVnode(item));
|
|
108
|
+
return Array.from(div.childNodes).map(hidrateDomToVnode);
|
|
212
109
|
}
|
|
213
110
|
|
|
214
|
-
/* ========================================================================== */
|
|
215
|
-
/* Main Component implementation */
|
|
216
|
-
/* ========================================================================== */
|
|
217
|
-
|
|
218
|
-
// These variables are used to store the main component, the main virtual node, and whether
|
|
219
|
-
// the main component is currently mounted.
|
|
220
111
|
let mainComponent: VnodeComponentInterface | null = null;
|
|
221
112
|
let mainVnode: VnodeWithDom | null = null;
|
|
222
113
|
let isMounted = false;
|
|
223
114
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
component: null,
|
|
229
|
-
event: null
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
/* Reserved props ----------------------------------------------------------- */
|
|
233
|
-
// This object is used to store the names of reserved props, which are props that are reserved
|
|
234
|
-
// for special purposes and should not be used as regular component props.
|
|
235
|
-
export const reservedProps: Record<string, true> = {
|
|
236
|
-
key: true,
|
|
237
|
-
state: true,
|
|
238
|
-
"v-keep": true,
|
|
239
|
-
|
|
240
|
-
// Built in directives
|
|
241
|
-
"v-if": true,
|
|
242
|
-
"v-unless": true,
|
|
243
|
-
"v-for": true,
|
|
244
|
-
"v-show": true,
|
|
245
|
-
"v-class": true,
|
|
246
|
-
"v-html": true,
|
|
247
|
-
"v-model": true,
|
|
248
|
-
"v-create": true,
|
|
249
|
-
"v-update": true,
|
|
250
|
-
"v-cleanup": true
|
|
115
|
+
export const current = {
|
|
116
|
+
vnode: null as Vnode | null,
|
|
117
|
+
component: null as ValyrianComponent | null,
|
|
118
|
+
event: null as Event | null
|
|
251
119
|
};
|
|
252
120
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
export
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// This function is used to call all the callbacks in a given set.
|
|
283
|
-
function callSet(set: Set<Function>) {
|
|
284
|
-
for (let callback of set) {
|
|
121
|
+
export const reservedProps = new Set<string>([
|
|
122
|
+
"key",
|
|
123
|
+
"state",
|
|
124
|
+
"v-keep",
|
|
125
|
+
"v-text",
|
|
126
|
+
"v-if",
|
|
127
|
+
"v-for",
|
|
128
|
+
"v-show",
|
|
129
|
+
"v-class",
|
|
130
|
+
"v-html",
|
|
131
|
+
"v-model",
|
|
132
|
+
"v-create",
|
|
133
|
+
"v-update",
|
|
134
|
+
"v-cleanup"
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
const onCleanupSet = new Set<Function>();
|
|
138
|
+
const onMountSet = new Set<Function>();
|
|
139
|
+
const onUpdateSet = new Set<Function>();
|
|
140
|
+
const onUnmountSet = new Set<Function>();
|
|
141
|
+
export const onMount = (callback: Function) => !isMounted && onMountSet.add(callback);
|
|
142
|
+
export const onUpdate = (callback: Function) => onUpdateSet.add(callback);
|
|
143
|
+
export const onCleanup = (callback: Function) => onCleanupSet.add(callback);
|
|
144
|
+
export const onUnmount = (callback: Function) => !isMounted && onUnmountSet.add(callback);
|
|
145
|
+
const callSet = (set: Set<Function>) => {
|
|
146
|
+
for (const callback of set) {
|
|
285
147
|
callback();
|
|
286
148
|
}
|
|
287
|
-
|
|
288
149
|
set.clear();
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/* Event listener ----------------------------------------------------------- */
|
|
292
|
-
|
|
293
|
-
// This object stores the names of event listeners that have been added
|
|
294
|
-
const eventListenerNames: Record<string, true> = {};
|
|
295
|
-
|
|
296
|
-
// This function is called when an event occurs
|
|
297
|
-
function eventListener(e: Event) {
|
|
298
|
-
// Set the current event to the event that occurred so that it can be prevented if necessary
|
|
299
|
-
current.event = e;
|
|
300
|
-
|
|
301
|
-
// Convert the target of the event to a DOM element
|
|
302
|
-
let dom = e.target as DomElement;
|
|
303
|
-
|
|
304
|
-
// Create the name of the event listener by adding "v-on" to the event type
|
|
305
|
-
let name = `v-on${e.type}`;
|
|
306
|
-
|
|
307
|
-
// Keep going up the DOM tree until we find an element with an event listener
|
|
308
|
-
// matching the event type
|
|
309
|
-
while (dom) {
|
|
310
|
-
if (dom[name]) {
|
|
311
|
-
// Call the event listener function
|
|
312
|
-
dom[name](e, dom);
|
|
313
|
-
|
|
314
|
-
// If the default action of the event hasn't been prevented, update the DOM
|
|
315
|
-
if (!e.defaultPrevented) {
|
|
316
|
-
update();
|
|
317
|
-
}
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
dom = dom.parentNode as DomElement;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
current.event = null;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/* Directives --------------------------------------------------------------- */
|
|
327
|
-
|
|
328
|
-
// This function creates a directive that hides an element based on a condition
|
|
329
|
-
let hideDirective = (test: boolean) => (bool: boolean, vnode: VnodeInterface, oldnode?: VnodeInterface) => {
|
|
330
|
-
// If test is true, use the value of bool. Otherwise, use the opposite of bool.
|
|
331
|
-
let value = test ? bool : !bool;
|
|
332
|
-
|
|
333
|
-
// If the value is true, hide the element by replacing it with a text node
|
|
334
|
-
if (value) {
|
|
335
|
-
let newdom = document.createTextNode("");
|
|
336
|
-
if (oldnode && oldnode.dom && oldnode.dom.parentNode) {
|
|
337
|
-
oldnode.dom.parentNode.replaceChild(newdom, oldnode.dom);
|
|
338
|
-
}
|
|
339
|
-
vnode.tag = "#text";
|
|
340
|
-
vnode.children = [];
|
|
341
|
-
vnode.props = {};
|
|
342
|
-
vnode.dom = newdom as unknown as DomElement;
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
150
|
};
|
|
346
151
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
152
|
+
export const directives: Record<string, Directive> = {
|
|
153
|
+
"v-if": (value, vnode) => {
|
|
154
|
+
if (!Boolean(value)) {
|
|
155
|
+
const parentNode = vnode.dom?.parentNode;
|
|
156
|
+
if (parentNode) {
|
|
157
|
+
parentNode.replaceChild(document.createTextNode(""), vnode.dom);
|
|
158
|
+
}
|
|
354
159
|
|
|
355
|
-
|
|
356
|
-
"v-for": (set: unknown[], vnode: VnodeWithDom) => {
|
|
357
|
-
let newChildren: VnodeInterface[] = [];
|
|
358
|
-
let callback = vnode.children[0];
|
|
359
|
-
for (let i = 0, l = set.length; i < l; i++) {
|
|
360
|
-
newChildren.push(callback(set[i], i));
|
|
160
|
+
return false;
|
|
361
161
|
}
|
|
362
|
-
vnode.children = newChildren;
|
|
363
162
|
},
|
|
364
163
|
|
|
365
|
-
|
|
366
|
-
|
|
164
|
+
"v-show": (value, vnode) => {
|
|
165
|
+
const bool = Boolean(value);
|
|
367
166
|
(
|
|
368
167
|
vnode.dom as unknown as {
|
|
369
168
|
style: { display: string };
|
|
@@ -371,37 +170,32 @@ export const directives: Directives = {
|
|
|
371
170
|
).style.display = bool ? "" : "none";
|
|
372
171
|
},
|
|
373
172
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
// Loop through all the class names in the classes object
|
|
377
|
-
for (let name in classes) {
|
|
378
|
-
// Add or remove the class name from the element's class list based on the value in the classes object
|
|
379
|
-
(vnode.dom as DomElement).classList.toggle(name, classes[name]);
|
|
380
|
-
}
|
|
381
|
-
},
|
|
382
|
-
|
|
383
|
-
// The "v-html" directive sets the inner HTML of an element to the given HTML string
|
|
384
|
-
"v-html": (html: string, vnode: VnodeWithDom) => {
|
|
385
|
-
// Set the children of the vnode to a trusted version of the HTML string
|
|
386
|
-
vnode.children = [trust(html)];
|
|
173
|
+
"v-html": (value, vnode) => {
|
|
174
|
+
vnode.children = trust(value as string);
|
|
387
175
|
},
|
|
388
176
|
|
|
389
177
|
// The "v-model" directive binds the value of an input element to a model property
|
|
390
|
-
"v-model": (
|
|
178
|
+
"v-model": (model, vnode) => {
|
|
179
|
+
// eslint-disable-next-line prefer-const
|
|
180
|
+
if ("name" in vnode.props === false) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
391
184
|
let value;
|
|
185
|
+
const property = vnode.props.name;
|
|
186
|
+
let event = "oninput";
|
|
187
|
+
|
|
392
188
|
// This function updates the model property when the input element's value changes
|
|
393
189
|
let handler = (e: Event) => (model[property] = (e.target as DomElement & Record<string, any>).value);
|
|
394
190
|
if (vnode.tag === "input") {
|
|
395
|
-
// If the element is an input, use the "input" event by default
|
|
396
|
-
event = event || "oninput";
|
|
397
191
|
// Depending on the type of input element, use a different handler function
|
|
398
192
|
switch (vnode.props.type) {
|
|
399
193
|
case "checkbox": {
|
|
400
194
|
if (Array.isArray(model[property])) {
|
|
401
195
|
// If the model property is an array, add or remove the value from the array when the checkbox is checked or unchecked
|
|
402
196
|
handler = (e: Event) => {
|
|
403
|
-
|
|
404
|
-
|
|
197
|
+
const val = (e.target as DomElement & Record<string, any>).value;
|
|
198
|
+
const idx = model[property].indexOf(val);
|
|
405
199
|
if (idx === -1) {
|
|
406
200
|
model[property].push(val);
|
|
407
201
|
} else {
|
|
@@ -444,14 +238,14 @@ export const directives: Directives = {
|
|
|
444
238
|
}
|
|
445
239
|
} else if (vnode.tag === "select") {
|
|
446
240
|
// If the element is a select element, use the "click" event by default
|
|
447
|
-
event =
|
|
241
|
+
event = "onclick";
|
|
448
242
|
if (vnode.props.multiple) {
|
|
449
243
|
// If the select element allows multiple selections, update the model property with an array of selected values
|
|
450
244
|
handler = (e: Event & Record<string, any>) => {
|
|
451
|
-
|
|
245
|
+
const val = (e.target as DomElement & Record<string, any>).value;
|
|
452
246
|
if (e.ctrlKey) {
|
|
453
247
|
// If the Ctrl key is pressed, add or remove the value from the array
|
|
454
|
-
|
|
248
|
+
const idx = model[property].indexOf(val);
|
|
455
249
|
if (idx === -1) {
|
|
456
250
|
model[property].push(val);
|
|
457
251
|
} else {
|
|
@@ -464,30 +258,28 @@ export const directives: Directives = {
|
|
|
464
258
|
}
|
|
465
259
|
};
|
|
466
260
|
// Set the "selected" attribute on the options based on whether they are in the model property array
|
|
467
|
-
vnode.children.forEach((child:
|
|
261
|
+
vnode.children.forEach((child: VnodeWithDom) => {
|
|
468
262
|
if (child.tag === "option") {
|
|
469
|
-
|
|
263
|
+
const value = "value" in child.props ? child.props.value : child.children.join("").trim();
|
|
470
264
|
child.props.selected = model[property].indexOf(value) !== -1;
|
|
471
265
|
}
|
|
472
266
|
});
|
|
473
267
|
} else {
|
|
474
268
|
// If the select element does not allow multiple selections, set the "selected" attribute on the options based on the value of the model property
|
|
475
|
-
vnode.children.forEach((child:
|
|
269
|
+
vnode.children.forEach((child: VnodeWithDom) => {
|
|
476
270
|
if (child.tag === "option") {
|
|
477
|
-
|
|
271
|
+
const value = "value" in child.props ? child.props.value : child.children.join("").trim();
|
|
478
272
|
child.props.selected = value === model[property];
|
|
479
273
|
}
|
|
480
274
|
});
|
|
481
275
|
}
|
|
482
276
|
} else if (vnode.tag === "textarea") {
|
|
483
|
-
// If the element is a textarea, use the "input" event by default
|
|
484
|
-
event = event || "oninput";
|
|
485
277
|
// Set the textarea's content to the value of the model property
|
|
486
278
|
vnode.children = [model[property]];
|
|
487
279
|
}
|
|
488
280
|
|
|
489
281
|
// We assume that the prev handler if any will not be changed by the user across patchs
|
|
490
|
-
|
|
282
|
+
const prevHandler = vnode.props[event];
|
|
491
283
|
|
|
492
284
|
// Set the event handler on the element
|
|
493
285
|
// eslint-disable-next-line no-use-before-define
|
|
@@ -501,524 +293,492 @@ export const directives: Directives = {
|
|
|
501
293
|
prevHandler(e);
|
|
502
294
|
}
|
|
503
295
|
},
|
|
504
|
-
vnode
|
|
505
|
-
oldVnode
|
|
296
|
+
vnode
|
|
506
297
|
);
|
|
507
298
|
},
|
|
508
299
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
// eslint-disable-next-line no-unused-vars
|
|
513
|
-
"v-create": (callback: (vnode: VnodeWithDom) => void, vnode: VnodeWithDom, oldVnode?: VnodeWithDom) => {
|
|
514
|
-
// If this is not an update, call the callback function with the new virtual node
|
|
515
|
-
if (!oldVnode) {
|
|
516
|
-
let cleanup = callback(vnode);
|
|
300
|
+
"v-create": (callback, vnode, oldProps) => {
|
|
301
|
+
if (!oldProps) {
|
|
302
|
+
const cleanup = callback(vnode);
|
|
517
303
|
|
|
518
|
-
// If the callback function returns a function, call it when the update is gonna be cleaned up
|
|
519
304
|
if (typeof cleanup === "function") {
|
|
520
305
|
onCleanup(cleanup);
|
|
521
306
|
}
|
|
522
307
|
}
|
|
523
308
|
},
|
|
524
309
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
// eslint-disable-next-line no-unused-vars
|
|
530
|
-
callback: (vnode: VnodeWithDom, oldVnode: VnodeWithDom) => void,
|
|
531
|
-
vnode: VnodeWithDom,
|
|
532
|
-
oldVnode?: VnodeWithDom
|
|
533
|
-
) => {
|
|
534
|
-
// If this is an update, call the callback function with the new and old virtual nodes
|
|
535
|
-
if (oldVnode) {
|
|
536
|
-
let cleanup = callback(vnode, oldVnode);
|
|
537
|
-
|
|
538
|
-
// If the callback function returns a function, call it when the update is gonna be cleaned up
|
|
310
|
+
"v-update": (callback, vnode, oldProps) => {
|
|
311
|
+
if (oldProps) {
|
|
312
|
+
const cleanup = callback(vnode, oldProps);
|
|
313
|
+
|
|
539
314
|
if (typeof cleanup === "function") {
|
|
540
315
|
onCleanup(cleanup);
|
|
541
316
|
}
|
|
542
317
|
}
|
|
543
318
|
},
|
|
544
319
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
320
|
+
"v-cleanup": (callback, vnode) => {
|
|
321
|
+
onCleanup(() => callback(vnode));
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
"v-class": (value, vnode) => {
|
|
325
|
+
if (typeof value === "string") {
|
|
326
|
+
vnode.dom.className = value;
|
|
327
|
+
} else if (Array.isArray(value)) {
|
|
328
|
+
vnode.dom.className = value.join(" ");
|
|
329
|
+
} else if (typeof value === "object") {
|
|
330
|
+
const classList = vnode.dom.classList;
|
|
331
|
+
for (const name in value) {
|
|
332
|
+
const val = typeof value[name] === "function" ? (value[name] as Function)() : value[name];
|
|
333
|
+
classList.toggle(name, val);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
// Frequent used properties
|
|
339
|
+
class(value, vnode) {
|
|
340
|
+
if (vnode.dom.className !== value) {
|
|
341
|
+
vnode.dom.className = value;
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
|
|
345
|
+
className(value, vnode) {
|
|
346
|
+
directives.class(value, vnode, null);
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
id: (value, vnode) => {
|
|
350
|
+
vnode.dom.id = value;
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
style: (value, vnode) => {
|
|
354
|
+
if (typeof value === "string") {
|
|
355
|
+
vnode.dom.style = value;
|
|
356
|
+
} else if (typeof value === "object") {
|
|
357
|
+
vnode.dom.style = "";
|
|
358
|
+
const domStyle = vnode.dom.style;
|
|
359
|
+
for (const name in value) {
|
|
360
|
+
domStyle[name] = value[name];
|
|
361
|
+
}
|
|
362
|
+
}
|
|
556
363
|
}
|
|
557
364
|
};
|
|
558
|
-
|
|
559
|
-
// preceded by "v-". Also add the name to the global reservedProps object.
|
|
365
|
+
|
|
560
366
|
export function directive(name: string, directive: Directive) {
|
|
561
|
-
|
|
367
|
+
const directiveName = `v-${name}`;
|
|
562
368
|
directives[directiveName] = directive;
|
|
563
|
-
reservedProps
|
|
369
|
+
reservedProps.add(directiveName);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export function setPropNameReserved(name: string) {
|
|
373
|
+
reservedProps.add(name);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const eventListenerNames = new Set<string>();
|
|
377
|
+
|
|
378
|
+
function eventListener(e: Event) {
|
|
379
|
+
current.event = e;
|
|
380
|
+
let dom = e.target as DomElement;
|
|
381
|
+
const name = `on${e.type}`;
|
|
382
|
+
|
|
383
|
+
while (dom) {
|
|
384
|
+
const oldProps = dom.props;
|
|
385
|
+
if (oldProps && oldProps[name]) {
|
|
386
|
+
oldProps[name](e, dom);
|
|
387
|
+
|
|
388
|
+
if (!e.defaultPrevented) {
|
|
389
|
+
// eslint-disable-next-line no-use-before-define
|
|
390
|
+
update();
|
|
391
|
+
}
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
dom = dom.parentNode as DomElement;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
current.event = null;
|
|
564
398
|
}
|
|
565
399
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
// name to the DOM element represented by mainVnode.
|
|
569
|
-
// If oldVnode is provided, compare the new attribute value to the old value
|
|
570
|
-
// and only update the attribute if the values are different.
|
|
571
|
-
function sharedSetAttribute(name: string, value: any, newVnode: VnodeWithDom, oldVnode?: VnodeWithDom): void | boolean {
|
|
572
|
-
// If the attribute value is a function, add an event listener for the attribute
|
|
573
|
-
// name to the DOM element represented by mainVnode.
|
|
400
|
+
function sharedSetAttribute(name: string, value: any, newVnode: VnodeWithDom): void | boolean {
|
|
401
|
+
const newVnodeDom = newVnode.dom;
|
|
574
402
|
if (typeof value === "function") {
|
|
575
|
-
|
|
576
|
-
|
|
403
|
+
if (!eventListenerNames.has(name)) {
|
|
404
|
+
// We attach the delegated event listener to the main vnode dom element, which is the root of the component
|
|
577
405
|
(mainVnode as VnodeWithDom).dom.addEventListener(name.slice(2), eventListener);
|
|
578
|
-
eventListenerNames
|
|
406
|
+
eventListenerNames.add(name);
|
|
579
407
|
}
|
|
580
|
-
newVnode.dom[`v-${name}`] = value;
|
|
581
408
|
return;
|
|
582
409
|
}
|
|
583
410
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
if (name in newVnode.dom && newVnode.isSVG === false) {
|
|
587
|
-
// eslint-disable-next-line eqeqeq
|
|
588
|
-
if (newVnode.dom[name] != value) {
|
|
589
|
-
newVnode.dom[name] = value;
|
|
590
|
-
}
|
|
411
|
+
if (name in newVnodeDom) {
|
|
412
|
+
newVnodeDom[name] = value;
|
|
591
413
|
return;
|
|
592
414
|
}
|
|
593
415
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
newVnode.dom.removeAttribute(name);
|
|
599
|
-
} else {
|
|
600
|
-
newVnode.dom.setAttribute(name, value);
|
|
601
|
-
}
|
|
416
|
+
if (value === false) {
|
|
417
|
+
newVnodeDom.removeAttribute(name);
|
|
418
|
+
} else {
|
|
419
|
+
newVnodeDom.setAttribute(name, value);
|
|
602
420
|
}
|
|
603
421
|
}
|
|
604
422
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
return;
|
|
423
|
+
export function setAttribute(name: string, value: any, newVnode: VnodeWithDom): void {
|
|
424
|
+
if (!reservedProps.has(name)) {
|
|
425
|
+
newVnode.props[name] = value;
|
|
426
|
+
sharedSetAttribute(name, value, newVnode);
|
|
610
427
|
}
|
|
611
|
-
newVnode.props[name] = value;
|
|
612
|
-
sharedSetAttribute(name, value, newVnode as VnodeWithDom, oldVnode);
|
|
613
428
|
}
|
|
614
429
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
// If oldVnode is provided, remove attributes from the DOM element that are not
|
|
625
|
-
// present in newVnode.props but are present in oldVnode.props.
|
|
626
|
-
if (oldVnode) {
|
|
627
|
-
for (let name in oldVnode.props) {
|
|
628
|
-
if (name in newVnode.props === false && name in eventListenerNames === false && name in reservedProps === false) {
|
|
629
|
-
if (name in newVnode.dom && newVnode.isSVG === false) {
|
|
630
|
-
newVnode.dom[name] = null;
|
|
430
|
+
export function updateAttributes(newVnode: VnodeWithDom, oldProps: VnodeProperties | null): void {
|
|
431
|
+
const vnodeDom = newVnode.dom;
|
|
432
|
+
const vnodeProps = newVnode.props;
|
|
433
|
+
|
|
434
|
+
if (oldProps) {
|
|
435
|
+
for (const name in oldProps) {
|
|
436
|
+
if (name in vnodeProps === false && !eventListenerNames.has(name) && !reservedProps.has(name)) {
|
|
437
|
+
if (name in vnodeDom) {
|
|
438
|
+
vnodeDom[name] = null;
|
|
631
439
|
} else {
|
|
632
|
-
|
|
440
|
+
vnodeDom.removeAttribute(name);
|
|
633
441
|
}
|
|
634
442
|
}
|
|
635
443
|
}
|
|
636
444
|
}
|
|
637
445
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
if (name in reservedProps) {
|
|
642
|
-
// If there is a directive for the attribute, call it with the attribute value
|
|
643
|
-
// and the two virtual DOM nodes as arguments. If the directive returns false,
|
|
644
|
-
// exit the loop.
|
|
645
|
-
if (name in directives && directives[name](newVnode.props[name], newVnode, oldVnode) === false) {
|
|
446
|
+
for (const name in vnodeProps) {
|
|
447
|
+
if (directives[name]) {
|
|
448
|
+
if (directives[name](vnodeProps[name], newVnode, oldProps) === false) {
|
|
646
449
|
break;
|
|
647
450
|
}
|
|
648
451
|
continue;
|
|
649
452
|
}
|
|
650
|
-
|
|
453
|
+
|
|
454
|
+
if (!reservedProps.has(name)) {
|
|
455
|
+
sharedSetAttribute(name, vnodeProps[name], newVnode);
|
|
456
|
+
}
|
|
651
457
|
}
|
|
652
458
|
}
|
|
653
459
|
|
|
654
|
-
|
|
460
|
+
export function createElement(tag: string, isSVG: boolean): DomElement {
|
|
461
|
+
return isSVG
|
|
462
|
+
? document.createElementNS("http://www.w3.org/2000/svg", tag)
|
|
463
|
+
: (document.createElement(tag) as DomElement);
|
|
464
|
+
}
|
|
655
465
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if (newVnode.
|
|
660
|
-
|
|
661
|
-
|
|
466
|
+
function flatTree(newVnode: VnodeWithDom) {
|
|
467
|
+
current.vnode = newVnode;
|
|
468
|
+
|
|
469
|
+
if ("v-for" in newVnode.props) {
|
|
470
|
+
const children = [];
|
|
471
|
+
const set = newVnode.props["v-for"];
|
|
472
|
+
const l = set.length;
|
|
473
|
+
const callback = newVnode.children[0];
|
|
474
|
+
|
|
475
|
+
for (let i = 0; i < l; i++) {
|
|
476
|
+
const newChild = callback(set[i], i);
|
|
477
|
+
if (newChild instanceof Vnode) {
|
|
478
|
+
newChild.props = newChild.props || {};
|
|
479
|
+
newChild.isSVG = newVnode.isSVG || newChild.tag === "svg";
|
|
480
|
+
}
|
|
481
|
+
children[i] = newChild;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return children;
|
|
662
485
|
}
|
|
663
486
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
let
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
// Create an object that maps keys to indices in the old tree
|
|
678
|
-
let oldKeyedList: Record<string, number> = {};
|
|
679
|
-
for (let i = 0; i < oldTreeLength; i++) {
|
|
680
|
-
oldKeyedList[oldTree[i].props.key] = i;
|
|
487
|
+
let i = 0;
|
|
488
|
+
const originalChildren = newVnode.children;
|
|
489
|
+
let children = originalChildren;
|
|
490
|
+
|
|
491
|
+
while (i < children.length) {
|
|
492
|
+
const newChild = children[i];
|
|
493
|
+
|
|
494
|
+
if (newChild == null) {
|
|
495
|
+
if (children === originalChildren) {
|
|
496
|
+
children = [...originalChildren];
|
|
497
|
+
}
|
|
498
|
+
children.splice(i, 1);
|
|
499
|
+
continue;
|
|
681
500
|
}
|
|
682
501
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
502
|
+
if (Array.isArray(newChild)) {
|
|
503
|
+
if (children === originalChildren) {
|
|
504
|
+
children = [...originalChildren];
|
|
505
|
+
}
|
|
506
|
+
children.splice(i, 1, ...newChild);
|
|
507
|
+
continue;
|
|
687
508
|
}
|
|
688
509
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
// If the old child exists, update the DOM element of the new child to match the old child's DOM element
|
|
698
|
-
if (oldChild) {
|
|
699
|
-
newChild.dom = oldChild.dom;
|
|
700
|
-
// If the new and old children have the same "v-keep" attribute value, update the children of the new child to match the old child's children
|
|
701
|
-
if ("v-keep" in newChild.props && newChild.props["v-keep"] === oldChild.props["v-keep"]) {
|
|
702
|
-
newChild.children = oldChild.children;
|
|
703
|
-
// Set the shouldPatch flag to false
|
|
704
|
-
shouldPatch = false;
|
|
705
|
-
} else {
|
|
706
|
-
updateAttributes(newChild, oldChild);
|
|
510
|
+
if (newChild instanceof Vnode) {
|
|
511
|
+
newChild.props = newChild.props || {};
|
|
512
|
+
newChild.isSVG = newVnode.isSVG || newChild.tag === "svg";
|
|
513
|
+
|
|
514
|
+
if (typeof newChild.tag !== "string") {
|
|
515
|
+
if (children === originalChildren) {
|
|
516
|
+
children = [...originalChildren];
|
|
707
517
|
}
|
|
708
518
|
|
|
709
|
-
|
|
710
|
-
} else {
|
|
711
|
-
newChild.dom = createDomElement(newChild.tag, newChild.isSVG);
|
|
712
|
-
updateAttributes(newChild);
|
|
713
|
-
}
|
|
519
|
+
const component = (current.component = newChild.tag);
|
|
714
520
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
521
|
+
children[i] = (isPOJOComponent(component) ? component.view : component).bind(component)(
|
|
522
|
+
newChild.props,
|
|
523
|
+
newChild.children
|
|
524
|
+
);
|
|
718
525
|
|
|
719
|
-
|
|
720
|
-
} else if (newVnode.dom.childNodes[i] !== newChild.dom) {
|
|
721
|
-
newVnode.dom.replaceChild(newChild.dom, newVnode.dom.childNodes[i]);
|
|
526
|
+
continue;
|
|
722
527
|
}
|
|
723
|
-
|
|
724
|
-
// If the shouldPatch flag is true, recursively call the patch function on the new child, passing in the old child as the second argument
|
|
725
|
-
shouldPatch && patch(newChild, oldChild);
|
|
726
528
|
}
|
|
727
529
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
530
|
+
i++;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return children;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function createNewElement(newChild: VnodeWithDom, newVnode: VnodeWithDom, oldChild: DomElement | null) {
|
|
537
|
+
const dom = createElement(newChild.tag, newChild.isSVG as boolean);
|
|
538
|
+
if (oldChild) {
|
|
539
|
+
newVnode.dom.replaceChild(dom, oldChild);
|
|
540
|
+
} else {
|
|
541
|
+
newVnode.dom.appendChild(dom);
|
|
542
|
+
}
|
|
543
|
+
newChild.dom = dom;
|
|
544
|
+
updateAttributes(newChild, null);
|
|
545
|
+
newChild.dom.props = newChild.props;
|
|
546
|
+
if ("v-text" in newChild.props) {
|
|
547
|
+
newChild.dom.textContent = newChild.props["v-text"];
|
|
735
548
|
return;
|
|
736
549
|
}
|
|
737
550
|
|
|
738
|
-
|
|
739
|
-
if (
|
|
740
|
-
|
|
551
|
+
const children = flatTree(newChild);
|
|
552
|
+
if (children.length === 0) {
|
|
553
|
+
newChild.dom.textContent = "";
|
|
741
554
|
return;
|
|
742
555
|
}
|
|
743
556
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
557
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
558
|
+
if (children[i] instanceof Vnode === false) {
|
|
559
|
+
newChild.dom.appendChild(document.createTextNode(children[i]));
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
createNewElement(children[i], newChild, null);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
747
565
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
566
|
+
function patchKeyed(newVnode: VnodeWithDom, children: Children) {
|
|
567
|
+
const oldTree = [...Array.from(newVnode.dom.childNodes)] as unknown as DomElement[];
|
|
568
|
+
const childNodes = newVnode.dom.childNodes;
|
|
569
|
+
const oldKeyedList: Record<string, number> = {};
|
|
570
|
+
const newKeyedList: Record<string, number> = {};
|
|
753
571
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
current.component = newChild.tag;
|
|
760
|
-
// Replace the new child with the result of calling its view or bind method, passing in the props and children as arguments
|
|
761
|
-
newTree.splice(
|
|
762
|
-
i--,
|
|
763
|
-
1,
|
|
764
|
-
("view" in newChild.tag ? newChild.tag.view.bind(newChild.tag) : newChild.tag.bind(newChild.tag))(
|
|
765
|
-
newChild.props,
|
|
766
|
-
...newChild.children
|
|
767
|
-
)
|
|
768
|
-
);
|
|
769
|
-
}
|
|
572
|
+
for (let i = 0, l = oldTree.length; i < l; i++) {
|
|
573
|
+
const oldProps = oldTree[i].props;
|
|
574
|
+
if (oldProps) {
|
|
575
|
+
oldKeyedList[oldProps.key as string] = i;
|
|
576
|
+
}
|
|
770
577
|
|
|
771
|
-
|
|
578
|
+
if (i < children.length && children[i] instanceof Vnode) {
|
|
579
|
+
newKeyedList[children[i].props.key as string] = i;
|
|
772
580
|
}
|
|
581
|
+
}
|
|
773
582
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
583
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
584
|
+
const newChild = children[i];
|
|
585
|
+
const oldChild = oldTree[oldKeyedList[newChild.props.key as string]];
|
|
586
|
+
|
|
587
|
+
if (!oldChild) {
|
|
588
|
+
createNewElement(newChild, newVnode, childNodes[i] as DomElement | null);
|
|
777
589
|
continue;
|
|
778
590
|
}
|
|
779
591
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
592
|
+
newChild.dom = oldChild;
|
|
593
|
+
const currentChild = childNodes[i];
|
|
594
|
+
if (!currentChild) {
|
|
595
|
+
newVnode.dom.appendChild(oldChild);
|
|
596
|
+
} else if (currentChild !== oldChild) {
|
|
597
|
+
newVnode.dom.replaceChild(oldChild, currentChild);
|
|
784
598
|
}
|
|
785
599
|
|
|
786
|
-
|
|
787
|
-
|
|
600
|
+
if ("v-keep" in newChild.props === false || oldChild.props["v-keep"] !== newChild.props["v-keep"]) {
|
|
601
|
+
updateAttributes(newChild as VnodeWithDom, oldChild.props);
|
|
602
|
+
oldChild.props = newChild.props;
|
|
603
|
+
|
|
604
|
+
if ("v-text" in newChild.props) {
|
|
605
|
+
// eslint-disable-next-line eqeqeq
|
|
606
|
+
if (oldChild.textContent != newChild.props["v-text"]) {
|
|
607
|
+
oldChild.textContent = newChild.props["v-text"];
|
|
608
|
+
}
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
// eslint-disable-next-line no-use-before-define
|
|
612
|
+
patch(newChild as VnodeWithDom);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
for (let i = children.length, l = childNodes.length; i < l; i++) {
|
|
617
|
+
childNodes[i]?.remove();
|
|
788
618
|
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// eslint-disable-next-line complexity
|
|
622
|
+
function patch(newVnode: VnodeWithDom): void {
|
|
623
|
+
const children = flatTree(newVnode);
|
|
624
|
+
|
|
625
|
+
const dom = newVnode.dom;
|
|
789
626
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
627
|
+
if (children.length === 0) {
|
|
628
|
+
if (dom.childNodes.length) {
|
|
629
|
+
dom.textContent = "";
|
|
630
|
+
}
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
const oldDomChildren = dom.childNodes as unknown as DomElement[];
|
|
635
|
+
const oldChildrenLength = oldDomChildren.length;
|
|
636
|
+
if (oldChildrenLength > 0) {
|
|
637
|
+
const firstOldProps = oldDomChildren[0].props;
|
|
638
|
+
const firstVnode = children[0] as VnodeWithDom;
|
|
639
|
+
if (firstOldProps && firstVnode instanceof Vnode && "key" in firstVnode.props && "key" in firstOldProps) {
|
|
640
|
+
patchKeyed(newVnode, children);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const childrenLength = children.length;
|
|
646
|
+
if (oldChildrenLength === 0) {
|
|
647
|
+
for (let i = 0; i < childrenLength; i++) {
|
|
648
|
+
if (children[i] instanceof Vnode === false) {
|
|
649
|
+
dom.appendChild(document.createTextNode(children[i]));
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
createNewElement(children[i], newVnode, null);
|
|
653
|
+
}
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
for (let i = 0; i < childrenLength; i++) {
|
|
658
|
+
const newChild = children[i] as VnodeWithDom;
|
|
659
|
+
const isText = newChild instanceof Vnode === false;
|
|
660
|
+
const oldChild = oldDomChildren[i];
|
|
661
|
+
|
|
662
|
+
if (!oldChild) {
|
|
663
|
+
if (isText) {
|
|
664
|
+
newVnode.dom.appendChild(document.createTextNode(newChild as unknown as string));
|
|
801
665
|
continue;
|
|
802
666
|
}
|
|
803
667
|
|
|
804
|
-
|
|
805
|
-
|
|
668
|
+
createNewElement(newChild as VnodeWithDom, newVnode, null);
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
806
671
|
|
|
807
|
-
|
|
808
|
-
if (oldChild.
|
|
809
|
-
|
|
810
|
-
newChild.dom = document.createTextNode(newChild.children[0]);
|
|
811
|
-
// Replace the old child in the dom with the new text node
|
|
812
|
-
newVnode.dom.replaceChild(newChild.dom, oldChild.dom);
|
|
672
|
+
if (isText) {
|
|
673
|
+
if (oldChild.nodeType !== 3) {
|
|
674
|
+
newVnode.dom.replaceChild(document.createTextNode(newChild as unknown as string), oldChild);
|
|
813
675
|
continue;
|
|
814
676
|
}
|
|
815
677
|
|
|
816
|
-
// If the old child is a text node
|
|
817
|
-
// Set the dom property of the text Vnode to the dom property of the old child
|
|
818
|
-
newChild.dom = oldChild.dom;
|
|
819
|
-
// If the text content of the old child is different from the new child, update the text content of the old child
|
|
820
678
|
// eslint-disable-next-line eqeqeq
|
|
821
|
-
if (
|
|
822
|
-
oldChild.
|
|
679
|
+
if (oldChild.nodeValue != (newChild as unknown as string)) {
|
|
680
|
+
oldChild.nodeValue = newChild as unknown as string;
|
|
823
681
|
}
|
|
824
682
|
continue;
|
|
825
683
|
}
|
|
826
684
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
// Append the new child to the dom
|
|
838
|
-
newVnode.dom.appendChild(newChild.dom);
|
|
839
|
-
// Recursively patch the new child
|
|
840
|
-
patch(newChild as VnodeWithDom);
|
|
841
|
-
continue;
|
|
685
|
+
if ("v-keep" in newChild.props) {
|
|
686
|
+
if (oldChild.props && oldChild.props["v-keep"] === newChild.props["v-keep"]) {
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const nextOldChild = oldDomChildren[i + 1];
|
|
691
|
+
if (nextOldChild && nextOldChild.props && nextOldChild.props["v-keep"] === newChild.props["v-keep"]) {
|
|
692
|
+
oldChild.remove();
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
842
695
|
}
|
|
843
696
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
// If the tag of the new child is different from the tag of the old child
|
|
848
|
-
if (newChild.tag !== oldChild.tag) {
|
|
849
|
-
// Create a new dom element for the new child
|
|
850
|
-
newChild.dom = createDomElement(newChild.tag as string, newChild.isSVG);
|
|
851
|
-
// Update the attributes of the new child
|
|
852
|
-
updateAttributes(newChild as VnodeWithDom);
|
|
853
|
-
// Replace the old child in the dom with the new child
|
|
854
|
-
newVnode.dom.replaceChild(newChild.dom, oldChild.dom);
|
|
855
|
-
// Recursively patch the new child
|
|
856
|
-
patch(newChild as VnodeWithDom);
|
|
697
|
+
if (newChild.tag !== oldChild.nodeName.toLowerCase()) {
|
|
698
|
+
createNewElement(newChild, newVnode, oldChild);
|
|
857
699
|
continue;
|
|
858
700
|
}
|
|
859
701
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
newChild.
|
|
702
|
+
newChild.dom = oldChild;
|
|
703
|
+
updateAttributes(newChild, oldChild.props || null);
|
|
704
|
+
oldChild.props = newChild.props;
|
|
705
|
+
if ("v-text" in newChild.props) {
|
|
706
|
+
// eslint-disable-next-line eqeqeq
|
|
707
|
+
if (newChild.dom.textContent != newChild.props["v-text"]) {
|
|
708
|
+
newChild.dom.textContent = newChild.props["v-text"];
|
|
709
|
+
}
|
|
866
710
|
continue;
|
|
867
711
|
}
|
|
868
|
-
|
|
869
|
-
// Update the attributes of the new child based on the old child
|
|
870
|
-
updateAttributes(newChild as VnodeWithDom, oldChild);
|
|
871
|
-
// Recursively patch the new and old children
|
|
872
|
-
patch(newChild as VnodeWithDom, oldChild);
|
|
712
|
+
patch(newChild);
|
|
873
713
|
}
|
|
874
714
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
newVnode.dom.removeChild(oldTree[i].dom);
|
|
715
|
+
for (let i = childrenLength, l = oldDomChildren.length; i < l; i++) {
|
|
716
|
+
oldDomChildren[i]?.remove();
|
|
878
717
|
}
|
|
879
718
|
}
|
|
880
719
|
|
|
881
|
-
|
|
720
|
+
export function updateVnode(vnode: VnodeWithDom): string | void {
|
|
721
|
+
callSet(onCleanupSet);
|
|
722
|
+
vnode.props = vnode.props || {};
|
|
723
|
+
patch(vnode);
|
|
724
|
+
callSet(isMounted ? onUpdateSet : onMountSet);
|
|
725
|
+
isMounted = true;
|
|
726
|
+
current.vnode = null;
|
|
727
|
+
current.component = null;
|
|
728
|
+
}
|
|
729
|
+
|
|
882
730
|
export function update(): void | string {
|
|
883
|
-
// If the main Vnode exists
|
|
884
731
|
if (mainVnode) {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
// Store a reference to the old main Vnode
|
|
888
|
-
let oldMainVnode = mainVnode;
|
|
889
|
-
// Create a new main Vnode with the main component as its only child
|
|
890
|
-
mainVnode = new Vnode(oldMainVnode.tag, oldMainVnode.props, [mainComponent]) as VnodeWithDom;
|
|
891
|
-
mainVnode.dom = oldMainVnode.dom;
|
|
892
|
-
mainVnode.isSVG = oldMainVnode.isSVG;
|
|
893
|
-
|
|
894
|
-
// Recursively patch the new and old main Vnodes
|
|
895
|
-
patch(mainVnode, oldMainVnode);
|
|
896
|
-
|
|
897
|
-
// Call any update or mount functions that are registered with the onUpdateSet or onMountSet set
|
|
898
|
-
callSet(isMounted ? onUpdateSet : onMountSet);
|
|
899
|
-
|
|
900
|
-
// Set the isMounted flag to true
|
|
901
|
-
isMounted = true;
|
|
902
|
-
|
|
903
|
-
// Reset the current vnode, oldVnode, and component properties
|
|
904
|
-
current.vnode = null;
|
|
905
|
-
current.oldVnode = null;
|
|
906
|
-
current.component = null;
|
|
907
|
-
|
|
908
|
-
// If the code is running in a Node.js environment, return the inner HTML of the main Vnode's dom element
|
|
732
|
+
mainVnode.children = [mainComponent];
|
|
733
|
+
updateVnode(mainVnode as VnodeWithDom);
|
|
909
734
|
if (isNodeJs) {
|
|
910
735
|
return mainVnode.dom.innerHTML;
|
|
911
736
|
}
|
|
912
737
|
}
|
|
913
738
|
}
|
|
914
739
|
|
|
915
|
-
|
|
916
|
-
// It is assumed that a first mount has already occurred, so,
|
|
917
|
-
// the oldVnode is not null and the dom property of the oldVnode is not null
|
|
918
|
-
// You need to set the dom property of the newVnode to the dom property of the oldVnode
|
|
919
|
-
// The same with the isSVG property
|
|
920
|
-
// Prefer this function over patch to allow for cleanup, onUpdate and onMount sets to be called
|
|
921
|
-
export function updateVnode(vnode: VnodeWithDom, oldVnode: VnodeWithDom): string | void {
|
|
922
|
-
// Call any cleanup functions that are registered with the onCleanupSet set
|
|
923
|
-
callSet(onCleanupSet);
|
|
924
|
-
|
|
925
|
-
// Recursively patch the new and old main Vnodes
|
|
926
|
-
patch(vnode, oldVnode);
|
|
740
|
+
let debouncedUpdateTimeout: any;
|
|
927
741
|
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
oldVnode.tag = vnode.tag;
|
|
931
|
-
oldVnode.props = { ...vnode.props };
|
|
932
|
-
oldVnode.children = [...vnode.children];
|
|
933
|
-
oldVnode.dom = vnode.dom;
|
|
934
|
-
oldVnode.isSVG = vnode.isSVG;
|
|
742
|
+
const clearDebouncedUpdateMethod = isNodeJs ? clearTimeout : cancelAnimationFrame;
|
|
743
|
+
const setDebouncedUpdateMethod = isNodeJs ? () => setTimeout(update, 5) : () => requestAnimationFrame(update);
|
|
935
744
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
// Set the isMounted flag to true
|
|
940
|
-
isMounted = true;
|
|
941
|
-
|
|
942
|
-
// Reset the current vnode, oldVnode, and component properties
|
|
943
|
-
current.vnode = null;
|
|
944
|
-
current.oldVnode = null;
|
|
945
|
-
current.component = null;
|
|
946
|
-
|
|
947
|
-
if (isNodeJs) {
|
|
948
|
-
return vnode.dom.innerHTML;
|
|
949
|
-
}
|
|
745
|
+
export function debouncedUpdate() {
|
|
746
|
+
clearDebouncedUpdateMethod(debouncedUpdateTimeout);
|
|
747
|
+
debouncedUpdateTimeout = setDebouncedUpdateMethod();
|
|
950
748
|
}
|
|
951
749
|
|
|
952
|
-
// Unmount the main Vnode
|
|
953
750
|
export function unmount() {
|
|
954
|
-
// If the main Vnode exists
|
|
955
751
|
if (mainVnode) {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
// Update the main Vnode
|
|
959
|
-
let result = update();
|
|
960
|
-
// Call any unmount functions that are registered with the onUnmountSet set
|
|
752
|
+
mainComponent = v(() => null, {}) as VnodeComponentInterface;
|
|
753
|
+
const result = update();
|
|
961
754
|
callSet(onUnmountSet);
|
|
962
|
-
|
|
963
|
-
// Remove any event listeners that were added to the main Vnode's dom element
|
|
964
|
-
for (let name in eventListenerNames) {
|
|
755
|
+
for (const name in eventListenerNames) {
|
|
965
756
|
mainVnode.dom.removeEventListener(name.slice(2).toLowerCase(), eventListener);
|
|
966
757
|
Reflect.deleteProperty(eventListenerNames, name);
|
|
967
758
|
}
|
|
968
759
|
|
|
969
|
-
// Reset the main component and main Vnode
|
|
970
760
|
mainComponent = null;
|
|
971
761
|
mainVnode = null;
|
|
972
|
-
// Set the isMounted flag to false
|
|
973
762
|
isMounted = false;
|
|
974
|
-
// Reset the current vnode, oldVnode, and component properties
|
|
975
763
|
current.vnode = null;
|
|
976
|
-
current.oldVnode = null;
|
|
977
764
|
current.component = null;
|
|
978
|
-
|
|
765
|
+
current.event = null;
|
|
979
766
|
return result;
|
|
980
767
|
}
|
|
981
768
|
}
|
|
982
|
-
|
|
983
|
-
export function mount(dom: string | DomElement, component: any) {
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
// Check if the 'component' argument is a Vnode component or a regular component.
|
|
994
|
-
// If it's a regular component, create a new Vnode component using the 'component' argument as the tag.
|
|
995
|
-
// If it's not a component at all, create a new Vnode component with the 'component' argument as the rendering function.
|
|
996
|
-
let vnodeComponent = isVnodeComponent(component)
|
|
997
|
-
? component
|
|
998
|
-
: isComponent(component)
|
|
999
|
-
? new Vnode(component, {}, [])
|
|
1000
|
-
: new Vnode(() => component, {}, []);
|
|
1001
|
-
|
|
1002
|
-
// If a main component already exists and it's not the same as the current 'vnodeComponent', unmount it.
|
|
1003
|
-
if (mainComponent && mainComponent.tag !== vnodeComponent.tag) {
|
|
1004
|
-
unmount();
|
|
769
|
+
|
|
770
|
+
export function mount(dom: string | DomElement, component: ValyrianComponent | VnodeComponentInterface | any) {
|
|
771
|
+
const container =
|
|
772
|
+
typeof dom === "string" ? (isNodeJs ? createElement(dom, dom === "svg") : document.querySelector(dom)) : dom;
|
|
773
|
+
|
|
774
|
+
if (isComponent(component)) {
|
|
775
|
+
mainComponent = v(component, {}, []) as VnodeComponentInterface;
|
|
776
|
+
} else if (isVnodeComponent(component)) {
|
|
777
|
+
mainComponent = component;
|
|
778
|
+
} else {
|
|
779
|
+
mainComponent = v(() => component, {}, []) as VnodeComponentInterface;
|
|
1005
780
|
}
|
|
1006
781
|
|
|
1007
|
-
|
|
1008
|
-
mainComponent = vnodeComponent as VnodeComponentInterface;
|
|
1009
|
-
// Convert the container element to a Vnode.
|
|
1010
|
-
mainVnode = domToVnode(container);
|
|
1011
|
-
// Update the DOM with the new component.
|
|
782
|
+
mainVnode = hidrateDomToVnode(container) as VnodeWithDom;
|
|
1012
783
|
return update();
|
|
1013
784
|
}
|
|
1014
|
-
|
|
1015
|
-
// This is a utility function for creating Vnode objects.
|
|
1016
|
-
// It takes in a tag or component, and optional props and children arguments.
|
|
1017
|
-
export const v: V = (tagOrComponent, props = {}, ...children) => {
|
|
1018
|
-
// Return a new Vnode object using the given arguments.
|
|
1019
|
-
return new Vnode(tagOrComponent, props || {}, children);
|
|
1020
|
-
};
|
|
1021
|
-
|
|
1022
|
-
// This utility function creates a fragment Vnode.
|
|
1023
|
-
// It takes in a placeholder and the children arguments, returns only the children.
|
|
1024
|
-
v.fragment = (_: VnodeProperties, ...children: Children) => children;
|