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.
- package/README.md +47 -1283
- package/build-bundles.mjs +109 -0
- package/cdom/helpers/array.js +70 -0
- package/cdom/helpers/compare.js +26 -0
- package/cdom/helpers/conditional.js +34 -0
- package/cdom/helpers/datetime.js +54 -0
- package/cdom/helpers/format.js +20 -0
- package/cdom/helpers/logic.js +24 -0
- package/cdom/helpers/lookup.js +25 -0
- package/cdom/helpers/math.js +34 -0
- package/cdom/helpers/network.js +41 -0
- package/cdom/helpers/state.js +77 -0
- package/cdom/helpers/stats.js +39 -0
- package/cdom/helpers/string.js +49 -0
- package/cdom/parser.js +602 -0
- package/components/actions/button.js +19 -6
- package/components/actions/dropdown.js +6 -6
- package/components/actions/modal.js +9 -9
- package/components/actions/swap.js +31 -8
- package/components/daisyui.js +1 -1
- package/components/data-display/accordion.js +6 -6
- package/components/data-display/alert.js +17 -7
- package/components/data-display/avatar.js +7 -7
- package/components/data-display/badge.js +14 -6
- package/components/data-display/card.js +7 -7
- package/components/data-display/carousel.js +4 -4
- package/components/data-display/chart.js +8 -8
- package/components/data-display/chat.js +7 -7
- package/components/data-display/collapse.js +5 -5
- package/components/data-display/countdown.js +3 -3
- package/components/data-display/diff.js +6 -6
- package/components/data-display/kbd.js +12 -6
- package/components/data-display/loading.js +14 -6
- package/components/data-display/progress.js +14 -6
- package/components/data-display/radial-progress.js +15 -6
- package/components/data-display/stats.js +9 -9
- package/components/data-display/table.js +9 -9
- package/components/data-display/timeline.js +8 -8
- package/components/data-display/toast.js +3 -3
- package/components/data-display/tooltip.js +20 -3
- package/components/data-input/checkbox.js +5 -5
- package/components/data-input/file-input.js +3 -3
- package/components/data-input/input.js +5 -5
- package/components/data-input/radio.js +9 -9
- package/components/data-input/range.js +3 -3
- package/components/data-input/rating.js +3 -3
- package/components/data-input/select.js +5 -5
- package/components/data-input/textarea.js +3 -3
- package/components/data-input/toggle.js +5 -5
- package/components/layout/divider.js +24 -4
- package/components/layout/drawer.js +7 -7
- package/components/layout/footer.js +5 -5
- package/components/layout/hero.js +5 -5
- package/components/layout/indicator.js +18 -4
- package/components/layout/join.js +4 -4
- package/components/layout/navbar.js +6 -6
- package/components/navigation/breadcrumbs.js +4 -4
- package/components/navigation/dock.js +5 -5
- package/components/navigation/menu.js +6 -6
- package/components/navigation/pagination.js +3 -3
- package/components/navigation/steps.js +4 -4
- package/components/navigation/tabs.js +296 -21
- package/components/theme/theme-switch.js +30 -30
- package/docs/about.html +141 -7
- package/docs/api/computed.html +1 -6
- package/docs/api/effects.html +1 -7
- package/docs/api/elements.html +130 -58
- package/docs/api/enhance.html +1 -6
- package/docs/api/hypermedia.html +182 -23
- package/docs/api/index.html +11 -12
- package/docs/api/nav.html +35 -4
- package/docs/api/signals.html +1 -6
- package/docs/api/state.html +1 -6
- package/docs/assets/js/examplify-sandbox.html +2 -2
- package/docs/assets/js/examplify.js +15 -15
- package/docs/cdom-nav.html +29 -0
- package/docs/cdom.html +362 -0
- package/docs/components/accordion.html +4 -4
- package/docs/components/alert.html +12 -12
- package/docs/components/avatar.html +4 -4
- package/docs/components/badge.html +59 -4
- package/docs/components/breadcrumbs.html +3 -3
- package/docs/components/button.html +83 -97
- package/docs/components/card.html +4 -4
- package/docs/components/carousel.html +3 -3
- package/docs/components/chart-area.html +6 -6
- package/docs/components/chart-bar.html +6 -6
- package/docs/components/chart-column.html +6 -6
- package/docs/components/chart-line.html +6 -6
- package/docs/components/chart-pie.html +6 -6
- package/docs/components/chart.html +2 -2
- package/docs/components/chat.html +4 -4
- package/docs/components/checkbox.html +4 -4
- package/docs/components/collapse.html +4 -4
- package/docs/components/component-nav.html +1 -1
- package/docs/components/countdown.html +4 -4
- package/docs/components/diff.html +3 -3
- package/docs/components/divider.html +68 -24
- package/docs/components/dock.html +3 -3
- package/docs/components/drawer.html +4 -4
- package/docs/components/dropdown.html +4 -4
- package/docs/components/file-input.html +4 -4
- package/docs/components/footer.html +3 -3
- package/docs/components/gallery.html +2 -2
- package/docs/components/hero.html +3 -3
- package/docs/components/index.css +5 -3
- package/docs/components/index.html +4 -4
- package/docs/components/indicator.html +88 -34
- package/docs/components/input.html +4 -4
- package/docs/components/join.html +3 -3
- package/docs/components/kbd.html +67 -28
- package/docs/components/loading.html +59 -43
- package/docs/components/menu.html +4 -4
- package/docs/components/modal.html +4 -4
- package/docs/components/navbar.html +3 -3
- package/docs/components/pagination.html +3 -3
- package/docs/components/progress.html +48 -7
- package/docs/components/radial-progress.html +35 -15
- package/docs/components/radio.html +4 -4
- package/docs/components/range.html +4 -4
- package/docs/components/rating.html +4 -4
- package/docs/components/select.html +4 -4
- package/docs/components/sidebar-setup.js +1 -1
- package/docs/components/spinner.html +4 -4
- package/docs/components/stats.html +4 -4
- package/docs/components/steps.html +3 -3
- package/docs/components/swap.html +187 -104
- package/docs/components/switch.html +4 -4
- package/docs/components/table.html +4 -4
- package/docs/components/tabs.html +147 -279
- package/docs/components/text-input.html +4 -4
- package/docs/components/textarea.html +4 -4
- package/docs/components/timeline.html +4 -4
- package/docs/components/toast.html +4 -4
- package/docs/components/toggle.html +4 -4
- package/docs/components/tooltip.html +75 -35
- package/docs/examples/getting-started-example.html +1 -1
- package/docs/examples/index.html +1 -2
- package/docs/getting-started/index.html +112 -19
- package/docs/index.html +1 -6
- package/docs/router-nav.html +13 -0
- package/docs/router.html +60 -17
- package/docs/styles/index.html +2 -7
- package/docs/syntax-nav.html +10 -0
- package/docs/syntax.html +146 -0
- package/functions/_middleware.js +17 -10
- package/functions/processServerScripts.js +127 -0
- package/index.html +8 -8
- package/lightview-all.js +1 -0
- package/lightview-cdom.js +1 -0
- package/lightview-router.js +71 -22
- package/lightview-x.js +1 -1247
- package/lightview.js +1 -760
- package/lightview.js.bak +1 -0
- package/package.json +37 -26
- package/scripts/analysis/README.md +2 -0
- package/scripts/analysis/analyze.js +266 -0
- package/scripts/analysis/latest_metrics.md +185 -0
- package/src/lightview-all.js +10 -0
- package/src/lightview-cdom.js +305 -0
- package/src/lightview-x.js +1581 -0
- package/src/lightview.js +694 -0
- package/src/reactivity/signal.js +133 -0
- package/src/reactivity/state.js +217 -0
- package/test-text-tag.js +6 -0
- package/tests/cdom/fixtures/helpers.cdomc +62 -0
- package/tests/cdom/fixtures/user.cdom +14 -0
- package/tests/cdom/fixtures/user.cdomc +12 -0
- package/tests/cdom/fixtures/user.odom +18 -0
- package/tests/cdom/fixtures/user.vdom +11 -0
- package/tests/cdom/helpers.test.js +121 -0
- package/tests/cdom/loader.test.js +125 -0
- package/tests/cdom/parser.test.js +108 -0
- package/tests/cdom/reactivity.test.js +186 -0
- package/tests/text-tag.test.js +77 -0
- package/vite.config.mjs +52 -0
- package/wrangler.toml +6 -0
- package/components/data-display/skeleton.js +0 -66
- package/docs/components/skeleton.html +0 -447
- 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>$/<name></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><div>
|
|
135
|
+
<h2>Shopping Cart</h2>
|
|
136
|
+
<ul>
|
|
137
|
+
<li>Apple - $1.00</li>
|
|
138
|
+
<li>Orange - $2.00</li>
|
|
139
|
+
</ul>
|
|
140
|
+
<p class="total">Total: $3.00</p>
|
|
141
|
+
</div></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><button cdom-on:click="increment($/count)">Click Me</button></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 (
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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: [
|
|
196
|
-
{ Alert: { color: 'success', icon: 'success', children: [
|
|
197
|
-
{ Alert: { color: 'warning', icon: 'warning', children: [
|
|
198
|
-
{ Alert: { color: 'error', icon: 'error', children: [
|
|
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
|
-
|
|
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
|
-
|
|
380
|
-
{ Button: { size: 'sm', color: 'ghost', onclick: () => { visible.value = false; },
|
|
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;',
|
|
389
|
-
{ Button: { size: 'sm', color: 'primary', onclick: () => { visible.value = true; },
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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><lv-badge></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 (
|
|
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
|
-
|
|
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>
|