lightview 2.0.8 → 2.1.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 (180) hide show
  1. package/README.md +47 -1283
  2. package/build-bundles.mjs +109 -0
  3. package/cdom/helpers/array.js +70 -0
  4. package/cdom/helpers/compare.js +26 -0
  5. package/cdom/helpers/conditional.js +34 -0
  6. package/cdom/helpers/datetime.js +54 -0
  7. package/cdom/helpers/format.js +20 -0
  8. package/cdom/helpers/logic.js +24 -0
  9. package/cdom/helpers/lookup.js +25 -0
  10. package/cdom/helpers/math.js +34 -0
  11. package/cdom/helpers/network.js +41 -0
  12. package/cdom/helpers/state.js +77 -0
  13. package/cdom/helpers/stats.js +39 -0
  14. package/cdom/helpers/string.js +49 -0
  15. package/cdom/parser.js +602 -0
  16. package/components/actions/button.js +19 -6
  17. package/components/actions/dropdown.js +6 -6
  18. package/components/actions/modal.js +9 -9
  19. package/components/actions/swap.js +31 -8
  20. package/components/daisyui.js +1 -1
  21. package/components/data-display/accordion.js +6 -6
  22. package/components/data-display/alert.js +17 -7
  23. package/components/data-display/avatar.js +7 -7
  24. package/components/data-display/badge.js +14 -6
  25. package/components/data-display/card.js +7 -7
  26. package/components/data-display/carousel.js +4 -4
  27. package/components/data-display/chart.js +8 -8
  28. package/components/data-display/chat.js +7 -7
  29. package/components/data-display/collapse.js +5 -5
  30. package/components/data-display/countdown.js +3 -3
  31. package/components/data-display/diff.js +6 -6
  32. package/components/data-display/kbd.js +12 -6
  33. package/components/data-display/loading.js +14 -6
  34. package/components/data-display/progress.js +14 -6
  35. package/components/data-display/radial-progress.js +15 -6
  36. package/components/data-display/stats.js +9 -9
  37. package/components/data-display/table.js +9 -9
  38. package/components/data-display/timeline.js +8 -8
  39. package/components/data-display/toast.js +3 -3
  40. package/components/data-display/tooltip.js +20 -3
  41. package/components/data-input/checkbox.js +5 -5
  42. package/components/data-input/file-input.js +3 -3
  43. package/components/data-input/input.js +5 -5
  44. package/components/data-input/radio.js +9 -9
  45. package/components/data-input/range.js +3 -3
  46. package/components/data-input/rating.js +3 -3
  47. package/components/data-input/select.js +5 -5
  48. package/components/data-input/textarea.js +3 -3
  49. package/components/data-input/toggle.js +5 -5
  50. package/components/layout/divider.js +24 -4
  51. package/components/layout/drawer.js +7 -7
  52. package/components/layout/footer.js +5 -5
  53. package/components/layout/hero.js +5 -5
  54. package/components/layout/indicator.js +18 -4
  55. package/components/layout/join.js +4 -4
  56. package/components/layout/navbar.js +6 -6
  57. package/components/navigation/breadcrumbs.js +4 -4
  58. package/components/navigation/dock.js +5 -5
  59. package/components/navigation/menu.js +6 -6
  60. package/components/navigation/pagination.js +3 -3
  61. package/components/navigation/steps.js +4 -4
  62. package/components/navigation/tabs.js +296 -21
  63. package/components/theme/theme-switch.js +30 -30
  64. package/docs/about.html +141 -7
  65. package/docs/api/computed.html +1 -6
  66. package/docs/api/effects.html +1 -7
  67. package/docs/api/elements.html +130 -58
  68. package/docs/api/enhance.html +1 -6
  69. package/docs/api/hypermedia.html +182 -23
  70. package/docs/api/index.html +11 -12
  71. package/docs/api/nav.html +35 -4
  72. package/docs/api/signals.html +1 -6
  73. package/docs/api/state.html +1 -6
  74. package/docs/assets/js/examplify-sandbox.html +2 -2
  75. package/docs/assets/js/examplify.js +15 -15
  76. package/docs/cdom-nav.html +29 -0
  77. package/docs/cdom.html +362 -0
  78. package/docs/components/accordion.html +4 -4
  79. package/docs/components/alert.html +12 -12
  80. package/docs/components/avatar.html +4 -4
  81. package/docs/components/badge.html +59 -4
  82. package/docs/components/breadcrumbs.html +3 -3
  83. package/docs/components/button.html +83 -97
  84. package/docs/components/card.html +4 -4
  85. package/docs/components/carousel.html +3 -3
  86. package/docs/components/chart-area.html +6 -6
  87. package/docs/components/chart-bar.html +6 -6
  88. package/docs/components/chart-column.html +6 -6
  89. package/docs/components/chart-line.html +6 -6
  90. package/docs/components/chart-pie.html +6 -6
  91. package/docs/components/chart.html +2 -2
  92. package/docs/components/chat.html +4 -4
  93. package/docs/components/checkbox.html +4 -4
  94. package/docs/components/collapse.html +4 -4
  95. package/docs/components/component-nav.html +1 -1
  96. package/docs/components/countdown.html +4 -4
  97. package/docs/components/diff.html +3 -3
  98. package/docs/components/divider.html +68 -24
  99. package/docs/components/dock.html +3 -3
  100. package/docs/components/drawer.html +4 -4
  101. package/docs/components/dropdown.html +4 -4
  102. package/docs/components/file-input.html +4 -4
  103. package/docs/components/footer.html +3 -3
  104. package/docs/components/gallery.html +2 -2
  105. package/docs/components/hero.html +3 -3
  106. package/docs/components/index.css +5 -3
  107. package/docs/components/index.html +4 -4
  108. package/docs/components/indicator.html +88 -34
  109. package/docs/components/input.html +4 -4
  110. package/docs/components/join.html +3 -3
  111. package/docs/components/kbd.html +67 -28
  112. package/docs/components/loading.html +59 -43
  113. package/docs/components/menu.html +4 -4
  114. package/docs/components/modal.html +4 -4
  115. package/docs/components/navbar.html +3 -3
  116. package/docs/components/pagination.html +3 -3
  117. package/docs/components/progress.html +48 -7
  118. package/docs/components/radial-progress.html +35 -15
  119. package/docs/components/radio.html +4 -4
  120. package/docs/components/range.html +4 -4
  121. package/docs/components/rating.html +4 -4
  122. package/docs/components/select.html +4 -4
  123. package/docs/components/sidebar-setup.js +1 -1
  124. package/docs/components/spinner.html +4 -4
  125. package/docs/components/stats.html +4 -4
  126. package/docs/components/steps.html +3 -3
  127. package/docs/components/swap.html +187 -104
  128. package/docs/components/switch.html +4 -4
  129. package/docs/components/table.html +4 -4
  130. package/docs/components/tabs.html +147 -279
  131. package/docs/components/text-input.html +4 -4
  132. package/docs/components/textarea.html +4 -4
  133. package/docs/components/timeline.html +4 -4
  134. package/docs/components/toast.html +4 -4
  135. package/docs/components/toggle.html +4 -4
  136. package/docs/components/tooltip.html +75 -35
  137. package/docs/examples/getting-started-example.html +1 -1
  138. package/docs/examples/index.html +1 -2
  139. package/docs/getting-started/index.html +112 -19
  140. package/docs/index.html +1 -6
  141. package/docs/router-nav.html +13 -0
  142. package/docs/router.html +60 -17
  143. package/docs/styles/index.html +2 -7
  144. package/docs/syntax-nav.html +10 -0
  145. package/docs/syntax.html +146 -0
  146. package/functions/_middleware.js +17 -10
  147. package/functions/processServerScripts.js +127 -0
  148. package/index.html +8 -8
  149. package/lightview-all.js +1 -0
  150. package/lightview-cdom.js +1 -0
  151. package/lightview-router.js +71 -22
  152. package/lightview-x.js +1 -1247
  153. package/lightview.js +1 -760
  154. package/lightview.js.bak +1 -0
  155. package/package.json +37 -26
  156. package/scripts/analysis/README.md +2 -0
  157. package/scripts/analysis/analyze.js +266 -0
  158. package/scripts/analysis/latest_metrics.md +185 -0
  159. package/src/lightview-all.js +10 -0
  160. package/src/lightview-cdom.js +305 -0
  161. package/src/lightview-x.js +1581 -0
  162. package/src/lightview.js +694 -0
  163. package/src/reactivity/signal.js +133 -0
  164. package/src/reactivity/state.js +217 -0
  165. package/test-text-tag.js +6 -0
  166. package/tests/cdom/fixtures/helpers.cdomc +62 -0
  167. package/tests/cdom/fixtures/user.cdom +14 -0
  168. package/tests/cdom/fixtures/user.cdomc +12 -0
  169. package/tests/cdom/fixtures/user.odom +18 -0
  170. package/tests/cdom/fixtures/user.vdom +11 -0
  171. package/tests/cdom/helpers.test.js +121 -0
  172. package/tests/cdom/loader.test.js +125 -0
  173. package/tests/cdom/parser.test.js +108 -0
  174. package/tests/cdom/reactivity.test.js +186 -0
  175. package/tests/text-tag.test.js +77 -0
  176. package/vite.config.mjs +52 -0
  177. package/wrangler.toml +6 -0
  178. package/components/data-display/skeleton.js +0 -66
  179. package/docs/components/skeleton.html +0 -447
  180. package/docs/playground.html +0 -416
package/docs/cdom.html ADDED
@@ -0,0 +1,362 @@
1
+ <!-- SEO-friendly SPA Shim -->
2
+ <script src="/lightview-router.js?base=/index.html"></script>
3
+
4
+ <div class="docs-layout">
5
+ <aside class="docs-sidebar" src="/docs/cdom-nav.html"></aside>
6
+
7
+ <main class="docs-content">
8
+ <h1>cDOM (Experimental)</h1>
9
+ <p class="text-secondary" style="font-size: 1.125rem;">
10
+ A declarative, expression-based way to build reactive UIs.
11
+ </p>
12
+
13
+ <h2 id="overview">Overview</h2>
14
+ <p>
15
+ The Computational DOM (cDOM) is a revolutionary way to describe user interfaces using reactive expressions
16
+ that feel as natural as spreadsheet formulas. Instead of writing complex JavaScript logic to update your UI,
17
+ you define the <em>relationships</em> between your data and your elements.
18
+ </p>
19
+
20
+ <p>
21
+ If you wish to explore the implementation further, you can visit the <a
22
+ href="https://github.com/anywhichway/lightview" target="_blank">GitHub repository</a>, browse the <a
23
+ href="https://github.com/anywhichway/lightview/tree/main/cdom" target="_blank">cdom directory</a>, and
24
+ check out the <a href="https://github.com/anywhichway/lightview/tree/main/tests/cdom" target="_blank">cdom
25
+ unit tests</a>.
26
+ </p>
27
+
28
+ <h2 id="advantages">Advantages</h2>
29
+ <div class="feature-grid" style="margin: 2rem 0;">
30
+ <div class="feature-card">
31
+ <h3 class="feature-title">🛡️ Enhanced Security</h3>
32
+ <p>
33
+ cDOM strictly avoids <code>eval()</code> and direct HTML injection. By using a custom
34
+ high-performance parser and a registry of pre-defined helper functions, it provides a safe sandbox
35
+ for dynamic content, making it highly resistant to XSS attacks.
36
+ </p>
37
+ </div>
38
+ <div class="feature-card">
39
+ <h3 class="feature-title">🤖 LLM Friendly</h3>
40
+ <p>
41
+ Large Language Models excel at generating structured data and formulaic expressions. cDOM's
42
+ declarative nature and concise syntax (CDOMC) make it far easier for AI to generate correct,
43
+ bug-free UI components compared to traditional JavaScript-heavy frameworks.
44
+ </p>
45
+ </div>
46
+ </div>
47
+
48
+ <h2 id="how-it-works">How It Works</h2>
49
+ <p>
50
+ cDOM uses a powerful path-based resolution system to link UI elements directly to reactive state.
51
+ </p>
52
+ <p>
53
+ cDOM paths can range from simple property access to complex, nested transformations. Consider this example:
54
+ </p>
55
+ <div class="code-block" style="margin-bottom: 1.5rem;">
56
+ <pre><code>currency(sum(map(filter($/orders, eq(_/status, 'paid')), _/total)...))</code></pre>
57
+ </div>
58
+ <ul>
59
+ <li><strong>$/orders</strong>: Access the global <code>orders</code> collection.</li>
60
+ <li><strong>filter(..., eq(...))</strong>: Apply a filter to keep only "paid" orders using
61
+ <code>_/status</code>.
62
+ </li>
63
+ <li><strong>map(..., _/total)</strong>: Transform each order into its <code>total</code> value using
64
+ <code>_/total</code>.
65
+ </li>
66
+ <li><strong>...</strong>: The <strong>Explosion Operator</strong> expands the array of totals into
67
+ individual arguments for the <code>sum</code> function.</li>
68
+ <li><strong>sum(...)</strong>: Calculates the total of the exploded arguments.</li>
69
+ <li><strong>currency(...)</strong>: Formats the result as a currency string.</li>
70
+ </ul>
71
+
72
+ <h2 id="anatomy-of-a-path">Anatomy of a Path</h2>
73
+ <p>
74
+ A path in cDOM is a powerful string that describes how to navigate your reactive state and apply
75
+ transformations.
76
+ </p>
77
+ <ul>
78
+ <li><strong>Root/Prefix:</strong>
79
+ <ul>
80
+ <li><code>helperName(...args)</code>: Call a registered helper function.</li>
81
+ <li><code>$/&lt;name&gt;</code>: Access the global named signal or state registry.</li>
82
+ <li><code>./</code>: Access the local context (inherited from parent).</li>
83
+ <li><code>../</code>: Access the parent of the local context.</li>
84
+ <li><code>/</code>: (Alias for global when not first item in path) Starts at the root of your state.
85
+ </li>
86
+ </ul>
87
+ </li>
88
+ <li><strong>Segments:</strong> Properties or indices (e.g., <code>cart/items/0/price</code> or
89
+ <code>cart[0]/name</code>).
90
+ </li>
91
+ <li><strong>Embedded Functions:</strong> Paths can contain function calls to transform data (e.g.,
92
+ <code>filter($/cart/items..., eq(_/status, 'paid'))</code>). Functions are executed and their results
93
+ can be passed to other helpers or used as element children.
94
+ </li>
95
+ <li><strong>Explosion Operator:</strong> <code>...</code> expands an array into multiple arguments for a
96
+ function or extracts a property from every item in an array (e.g., <code>$/items...name</code>).</li>
97
+ <li><strong>Placeholders:</strong>
98
+ <ul>
99
+ <li><code>_</code>: Represents the current item during iteration (like in <code>map(_)</code>).
100
+ </li>
101
+ <li><code>$event</code>: Represents the event object in event handlers (e.g.,
102
+ <code>cdom-on:click="set($/current, $event.target.value)"</code>).
103
+ </li>
104
+ </ul>
105
+ </li>
106
+ </ul>
107
+
108
+ <h2 id="examples">Examples</h2>
109
+ <p>Representing a shopping cart total with reactive expressions:</p>
110
+
111
+ <div class="code-block">
112
+ <pre><code>// Example CDOM structure
113
+ {
114
+ div: {
115
+ children: [
116
+ { h2: "Shopping Cart" }, // Static header
117
+ { ul: {
118
+ // Map over the items in the cart: name - $price
119
+ children: "map($/cart/items, li(_/name, ' - $', _/price))"
120
+ }},
121
+ { p: {
122
+ class: "total",
123
+ // Calculate the total by summing item prices
124
+ children: ["Total: $", "sum(map($/cart/items, _/price)...)"]
125
+ }}
126
+ ]
127
+ }
128
+ }</code></pre>
129
+ </div>
130
+
131
+ <h3 class="text-sm font-bold opacity-70" style="margin-top: 1.5rem; margin-bottom: 0.5rem;">Expected HTML Output
132
+ </h3>
133
+ <div class="code-block">
134
+ <pre><code>&lt;div&gt;
135
+ &lt;h2&gt;Shopping Cart&lt;/h2&gt;
136
+ &lt;ul&gt;
137
+ &lt;li&gt;Apple - $1.00&lt;/li&gt;
138
+ &lt;li&gt;Orange - $2.00&lt;/li&gt;
139
+ &lt;/ul&gt;
140
+ &lt;p class="total"&gt;Total: $3.00&lt;/p&gt;
141
+ &lt;/div&gt;</code></pre>
142
+ </div>
143
+
144
+ <h3 class="text-sm font-bold opacity-70" style="margin-top: 1.5rem; margin-bottom: 0.5rem;">Actual Rendering
145
+ </h3>
146
+ <div class="card bg-base-200"
147
+ style="margin-bottom: 2rem; border: 1px solid var(--site-border); border-radius: 0.5rem;">
148
+ <div class="card-body" style="padding: 1.5rem; color: var(--bc);">
149
+ <h2 style="margin-top: 0; font-size: 1.5rem; font-weight: bold; color: var(--bc);">Shopping Cart</h2>
150
+ <ul style="margin-bottom: 1rem; padding-left: 1.5rem; list-style-type: disc;">
151
+ <li>Apple - $1.00</li>
152
+ <li>Orange - $2.00</li>
153
+ </ul>
154
+ <p style="font-weight: bold; font-size: 1.125rem;">Total: $3.00</p>
155
+ </div>
156
+ </div>
157
+
158
+ <h2 id="comparison">Comparison to Excel</h2>
159
+ <p>
160
+ Think of your UI as a spreadsheet. In Excel, if Cell C1 has the formula <code>=A1+B1</code>, C1 updates
161
+ automatically whenever A1 or B1 changes.
162
+ </p>
163
+ <p>
164
+ cDOM brings this exact paradigm to the web. Every attribute and text node can be a "cell" that computes its
165
+ value based on other "cells" (reactive signals).
166
+ </p>
167
+
168
+ <table class="api-table">
169
+ <thead>
170
+ <tr>
171
+ <th>Feature</th>
172
+ <th>Excel</th>
173
+ <th>cDOM</th>
174
+ </tr>
175
+ </thead>
176
+ <tbody>
177
+ <tr>
178
+ <td><strong>Reactive Unit</strong></td>
179
+ <td>Cell</td>
180
+ <td>Signal / State Proxy</td>
181
+ </tr>
182
+ <tr>
183
+ <td><strong>Formulas</strong></td>
184
+ <td><code>=SUM(A1:A10)</code></td>
185
+ <td><code>sum($/items...)</code></td>
186
+ </tr>
187
+ <tr>
188
+ <td><strong>Path Resolution</strong></td>
189
+ <td>Cell References (A1, $B$2)</td>
190
+ <td>JSON Paths (./name, $/global)</td>
191
+ </tr>
192
+ <tr>
193
+ <td><strong>Recalculation</strong></td>
194
+ <td>Automatic on change</td>
195
+ <td>Automatic on change</td>
196
+ </tr>
197
+ </tbody>
198
+ </table>
199
+
200
+ <h2 id="interaction">Events and Interaction</h2>
201
+ <p>
202
+ cDOM is designed to handle user interactions gracefully, whether in a traditional standalone application or
203
+ in
204
+ a dynamic, LLM-driven environment.
205
+ </p>
206
+
207
+ <h3 id="interaction-standalone">Manual Implementation (Standalone Apps)</h3>
208
+ <p>
209
+ Developers can use the <code>cdom-on:</code> directive to bind expressions directly to DOM events. This
210
+ allows for clear, declarative event handling that updates local state or calls helper functions.
211
+ </p>
212
+ <div class="code-block">
213
+ <pre><code>&lt;button cdom-on:click="increment($/count)"&gt;Click Me&lt;/button&gt;</code></pre>
214
+ </div>
215
+
216
+ <h3 id="interaction-llm">LLM-Generated Interaction</h3>
217
+ <p>
218
+ Because cDOM represents the UI as data, an LLM can easily generate event handlers to register its interest
219
+ in
220
+ specific user actions. Instead of writing complex JavaScript observers, the LLM simply includes event
221
+ handlers
222
+ that notify the server.
223
+ </p>
224
+ <div class="code-block">
225
+ <pre><code>// Example of an LLM 'registering' for a click event
226
+ {
227
+ button: {
228
+ "cdom-on:click": "fetch('/api/notify', { method: 'POST', body: { $event } })",
229
+ children: ["Notify LLM"]
230
+ }
231
+ }</code></pre>
232
+ </div>
233
+ <p>
234
+ By generating these attributes on specific elements, the LLM effectively "subscribes" to the behavioral data
235
+ it needs to reason about the user's next steps. The <code>$event</code> placeholder ensures the LLM receives
236
+ the
237
+ full context of the interaction.
238
+ </p>
239
+
240
+ <h3 id="interaction-lifecycle">The Interaction Lifecycle</h3>
241
+ <div class="feature-grid" style="margin: 2rem 0;">
242
+ <div class="feature-card">
243
+ <h4 class="feature-title">🤖 LLM-Driven Flow</h4>
244
+ <ol style="margin-top: 1rem; font-size: 0.9em; line-height: 1.6;">
245
+ <li><strong>LLM</strong> generates the initial UI structure as JSON.</li>
246
+ <li><strong>HTTP Server</strong> receives the JSON and serves it to the <strong>Client</strong>.
247
+ </li>
248
+ <li><strong>Client</strong> renders the cDOM and activates local reactivity.</li>
249
+ <li><strong>User Interacts</strong> (e.g., clicks a 'notify' button).</li>
250
+ <li><strong>Client</strong> sends the interaction data back to the <strong>HTTP Server</strong>.
251
+ </li>
252
+ <li><strong>HTTP Server</strong> relays the event context to the <strong>LLM</strong>.</li>
253
+ <li><strong>LLM</strong> processes the event and sends a <strong>Patch/Update</strong> back to the
254
+ <strong>HTTP Server</strong>.
255
+ </li>
256
+ <li><strong>HTTP Server</strong> relays the update to the <strong>Client</strong>.</li>
257
+ <li><strong>Client</strong> merges the update, instantly refreshing the UI.</li>
258
+ </ol>
259
+ </div>
260
+ <div class="feature-card">
261
+ <h4 class="feature-title">🏠 Standalone Flow</h4>
262
+ <ol style="margin-top: 1rem; font-size: 0.9em; line-height: 1.6;">
263
+ <li><strong>Static cDOM</strong> is defined in the Client's source code or local files.</li>
264
+ <li><strong>Client</strong> activates the UI locally on page load.</li>
265
+ <li><strong>User Interacts</strong> (e.g., clicks a local toggle).</li>
266
+ <li><strong>Local State</strong> is updated immediately.</li>
267
+ <li><strong>UI Recalculates</strong> based on reactive expressions (0 latency).</li>
268
+ <li><strong>HTTP Server</strong> is only contacted for persistence or traditional API calls.</li>
269
+ </ol>
270
+ </div>
271
+ </div>
272
+
273
+ <h2 id="helpers">Helper Functions</h2>
274
+ <p>
275
+ cDOM comes with a rich set of built-in helpers that cover most common UI logic and data transformations.
276
+ Developers can also register their own custom functions to extend cDOM's capabilities:
277
+ </p>
278
+ <div class="code-block">
279
+ <pre><code>// Register a custom function
280
+ cDOM.register(f, name=f.name);</code></pre>
281
+ </div>
282
+ <p>
283
+ For security and deterministic behavior, cDOM operates in a sandbox. It <strong>cannot</strong> access
284
+ <code>globalThis</code> or arbitrary window properties. Only functions explicitly registered via
285
+ <code>cDOM.register()</code> are available for use within cDOM expressions.
286
+ </p>
287
+
288
+ <h3 id="helpers-math">Math</h3>
289
+ <p>Basic arithmetic and mathematical operations.</p>
290
+ <div class="code-block">
291
+ <pre><code>+, add, -, sub, *, mul, /, div, round, ceil, floor, abs, mod, pow, sqrt</code></pre>
292
+ </div>
293
+
294
+ <h3 id="helpers-stats">Stats</h3>
295
+ <p>Aggregate results from arrays of numbers.</p>
296
+ <div class="code-block">
297
+ <pre><code>sum, avg, min, max, median, stdev, var</code></pre>
298
+ </div>
299
+
300
+ <h3 id="helpers-string">String</h3>
301
+ <p>Text manipulation and formatting.</p>
302
+ <div class="code-block">
303
+ <pre><code>upper, lower, trim, capitalize, titleCase, contains, startsWith, endsWith, replace, split, len, join, default</code></pre>
304
+ </div>
305
+
306
+ <h3 id="helpers-array">Array</h3>
307
+ <p>Collection processing and iteration.</p>
308
+ <div class="code-block">
309
+ <pre><code>count(len), map, filter, find, unique, sort, reverse, first, last, slice, flatten, join</code></pre>
310
+ </div>
311
+
312
+ <h3 id="helpers-logic">Logic & Comparison</h3>
313
+ <p>Boolean logic and value comparison.</p>
314
+ <div class="code-block">
315
+ <pre><code>if, and(&&), or(||), not(!), eq(==, ===), neq(!=), gt(>), lt(<), gte(>=), lte(<=), between, in</code></pre>
316
+ </div>
317
+
318
+ <h3 id="helpers-conditional">Conditional Aggregates</h3>
319
+ <p>Statistical functions that take a filter predicate.</p>
320
+ <div class="code-block">
321
+ <pre><code>sumIf, countIf, avgIf</code></pre>
322
+ </div>
323
+
324
+ <h3 id="helpers-formatting">Formatting</h3>
325
+ <p>Display helpers for various data types.</p>
326
+ <div class="code-block">
327
+ <pre><code>number, currency, percent, thousands</code></pre>
328
+ </div>
329
+
330
+ <h3 id="helpers-datetime">DateTime</h3>
331
+ <p>Date creation, parsing, and arithmetic.</p>
332
+ <div class="code-block">
333
+ <pre><code>now, today, date, formatDate, year, month, day, weekday, addDays, dateDiff</code></pre>
334
+ </div>
335
+
336
+ <h3 id="helpers-lookup">Lookup</h3>
337
+ <p>Data retrieval from indexed structures.</p>
338
+ <div class="code-block">
339
+ <pre><code>lookup, vlookup, index, match</code></pre>
340
+ </div>
341
+
342
+ <h3 id="helpers-mutation">State Mutation</h3>
343
+ <p>Directly modify reactive state from event handlers.</p>
344
+ <div class="code-block">
345
+ <pre><code>set, increment(++), decrement(--), toggle(!!), push, pop, assign, clear</code></pre>
346
+ </div>
347
+
348
+ <h3 id="helpers-network">Network</h3>
349
+ <p>Data fetching and network requests.</p>
350
+ <div class="code-block">
351
+ <pre><code>fetch(url, options?)</code></pre>
352
+ </div>
353
+ <p>
354
+ The <code>fetch</code> helper simplifies network requests by handling body serialization.
355
+ If the <code>body</code> is a non-null object, it is automatically stringified as JSON and the
356
+ <code>Content-Type</code> is set to <code>application/json</code> (if not already set).
357
+ Otherwise, the body is converted to a string and <code>Content-Type</code> is set to
358
+ <code>text/plain</code>.
359
+ </p>
360
+
361
+ </main>
362
+ </div>
@@ -1,7 +1,7 @@
1
1
  <!-- SEO-friendly SPA Shim -->
2
2
  <script src="/lightview-router.js"></script>
3
3
  <script>
4
- if (window.LightviewRouter) {
4
+ if (globalThis.LightviewRouter) {
5
5
  LightviewRouter.base('/index.html');
6
6
  }
7
7
  </script>
@@ -69,7 +69,7 @@
69
69
 
70
70
  <!-- Tabs -->
71
71
  <script>
72
- window.switchSyntaxTab = (tabId) => {
72
+ globalThis.switchSyntaxTab = (tabId) => {
73
73
  const tabs = ['tagged', 'vdom', 'object'];
74
74
  tabs.forEach(t => {
75
75
  const tabEl = document.getElementById(`tab-btn-${t}`);
@@ -210,7 +210,7 @@ $('#example').content(accordion);</code></pre>
210
210
 
211
211
  <!-- Tabs -->
212
212
  <script>
213
- window.switchReactiveSyntaxTab = (tabId) => {
213
+ globalThis.switchReactiveSyntaxTab = (tabId) => {
214
214
  const tabs = ['tagged', 'vdom', 'object'];
215
215
  tabs.forEach(t => {
216
216
  const tabEl = document.getElementById(`reactive-tab-btn-${t}`);
@@ -436,4 +436,4 @@ $('#example').content(accordion);</code></pre>
436
436
  </div>
437
437
  </div>
438
438
  </div>
439
- </div>
439
+ </div>
@@ -1,7 +1,7 @@
1
1
  <!-- SEO-friendly SPA Shim -->
2
2
  <script src="/lightview-router.js"></script>
3
3
  <script>
4
- if (window.LightviewRouter) {
4
+ if (globalThis.LightviewRouter) {
5
5
  LightviewRouter.base('/index.html');
6
6
  }
7
7
  </script>
@@ -71,7 +71,7 @@
71
71
 
72
72
  <!-- Tabs -->
73
73
  <script>
74
- window.switchSyntaxTab = (tabId) => {
74
+ globalThis.switchSyntaxTab = (tabId) => {
75
75
  const tabs = ['tagged', 'vdom', 'object', 'html'];
76
76
  tabs.forEach(t => {
77
77
  const tabEl = document.getElementById(`tab-btn-${t}`);
@@ -192,10 +192,10 @@ const alerts = {
192
192
  div: {
193
193
  style: 'display: flex; flex-direction: column; gap: 1rem;',
194
194
  children: [
195
- { Alert: { color: 'info', icon: 'info', children: [{ span: { text: 'New update available! Click to learn more.' } }] } },
196
- { Alert: { color: 'success', icon: 'success', children: [{ span: { text: 'Your order has been placed successfully!' } }] } },
197
- { Alert: { color: 'warning', icon: 'warning', children: [{ span: { text: 'Please review your information before proceeding.' } }] } },
198
- { Alert: { color: 'error', icon: 'error', children: [{ span: { text: 'Unable to connect to server. Please try again.' } }] } }
195
+ { Alert: { color: 'info', icon: 'info', children: ['New update available! Click to learn more.'] } },
196
+ { Alert: { color: 'success', icon: 'success', children: ['Your order has been placed successfully!'] } },
197
+ { Alert: { color: 'warning', icon: 'warning', children: ['Please review your information before proceeding.'] } },
198
+ { Alert: { color: 'error', icon: 'error', children: ['Unable to connect to server. Please try again.'] } }
199
199
  ]
200
200
  }
201
201
  };
@@ -236,7 +236,7 @@ $('#example').content(alerts);</code></pre>
236
236
 
237
237
  <!-- Tabs -->
238
238
  <script>
239
- window.switchReactiveSyntaxTab = (tabId) => {
239
+ globalThis.switchReactiveSyntaxTab = (tabId) => {
240
240
  const tabs = ['tagged', 'vdom', 'object'];
241
241
  tabs.forEach(t => {
242
242
  const tabEl = document.getElementById(`reactive-tab-btn-${t}`);
@@ -376,8 +376,8 @@ const demo = {
376
376
  color: 'success',
377
377
  icon: 'success',
378
378
  children: [
379
- { span: { text: 'Message sent successfully!' } },
380
- { Button: { size: 'sm', color: 'ghost', onclick: () => { visible.value = false; }, text: '✕' } }
379
+ 'Message sent successfully!',
380
+ { Button: { size: 'sm', color: 'ghost', onclick: () => { visible.value = false; }, children: ['✕'] } }
381
381
  ]
382
382
  }
383
383
  }
@@ -385,8 +385,8 @@ const demo = {
385
385
  div: {
386
386
  style: 'display: flex; gap: 0.5rem;',
387
387
  children: [
388
- { span: { style: 'font-size: 0.875rem; opacity: 0.5;', text: 'Alert dismissed' } },
389
- { Button: { size: 'sm', color: 'primary', onclick: () => { visible.value = true; }, text: 'Show again' } }
388
+ { span: { style: 'font-size: 0.875rem; opacity: 0.5;', children: ['Alert dismissed'] } },
389
+ { Button: { size: 'sm', color: 'primary', onclick: () => { visible.value = true; }, children: ['Show again'] } }
390
390
  ]
391
391
  }
392
392
  }
@@ -525,4 +525,4 @@ $('#example').content(demo);</code></pre>
525
525
  </div>
526
526
  </div>
527
527
  </div>
528
- </div>
528
+ </div>
@@ -1,7 +1,7 @@
1
1
  <!-- SEO-friendly SPA Shim -->
2
2
  <script src="/lightview-router.js"></script>
3
3
  <script>
4
- if (window.LightviewRouter) {
4
+ if (globalThis.LightviewRouter) {
5
5
  LightviewRouter.base('/index.html');
6
6
  }
7
7
  </script>
@@ -74,7 +74,7 @@
74
74
 
75
75
  <!-- Tabs -->
76
76
  <script>
77
- window.switchSyntaxTab = (tabId) => {
77
+ globalThis.switchSyntaxTab = (tabId) => {
78
78
  const tabs = ['tagged', 'vdom', 'object', 'html'];
79
79
  tabs.forEach(t => {
80
80
  const tabEl = document.getElementById(`tab-btn-${t}`);
@@ -255,7 +255,7 @@ $('#example').content(avatars);</code></pre>
255
255
 
256
256
  <!-- Tabs -->
257
257
  <script>
258
- window.switchReactiveSyntaxTab = (tabId) => {
258
+ globalThis.switchReactiveSyntaxTab = (tabId) => {
259
259
  const tabs = ['tagged', 'vdom', 'object'];
260
260
  tabs.forEach(t => {
261
261
  const tabEl = document.getElementById(`reactive-tab-btn-${t}`);
@@ -583,4 +583,4 @@ Avatar.Group({},
583
583
  </div>
584
584
  </div>
585
585
  </div>
586
- </div>
586
+ </div>
@@ -1,7 +1,7 @@
1
1
  <!-- SEO-friendly SPA Shim -->
2
2
  <script src="/lightview-router.js"></script>
3
3
  <script>
4
- if (window.LightviewRouter) {
4
+ if (globalThis.LightviewRouter) {
5
5
  LightviewRouter.base('/index.html');
6
6
  }
7
7
  </script>
@@ -71,7 +71,7 @@
71
71
 
72
72
  <!-- Tabs -->
73
73
  <script>
74
- window.switchSyntaxTab = (tabId) => {
74
+ globalThis.switchSyntaxTab = (tabId) => {
75
75
  const tabs = ['tagged', 'vdom', 'object', 'html'];
76
76
  tabs.forEach(t => {
77
77
  const tabEl = document.getElementById(`tab-btn-${t}`);
@@ -272,7 +272,7 @@ $('#example').content(badges);</code></pre>
272
272
 
273
273
  <!-- Tabs -->
274
274
  <script>
275
- window.switchReactiveSyntaxTab = (tabId) => {
275
+ globalThis.switchReactiveSyntaxTab = (tabId) => {
276
276
  const tabs = ['tagged', 'vdom', 'object'];
277
277
  tabs.forEach(t => {
278
278
  const tabEl = document.getElementById(`reactive-tab-btn-${t}`);
@@ -524,8 +524,63 @@ $('#example').content(demo);</code></pre>
524
524
  <div class="badge badge-secondary">+99</div>
525
525
  </button>
526
526
  </div>
527
+
528
+ <!-- Custom Element Gallery -->
529
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Custom Element Gallery</h2>
530
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 1rem;">
531
+ Live examples using <code>&lt;lv-badge&gt;</code> custom elements with various options.
532
+ </p>
533
+
534
+ <script type="module" src="/components/data-display/badge.js"></script>
535
+
536
+ <!-- All Colors -->
537
+ <h3 class="text-lg font-semibold" style="margin-top: 1.5rem; margin-bottom: 0.75rem;">All Colors
538
+ </h3>
539
+ <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
540
+ <lv-badge>Default</lv-badge>
541
+ <lv-badge color="neutral">Neutral</lv-badge>
542
+ <lv-badge color="primary">Primary</lv-badge>
543
+ <lv-badge color="secondary">Secondary</lv-badge>
544
+ <lv-badge color="accent">Accent</lv-badge>
545
+ <lv-badge color="ghost">Ghost</lv-badge>
546
+ <lv-badge color="info">Info</lv-badge>
547
+ <lv-badge color="success">Success</lv-badge>
548
+ <lv-badge color="warning">Warning</lv-badge>
549
+ <lv-badge color="error">Error</lv-badge>
550
+ </div>
551
+
552
+ <!-- All Sizes -->
553
+ <h3 class="text-lg font-semibold" style="margin-bottom: 0.75rem;">All Sizes</h3>
554
+ <div style="display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem;">
555
+ <lv-badge size="xs" color="primary">Extra Small</lv-badge>
556
+ <lv-badge size="sm" color="primary">Small</lv-badge>
557
+ <lv-badge size="md" color="primary">Medium</lv-badge>
558
+ <lv-badge size="lg" color="primary">Large</lv-badge>
559
+ </div>
560
+
561
+ <!-- All Variants -->
562
+ <h3 class="text-lg font-semibold" style="margin-bottom: 0.75rem;">All Variants</h3>
563
+ <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem;">
564
+ <lv-badge color="primary">Solid</lv-badge>
565
+ <lv-badge variant="outline" color="primary">Outline</lv-badge>
566
+ <lv-badge variant="soft" color="primary">Soft</lv-badge>
567
+ <lv-badge variant="dash" color="primary">Dash</lv-badge>
568
+ </div>
569
+
570
+ <!-- Mixed Combinations -->
571
+ <h3 class="text-lg font-semibold" style="margin-bottom: 0.75rem;">Mixed Combinations</h3>
572
+ <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 2rem;">
573
+ <lv-badge size="xs" color="success">New</lv-badge>
574
+ <lv-badge size="sm" variant="outline" color="info">Beta</lv-badge>
575
+ <lv-badge variant="soft" color="warning">Hot</lv-badge>
576
+ <lv-badge size="lg" variant="dash" color="error">Sale</lv-badge>
577
+ <lv-badge color="secondary">v2.0</lv-badge>
578
+ <lv-badge size="xs" variant="outline" color="accent">Pro</lv-badge>
579
+ <lv-badge size="sm" variant="soft" color="success">Updated</lv-badge>
580
+ <lv-badge variant="dash" color="neutral">Draft</lv-badge>
581
+ </div>
527
582
  </div>
528
583
  </div>
529
584
  </div>
530
585
  </div>
531
- </div>
586
+ </div>
@@ -1,7 +1,7 @@
1
1
  <!-- SEO-friendly SPA Shim -->
2
2
  <script src="/lightview-router.js"></script>
3
3
  <script>
4
- if (window.LightviewRouter) {
4
+ if (globalThis.LightviewRouter) {
5
5
  LightviewRouter.base('/index.html');
6
6
  }
7
7
  </script>
@@ -71,7 +71,7 @@
71
71
 
72
72
  <!-- Tabs -->
73
73
  <script>
74
- window.switchSyntaxTab = (tabId) => {
74
+ globalThis.switchSyntaxTab = (tabId) => {
75
75
  const tabs = ['tagged', 'vdom', 'object'];
76
76
  tabs.forEach(t => {
77
77
  const tabEl = document.getElementById(`tab-btn-${t}`);
@@ -275,4 +275,4 @@ $('#example').content(breadcrumbs);</code></pre>
275
275
  </div>
276
276
  </div>
277
277
  </div>
278
- </div>
278
+ </div>