@ryupold/vode 0.9.5 → 0.10.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.
@@ -6,19 +6,24 @@ on:
6
6
  - 'main'
7
7
 
8
8
  jobs:
9
- build:
9
+ test-build-and-publish-to-npm:
10
10
  runs-on: ubuntu-latest
11
11
  permissions:
12
12
  contents: read
13
13
  id-token: write
14
14
  steps:
15
15
  - uses: actions/checkout@v4
16
- - uses: actions/setup-node@v4
17
- with:
18
- node-version: '22.x'
19
- registry-url: 'https://registry.npmjs.org'
20
16
  - uses: oven-sh/setup-bun@v2
21
17
  - run: bun run build
22
- - run: bun publish --provenance --access public
18
+ - run: |
19
+ echo "releasing to npm..."
20
+ bun publish --provenance --access public | grep "+ @ryupold/vode@" > version.txt
21
+ NEWVERSION=$(cat version.txt)
22
+ if [[ $NEWVERSION == *"vode"* ]]; then
23
+ echo "...success: $NEWVERSION"
24
+ else
25
+ echo "...failed to publish"
26
+ fi
27
+
23
28
  env:
24
29
  NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -7,7 +7,14 @@ The state is a singleton object that can be updated, and the UI will re-render w
7
7
  ## Install
8
8
 
9
9
  ```bash
10
+ # npm
10
11
  npm install @ryupold/vode --save
12
+
13
+ # yarn
14
+ yarn add @ryupold/vode
15
+
16
+ # bun
17
+ bun add @ryupold/vode
11
18
  ```
12
19
 
13
20
  ## Patch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryupold/vode",
3
- "version": "0.9.5",
3
+ "version": "0.10.0",
4
4
  "description": "Small web framework for minimal websites",
5
5
  "author": "Michael Scherbakow (ryupold)",
6
6
  "license": "MIT",
@@ -22,7 +22,8 @@
22
22
  "homepage": "https://github.com/ryupold/vode#readme",
23
23
  "module": "index.ts",
24
24
  "scripts": {
25
- "build": "bun build index.ts --outfile index.js",
25
+ "build": "bun build index.ts --outfile vode.mjs",
26
+ "build-min": "bun build index.ts --outfile vode.min.mjs --minify",
26
27
  "pack": "rm *.tgz && bun run build && bun pm pack",
27
28
  "publish": "bun publish --provenance --access public",
28
29
  "clean": "tsc -b --clean",
package/src/vode.ts CHANGED
@@ -69,21 +69,23 @@ export type EventsMap =
69
69
  export type PropertyValue<S> = string | boolean | null | undefined | StyleProp | ClassProp | Patch<S> | void;
70
70
 
71
71
  export type ContainerNode<S> = HTMLElement & {
72
- state: PatchableState<S>,
73
- vode: AttachedVode<S>,
74
- patch: Dispatch<S>,
75
- render: () => void,
76
- q: Patch<S>[]
77
- isRendering: boolean,
78
- stats: {
79
- patchCount: number,
80
- liveEffectCount: number,
81
- renderPatchCount: number,
82
- renderCount: number,
83
- renderTime: number,
84
- queueLengthBeforeRender: number,
85
- queueLengthAfterRender: number,
86
- },
72
+ _vode: {
73
+ state: PatchableState<S>,
74
+ vode: AttachedVode<S>,
75
+ patch: Dispatch<S>,
76
+ render: () => void,
77
+ q: Patch<S>[]
78
+ isRendering: boolean,
79
+ stats: {
80
+ patchCount: number,
81
+ liveEffectCount: number,
82
+ renderPatchCount: number,
83
+ renderCount: number,
84
+ renderTime: number,
85
+ queueLengthBeforeRender: number,
86
+ queueLengthAfterRender: number,
87
+ },
88
+ }
87
89
  };
88
90
 
89
91
  /** type-safe way to create a vode. useful for type inference and autocompletion.
@@ -120,98 +122,102 @@ export function patch<S>(p: DeepPartial<S> | Effect<S> | NoRenderPatch): typeof
120
122
  * @returns a patch function that can be used to update the state
121
123
  */
122
124
  export function app<S>(container: HTMLElement, initialState: Omit<S, "patch">, dom: Component<S>, ...initialPatches: Patch<S>[]) {
123
- const root = container as ContainerNode<S>;
124
- root.stats = { renderTime: 0, renderCount: 0, queueLengthBeforeRender: 0, queueLengthAfterRender: 0, liveEffectCount: 0, patchCount: 0, renderPatchCount: 0 };
125
+ const _vode = {} as ContainerNode<S>["_vode"];
126
+ _vode.stats = { renderTime: 0, renderCount: 0, queueLengthBeforeRender: 0, queueLengthAfterRender: 0, liveEffectCount: 0, patchCount: 0, renderPatchCount: 0 };
125
127
 
126
128
  Object.defineProperty(initialState, "patch", {
127
129
  enumerable: false, configurable: true,
128
130
  writable: false, value: async (action: Patch<S>) => {
129
131
  if (!action || (typeof action !== "function" && typeof action !== "object")) return;
130
- root.stats.patchCount++;
132
+ _vode.stats.patchCount++;
131
133
 
132
134
  if ((action as AsyncGenerator<Patch<S>, unknown, void>)?.next) {
133
135
  const generator = action as AsyncGenerator<Patch<S>, unknown, void>;
134
- root.stats.liveEffectCount++;
136
+ _vode.stats.liveEffectCount++;
135
137
  try {
136
138
  let v = await generator.next();
137
139
  while (v.done === false) {
138
- root.stats.liveEffectCount++;
140
+ _vode.stats.liveEffectCount++;
139
141
  try {
140
- root.patch!(v.value);
142
+ _vode.patch!(v.value);
141
143
  v = await generator.next();
142
144
  } finally {
143
- root.stats.liveEffectCount--;
145
+ _vode.stats.liveEffectCount--;
144
146
  }
145
147
  }
146
- root.patch!(v.value as Patch<S>);
148
+ _vode.patch!(v.value as Patch<S>);
147
149
  } finally {
148
- root.stats.liveEffectCount--;
150
+ _vode.stats.liveEffectCount--;
149
151
  }
150
152
  } else if ((action as Promise<S>).then) {
151
- root.stats.liveEffectCount++;
153
+ _vode.stats.liveEffectCount++;
152
154
  try {
153
155
  const nextState = await (action as Promise<S>);
154
- root.patch!(<Patch<S>>nextState);
156
+ _vode.patch!(<Patch<S>>nextState);
155
157
  } finally {
156
- root.stats.liveEffectCount--;
158
+ _vode.stats.liveEffectCount--;
157
159
  }
158
160
  } else if (Array.isArray(action)) {
159
161
  if (typeof action[0] === "function") {
160
162
  if (action.length > 1)
161
- root.patch!(action[0](root.state!, ...(action as any[]).slice(1)));
162
- else root.patch!(action[0](root.state!));
163
+ _vode.patch!(action[0](_vode.state!, ...(action as any[]).slice(1)));
164
+ else _vode.patch!(action[0](_vode.state!));
163
165
  } else {
164
- root.stats.patchCount--;
166
+ _vode.stats.patchCount--;
165
167
  }
166
168
  } else if (typeof action === "function") {
167
- root.patch!((<EffectFunction<S>>action)(root.state));
169
+ _vode.patch!((<EffectFunction<S>>action)(_vode.state));
168
170
  } else {
169
- root.stats.renderPatchCount++;
170
- root.q!.push(<Patch<S>>action);
171
- if (!root.isRendering) root.render!();
171
+ _vode.stats.renderPatchCount++;
172
+ _vode.q!.push(<Patch<S>>action);
173
+ if (!_vode.isRendering) _vode.render!();
172
174
  }
173
175
  }
174
176
  });
175
177
 
176
- Object.defineProperty(root, "render", {
178
+ Object.defineProperty(_vode, "render", {
177
179
  enumerable: false, configurable: true,
178
180
  writable: false, value: () => requestAnimationFrame(() => {
179
- if (root.isRendering || root.q!.length === 0) return;
180
- root.isRendering = true;
181
+ if (_vode.isRendering || _vode.q!.length === 0) return;
182
+ _vode.isRendering = true;
181
183
  const sw = Date.now();
182
184
  try {
183
- root.stats.queueLengthBeforeRender = root.q!.length;
185
+ _vode.stats.queueLengthBeforeRender = _vode.q!.length;
184
186
 
185
- while (root.q!.length > 0) {
186
- const patch = root.q!.shift();
187
- if(patch === EmptyPatch) continue;
188
- mergeState(root.state, patch);
187
+ while (_vode.q!.length > 0) {
188
+ const patch = _vode.q!.shift();
189
+ if (patch === EmptyPatch) continue;
190
+ mergeState(_vode.state, patch);
189
191
  }
190
- root.vode = render(root.state, root.patch, container, 0, root.vode, dom(root.state))!;
192
+ _vode.vode = render(_vode.state, _vode.patch, container, 0, _vode.vode, dom(_vode.state))!;
191
193
  } finally {
192
- root.isRendering = false;
193
- root.stats.renderCount++;
194
- root.stats.renderTime = Date.now() - sw;
195
- root.stats.queueLengthAfterRender = root.q!.length;
196
- if (root.q!.length > 0) {
197
- root.render!();
194
+ _vode.isRendering = false;
195
+ _vode.stats.renderCount++;
196
+ _vode.stats.renderTime = Date.now() - sw;
197
+ _vode.stats.queueLengthAfterRender = _vode.q!.length;
198
+ if (_vode.q!.length > 0) {
199
+ _vode.render!();
198
200
  }
199
201
  }
200
202
  })
201
203
  });
202
204
 
203
- root.patch = (<PatchableState<S>>initialState).patch;
204
- root.state = <PatchableState<S>>initialState;
205
- root.q = [];
205
+ _vode.patch = (<PatchableState<S>>initialState).patch;
206
+ _vode.state = <PatchableState<S>>initialState;
207
+ _vode.q = [];
208
+
209
+ const root = container as ContainerNode<S>;
210
+ root._vode = _vode;
211
+
206
212
  const initialVode = dom(<S>initialState);
207
- root.vode = <AttachedVode<S>>initialVode;
208
- root.vode = render(<S>initialState, root.patch!, container, 0, undefined, initialVode)!;
213
+ _vode.vode = <AttachedVode<S>>initialVode;
214
+ _vode.vode = render(<S>initialState, _vode.patch!, container, 0, undefined, initialVode)!;
209
215
 
210
216
  for (const effect of initialPatches) {
211
- root.patch!(effect);
217
+ _vode.patch!(effect);
212
218
  }
213
219
 
214
- return root.patch;
220
+ return _vode.patch;
215
221
  }
216
222
 
217
223
  /** get properties of a vode, if there are any */
package/version.txt ADDED
File without changes
package/vode.mjs ADDED
@@ -0,0 +1,962 @@
1
+ // src/vode.ts
2
+ var EmptyPatch = {};
3
+ function vode(tag, props, ...children) {
4
+ if (Array.isArray(tag)) {
5
+ return tag;
6
+ }
7
+ if (props) {
8
+ return [tag, props, ...children];
9
+ }
10
+ return [tag, ...children];
11
+ }
12
+ function createState(state) {
13
+ return state;
14
+ }
15
+ function patch(p) {
16
+ return p;
17
+ }
18
+ function app(container, initialState, dom, ...initialPatches) {
19
+ const _vode = {};
20
+ _vode.stats = { renderTime: 0, renderCount: 0, queueLengthBeforeRender: 0, queueLengthAfterRender: 0, liveEffectCount: 0, patchCount: 0, renderPatchCount: 0 };
21
+ Object.defineProperty(initialState, "patch", {
22
+ enumerable: false,
23
+ configurable: true,
24
+ writable: false,
25
+ value: async (action) => {
26
+ if (!action || typeof action !== "function" && typeof action !== "object")
27
+ return;
28
+ _vode.stats.patchCount++;
29
+ if (action?.next) {
30
+ const generator = action;
31
+ _vode.stats.liveEffectCount++;
32
+ try {
33
+ let v = await generator.next();
34
+ while (v.done === false) {
35
+ _vode.stats.liveEffectCount++;
36
+ try {
37
+ _vode.patch(v.value);
38
+ v = await generator.next();
39
+ } finally {
40
+ _vode.stats.liveEffectCount--;
41
+ }
42
+ }
43
+ _vode.patch(v.value);
44
+ } finally {
45
+ _vode.stats.liveEffectCount--;
46
+ }
47
+ } else if (action.then) {
48
+ _vode.stats.liveEffectCount++;
49
+ try {
50
+ const nextState = await action;
51
+ _vode.patch(nextState);
52
+ } finally {
53
+ _vode.stats.liveEffectCount--;
54
+ }
55
+ } else if (Array.isArray(action)) {
56
+ if (typeof action[0] === "function") {
57
+ if (action.length > 1)
58
+ _vode.patch(action[0](_vode.state, ...action.slice(1)));
59
+ else
60
+ _vode.patch(action[0](_vode.state));
61
+ } else {
62
+ _vode.stats.patchCount--;
63
+ }
64
+ } else if (typeof action === "function") {
65
+ _vode.patch(action(_vode.state));
66
+ } else {
67
+ _vode.stats.renderPatchCount++;
68
+ _vode.q.push(action);
69
+ if (!_vode.isRendering)
70
+ _vode.render();
71
+ }
72
+ }
73
+ });
74
+ Object.defineProperty(_vode, "render", {
75
+ enumerable: false,
76
+ configurable: true,
77
+ writable: false,
78
+ value: () => requestAnimationFrame(() => {
79
+ if (_vode.isRendering || _vode.q.length === 0)
80
+ return;
81
+ _vode.isRendering = true;
82
+ const sw = Date.now();
83
+ try {
84
+ _vode.stats.queueLengthBeforeRender = _vode.q.length;
85
+ while (_vode.q.length > 0) {
86
+ const patch2 = _vode.q.shift();
87
+ if (patch2 === EmptyPatch)
88
+ continue;
89
+ mergeState(_vode.state, patch2);
90
+ }
91
+ _vode.vode = render(_vode.state, _vode.patch, container, 0, _vode.vode, dom(_vode.state));
92
+ } finally {
93
+ _vode.isRendering = false;
94
+ _vode.stats.renderCount++;
95
+ _vode.stats.renderTime = Date.now() - sw;
96
+ _vode.stats.queueLengthAfterRender = _vode.q.length;
97
+ if (_vode.q.length > 0) {
98
+ _vode.render();
99
+ }
100
+ }
101
+ })
102
+ });
103
+ _vode.patch = initialState.patch;
104
+ _vode.state = initialState;
105
+ _vode.q = [];
106
+ const root = container;
107
+ root._vode = _vode;
108
+ const initialVode = dom(initialState);
109
+ _vode.vode = initialVode;
110
+ _vode.vode = render(initialState, _vode.patch, container, 0, undefined, initialVode);
111
+ for (const effect of initialPatches) {
112
+ _vode.patch(effect);
113
+ }
114
+ return _vode.patch;
115
+ }
116
+ function props(vode2) {
117
+ if (Array.isArray(vode2) && vode2.length > 1 && vode2[1] && !Array.isArray(vode2[1])) {
118
+ if (typeof vode2[1] === "object" && vode2[1].nodeType !== Node.TEXT_NODE) {
119
+ return vode2[1];
120
+ }
121
+ }
122
+ return;
123
+ }
124
+ function mergeClass(a, b) {
125
+ if (!a)
126
+ return b;
127
+ if (!b)
128
+ return a;
129
+ if (typeof a === "string" && typeof b === "string") {
130
+ const aSplit = a.split(" ");
131
+ const bSplit = b.split(" ");
132
+ const classSet = new Set([...aSplit, ...bSplit]);
133
+ return Array.from(classSet).join(" ").trim();
134
+ } else if (typeof a === "string" && Array.isArray(b)) {
135
+ const classSet = new Set([...b, ...a.split(" ")]);
136
+ return Array.from(classSet).join(" ").trim();
137
+ } else if (Array.isArray(a) && typeof b === "string") {
138
+ const classSet = new Set([...a, ...b.split(" ")]);
139
+ return Array.from(classSet).join(" ").trim();
140
+ } else if (Array.isArray(a) && Array.isArray(b)) {
141
+ const classSet = new Set([...a, ...b]);
142
+ return Array.from(classSet).join(" ").trim();
143
+ } else if (typeof a === "string" && typeof b === "object") {
144
+ return { [a]: true, ...b };
145
+ } else if (typeof a === "object" && typeof b === "string") {
146
+ return { ...a, [b]: true };
147
+ } else if (typeof a === "object" && typeof b === "object") {
148
+ return { ...a, ...b };
149
+ } else if (typeof a === "object" && Array.isArray(b)) {
150
+ const aa = { ...a };
151
+ for (const item of b) {
152
+ aa[item] = true;
153
+ }
154
+ return aa;
155
+ } else if (Array.isArray(a) && typeof b === "object") {
156
+ const aa = {};
157
+ for (const item of a) {
158
+ aa[item] = true;
159
+ }
160
+ for (const bKey of b.keys) {
161
+ aa[bKey] = b[bKey];
162
+ }
163
+ return b;
164
+ }
165
+ throw new Error(`cannot merge classes of ${a} (${typeof a}) and ${b} (${typeof b})`);
166
+ }
167
+ function patchProps(vode2, props2) {
168
+ if (!Array.isArray(vode2))
169
+ return;
170
+ if (vode2.length > 1) {
171
+ if (!Array.isArray(vode2[1]) && typeof vode2[1] === "object") {
172
+ vode2[1] = merge(vode2[1], props2);
173
+ return;
174
+ }
175
+ if (childCount(vode2) > 0) {
176
+ vode2.push(null);
177
+ }
178
+ for (let i = vode2.length - 1;i > 0; i--) {
179
+ if (i > 1)
180
+ vode2[i] = vode2[i - 1];
181
+ }
182
+ vode2[1] = props2;
183
+ } else {
184
+ vode2.push(props2);
185
+ }
186
+ }
187
+ function children(vode2) {
188
+ const start = childrenStart(vode2);
189
+ if (start > 0) {
190
+ return vode2.slice(start);
191
+ }
192
+ return;
193
+ }
194
+ function childrenStart(vode2) {
195
+ return props(vode2) ? 2 : 1;
196
+ }
197
+ function tag(v) {
198
+ return v ? Array.isArray(v) ? v[0] : typeof v === "string" || v.nodeType === Node.TEXT_NODE ? "#text" : undefined : undefined;
199
+ }
200
+ function childCount(vode2) {
201
+ return vode2.length - childrenStart(vode2);
202
+ }
203
+ function child(vode2, index) {
204
+ return vode2[index + childrenStart(vode2)];
205
+ }
206
+ function merge(first, ...p) {
207
+ first = mergeState({}, first);
208
+ for (const pp of p) {
209
+ if (!pp)
210
+ continue;
211
+ first = mergeState(first, pp);
212
+ }
213
+ return first;
214
+ }
215
+ function classString(classProp) {
216
+ if (typeof classProp === "string") {
217
+ return classProp;
218
+ } else if (Array.isArray(classProp)) {
219
+ return classProp.map(classString).join(" ");
220
+ } else if (typeof classProp === "object") {
221
+ return Object.keys(classProp).filter((k) => classProp[k]).join(" ");
222
+ } else {
223
+ return "";
224
+ }
225
+ }
226
+ function isNaturalVode(x) {
227
+ return Array.isArray(x) && x.length > 0 && typeof x[0] === "string";
228
+ }
229
+ function isTextVode(x) {
230
+ return typeof x === "string" || x?.nodeType === Node.TEXT_NODE;
231
+ }
232
+ function unwrap(c, s) {
233
+ if (typeof c === "function") {
234
+ return unwrap(c(s), s);
235
+ } else {
236
+ return c;
237
+ }
238
+ }
239
+ function memo(compare, componentOrProps) {
240
+ componentOrProps.__memo = compare;
241
+ return componentOrProps;
242
+ }
243
+ function remember(state, present, past) {
244
+ if (typeof present !== "function")
245
+ return present;
246
+ const presentMemo = present?.__memo;
247
+ const pastMemo = past?.__memo;
248
+ if (Array.isArray(presentMemo) && Array.isArray(pastMemo) && presentMemo.length === pastMemo.length) {
249
+ let same = true;
250
+ for (let i = 0;i < presentMemo.length; i++) {
251
+ if (presentMemo[i] !== pastMemo[i]) {
252
+ same = false;
253
+ break;
254
+ }
255
+ }
256
+ if (same)
257
+ return past;
258
+ }
259
+ const newRender = unwrap(present, state);
260
+ if (typeof newRender === "object") {
261
+ newRender.__memo = present?.__memo;
262
+ }
263
+ return newRender;
264
+ }
265
+ function render(state, patch2, parent, childIndex, oldVode, newVode, svg) {
266
+ newVode = remember(state, newVode, oldVode);
267
+ const isNoVode = !newVode || typeof newVode === "number" || typeof newVode === "boolean";
268
+ if (newVode === oldVode || !oldVode && isNoVode) {
269
+ return oldVode;
270
+ }
271
+ const oldIsText = oldVode?.nodeType === Node.TEXT_NODE;
272
+ const oldNode = oldIsText ? oldVode : oldVode?.node;
273
+ if (isNoVode) {
274
+ oldNode?.onUnmount && patch2(oldNode.onUnmount(oldNode));
275
+ oldNode?.remove();
276
+ return;
277
+ }
278
+ const isText = !isNoVode && isTextVode(newVode);
279
+ const isNode = !isNoVode && isNaturalVode(newVode);
280
+ const alreadyAttached = !!newVode && typeof newVode !== "string" && !!(newVode?.node || newVode?.nodeType === Node.TEXT_NODE);
281
+ if (!isText && !isNode && !alreadyAttached && !oldVode) {
282
+ throw new Error("Invalid vode: " + typeof newVode + " " + JSON.stringify(newVode));
283
+ } else if (alreadyAttached && isText) {
284
+ newVode = newVode.wholeText;
285
+ } else if (alreadyAttached && isNode) {
286
+ newVode = [...newVode];
287
+ }
288
+ if (oldIsText && isText) {
289
+ if (oldNode.nodeValue !== newVode) {
290
+ oldNode.nodeValue = newVode;
291
+ }
292
+ return oldVode;
293
+ }
294
+ if (isText && (!oldNode || !oldIsText)) {
295
+ const text = document.createTextNode(newVode);
296
+ if (oldNode) {
297
+ oldNode.onUnmount && patch2(oldNode.onUnmount(oldNode));
298
+ oldNode.replaceWith(text);
299
+ } else {
300
+ if (parent.childNodes[childIndex]) {
301
+ parent.insertBefore(text, parent.childNodes[childIndex]);
302
+ } else {
303
+ parent.appendChild(text);
304
+ }
305
+ }
306
+ return text;
307
+ }
308
+ if (isNode && (!oldNode || oldIsText || oldVode[0] !== newVode[0])) {
309
+ svg = svg || newVode[0] === "svg";
310
+ const newNode = svg ? document.createElementNS("http://www.w3.org/2000/svg", newVode[0]) : document.createElement(newVode[0]);
311
+ newVode.node = newNode;
312
+ const newvode = newVode;
313
+ if (1 in newvode) {
314
+ newvode[1] = remember(state, newvode[1], undefined);
315
+ }
316
+ const properties = props(newVode);
317
+ patchProperties(patch2, newNode, undefined, properties, svg);
318
+ if (oldNode) {
319
+ oldNode.onUnmount && patch2(oldNode.onUnmount(oldNode));
320
+ oldNode.replaceWith(newNode);
321
+ } else {
322
+ if (parent.childNodes[childIndex]) {
323
+ parent.insertBefore(newNode, parent.childNodes[childIndex]);
324
+ } else {
325
+ parent.appendChild(newNode);
326
+ }
327
+ }
328
+ const newChildren = children(newVode);
329
+ if (newChildren) {
330
+ for (let i = 0;i < newChildren.length; i++) {
331
+ const child2 = newChildren[i];
332
+ const attached = render(state, patch2, newNode, i, undefined, child2, svg);
333
+ newVode[properties ? i + 2 : i + 1] = attached;
334
+ }
335
+ }
336
+ newNode.onMount && patch2(newNode.onMount(newNode));
337
+ return newVode;
338
+ }
339
+ if (!oldIsText && isNode && oldVode[0] === newVode[0]) {
340
+ svg = svg || newVode[0] === "svg";
341
+ newVode.node = oldNode;
342
+ const newvode = newVode;
343
+ const oldvode = oldVode;
344
+ let hasProps = false;
345
+ if (newvode[1]?.__memo) {
346
+ const prev = newvode[1];
347
+ newvode[1] = remember(state, newvode[1], oldvode[1]);
348
+ if (prev !== newvode[1]) {
349
+ const properties = props(newVode);
350
+ patchProperties(patch2, oldNode, props(oldVode), properties, svg);
351
+ hasProps = !!properties;
352
+ }
353
+ } else {
354
+ const properties = props(newVode);
355
+ patchProperties(patch2, oldNode, props(oldVode), properties, svg);
356
+ hasProps = !!properties;
357
+ }
358
+ const newKids = children(newVode);
359
+ const oldKids = children(oldVode);
360
+ if (newKids) {
361
+ for (let i = 0;i < newKids.length; i++) {
362
+ const child2 = newKids[i];
363
+ const oldChild = oldKids && oldKids[i];
364
+ const attached = render(state, patch2, oldNode, i, oldChild, child2, svg);
365
+ if (attached) {
366
+ newVode[hasProps ? i + 2 : i + 1] = attached;
367
+ }
368
+ }
369
+ for (let i = newKids.length;oldKids && i < oldKids.length; i++) {
370
+ if (oldKids[i]?.node)
371
+ oldKids[i].node.remove();
372
+ else if (oldKids[i]?.nodeType === Node.TEXT_NODE)
373
+ oldKids[i].remove();
374
+ }
375
+ }
376
+ for (let i = newKids?.length || 0;i < oldKids?.length; i++) {
377
+ if (oldKids[i]?.node)
378
+ oldKids[i].node.remove();
379
+ else if (oldKids[i]?.nodeType === Node.TEXT_NODE)
380
+ oldKids[i].remove();
381
+ }
382
+ return newVode;
383
+ }
384
+ return;
385
+ }
386
+ function patchProperties(patch2, node, oldProps, newProps, isSvg) {
387
+ if (!newProps && !oldProps)
388
+ return;
389
+ if (!oldProps) {
390
+ for (const key in newProps) {
391
+ const newValue = newProps[key];
392
+ newProps[key] = patchProperty(patch2, node, key, undefined, newValue, isSvg);
393
+ }
394
+ } else if (newProps) {
395
+ const combinedKeys = new Set([...Object.keys(oldProps), ...Object.keys(newProps)]);
396
+ for (const key of combinedKeys) {
397
+ const oldValue = oldProps[key];
398
+ const newValue = newProps[key];
399
+ if (key[0] === "o" && key[1] === "n") {
400
+ const oldEvent = node["__" + key];
401
+ if (oldEvent && oldEvent !== newValue || !oldEvent && oldValue !== newValue) {
402
+ newProps[key] = patchProperty(patch2, node, key, oldValue, newValue, isSvg);
403
+ }
404
+ node["__" + key] = newValue;
405
+ } else if (oldValue !== newValue) {
406
+ newProps[key] = patchProperty(patch2, node, key, oldValue, newValue, isSvg);
407
+ }
408
+ }
409
+ } else {
410
+ for (const key in oldProps) {
411
+ const oldValue = oldProps[key];
412
+ oldProps[key] = patchProperty(patch2, node, key, oldValue, undefined, isSvg);
413
+ }
414
+ }
415
+ }
416
+ function patchProperty(patch2, node, key, oldValue, newValue, isSvg) {
417
+ if (key === "style") {
418
+ if (!newValue) {
419
+ node.style.cssText = "";
420
+ } else if (oldValue) {
421
+ for (let k in { ...oldValue, ...newValue }) {
422
+ if (!oldValue || newValue[k] !== oldValue[k]) {
423
+ node.style[k] = newValue[k];
424
+ } else if (oldValue[k] && !newValue[k]) {
425
+ node.style[k] = undefined;
426
+ }
427
+ }
428
+ } else {
429
+ for (let k in newValue) {
430
+ node.style[k] = newValue[k];
431
+ }
432
+ }
433
+ } else if (key === "class") {
434
+ if (isSvg) {
435
+ if (newValue) {
436
+ const newClass = classString(newValue);
437
+ node.classList.value = newClass;
438
+ } else {
439
+ node.classList.value = "";
440
+ }
441
+ } else {
442
+ if (newValue) {
443
+ const newClass = classString(newValue);
444
+ node.className = newClass;
445
+ } else {
446
+ node.className = "";
447
+ }
448
+ }
449
+ } else if (key[0] === "o" && key[1] === "n") {
450
+ if (newValue) {
451
+ let eventHandler = null;
452
+ if (typeof newValue === "function") {
453
+ const action = newValue;
454
+ eventHandler = (evt) => patch2([action, evt]);
455
+ } else if (Array.isArray(newValue)) {
456
+ const arr = newValue;
457
+ const action = newValue[0];
458
+ if (arr.length > 1) {
459
+ eventHandler = () => patch2([action, ...arr.slice(1)]);
460
+ } else {
461
+ eventHandler = (evt) => patch2([action, evt]);
462
+ }
463
+ } else if (typeof newValue === "object") {
464
+ eventHandler = () => patch2(newValue);
465
+ }
466
+ node[key] = eventHandler;
467
+ } else {
468
+ node[key] = null;
469
+ }
470
+ } else if (newValue !== null && newValue !== undefined && newValue !== false) {
471
+ node.setAttribute(key, newValue);
472
+ } else {
473
+ node.removeAttribute(key);
474
+ }
475
+ return newValue;
476
+ }
477
+ function mergeState(target, source) {
478
+ if (!source)
479
+ return target;
480
+ for (const key in source) {
481
+ const value = source[key];
482
+ if (value && typeof value === "object") {
483
+ const targetValue = target[key];
484
+ if (targetValue) {
485
+ if (Array.isArray(value)) {
486
+ target[key] = [...value];
487
+ } else if (value instanceof Date && targetValue !== value) {
488
+ target[key] = new Date(value);
489
+ } else {
490
+ if (Array.isArray(targetValue))
491
+ target[key] = mergeState({}, value);
492
+ else if (typeof targetValue === "object")
493
+ mergeState(target[key], value);
494
+ else
495
+ target[key] = mergeState({}, value);
496
+ }
497
+ } else if (Array.isArray(value)) {
498
+ target[key] = [...value];
499
+ } else if (value instanceof Date) {
500
+ target[key] = new Date(value);
501
+ } else {
502
+ target[key] = mergeState({}, value);
503
+ }
504
+ } else if (value === undefined) {
505
+ delete target[key];
506
+ } else {
507
+ target[key] = value;
508
+ }
509
+ }
510
+ return target;
511
+ }
512
+ // src/vode-tags.ts
513
+ var A = "a";
514
+ var ABBR = "abbr";
515
+ var ADDRESS = "address";
516
+ var AREA = "area";
517
+ var ARTICLE = "article";
518
+ var ASIDE = "aside";
519
+ var AUDIO = "audio";
520
+ var B = "b";
521
+ var BASE = "base";
522
+ var BDI = "bdi";
523
+ var BDO = "bdo";
524
+ var BLOCKQUOTE = "blockquote";
525
+ var BODY = "body";
526
+ var BR = "br";
527
+ var BUTTON = "button";
528
+ var CANVAS = "canvas";
529
+ var CAPTION = "caption";
530
+ var CITE = "cite";
531
+ var CODE = "code";
532
+ var COL = "col";
533
+ var COLGROUP = "colgroup";
534
+ var DATA = "data";
535
+ var DATALIST = "datalist";
536
+ var DD = "dd";
537
+ var DEL = "del";
538
+ var DETAILS = "details";
539
+ var DFN = "dfn";
540
+ var DIALOG = "dialog";
541
+ var DIV = "div";
542
+ var DL = "dl";
543
+ var DT = "dt";
544
+ var EM = "em";
545
+ var EMBED = "embed";
546
+ var FIELDSET = "fieldset";
547
+ var FIGCAPTION = "figcaption";
548
+ var FIGURE = "figure";
549
+ var FOOTER = "footer";
550
+ var FORM = "form";
551
+ var H1 = "h1";
552
+ var H2 = "h2";
553
+ var H3 = "h3";
554
+ var H4 = "h4";
555
+ var H5 = "h5";
556
+ var H6 = "h6";
557
+ var HEAD = "head";
558
+ var HEADER = "header";
559
+ var HGROUP = "hgroup";
560
+ var HR = "hr";
561
+ var HTML = "html";
562
+ var I = "i";
563
+ var IFRAME = "iframe";
564
+ var IMG = "img";
565
+ var INPUT = "input";
566
+ var INS = "ins";
567
+ var KBD = "kbd";
568
+ var LABEL = "label";
569
+ var LEGEND = "legend";
570
+ var LI = "li";
571
+ var LINK = "link";
572
+ var MAIN = "main";
573
+ var MAP = "map";
574
+ var MARK = "mark";
575
+ var MENU = "menu";
576
+ var META = "meta";
577
+ var METER = "meter";
578
+ var NAV = "nav";
579
+ var NOSCRIPT = "noscript";
580
+ var OBJECT = "object";
581
+ var OL = "ol";
582
+ var OPTGROUP = "optgroup";
583
+ var OPTION = "option";
584
+ var OUTPUT = "output";
585
+ var P = "p";
586
+ var PICTURE = "picture";
587
+ var PRE = "pre";
588
+ var PROGRESS = "progress";
589
+ var Q = "q";
590
+ var RP = "rp";
591
+ var RT = "rt";
592
+ var RUBY = "ruby";
593
+ var S = "s";
594
+ var SAMP = "samp";
595
+ var SCRIPT = "script";
596
+ var SECTION = "section";
597
+ var SELECT = "select";
598
+ var SLOT = "slot";
599
+ var SMALL = "small";
600
+ var SOURCE = "source";
601
+ var SPAN = "span";
602
+ var STRONG = "strong";
603
+ var STYLE = "style";
604
+ var SUB = "sub";
605
+ var SUMMARY = "summary";
606
+ var SUP = "sup";
607
+ var TABLE = "table";
608
+ var TBODY = "tbody";
609
+ var TD = "td";
610
+ var TEMPLATE = "template";
611
+ var TEXTAREA = "textarea";
612
+ var TFOOT = "tfoot";
613
+ var TH = "th";
614
+ var THEAD = "thead";
615
+ var TIME = "time";
616
+ var TITLE = "title";
617
+ var TR = "tr";
618
+ var TRACK = "track";
619
+ var U = "u";
620
+ var UL = "ul";
621
+ var VIDEO = "video";
622
+ var WBR = "wbr";
623
+ var ANIMATE = "animate";
624
+ var ANIMATEMOTION = "animateMotion";
625
+ var ANIMATETRANSFORM = "animateTransform";
626
+ var CIRCLE = "circle";
627
+ var CLIPPATH = "clipPath";
628
+ var DEFS = "defs";
629
+ var DESC = "desc";
630
+ var ELLIPSE = "ellipse";
631
+ var FEBLEND = "feBlend";
632
+ var FECOLORMATRIX = "feColorMatrix";
633
+ var FECOMPONENTTRANSFER = "feComponentTransfer";
634
+ var FECOMPOSITE = "feComposite";
635
+ var FECONVOLVEMATRIX = "feConvolveMatrix";
636
+ var FEDIFFUSELIGHTING = "feDiffuseLighting";
637
+ var FEDISPLACEMENTMAP = "feDisplacementMap";
638
+ var FEDISTANTLIGHT = "feDistantLight";
639
+ var FEDROPSHADOW = "feDropShadow";
640
+ var FEFLOOD = "feFlood";
641
+ var FEFUNCA = "feFuncA";
642
+ var FEFUNCB = "feFuncB";
643
+ var FEFUNCG = "feFuncG";
644
+ var FEFUNCR = "feFuncR";
645
+ var FEGAUSSIANBLUR = "feGaussianBlur";
646
+ var FEIMAGE = "feImage";
647
+ var FEMERGE = "feMerge";
648
+ var FEMERGENODE = "feMergeNode";
649
+ var FEMORPHOLOGY = "feMorphology";
650
+ var FEOFFSET = "feOffset";
651
+ var FEPOINTLIGHT = "fePointLight";
652
+ var FESPECULARLIGHTING = "feSpecularLighting";
653
+ var FESPOTLIGHT = "feSpotLight";
654
+ var FETILE = "feTile";
655
+ var FETURBULENCE = "feTurbulence";
656
+ var FILTER = "filter";
657
+ var FOREIGNOBJECT = "foreignObject";
658
+ var G = "g";
659
+ var IMAGE = "image";
660
+ var LINE = "line";
661
+ var LINEARGRADIENT = "linearGradient";
662
+ var MARKER = "marker";
663
+ var MASK = "mask";
664
+ var METADATA = "metadata";
665
+ var MPATH = "mpath";
666
+ var PATH = "path";
667
+ var PATTERN = "pattern";
668
+ var POLYGON = "polygon";
669
+ var POLYLINE = "polyline";
670
+ var RADIALGRADIENT = "radialGradient";
671
+ var RECT = "rect";
672
+ var SET = "set";
673
+ var STOP = "stop";
674
+ var SVG = "svg";
675
+ var SWITCH = "switch";
676
+ var SYMBOL = "symbol";
677
+ var TEXT = "text";
678
+ var TEXTPATH = "textPath";
679
+ var TSPAN = "tspan";
680
+ var USE = "use";
681
+ var VIEW = "view";
682
+ var ANNOTATION = "annotation";
683
+ var ANNOTATION_XML = "annotation-xml";
684
+ var MACTION = "maction";
685
+ var MATH = "math";
686
+ var MERROR = "merror";
687
+ var MFRAC = "mfrac";
688
+ var MI = "mi";
689
+ var MMULTISCRIPTS = "mmultiscripts";
690
+ var MN = "mn";
691
+ var MO = "mo";
692
+ var MOVER = "mover";
693
+ var MPADDED = "mpadded";
694
+ var MPHANTOM = "mphantom";
695
+ var MPRESCRIPTS = "mprescripts";
696
+ var MROOT = "mroot";
697
+ var MROW = "mrow";
698
+ var MS = "ms";
699
+ var MSPACE = "mspace";
700
+ var MSQRT = "msqrt";
701
+ var MSTYLE = "mstyle";
702
+ var MSUB = "msub";
703
+ var MSUBSUP = "msubsup";
704
+ var MSUP = "msup";
705
+ var MTABLE = "mtable";
706
+ var MTD = "mtd";
707
+ var MTEXT = "mtext";
708
+ var MTR = "mtr";
709
+ var MUNDER = "munder";
710
+ var MUNDEROVER = "munderover";
711
+ var SEMANTICS = "semantics";
712
+ // src/html.ts
713
+ function htmlToVode(html) {
714
+ const div = document.createElement("div");
715
+ div.innerHTML = html.trim();
716
+ const vodes = [];
717
+ for (const child2 of div.childNodes) {
718
+ const v = elementToVode(child2);
719
+ if (v != null)
720
+ vodes.push(v);
721
+ }
722
+ return vodes;
723
+ }
724
+ function elementToVode(element) {
725
+ if (element.nodeType === Node.TEXT_NODE) {
726
+ return element.textContent;
727
+ }
728
+ if (element.nodeType !== Node.ELEMENT_NODE) {
729
+ return;
730
+ }
731
+ const vode2 = [element.tagName.toLowerCase()];
732
+ if (element.hasAttributes()) {
733
+ const props2 = {};
734
+ for (const att of element.attributes) {
735
+ props2[att.name] = att.value;
736
+ }
737
+ vode2.push(props2);
738
+ }
739
+ for (const child2 of element.childNodes) {
740
+ const v = elementToVode(child2);
741
+ if (v && (typeof v !== "string" || v.length > 0))
742
+ vode2.push(v);
743
+ }
744
+ return vode2;
745
+ }
746
+ export {
747
+ vode,
748
+ tag,
749
+ props,
750
+ patchProps,
751
+ patch,
752
+ mergeClass,
753
+ merge,
754
+ memo,
755
+ htmlToVode,
756
+ createState,
757
+ childrenStart,
758
+ children,
759
+ childCount,
760
+ child,
761
+ app,
762
+ WBR,
763
+ VIEW,
764
+ VIDEO,
765
+ USE,
766
+ UL,
767
+ U,
768
+ TSPAN,
769
+ TRACK,
770
+ TR,
771
+ TITLE,
772
+ TIME,
773
+ THEAD,
774
+ TH,
775
+ TFOOT,
776
+ TEXTPATH,
777
+ TEXTAREA,
778
+ TEXT,
779
+ TEMPLATE,
780
+ TD,
781
+ TBODY,
782
+ TABLE,
783
+ SYMBOL,
784
+ SWITCH,
785
+ SVG,
786
+ SUP,
787
+ SUMMARY,
788
+ SUB,
789
+ STYLE,
790
+ STRONG,
791
+ STOP,
792
+ SPAN,
793
+ SOURCE,
794
+ SMALL,
795
+ SLOT,
796
+ SET,
797
+ SEMANTICS,
798
+ SELECT,
799
+ SECTION,
800
+ SCRIPT,
801
+ SAMP,
802
+ S,
803
+ RUBY,
804
+ RT,
805
+ RP,
806
+ RECT,
807
+ RADIALGRADIENT,
808
+ Q,
809
+ PROGRESS,
810
+ PRE,
811
+ POLYLINE,
812
+ POLYGON,
813
+ PICTURE,
814
+ PATTERN,
815
+ PATH,
816
+ P,
817
+ OUTPUT,
818
+ OPTION,
819
+ OPTGROUP,
820
+ OL,
821
+ OBJECT,
822
+ NOSCRIPT,
823
+ NAV,
824
+ MUNDEROVER,
825
+ MUNDER,
826
+ MTR,
827
+ MTEXT,
828
+ MTD,
829
+ MTABLE,
830
+ MSUP,
831
+ MSUBSUP,
832
+ MSUB,
833
+ MSTYLE,
834
+ MSQRT,
835
+ MSPACE,
836
+ MS,
837
+ MROW,
838
+ MROOT,
839
+ MPRESCRIPTS,
840
+ MPHANTOM,
841
+ MPATH,
842
+ MPADDED,
843
+ MOVER,
844
+ MO,
845
+ MN,
846
+ MMULTISCRIPTS,
847
+ MI,
848
+ MFRAC,
849
+ METER,
850
+ METADATA,
851
+ META,
852
+ MERROR,
853
+ MENU,
854
+ MATH,
855
+ MASK,
856
+ MARKER,
857
+ MARK,
858
+ MAP,
859
+ MAIN,
860
+ MACTION,
861
+ LINK,
862
+ LINEARGRADIENT,
863
+ LINE,
864
+ LI,
865
+ LEGEND,
866
+ LABEL,
867
+ KBD,
868
+ INS,
869
+ INPUT,
870
+ IMG,
871
+ IMAGE,
872
+ IFRAME,
873
+ I,
874
+ HTML,
875
+ HR,
876
+ HGROUP,
877
+ HEADER,
878
+ HEAD,
879
+ H6,
880
+ H5,
881
+ H4,
882
+ H3,
883
+ H2,
884
+ H1,
885
+ G,
886
+ FORM,
887
+ FOREIGNOBJECT,
888
+ FOOTER,
889
+ FILTER,
890
+ FIGURE,
891
+ FIGCAPTION,
892
+ FIELDSET,
893
+ FETURBULENCE,
894
+ FETILE,
895
+ FESPOTLIGHT,
896
+ FESPECULARLIGHTING,
897
+ FEPOINTLIGHT,
898
+ FEOFFSET,
899
+ FEMORPHOLOGY,
900
+ FEMERGENODE,
901
+ FEMERGE,
902
+ FEIMAGE,
903
+ FEGAUSSIANBLUR,
904
+ FEFUNCR,
905
+ FEFUNCG,
906
+ FEFUNCB,
907
+ FEFUNCA,
908
+ FEFLOOD,
909
+ FEDROPSHADOW,
910
+ FEDISTANTLIGHT,
911
+ FEDISPLACEMENTMAP,
912
+ FEDIFFUSELIGHTING,
913
+ FECONVOLVEMATRIX,
914
+ FECOMPOSITE,
915
+ FECOMPONENTTRANSFER,
916
+ FECOLORMATRIX,
917
+ FEBLEND,
918
+ EmptyPatch,
919
+ EMBED,
920
+ EM,
921
+ ELLIPSE,
922
+ DT,
923
+ DL,
924
+ DIV,
925
+ DIALOG,
926
+ DFN,
927
+ DETAILS,
928
+ DESC,
929
+ DEL,
930
+ DEFS,
931
+ DD,
932
+ DATALIST,
933
+ DATA,
934
+ COLGROUP,
935
+ COL,
936
+ CODE,
937
+ CLIPPATH,
938
+ CITE,
939
+ CIRCLE,
940
+ CAPTION,
941
+ CANVAS,
942
+ BUTTON,
943
+ BR,
944
+ BODY,
945
+ BLOCKQUOTE,
946
+ BDO,
947
+ BDI,
948
+ BASE,
949
+ B,
950
+ AUDIO,
951
+ ASIDE,
952
+ ARTICLE,
953
+ AREA,
954
+ ANNOTATION_XML,
955
+ ANNOTATION,
956
+ ANIMATETRANSFORM,
957
+ ANIMATEMOTION,
958
+ ANIMATE,
959
+ ADDRESS,
960
+ ABBR,
961
+ A
962
+ };