@luna_ui/luna 0.7.3 → 0.17.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 (83) 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-vO066aMd.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 +50 -0
  22. package/dist/signals.js +1 -0
  23. package/dist/vite-plugin.d.ts +7708 -2
  24. package/dist/vite-plugin.js +7 -6
  25. package/package.json +34 -11
  26. package/dist/event-utils-C_M2XBNj.js +0 -1
  27. package/dist/src-BbjOW18q.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/vite-plugin.ts +0 -718
  58. package/tests/__screenshots__/apg.test.ts/APG-Components---Accessibility-Tests-Button-Pattern-disabled-button-has-aria-disabled-1.png +0 -0
  59. package/tests/apg.test.ts +0 -466
  60. package/tests/context.test.ts +0 -118
  61. package/tests/css-optimizer-extractors.test.ts +0 -264
  62. package/tests/css-optimizer-integration.test.ts +0 -566
  63. package/tests/css-optimizer-transformers.test.ts +0 -301
  64. package/tests/css-optimizer.test.ts +0 -646
  65. package/tests/css-runtime.bench.ts +0 -442
  66. package/tests/css-runtime.test.ts +0 -342
  67. package/tests/debounced.test.ts +0 -165
  68. package/tests/dom.test.ts +0 -873
  69. package/tests/integration.test.ts +0 -405
  70. package/tests/issue-11-show-null-to-truthy.test.ts +0 -176
  71. package/tests/issue-5-for-infinite-loop.test.ts +0 -516
  72. package/tests/jsx-runtime.test.tsx +0 -393
  73. package/tests/lifecycle.test.ts +0 -833
  74. package/tests/move-before.bench.ts +0 -304
  75. package/tests/preact-signals-comparison.test.ts +0 -1608
  76. package/tests/resource.test.ts +0 -160
  77. package/tests/router.test.ts +0 -117
  78. package/tests/show-initial-mount-leak.test.tsx +0 -182
  79. package/tests/solidjs-api.test.ts +0 -660
  80. package/tests/static-perf.bench.ts +0 -64
  81. package/tests/store.test.ts +0 -263
  82. package/tests/tsx-syntax.test.tsx +0 -404
  83. /package/dist/{event-utils-Cd5f3Njd.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
- });