@esportsplus/template 0.28.3 → 0.29.2

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 (110) hide show
  1. package/README.md +431 -0
  2. package/build/attributes.d.ts +7 -1
  3. package/build/attributes.js +86 -33
  4. package/build/constants.d.ts +3 -11
  5. package/build/constants.js +4 -32
  6. package/build/event/constants.d.ts +3 -0
  7. package/build/event/constants.js +13 -0
  8. package/build/event/index.d.ts +9 -1
  9. package/build/event/index.js +29 -35
  10. package/build/event/ontick.js +6 -9
  11. package/build/html.d.ts +9 -0
  12. package/build/html.js +7 -0
  13. package/build/index.d.ts +8 -2
  14. package/build/index.js +8 -1
  15. package/build/render.d.ts +2 -2
  16. package/build/render.js +2 -3
  17. package/build/runtime.d.ts +1 -0
  18. package/build/runtime.js +5 -0
  19. package/build/slot/array.d.ts +3 -3
  20. package/build/slot/array.js +11 -14
  21. package/build/slot/cleanup.d.ts +1 -1
  22. package/build/slot/cleanup.js +1 -2
  23. package/build/slot/effect.js +5 -7
  24. package/build/slot/index.js +1 -7
  25. package/build/slot/render.js +6 -8
  26. package/build/svg.d.ts +1 -1
  27. package/build/svg.js +1 -1
  28. package/build/transformer/codegen.d.ts +18 -0
  29. package/build/transformer/codegen.js +316 -0
  30. package/build/transformer/index.d.ts +12 -0
  31. package/build/transformer/index.js +62 -0
  32. package/build/transformer/parser.d.ts +18 -0
  33. package/build/transformer/parser.js +166 -0
  34. package/build/transformer/plugins/esbuild.d.ts +5 -0
  35. package/build/transformer/plugins/esbuild.js +35 -0
  36. package/build/transformer/plugins/tsc.d.ts +3 -0
  37. package/build/transformer/plugins/tsc.js +4 -0
  38. package/build/transformer/plugins/vite.d.ts +5 -0
  39. package/build/transformer/plugins/vite.js +37 -0
  40. package/build/transformer/ts-parser.d.ts +21 -0
  41. package/build/transformer/ts-parser.js +72 -0
  42. package/build/transformer/type-analyzer.d.ts +7 -0
  43. package/build/transformer/type-analyzer.js +230 -0
  44. package/build/types.d.ts +2 -3
  45. package/build/utilities.d.ts +7 -0
  46. package/build/utilities.js +31 -0
  47. package/package.json +33 -4
  48. package/src/attributes.ts +115 -51
  49. package/src/constants.ts +6 -53
  50. package/src/event/constants.ts +16 -0
  51. package/src/event/index.ts +36 -42
  52. package/src/event/onconnect.ts +1 -1
  53. package/src/event/onresize.ts +1 -1
  54. package/src/event/ontick.ts +7 -11
  55. package/src/html.ts +18 -0
  56. package/src/index.ts +8 -2
  57. package/src/render.ts +6 -7
  58. package/src/runtime.ts +8 -0
  59. package/src/slot/array.ts +18 -24
  60. package/src/slot/cleanup.ts +3 -4
  61. package/src/slot/effect.ts +6 -8
  62. package/src/slot/index.ts +2 -8
  63. package/src/slot/render.ts +7 -9
  64. package/src/svg.ts +1 -1
  65. package/src/transformer/codegen.ts +518 -0
  66. package/src/transformer/index.ts +98 -0
  67. package/src/transformer/parser.ts +239 -0
  68. package/src/transformer/plugins/esbuild.ts +46 -0
  69. package/src/transformer/plugins/tsc.ts +7 -0
  70. package/src/transformer/plugins/vite.ts +49 -0
  71. package/src/transformer/ts-parser.ts +123 -0
  72. package/src/transformer/type-analyzer.ts +334 -0
  73. package/src/types.ts +3 -4
  74. package/src/utilities.ts +52 -0
  75. package/storage/rewrite-analysis-2026-01-04.md +439 -0
  76. package/test/constants.ts +69 -0
  77. package/test/effects.ts +237 -0
  78. package/test/events.ts +318 -0
  79. package/test/imported-values.ts +253 -0
  80. package/test/nested.ts +298 -0
  81. package/test/slots.ts +259 -0
  82. package/test/spread.ts +290 -0
  83. package/test/static.ts +118 -0
  84. package/test/templates.ts +473 -0
  85. package/test/tsconfig.json +17 -0
  86. package/test/vite.config.ts +50 -0
  87. package/build/html/index.d.ts +0 -9
  88. package/build/html/index.js +0 -29
  89. package/build/html/parser.d.ts +0 -5
  90. package/build/html/parser.js +0 -165
  91. package/build/utilities/element.d.ts +0 -11
  92. package/build/utilities/element.js +0 -9
  93. package/build/utilities/fragment.d.ts +0 -3
  94. package/build/utilities/fragment.js +0 -10
  95. package/build/utilities/marker.d.ts +0 -2
  96. package/build/utilities/marker.js +0 -4
  97. package/build/utilities/node.d.ts +0 -9
  98. package/build/utilities/node.js +0 -10
  99. package/build/utilities/raf.d.ts +0 -2
  100. package/build/utilities/raf.js +0 -1
  101. package/build/utilities/text.d.ts +0 -2
  102. package/build/utilities/text.js +0 -9
  103. package/src/html/index.ts +0 -48
  104. package/src/html/parser.ts +0 -235
  105. package/src/utilities/element.ts +0 -28
  106. package/src/utilities/fragment.ts +0 -19
  107. package/src/utilities/marker.ts +0 -6
  108. package/src/utilities/node.ts +0 -29
  109. package/src/utilities/raf.ts +0 -1
  110. package/src/utilities/text.ts +0 -15
@@ -0,0 +1,253 @@
1
+ // Imported Values Templates - Using constants from external modules
2
+ // Tests that imported values are preserved correctly during compilation
3
+
4
+
5
+ import { html } from '../src';
6
+ import {
7
+ ACTIVE_CLASS,
8
+ APP_NAME,
9
+ BUTTON_ATTRS,
10
+ COLUMNS,
11
+ createCardAttrs,
12
+ DEFAULT_ATTRS,
13
+ DEFAULT_CLASS,
14
+ DEFAULT_TIMEOUT,
15
+ FLEX_CENTER,
16
+ HIDDEN_STYLE,
17
+ INACTIVE_CLASS,
18
+ MAX_ITEMS,
19
+ NAV_ITEMS,
20
+ noop,
21
+ preventDefault,
22
+ PRIORITIES,
23
+ STATUS,
24
+ stopPropagation,
25
+ THEME,
26
+ VERSION
27
+ } from './constants';
28
+
29
+
30
+ // =============================================================================
31
+ // IMPORTED STRING CONSTANTS
32
+ // =============================================================================
33
+
34
+ // Using imported string in text slot
35
+ export const importedTextSlot = () =>
36
+ html`<h1>${APP_NAME}</h1>`;
37
+
38
+ // Using imported string in attribute
39
+ export const importedClassAttr = () =>
40
+ html`<div class="${DEFAULT_CLASS}">Content</div>`;
41
+
42
+ // Using imported style string
43
+ export const importedStyleAttr = () =>
44
+ html`<div style="${FLEX_CENTER}">Centered</div>`;
45
+
46
+ // Multiple imported strings
47
+ export const importedMultipleStrings = () =>
48
+ html`<div class="${DEFAULT_CLASS}" style="${FLEX_CENTER}">
49
+ <span>${APP_NAME}</span>
50
+ <span>${VERSION}</span>
51
+ </div>`;
52
+
53
+
54
+ // =============================================================================
55
+ // IMPORTED NUMBER CONSTANTS
56
+ // =============================================================================
57
+
58
+ // Number in text slot
59
+ export const importedNumberText = () =>
60
+ html`<span>Max items: ${MAX_ITEMS}</span>`;
61
+
62
+ // Number in data attribute
63
+ export const importedNumberData = () =>
64
+ html`<div data-timeout="${DEFAULT_TIMEOUT}">Timeout element</div>`;
65
+
66
+ // Number in style (grid columns)
67
+ export const importedNumberStyle = () =>
68
+ html`<div style="grid-template-columns: repeat(${COLUMNS}, 1fr)">Grid</div>`;
69
+
70
+
71
+ // =============================================================================
72
+ // IMPORTED OBJECT CONSTANTS
73
+ // =============================================================================
74
+
75
+ // Spread with imported object
76
+ export const importedSpreadObject = () =>
77
+ html`<div ${DEFAULT_ATTRS}>Default element</div>`;
78
+
79
+ // Spread with imported button attrs
80
+ export const importedSpreadButton = () =>
81
+ html`<button ${BUTTON_ATTRS}>Action</button>`;
82
+
83
+ // Accessing object properties
84
+ export const importedObjectProperty = () =>
85
+ html`<div class="${STATUS.ACTIVE}">Active status</div>`;
86
+
87
+ // Using enum-like constant
88
+ export const importedThemeClass = () =>
89
+ html`<div class="${THEME.DARK}">Dark themed</div>`;
90
+
91
+
92
+ // =============================================================================
93
+ // IMPORTED ARRAY CONSTANTS
94
+ // =============================================================================
95
+
96
+ // Mapping over imported array
97
+ export const importedArrayMap = () =>
98
+ html`<nav>
99
+ <ul>${NAV_ITEMS.map(item => html`<li>${item}</li>`)}</ul>
100
+ </nav>`;
101
+
102
+ // Using array with index
103
+ export const importedArrayIndex = () =>
104
+ html`<ul>${NAV_ITEMS.map((item, i) =>
105
+ html`<li data-index="${i}">${item}</li>`
106
+ )}</ul>`;
107
+
108
+ // Priorities list
109
+ export const importedPriorities = () =>
110
+ html`<select>
111
+ ${PRIORITIES.map(p => html`<option value="${p}">${p}</option>`)}
112
+ </select>`;
113
+
114
+
115
+ // =============================================================================
116
+ // IMPORTED FUNCTION CONSTANTS
117
+ // =============================================================================
118
+
119
+ // Using noop handler
120
+ export const importedNoopHandler = () =>
121
+ html`<button onclick="${noop}">No-op button</button>`;
122
+
123
+ // Using preventDefault handler
124
+ export const importedPreventDefault = () =>
125
+ html`<form onsubmit="${preventDefault}">
126
+ <button type="submit">Submit</button>
127
+ </form>`;
128
+
129
+ // Using stopPropagation handler
130
+ export const importedStopPropagation = () =>
131
+ html`<div onclick="${stopPropagation}">
132
+ <button>Contained click</button>
133
+ </div>`;
134
+
135
+
136
+ // =============================================================================
137
+ // IMPORTED FUNCTION THAT RETURNS OBJECT (Factory)
138
+ // =============================================================================
139
+
140
+ // Using factory function for spread
141
+ export const importedFactory = () =>
142
+ html`<div ${createCardAttrs(123, 'user')}>Card 123</div>`;
143
+
144
+ // Factory in list
145
+ export const importedFactoryInList = (ids: number[]) =>
146
+ html`<div>${ids.map(id =>
147
+ html`<div ${createCardAttrs(id, 'item')}>Item ${id}</div>`
148
+ )}</div>`;
149
+
150
+
151
+ // =============================================================================
152
+ // CONDITIONAL USING IMPORTED VALUES
153
+ // =============================================================================
154
+
155
+ // Conditional class with imported constants
156
+ export const importedConditionalClass = (isActive: boolean) =>
157
+ html`<div class="${isActive ? ACTIVE_CLASS : INACTIVE_CLASS}">Status</div>`;
158
+
159
+ // Conditional style with imported constants
160
+ export const importedConditionalStyle = (isHidden: boolean) =>
161
+ html`<div style="${isHidden ? HIDDEN_STYLE : FLEX_CENTER}">Visibility</div>`;
162
+
163
+ // Conditional with STATUS enum
164
+ export const importedConditionalEnum = (status: string) =>
165
+ html`<div class="${
166
+ status === STATUS.ACTIVE ? 'active' :
167
+ status === STATUS.PENDING ? 'pending' :
168
+ status === STATUS.COMPLETED ? 'completed' :
169
+ 'cancelled'
170
+ }">${status}</div>`;
171
+
172
+
173
+ // =============================================================================
174
+ // TEMPLATE LITERALS WITH IMPORTED VALUES
175
+ // =============================================================================
176
+
177
+ // Interpolated in template literal text
178
+ export const importedInterpolatedText = () =>
179
+ html`<p>${`Welcome to ${APP_NAME} v${VERSION}`}</p>`;
180
+
181
+ // Interpolated in class
182
+ export const importedInterpolatedClass = (variant: string) =>
183
+ html`<button class="${`btn ${variant} ${DEFAULT_CLASS}`}">Button</button>`;
184
+
185
+
186
+ // =============================================================================
187
+ // COMPLEX COMBINATIONS
188
+ // =============================================================================
189
+
190
+ // Full component using multiple imports
191
+ export const importedFullComponent = (isActive: boolean) =>
192
+ html`<div class="${isActive ? ACTIVE_CLASS : INACTIVE_CLASS}" style="${FLEX_CENTER}">
193
+ <h1>${APP_NAME}</h1>
194
+ <nav>
195
+ <ul>${NAV_ITEMS.map(item => html`<li>${item}</li>`)}</ul>
196
+ </nav>
197
+ <span>Version: ${VERSION}</span>
198
+ </div>`;
199
+
200
+ // Card with imported factory and constants
201
+ export const importedCard = (id: number, type: string, title: string) =>
202
+ html`<article ${createCardAttrs(id, type)}>
203
+ <header class="${DEFAULT_CLASS}">
204
+ <h2>${title}</h2>
205
+ <span class="${THEME.LIGHT}">${type}</span>
206
+ </header>
207
+ <footer onclick="${noop}">
208
+ <span>${APP_NAME}</span>
209
+ </footer>
210
+ </article>`;
211
+
212
+ // Priority list with theme
213
+ export const importedPriorityList = (currentPriority: string) =>
214
+ html`<div class="${THEME.SYSTEM}">
215
+ <h3>Select Priority</h3>
216
+ <ul>${PRIORITIES.map(p =>
217
+ html`<li class="${p === currentPriority ? ACTIVE_CLASS : INACTIVE_CLASS}">${p}</li>`
218
+ )}</ul>
219
+ </div>`;
220
+
221
+
222
+ // =============================================================================
223
+ // STRESS TESTS
224
+ // =============================================================================
225
+
226
+ // Many imported values
227
+ export const importedStress = () =>
228
+ html`<div
229
+ class="${DEFAULT_CLASS}"
230
+ style="${FLEX_CENTER}"
231
+ data-app="${APP_NAME}"
232
+ data-version="${VERSION}"
233
+ data-max="${MAX_ITEMS}"
234
+ data-timeout="${DEFAULT_TIMEOUT}"
235
+ onclick="${noop}"
236
+ >
237
+ ${NAV_ITEMS.map(item => html`<span>${item}</span>`)}
238
+ </div>`;
239
+
240
+ // Nested with many imports
241
+ export const importedNestedStress = () =>
242
+ html`<div class="${THEME.DARK}">
243
+ ${PRIORITIES.map(priority =>
244
+ html`<section class="${priority === 'critical' ? ACTIVE_CLASS : INACTIVE_CLASS}">
245
+ <h2>${priority}</h2>
246
+ ${NAV_ITEMS.map(item =>
247
+ html`<div ${DEFAULT_ATTRS} onclick="${stopPropagation}">
248
+ ${item} - ${priority}
249
+ </div>`
250
+ )}
251
+ </section>`
252
+ )}
253
+ </div>`;
package/test/nested.ts ADDED
@@ -0,0 +1,298 @@
1
+ // Nested Templates - Template hoisting and depth sorting
2
+ // Tests nested html`` calls, array mapping, and conditional templates
3
+
4
+
5
+ import { html } from '../src';
6
+
7
+
8
+ // =============================================================================
9
+ // SIMPLE NESTED TEMPLATES
10
+ // =============================================================================
11
+
12
+ // Basic nested template in slot
13
+ export const nestedSimple = (items: string[]) =>
14
+ html`<ul>${items.map(item => html`<li>${item}</li>`)}</ul>`;
15
+
16
+ // Nested with static content
17
+ export const nestedStatic = (items: string[]) =>
18
+ html`<ul class="list">${items.map(item => html`<li class="item">${item}</li>`)}</ul>`;
19
+
20
+ // Nested with index
21
+ export const nestedWithIndex = (items: string[]) =>
22
+ html`<ul>${items.map((item, i) => html`<li data-index="${i}">${item}</li>`)}</ul>`;
23
+
24
+
25
+ // =============================================================================
26
+ // NESTED WITH ATTRIBUTES
27
+ // =============================================================================
28
+
29
+ // Nested template with dynamic class
30
+ export const nestedAttrClass = (items: { cls: string; text: string }[]) =>
31
+ html`<ul>${items.map(item => html`<li class="${item.cls}">${item.text}</li>`)}</ul>`;
32
+
33
+ // Nested template with multiple attributes
34
+ export const nestedAttrMultiple = (items: { id: string; cls: string; text: string }[]) =>
35
+ html`<ul>${items.map(item =>
36
+ html`<li id="${item.id}" class="${item.cls}">${item.text}</li>`
37
+ )}</ul>`;
38
+
39
+ // Nested with data attributes
40
+ export const nestedAttrData = (items: { id: number; value: string }[]) =>
41
+ html`<div>${items.map(item =>
42
+ html`<span data-id="${item.id}" data-value="${item.value}">${item.value}</span>`
43
+ )}</div>`;
44
+
45
+
46
+ // =============================================================================
47
+ // DEEPLY NESTED TEMPLATES (2+ levels)
48
+ // =============================================================================
49
+
50
+ // Two levels of nesting
51
+ export const nestedTwoLevel = (sections: { title: string; items: string[] }[]) =>
52
+ html`<div>${sections.map(section => html`
53
+ <section>
54
+ <h2>${section.title}</h2>
55
+ <ul>${section.items.map(item => html`<li>${item}</li>`)}</ul>
56
+ </section>
57
+ `)}</div>`;
58
+
59
+ // Three levels of nesting
60
+ export const nestedThreeLevel = (groups: {
61
+ name: string;
62
+ sections: { title: string; items: string[] }[];
63
+ }[]) => html`<div>${groups.map(group => html`
64
+ <div class="group">
65
+ <h1>${group.name}</h1>
66
+ ${group.sections.map(section => html`
67
+ <section>
68
+ <h2>${section.title}</h2>
69
+ <ul>${section.items.map(item => html`<li>${item}</li>`)}</ul>
70
+ </section>
71
+ `)}
72
+ </div>
73
+ `)}</div>`;
74
+
75
+
76
+ // =============================================================================
77
+ // TABLE STRUCTURES
78
+ // =============================================================================
79
+
80
+ // Simple table rows
81
+ export const tableRows = (rows: { id: number; name: string }[]) =>
82
+ html`<table>
83
+ <thead><tr><th>ID</th><th>Name</th></tr></thead>
84
+ <tbody>${rows.map(row => html`<tr><td>${row.id}</td><td>${row.name}</td></tr>`)}</tbody>
85
+ </table>`;
86
+
87
+ // Table with multiple columns
88
+ export const tableMultiColumn = (rows: { id: number; name: string; email: string; role: string }[]) =>
89
+ html`<table>
90
+ <thead><tr><th>ID</th><th>Name</th><th>Email</th><th>Role</th></tr></thead>
91
+ <tbody>${rows.map(row => html`
92
+ <tr>
93
+ <td>${row.id}</td>
94
+ <td>${row.name}</td>
95
+ <td>${row.email}</td>
96
+ <td>${row.role}</td>
97
+ </tr>
98
+ `)}</tbody>
99
+ </table>`;
100
+
101
+ // Grouped table
102
+ export const tableGrouped = (groups: { category: string; items: { name: string; value: number }[] }[]) =>
103
+ html`<table>
104
+ <tbody>${groups.map(group => html`
105
+ <tr class="group-header"><th colspan="2">${group.category}</th></tr>
106
+ ${group.items.map(item => html`<tr><td>${item.name}</td><td>${item.value}</td></tr>`)}
107
+ `)}</tbody>
108
+ </table>`;
109
+
110
+
111
+ // =============================================================================
112
+ // LIST STRUCTURES
113
+ // =============================================================================
114
+
115
+ // Definition list
116
+ export const definitionList = (items: { term: string; definition: string }[]) =>
117
+ html`<dl>${items.map(item => html`<dt>${item.term}</dt><dd>${item.definition}</dd>`)}</dl>`;
118
+
119
+ // Nested list (ul > li > ul)
120
+ export const nestedList = (items: { text: string; children: string[] }[]) =>
121
+ html`<ul>${items.map(item => html`
122
+ <li>
123
+ ${item.text}
124
+ ${item.children.length > 0 ? html`<ul>${item.children.map(c => html`<li>${c}</li>`)}</ul>` : ''}
125
+ </li>
126
+ `)}</ul>`;
127
+
128
+ // Ordered list with nesting
129
+ export const orderedNestedList = (items: { text: string; subItems: string[] }[]) =>
130
+ html`<ol>${items.map(item => html`
131
+ <li>
132
+ <span>${item.text}</span>
133
+ <ol>${item.subItems.map(sub => html`<li>${sub}</li>`)}</ol>
134
+ </li>
135
+ `)}</ol>`;
136
+
137
+
138
+ // =============================================================================
139
+ // CARD/GRID LAYOUTS
140
+ // =============================================================================
141
+
142
+ // Card grid
143
+ export const cardGrid = (cards: { title: string; body: string; footer: string }[]) =>
144
+ html`<div class="grid">${cards.map(card => html`
145
+ <div class="card">
146
+ <div class="card-header">${card.title}</div>
147
+ <div class="card-body">${card.body}</div>
148
+ <div class="card-footer">${card.footer}</div>
149
+ </div>
150
+ `)}</div>`;
151
+
152
+ // Product grid
153
+ export const productGrid = (products: {
154
+ id: number;
155
+ name: string;
156
+ price: number;
157
+ image: string;
158
+ }[]) => html`<div class="products">${products.map(p => html`
159
+ <div class="product" data-id="${p.id}">
160
+ <img src="${p.image}" alt="${p.name}">
161
+ <h3>${p.name}</h3>
162
+ <span class="price">$${p.price}</span>
163
+ </div>
164
+ `)}</div>`;
165
+
166
+
167
+ // =============================================================================
168
+ // CONDITIONAL NESTED TEMPLATES
169
+ // =============================================================================
170
+
171
+ // Conditional inner template
172
+ export const conditionalNested = (items: string[] | null) =>
173
+ html`<div>
174
+ ${items
175
+ ? html`<ul>${items.map(i => html`<li>${i}</li>`)}</ul>`
176
+ : html`<p>No items</p>`
177
+ }
178
+ </div>`;
179
+
180
+ // Conditional based on length
181
+ export const conditionalLength = (items: string[]) =>
182
+ html`<div>
183
+ ${items.length > 0
184
+ ? html`<ul>${items.map(i => html`<li>${i}</li>`)}</ul>`
185
+ : html`<p class="empty">Empty list</p>`
186
+ }
187
+ </div>`;
188
+
189
+ // Conditional class in nested
190
+ export const conditionalClassNested = (items: { text: string; active: boolean }[]) =>
191
+ html`<ul>${items.map(item =>
192
+ html`<li class="${item.active ? 'active' : 'inactive'}">${item.text}</li>`
193
+ )}</ul>`;
194
+
195
+
196
+ // =============================================================================
197
+ // COMPLEX REAL-WORLD PATTERNS
198
+ // =============================================================================
199
+
200
+ // Navigation menu
201
+ export const navMenu = (items: { href: string; text: string; active: boolean }[]) =>
202
+ html`<nav class="nav">
203
+ <ul class="nav-list">${items.map(item => html`
204
+ <li class="${item.active ? 'active' : ''}">
205
+ <a href="${item.href}">${item.text}</a>
206
+ </li>
207
+ `)}</ul>
208
+ </nav>`;
209
+
210
+ // Blog post card
211
+ export const blogCard = (post: {
212
+ title: string;
213
+ author: string;
214
+ date: string;
215
+ excerpt: string;
216
+ tags: string[];
217
+ }) => html`
218
+ <article class="blog-card">
219
+ <h2>${post.title}</h2>
220
+ <p class="meta">By ${post.author} on ${post.date}</p>
221
+ <p>${post.excerpt}</p>
222
+ <div class="tags">${post.tags.map(tag => html`<span class="tag">${tag}</span>`)}</div>
223
+ </article>
224
+ `;
225
+
226
+ // Comment thread
227
+ export const commentThread = (comments: {
228
+ author: string;
229
+ text: string;
230
+ replies: { author: string; text: string }[];
231
+ }[]) => html`
232
+ <div class="comments">${comments.map(comment => html`
233
+ <div class="comment">
234
+ <p class="author">${comment.author}</p>
235
+ <p class="text">${comment.text}</p>
236
+ ${comment.replies.length > 0 ? html`
237
+ <div class="replies">${comment.replies.map(reply => html`
238
+ <div class="reply">
239
+ <p class="author">${reply.author}</p>
240
+ <p class="text">${reply.text}</p>
241
+ </div>
242
+ `)}</div>
243
+ ` : ''}
244
+ </div>
245
+ `)}</div>
246
+ `;
247
+
248
+ // Dashboard widget
249
+ export const dashboardWidget = (widget: {
250
+ title: string;
251
+ value: number;
252
+ chartData: number[];
253
+ }) => html`
254
+ <div class="widget">
255
+ <h3>${widget.title}</h3>
256
+ <p class="value">${widget.value}</p>
257
+ <div class="chart">${widget.chartData.map(point =>
258
+ html`<div class="bar" style="height: ${point}%"></div>`
259
+ )}</div>
260
+ </div>
261
+ `;
262
+
263
+
264
+ // =============================================================================
265
+ // STRESS TESTS
266
+ // =============================================================================
267
+
268
+ // 50 item list
269
+ export const stressList50 = (items: string[]) =>
270
+ html`<ul>${items.slice(0, 50).map(item => html`<li>${item}</li>`)}</ul>`;
271
+
272
+ // 100 item list
273
+ export const stressList100 = (items: string[]) =>
274
+ html`<ul>${items.slice(0, 100).map(item => html`<li>${item}</li>`)}</ul>`;
275
+
276
+ // Complex nested structure
277
+ export const stressComplex = (data: {
278
+ header: { title: string; subtitle: string };
279
+ sections: { title: string; items: { name: string; value: string }[] }[];
280
+ footer: string;
281
+ }) => html`
282
+ <div class="complex">
283
+ <header>
284
+ <h1>${data.header.title}</h1>
285
+ <p>${data.header.subtitle}</p>
286
+ </header>
287
+ <main>${data.sections.map(section => html`
288
+ <section>
289
+ <h2>${section.title}</h2>
290
+ <dl>${section.items.map(item => html`
291
+ <dt>${item.name}</dt>
292
+ <dd>${item.value}</dd>
293
+ `)}</dl>
294
+ </section>
295
+ `)}</main>
296
+ <footer>${data.footer}</footer>
297
+ </div>
298
+ `;