@luna_ui/luna 0.11.0 → 0.20.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.
Files changed (86) hide show
  1. package/dist/api-DAWeanTX.js +1 -0
  2. package/dist/api-qXll116-.d.ts +80 -0
  3. package/dist/cli.mjs +27 -22
  4. package/dist/css/index.js +1 -0
  5. package/dist/event-utils.d.ts +1 -1
  6. package/dist/event-utils.js +1 -1
  7. package/dist/{index-BZoM-af5.d.ts → index-VY8G32hr.d.ts} +16 -76
  8. package/dist/index.d.ts +4 -3
  9. package/dist/index.js +1 -1
  10. package/dist/jsx-dev-runtime.js +1 -1
  11. package/dist/jsx-runtime.d.ts +1 -1
  12. package/dist/jsx-runtime.js +1 -1
  13. package/dist/raw.d.ts +2 -0
  14. package/dist/raw.js +1 -0
  15. package/dist/resource.d.ts +41 -0
  16. package/dist/resource.js +1 -0
  17. package/dist/router-lite.d.ts +44 -0
  18. package/dist/router-lite.js +1 -0
  19. package/dist/signals-shared.d.ts +12 -0
  20. package/dist/signals-shared.js +1 -0
  21. package/dist/signals.d.ts +2 -3
  22. package/dist/signals.js +1 -1
  23. package/dist/vite-plugin.d.ts +7708 -2
  24. package/dist/vite-plugin.js +7 -6
  25. package/package.json +30 -11
  26. package/dist/event-utils-9cHYnvun.js +0 -1
  27. package/dist/src-BFWjzzPo.js +0 -1
  28. package/src/css/extract.ts +0 -798
  29. package/src/css/index.ts +0 -10
  30. package/src/css/inject.ts +0 -205
  31. package/src/css/inline.ts +0 -182
  32. package/src/css/minify.ts +0 -70
  33. package/src/css/optimizer.ts +0 -6
  34. package/src/css/runtime.ts +0 -344
  35. package/src/css-optimizer/README.md +0 -353
  36. package/src/css-optimizer/cooccurrence.ts +0 -100
  37. package/src/css-optimizer/core.ts +0 -263
  38. package/src/css-optimizer/extractors.ts +0 -243
  39. package/src/css-optimizer/hash.ts +0 -54
  40. package/src/css-optimizer/index.ts +0 -129
  41. package/src/css-optimizer/merge.ts +0 -109
  42. package/src/css-optimizer/moonbit-analyzer.ts +0 -210
  43. package/src/css-optimizer/parser.ts +0 -120
  44. package/src/css-optimizer/pattern.ts +0 -171
  45. package/src/css-optimizer/transformers.ts +0 -301
  46. package/src/css-optimizer/types.ts +0 -128
  47. package/src/event-utils.ts +0 -227
  48. package/src/hydration/createHydrator.ts +0 -62
  49. package/src/hydration/delegate.ts +0 -62
  50. package/src/hydration/drag.ts +0 -214
  51. package/src/hydration/index.ts +0 -12
  52. package/src/hydration/keyboard.ts +0 -64
  53. package/src/hydration/toggle.ts +0 -101
  54. package/src/index.ts +0 -908
  55. package/src/jsx-dev-runtime.ts +0 -2
  56. package/src/jsx-runtime.ts +0 -398
  57. package/src/signals.ts +0 -113
  58. package/src/vite-plugin.ts +0 -718
  59. package/tests/__screenshots__/apg.test.ts/APG-Components---Accessibility-Tests-Button-Pattern-disabled-button-has-aria-disabled-1.png +0 -0
  60. package/tests/__screenshots__/resource.test.ts/Resource-API--SolidJS-style--createResource-error-is-undefined-when-pending-1.png +0 -0
  61. package/tests/__screenshots__/resource.test.ts/Resource-API--SolidJS-style--createResource-transitions-to-success-on-resolve-1.png +0 -0
  62. package/tests/apg.test.ts +0 -466
  63. package/tests/context.test.ts +0 -118
  64. package/tests/css-optimizer-extractors.test.ts +0 -264
  65. package/tests/css-optimizer-integration.test.ts +0 -566
  66. package/tests/css-optimizer-transformers.test.ts +0 -301
  67. package/tests/css-optimizer.test.ts +0 -646
  68. package/tests/css-runtime.bench.ts +0 -442
  69. package/tests/css-runtime.test.ts +0 -342
  70. package/tests/debounced.test.ts +0 -165
  71. package/tests/dom.test.ts +0 -873
  72. package/tests/integration.test.ts +0 -405
  73. package/tests/issue-11-show-null-to-truthy.test.ts +0 -176
  74. package/tests/issue-5-for-infinite-loop.test.ts +0 -516
  75. package/tests/jsx-runtime.test.tsx +0 -393
  76. package/tests/lifecycle.test.ts +0 -833
  77. package/tests/move-before.bench.ts +0 -304
  78. package/tests/preact-signals-comparison.test.ts +0 -1608
  79. package/tests/resource.test.ts +0 -170
  80. package/tests/router.test.ts +0 -117
  81. package/tests/show-initial-mount-leak.test.tsx +0 -182
  82. package/tests/solidjs-api.test.ts +0 -660
  83. package/tests/static-perf.bench.ts +0 -64
  84. package/tests/store.test.ts +0 -263
  85. package/tests/tsx-syntax.test.tsx +0 -404
  86. /package/dist/{event-utils-BkTM7rk5.d.ts → event-utils-BvAf0NwN.d.ts} +0 -0
@@ -1,660 +0,0 @@
1
- /**
2
- * Tests for SolidJS-compatible API utilities
3
- */
4
- import { describe, test, expect, beforeEach, afterEach } from "vitest";
5
- import {
6
- createSignal,
7
- createRenderEffect,
8
- createMemo,
9
- createRoot,
10
- on,
11
- mergeProps,
12
- splitProps,
13
- Provider,
14
- Index,
15
- Switch,
16
- Match,
17
- Portal,
18
- portalToBody,
19
- portalToSelector,
20
- createContext,
21
- useContext,
22
- createElement,
23
- text,
24
- mount,
25
- For,
26
- } from "../src/index";
27
-
28
- // MoonBit AttrValue constructors
29
- const AttrValue = {
30
- Static: (value: string) => ({ $tag: 0, _0: value }),
31
- Dynamic: (getter: () => string) => ({ $tag: 1, _0: getter }),
32
- };
33
-
34
- function attr(name: string, value: unknown) {
35
- return { _0: name, _1: value };
36
- }
37
-
38
- describe("on() utility", () => {
39
- test("on tracks single dependency", () => {
40
- const results: [number, number | undefined][] = [];
41
-
42
- createRoot((dispose) => {
43
- const [count, setCount] = createSignal(0);
44
-
45
- createRenderEffect(
46
- on(count, (value, prev) => {
47
- results.push([value, prev]);
48
- })
49
- );
50
-
51
- setCount(1);
52
- setCount(2);
53
- dispose();
54
- });
55
-
56
- expect(results).toEqual([
57
- [0, undefined],
58
- [1, 0],
59
- [2, 1],
60
- ]);
61
- });
62
-
63
- test("on tracks multiple dependencies", () => {
64
- const results: [[number, string], [number, string] | undefined][] = [];
65
-
66
- createRoot((dispose) => {
67
- const [a, setA] = createSignal(1);
68
- const [b, setB] = createSignal("x");
69
-
70
- createRenderEffect(
71
- on([a, b], (values, prev) => {
72
- results.push([values as [number, string], prev as [number, string] | undefined]);
73
- })
74
- );
75
-
76
- setA(2);
77
- setB("y");
78
- dispose();
79
- });
80
-
81
- expect(results).toEqual([
82
- [[1, "x"], undefined],
83
- [[2, "x"], [1, "x"]],
84
- [[2, "y"], [2, "x"]],
85
- ]);
86
- });
87
-
88
- test("on with defer option skips initial run", () => {
89
- const results: number[] = [];
90
-
91
- createRoot((dispose) => {
92
- const [count, setCount] = createSignal(0);
93
-
94
- createRenderEffect(
95
- on(
96
- count,
97
- (value) => {
98
- results.push(value);
99
- },
100
- { defer: true }
101
- )
102
- );
103
-
104
- // Initial run should be skipped
105
- expect(results).toEqual([]);
106
-
107
- setCount(1);
108
- expect(results).toEqual([1]);
109
-
110
- setCount(2);
111
- expect(results).toEqual([1, 2]);
112
-
113
- dispose();
114
- });
115
- });
116
- });
117
-
118
- describe("mergeProps()", () => {
119
- test("merges simple props", () => {
120
- const a = { foo: 1, bar: 2 };
121
- const b = { bar: 3, baz: 4 };
122
- const result = mergeProps(a, b);
123
-
124
- expect(result).toEqual({ foo: 1, bar: 3, baz: 4 });
125
- });
126
-
127
- test("merges event handlers", () => {
128
- const calls: string[] = [];
129
- const a = { onClick: () => calls.push("a") };
130
- const b = { onClick: () => calls.push("b") };
131
- const result = mergeProps(a, b) as { onClick: () => void };
132
-
133
- result.onClick();
134
- expect(calls).toEqual(["a", "b"]);
135
- });
136
-
137
- test("merges ref callbacks", () => {
138
- const refs: string[] = [];
139
- const a = { ref: (el: string) => refs.push(`a:${el}`) };
140
- const b = { ref: (el: string) => refs.push(`b:${el}`) };
141
- const result = mergeProps(a, b) as { ref: (el: string) => void };
142
-
143
- result.ref("element");
144
- expect(refs).toEqual(["a:element", "b:element"]);
145
- });
146
-
147
- test("merges class names", () => {
148
- const a = { class: "foo" };
149
- const b = { class: "bar" };
150
- const result = mergeProps(a, b);
151
-
152
- expect(result.class).toBe("foo bar");
153
- });
154
-
155
- test("merges className", () => {
156
- const a = { className: "foo" };
157
- const b = { className: "bar" };
158
- const result = mergeProps(a, b);
159
-
160
- expect(result.className).toBe("foo bar");
161
- });
162
-
163
- test("merges style objects", () => {
164
- const a = { style: { color: "red", margin: "10px" } } as const;
165
- const b = { style: { color: "blue", padding: "5px" } } as const;
166
- const result = mergeProps<{ style: Record<string, string> }>(a as any, b as any);
167
-
168
- expect(result.style).toEqual({ color: "blue", margin: "10px", padding: "5px" });
169
- });
170
-
171
- test("handles undefined sources", () => {
172
- const a = { foo: 1 };
173
- const result = mergeProps<{ foo?: number; bar?: number }>(undefined, a, undefined, { bar: 2 });
174
-
175
- expect(result).toEqual({ foo: 1, bar: 2 });
176
- });
177
- });
178
-
179
- describe("splitProps()", () => {
180
- test("splits props into specified groups", () => {
181
- const props = { a: 1, b: 2, c: 3, d: 4 };
182
- const [ab, cd] = splitProps(props, ["a", "b"]);
183
-
184
- expect(ab).toEqual({ a: 1, b: 2 });
185
- expect(cd).toEqual({ c: 3, d: 4 });
186
- });
187
-
188
- test("splits props into multiple groups", () => {
189
- const props = { a: 1, b: 2, c: 3, d: 4, e: 5 };
190
- const [group1, group2, rest] = splitProps(props, ["a", "b"], ["c"]);
191
-
192
- expect(group1).toEqual({ a: 1, b: 2 });
193
- expect(group2).toEqual({ c: 3 });
194
- expect(rest).toEqual({ d: 4, e: 5 });
195
- });
196
-
197
- test("handles missing keys", () => {
198
- const props = { a: 1, b: 2 };
199
- const [group, rest] = splitProps(props, ["a", "c"] as (keyof typeof props)[]);
200
-
201
- expect(group).toEqual({ a: 1 });
202
- expect(rest).toEqual({ b: 2 });
203
- });
204
- });
205
-
206
- describe("Provider component", () => {
207
- let container: HTMLElement;
208
-
209
- beforeEach(() => {
210
- container = document.createElement("div");
211
- document.body.appendChild(container);
212
- });
213
-
214
- test("Provider provides context value", () => {
215
- const themeCtx = createContext("light");
216
- let capturedTheme = "";
217
-
218
- const Child = () => {
219
- capturedTheme = useContext(themeCtx);
220
- return text(capturedTheme);
221
- };
222
-
223
- Provider({
224
- context: themeCtx,
225
- value: "dark",
226
- children: () => {
227
- mount(container, Child());
228
- return text("");
229
- },
230
- });
231
-
232
- expect(capturedTheme).toBe("dark");
233
- });
234
-
235
- test("Provider works with function children", () => {
236
- const countCtx = createContext(0);
237
- let capturedCount = -1;
238
-
239
- Provider({
240
- context: countCtx,
241
- value: 42,
242
- children: () => {
243
- capturedCount = useContext(countCtx);
244
- return text(String(capturedCount));
245
- },
246
- });
247
-
248
- expect(capturedCount).toBe(42);
249
- });
250
- });
251
-
252
- describe("Index component", () => {
253
- let container: HTMLElement;
254
-
255
- beforeEach(() => {
256
- container = document.createElement("div");
257
- document.body.appendChild(container);
258
- });
259
-
260
- test("Index renders list with item getters", () => {
261
- const [items] = createSignal(["a", "b", "c"]);
262
-
263
- const node = Index({
264
- each: items,
265
- children: (itemGetter, index) =>
266
- createElement(
267
- "span",
268
- [attr("data-index", AttrValue.Static(String(index)))],
269
- [text(itemGetter())]
270
- ),
271
- });
272
-
273
- mount(container, node);
274
-
275
- const spans = container.querySelectorAll("span");
276
- expect(spans.length).toBe(3);
277
- expect(spans[0].textContent).toBe("a");
278
- expect(spans[1].textContent).toBe("b");
279
- expect(spans[2].textContent).toBe("c");
280
- });
281
-
282
- test("Index provides working item getter", () => {
283
- const values: string[] = [];
284
- const [items] = createSignal(["x", "y"]);
285
-
286
- Index({
287
- each: items,
288
- children: (itemGetter, _index) => {
289
- values.push(itemGetter());
290
- return text(itemGetter());
291
- },
292
- });
293
-
294
- expect(values).toEqual(["x", "y"]);
295
- });
296
- });
297
-
298
- describe("Switch/Match components", () => {
299
- let container: HTMLElement;
300
-
301
- beforeEach(() => {
302
- container = document.createElement("div");
303
- document.body.appendChild(container);
304
- });
305
-
306
- afterEach(() => {
307
- container.remove();
308
- });
309
-
310
- test("Switch renders first truthy Match", () => {
311
- const [value, setValue] = createSignal("a");
312
-
313
- let rendered = "";
314
- createRoot((dispose) => {
315
- const result = Switch({
316
- fallback: text("none"),
317
- children: [
318
- Match({
319
- when: () => value() === "a",
320
- children: text("matched-a"),
321
- }),
322
- Match({
323
- when: () => value() === "b",
324
- children: text("matched-b"),
325
- }),
326
- ],
327
- });
328
-
329
- // result should be the matched content
330
- rendered = result ? "has-result" : "no-result";
331
- dispose();
332
- });
333
-
334
- expect(rendered).toBe("has-result");
335
- });
336
-
337
- test("Switch updates DOM when signal changes", () => {
338
- const [value, setValue] = createSignal("a");
339
-
340
- createRoot((dispose) => {
341
- const node = Switch({
342
- fallback: text("fallback"),
343
- children: [
344
- Match({
345
- when: () => value() === "a",
346
- children: text("A"),
347
- }),
348
- Match({
349
- when: () => value() === "b",
350
- children: text("B"),
351
- }),
352
- ],
353
- });
354
-
355
- mount(container, node);
356
- expect(container.textContent).toBe("A");
357
-
358
- setValue("b");
359
- expect(container.textContent).toBe("B");
360
-
361
- setValue("c");
362
- expect(container.textContent).toBe("fallback");
363
-
364
- setValue("a");
365
- expect(container.textContent).toBe("A");
366
-
367
- dispose();
368
- });
369
- });
370
-
371
- test("Switch returns fallback when no match", () => {
372
- const [value] = createSignal("c");
373
-
374
- const result = Switch({
375
- fallback: text("fallback"),
376
- children: [
377
- Match({
378
- when: () => value() === "a",
379
- children: text("a"),
380
- }),
381
- Match({
382
- when: () => value() === "b",
383
- children: text("b"),
384
- }),
385
- ],
386
- });
387
-
388
- // Result should be fallback text node
389
- expect(result).toBeDefined();
390
- });
391
-
392
- test("Match with function children receives accessor (SolidJS-style)", () => {
393
- const [user, setUser] = createSignal<{ name: string } | null>(null);
394
- let receivedName = "";
395
-
396
- createRoot((dispose) => {
397
- const match = Match({
398
- when: user,
399
- // SolidJS-style: children receives accessor function, call with ()
400
- children: (userAccessor: () => { name: string }) => {
401
- receivedName = userAccessor().name;
402
- return text(userAccessor().name);
403
- },
404
- });
405
-
406
- // First, user is null, so match.when() should be false
407
- expect(match.when()).toBe(false);
408
-
409
- setUser({ name: "Alice" });
410
- expect(match.when()).toBe(true);
411
-
412
- // Call children with the value
413
- if (match.when() && typeof match.children === "function") {
414
- match.children();
415
- expect(receivedName).toBe("Alice");
416
- }
417
-
418
- dispose();
419
- });
420
- });
421
- });
422
-
423
- describe("SolidJS API compatibility", () => {
424
- test("createSignal returns tuple [getter, setter]", () => {
425
- const [count, setCount] = createSignal(0);
426
-
427
- expect(typeof count).toBe("function");
428
- expect(typeof setCount).toBe("function");
429
- expect(count()).toBe(0);
430
-
431
- setCount(5);
432
- expect(count()).toBe(5);
433
-
434
- setCount((c) => c + 1);
435
- expect(count()).toBe(6);
436
- });
437
-
438
- test("createMemo returns accessor", () => {
439
- const [count, setCount] = createSignal(2);
440
- const doubled = createMemo(() => count() * 2);
441
-
442
- expect(typeof doubled).toBe("function");
443
- expect(doubled()).toBe(4);
444
-
445
- setCount(5);
446
- expect(doubled()).toBe(10);
447
- });
448
-
449
- test("createRenderEffect tracks dependencies automatically", () => {
450
- const values: number[] = [];
451
-
452
- createRoot((dispose) => {
453
- const [count, setCount] = createSignal(0);
454
-
455
- createRenderEffect(() => {
456
- values.push(count());
457
- });
458
-
459
- setCount(1);
460
- setCount(2);
461
- dispose();
462
- });
463
-
464
- expect(values).toEqual([0, 1, 2]);
465
- });
466
- });
467
-
468
- describe("Portal component", () => {
469
- let container: HTMLElement;
470
- let portalTarget: HTMLElement;
471
-
472
- beforeEach(() => {
473
- container = document.createElement("div");
474
- container.id = "test-container";
475
- document.body.appendChild(container);
476
-
477
- portalTarget = document.createElement("div");
478
- portalTarget.id = "portal-target";
479
- document.body.appendChild(portalTarget);
480
- });
481
-
482
- afterEach(() => {
483
- container.remove();
484
- portalTarget.remove();
485
- });
486
-
487
- test("Portal renders children to body by default", () => {
488
- const placeholder = Portal({
489
- children: () => createElement("div", [attr("id", AttrValue.Static("portal-content"))], [text("Portal content")]),
490
- });
491
-
492
- // Placeholder should be returned
493
- expect(placeholder).toBeDefined();
494
-
495
- // Content should be in body
496
- const rendered = document.getElementById("portal-content");
497
- expect(rendered).not.toBeNull();
498
- expect(rendered?.textContent).toBe("Portal content");
499
-
500
- // Clean up
501
- rendered?.remove();
502
- });
503
-
504
- test("Portal renders to selector mount target", () => {
505
- Portal({
506
- mount: "#portal-target",
507
- children: () => createElement("div", [attr("id", AttrValue.Static("selector-portal"))], [text("Selector portal")]),
508
- });
509
-
510
- // Content should be in the portal target
511
- const rendered = portalTarget.querySelector("#selector-portal");
512
- expect(rendered).not.toBeNull();
513
- expect(rendered?.textContent).toBe("Selector portal");
514
- });
515
-
516
- test("portalToBody low-level API works", () => {
517
- const content = createElement("div", [attr("id", AttrValue.Static("low-level-portal"))], [text("Low level")]);
518
-
519
- portalToBody([content]);
520
-
521
- const rendered = document.getElementById("low-level-portal");
522
- expect(rendered).not.toBeNull();
523
- expect(rendered?.textContent).toBe("Low level");
524
-
525
- rendered?.remove();
526
- });
527
-
528
- test("portalToSelector low-level API works", () => {
529
- const content = createElement("div", [attr("class", AttrValue.Static("selector-content"))], [text("Selector content")]);
530
-
531
- portalToSelector("#portal-target", [content]);
532
-
533
- const rendered = portalTarget.querySelector(".selector-content");
534
- expect(rendered).not.toBeNull();
535
- expect(rendered?.textContent).toBe("Selector content");
536
- });
537
-
538
- test("Portal accepts function children", () => {
539
- const content = () => createElement("span", [attr("id", AttrValue.Static("func-portal"))], [text("Function child")]);
540
-
541
- Portal({
542
- children: content,
543
- });
544
-
545
- const rendered = document.getElementById("func-portal");
546
- expect(rendered).not.toBeNull();
547
- expect(rendered?.textContent).toBe("Function child");
548
-
549
- rendered?.remove();
550
- });
551
- });
552
-
553
- describe("Switch/Match component", () => {
554
- let container: HTMLElement;
555
-
556
- beforeEach(() => {
557
- container = document.createElement("div");
558
- document.body.appendChild(container);
559
- });
560
-
561
- afterEach(() => {
562
- container.remove();
563
- });
564
-
565
- test("Switch with single Match renders correctly", () => {
566
- createRoot((dispose) => {
567
- const [value, setValue] = createSignal(true);
568
-
569
- const node = Switch({
570
- children: Match({
571
- when: value,
572
- children: createElement("div", [], [text("Match 1")]),
573
- }),
574
- });
575
-
576
- mount(container, node);
577
- expect(container.textContent).toContain("Match 1");
578
- dispose();
579
- });
580
- });
581
-
582
- test("Switch with single Match and fallback", () => {
583
- createRoot((dispose) => {
584
- const [value, setValue] = createSignal(false);
585
-
586
- const node = Switch({
587
- fallback: createElement("div", [], [text("Fallback")]),
588
- children: Match({
589
- when: value,
590
- children: createElement("div", [], [text("Match 1")]),
591
- }),
592
- });
593
-
594
- mount(container, node);
595
- expect(container.textContent).toContain("Fallback");
596
-
597
- // Trigger update
598
- setValue(true);
599
- expect(container.textContent).toContain("Match 1");
600
- dispose();
601
- });
602
- });
603
-
604
- test("Switch with multiple Match components", () => {
605
- createRoot((dispose) => {
606
- const [value, setValue] = createSignal(1);
607
-
608
- const node = Switch({
609
- fallback: createElement("div", [], [text("Fallback")]),
610
- children: [
611
- Match({
612
- when: () => value() === 1,
613
- children: createElement("div", [], [text("First")]),
614
- }),
615
- Match({
616
- when: () => value() === 2,
617
- children: createElement("div", [], [text("Second")]),
618
- }),
619
- ],
620
- });
621
-
622
- mount(container, node);
623
- expect(container.textContent).toContain("First");
624
-
625
- setValue(2);
626
- expect(container.textContent).toContain("Second");
627
-
628
- setValue(3);
629
- expect(container.textContent).toContain("Fallback");
630
- dispose();
631
- });
632
- });
633
-
634
- test("Switch with accessor condition in Match", () => {
635
- createRoot((dispose) => {
636
- const [count, setCount] = createSignal(0);
637
-
638
- const node = Switch({
639
- fallback: createElement("div", [], [text("Default")]),
640
- children: Match({
641
- when: () => count() % 3 === 0 && count() > 0,
642
- children: createElement("div", [], [text("Bang!")]),
643
- }),
644
- });
645
-
646
- mount(container, node);
647
- expect(container.textContent).toContain("Default");
648
-
649
- setCount(3);
650
- expect(container.textContent).toContain("Bang!");
651
-
652
- setCount(4);
653
- expect(container.textContent).toContain("Default");
654
-
655
- setCount(6);
656
- expect(container.textContent).toContain("Bang!");
657
- dispose();
658
- });
659
- });
660
- });
@@ -1,64 +0,0 @@
1
- import { bench, describe } from "vitest";
2
-
3
- // Generate HTML for list items
4
- function generateListHTML(count: number): string {
5
- let html = "<ul>";
6
- for (let i = 0; i < count; i++) {
7
- html += `<li>Item ${i}</li>`;
8
- }
9
- html += "</ul>";
10
- return html;
11
- }
12
-
13
- // Generate DOM using createElement (like render_vnode_to_dom)
14
- function createListDOM(count: number): Node {
15
- const ul = document.createElement("ul");
16
- for (let i = 0; i < count; i++) {
17
- const li = document.createElement("li");
18
- li.textContent = `Item ${i}`;
19
- ul.appendChild(li);
20
- }
21
- return ul;
22
- }
23
-
24
- describe("Static Content: innerHTML vs createElement (Real Browser)", () => {
25
- const html100 = generateListHTML(100);
26
- const html500 = generateListHTML(500);
27
- const html1000 = generateListHTML(1000);
28
-
29
- describe("100 items", () => {
30
- bench("createElement (render_vnode_to_dom style)", () => {
31
- const container = document.createElement("div");
32
- container.appendChild(createListDOM(100));
33
- });
34
-
35
- bench("innerHTML (inject_static style)", () => {
36
- const container = document.createElement("div");
37
- container.innerHTML = html100;
38
- });
39
- });
40
-
41
- describe("500 items", () => {
42
- bench("createElement (render_vnode_to_dom style)", () => {
43
- const container = document.createElement("div");
44
- container.appendChild(createListDOM(500));
45
- });
46
-
47
- bench("innerHTML (inject_static style)", () => {
48
- const container = document.createElement("div");
49
- container.innerHTML = html500;
50
- });
51
- });
52
-
53
- describe("1000 items", () => {
54
- bench("createElement (render_vnode_to_dom style)", () => {
55
- const container = document.createElement("div");
56
- container.appendChild(createListDOM(1000));
57
- });
58
-
59
- bench("innerHTML (inject_static style)", () => {
60
- const container = document.createElement("div");
61
- container.innerHTML = html1000;
62
- });
63
- });
64
- });