lightview 2.3.4 → 2.3.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightview",
3
- "version": "2.3.4",
3
+ "version": "2.3.5",
4
4
  "description": "A lightweight reactive UI library with features of Bau, Juris, and HTMX",
5
5
  "main": "lightview.js",
6
6
  "workspaces": [
@@ -35,7 +35,8 @@
35
35
  "wrangler": "^4.54.0"
36
36
  },
37
37
  "dependencies": {
38
- "jprx": "^1.2.0",
38
+ "expr-eval": "^2.0.2",
39
+ "jprx": "^1.2.1",
39
40
  "linkedom": "^0.18.12",
40
41
  "marked": "^17.0.1"
41
42
  }
@@ -16,6 +16,7 @@ import { registerLookupHelpers } from '../jprx/helpers/lookup.js';
16
16
  import { registerStatsHelpers } from '../jprx/helpers/stats.js';
17
17
  import { registerStateHelpers, set } from '../jprx/helpers/state.js';
18
18
  import { registerNetworkHelpers } from '../jprx/helpers/network.js';
19
+ import { registerCalcHelpers } from '../jprx/helpers/calc.js';
19
20
 
20
21
  import { signal, effect, getRegistry } from './reactivity/signal.js';
21
22
  import { state } from './reactivity/state.js';
@@ -33,6 +34,7 @@ registerLookupHelpers(registerHelper);
33
34
  registerStatsHelpers(registerHelper);
34
35
  registerStateHelpers((name, fn) => registerHelper(name, fn, { pathAware: true }));
35
36
  registerNetworkHelpers(registerHelper);
37
+ registerCalcHelpers(registerHelper);
36
38
  registerHelper('move', (selector, location = 'beforeend') => {
37
39
  return {
38
40
  isLazy: true,
@@ -219,7 +221,7 @@ const makeEventHandler = (expr) => (eventOrNode) => {
219
221
  const target = isEvent ? (eventOrNode.currentTarget || eventOrNode.target) : eventOrNode;
220
222
  const context = getContext(target, isEvent ? eventOrNode : null);
221
223
  const result = resolveExpression(expr, context);
222
- if (result && typeof result === 'object' && result.isLazy) return result.resolve(eventOrNode);
224
+ if (result && typeof result === 'object' && result.isLazy) return result.resolve(context);
223
225
  return result;
224
226
  };
225
227
 
package/start-dev.js CHANGED
@@ -14,7 +14,7 @@ const allowedDirs = ['docs', 'components', 'middleware'];
14
14
  function build() {
15
15
  try {
16
16
  console.log('Running full build...');
17
- execSync('node build-bundles.mjs',, { stdio: 'inherit' });
17
+ execSync('node build-bundles.mjs', { stdio: 'inherit' });
18
18
  execSync('node build.js --env=dev', { stdio: 'inherit' });
19
19
  } catch (e) {
20
20
  console.error('Build failed:', e);
package/cDOMIntro.md DELETED
@@ -1,279 +0,0 @@
1
- # The Future of AI-Generated UI: Why I Built cDOM and JPRX
2
-
3
- **A declarative, secure, and reactive approach to let both humans and LLMs build rich user interfaces.**
4
-
5
- ---
6
-
7
- ## The Problem with AI-Generated Interfaces
8
-
9
- We are at an inflection point in software development. Large Language Models (LLMs) are rapidly evolving from text-generation tools into full-fledged software agents capable of building applications, analyzing data, and interacting with users in real-time. But there's a critical bottleneck: **how do these agents communicate visually with humans?**
10
-
11
- The traditional options are bleak:
12
- 1. **Text-Only Responses**: The chatbot experience. Great for conversation, terrible for complex interactions. Ever tried to book a flight through a wall of text? It's exhausting.
13
- 2. **Raw Code Generation (HTML/JS/React)**: The agent spits out code, and you hope it works. This is a **massive security risk**. Arbitrary code execution is the original sin of computing—do you really want to `eval()` whatever a cloud-based AI model sends you? The answer is no. And, the flexibility of raw language generation can result in either too much brittle code or too much variance from UI exprience to UI experience, something humans do not handle well.
14
- The end states are far away:
15
- 1. **Direct generation of images and video** with which users can interact in real-time is too expensive and slow.
16
- 2. **Direct mind interfaces** are not yet possible except for the simplest of tasks.
17
-
18
- Google recognized the traditional options gap or and perhaps the distance to an ultimate end-state and introduced **A2UI (Agent-to-User Interface)** in late 2025. It's a declarative JSON format where agents describe UI components like `text_field` or `button`, and client applications render them natively. It's a solid approach with a security-first architecture.
19
-
20
- But I asked a additional questions:
21
-
22
- * **Why just *describe* the UI? Why not make it *reactive* by design?**
23
- * **Why limit this approach to LLMs?** Why not provide a reactive, cross-platform way for *human developers* to safely express UIs too?
24
-
25
- This is why I built **cDOM (Computational DOM)** and its expression language, **JPRX (JSON Pointer Reactive eXpressions)**.
26
-
27
- Let me show you how it works, step by step.
28
-
29
- ---
30
-
31
- ## Step 1: A Reactive UI with Zero Server Code or Custom JavaScript
32
-
33
- Consider a simple counter. In cDOM, you write this:
34
-
35
- ```json
36
- {
37
- "div": {
38
- "onmount": "=state({ count: 0 }, { name: 'local', scope: $this })",
39
- "children": [
40
- { "p": ["Count: ", "=local/count"] },
41
- { "button": { "onclick": "=local/count++", "children": ["+"] } }
42
- ]
43
- }
44
- }
45
- ```
46
-
47
- That's it. No server. No round-trip. No JavaScript except the underlying cDOM library (which could be JavaScript, Dart or some other language).
48
-
49
- * The `state` helper initializes reactive state (`{ count: 0 }`) scoped to this element.
50
- * The `=local/count` expression is a **live binding**—the paragraph text updates automatically whenever `count` changes.
51
- * The `=local/count++` operator is a direct increment.
52
-
53
- The entire UI is reactive, self-contained, and runs instantly in the browser.
54
-
55
- **This is the spreadsheet paradigm applied to UI**: you define the relationships, and the system handles the updates. JPRX has **over 100** helper functions, covering everything from math and string manipulation to complex array processing and lookup logic, e.g. sum, min, max, sort, filter, etc.
56
-
57
- ---
58
-
59
- ## Step 2: But What If You *Do* Want LLM Integration?
60
-
61
- The counter example is great for client-only interactions. But what if you want to notify an LLM (or any server) when the user clicks a button?
62
-
63
- Just swap the operator for a `=fetch` helper:
64
-
65
- ```json
66
- {
67
- "button": {
68
- "onclick": "=fetch('/api/notify', { method: 'POST', body: $event })",
69
- "children": ["Notify LLM"]
70
- }
71
- }
72
- ```
73
-
74
- When the button is clicked:
75
- 1. The `=fetch` helper sends a POST request to `/api/notify` with a JSON body.
76
- 2. Object bodies are automatically stringified, and `Content-Type: application/json` is set for you.
77
- 3. The LLM (or your backend) receives the event and can respond however it likes.
78
-
79
- This is the **event registration model**: the LLM doesn't need to be notified of *every* interaction. It only hears about the events that matter—the ones where you've wired up a `fetch`. Developers can wire up `fetch` to any event they want, or when LLMs generate a cDOM component, they can wire up `fetch` to notify them of specific user actions.
80
-
81
- This avoids the potential chatty nature of A2UI. Do you really want the LLM notified of every mouse move? Keyboard stroke? Scroll position? If it time and cost effective to have an LLM deal with things like sorting and filtering, or should you let the client handle it?
82
-
83
- ---
84
-
85
- ## Step 3: What If the LLM Wants to *Modify* the UI?
86
-
87
- Here's where cDOM gets truly powerful. What if the server (or LLM) wants to push a new component into the page?
88
-
89
- Enter `=mount`:
90
-
91
- ```json
92
- {
93
- "button": {
94
- "onclick": "=mount('/api/get-widget')",
95
- "children": ["Load Widget"]
96
- }
97
- }
98
- ```
99
-
100
- When clicked, `mount` fetches JSON from `/api/get-widget`, hydrates it as a reactive cDOM element, and **appends it to the document body**.
101
-
102
- But wait, what if the LLM wants to place that widget somewhere specific, like a sidebar? That's where `move` comes in.
103
-
104
- The LLM simply includes a `=move` directive in the component it returns:
105
-
106
- ```json
107
- {
108
- "div": {
109
- "id": "weather-widget",
110
- "onmount": "=move('#dashboard-sidebar', 'afterbegin')",
111
- "children": ["Sunny, 75°F"]
112
- }
113
- }
114
- ```
115
-
116
- Here's what happens:
117
- 1. `mount` fetches the widget and appends it to the `body` (a "safe landing").
118
- 2. The moment the widget mounts, `move` **rips it out** and **teleports** it to `#dashboard-sidebar`.
119
- 3. If a widget with the same `id` already exists there, it's **replaced** - making the operation idempotent.
120
-
121
- **The LLM doesn't need to regenerate the entire page.** It just pushes components that know how to place themselves.
122
-
123
- ---
124
-
125
- ## The Full Picture: Three Levels of Power
126
-
127
- You've now seen the three core capabilities:
128
-
129
- | Level | Use Case | Helper | Server Involved? |
130
- |-------|-----------------------------------|----------------------|------------------|
131
- | 1 | Client-only reactivity | `=state`, `=++`, etc | ❌ No |
132
- | 2 | Notify LLM of user actions | `=fetch` | ✅ Yes (one-way) |
133
- | 3 | LLM pushes new UI to the client | `=mount`, `=move` | ✅ Yes (returns UI)|
134
-
135
- This layered approach means you can build:
136
- * Fully offline-capable apps (Level 1)
137
- * Hybrid apps where the LLM is notified selectively (Level 2)
138
- * Agent-driven apps where the LLM controls the UI in real-time (Level 3)
139
-
140
- All with the same declarative JSON format.
141
-
142
- ---
143
-
144
- ## JPRX: The Expression Language Behind the Magic
145
-
146
- You've been looking at JPRX expressions this whole time. Let me explain what's under the hood.
147
-
148
- **JPRX (JSON Pointer Reactive eXpressions)** is an extension of RFC 6901 JSON Pointer. It adds:
149
-
150
- * **Expressions**: Any path or function name beginning with `=` is an expression. Only the first expression of a nested expression needs to start with `=`.
151
- * **Reactivity**: Any path starting with `=` (e.g., `=app/user/name`) creates a live subscription. When the data changes, so does the UI.
152
- * **Operators**: Prefix and postfix mutation (`=++/count`, `=count--`, `=!!/enabled`).
153
- * **Helper Functions**: Over 100 Excel-like functions (`sum`, `if`, `upper`, `filter`, `map`, `formatDate`) plus state-mutating helpers (`set`, `push`, `assign`), e.g. `=set(/app/user/name, 'John Doe')`.
154
- * **Relative Paths**: Use `../` to navigate up context hierarchies, just like a file system.
155
-
156
- Why is this perfect for LLMs?
157
- 1. **Context-Free Grammar**: No closures, no callbacks. An LLM generates JPRX as easily as it generates a sentence.
158
- 2. **Safe by Design**: No access to `globalThis`, `eval`, or the DOM API outside registered helpers. The application developer controls the helper catalog.
159
- 3. **Streamable**: The LLM can stream components one by one. Each piece is self-describing and self-mounting.
160
-
161
- And why is it great for human developers? Because JPRX reads like a spreadsheet formula. If you can write `=SUM(A1:A10)`, you can write `=sum(/cart/items...price)`.
162
-
163
- ---
164
-
165
- ## The Chattiness Trade-Off
166
-
167
- A key difference between cDOM and A2UI is how user interactions are handled.
168
-
169
- In A2UI, the interaction follows a continuous loop:
170
- 1. **Agent emits** a UI description.
171
- 2. **Client renders** it.
172
- 3. **User interacts** (clicks a button).
173
- 4. **Client signals** the action back to the agent.
174
- 5. **Agent reasons** and emits a new UI.
175
-
176
- This is architecturally clean and ensures the agent is always the "brain" of the operation. However, it can become **chatty**. When every interaction requires a network round-trip, latency and bandwidth usage can accumulate, potentially affecting the user experience.
177
-
178
- More importantly, it creates an **over-reliance on the LLM for trivial tasks**. Does an agent really need to "reason" about how to sort a list of five items alphabetically? Or how to toggle a "Show Details" pane?
179
-
180
- cDOM flips this model. Event handlers are JPRX expressions that execute **client-side**. The user clicks "+", the count increments *locally*. The user clicks "Sort", the list reorders instantly in the browser.
181
-
182
- If the LLM *does* need to know about a significant interaction, you explicitly wire up a `fetch`. But routine UI logic stays where it belongs: on the client.
183
-
184
- **LLM-driven architecture. Native-like responsiveness.**
185
-
186
- ---
187
-
188
- ## Head-to-Head: cDOM vs. A2UI
189
-
190
- | Feature | cDOM/JPRX (Lightview) | A2UI (Google) |
191
- |--------------------------------|------------------------------------------------------------|-----------------------------------------------------------|
192
- | **Core Paradigm** | Declarative + Reactive Computation | Declarative Description |
193
- | **Client-Side Reactivity** | ✅ Built-in via signals & computed expressions | ❌ Requires server round-trip for state changes |
194
- | **Interaction Model** | ✅ Handlers execute client-side (low latency) | ⚠️ Every interaction signals back to agent (chatty) |
195
- | **Security Model** | ✅ Sandboxed helper functions, no arbitrary code | ✅ Sandboxed component catalog, no arbitrary code |
196
- | **Expression Language** | ✅ Full formula language with 100+ helpers | ❌ Data binding only, no computation in the format |
197
- | **LLM Streaming** | ✅ Components self-mount & teleport via `=move` | ✅ Flat component list with IDs for incremental updates |
198
- | **Two-Way Binding** | ✅ `=bind(/path)` for inputs, selects, checkboxes | ⚠️ Component-specific, varies by renderer |
199
- | **State Management** | ✅ Scoped, schema-validated `state` objects | ❌ External state managed by agent or backend |
200
- | **Framework** | Lightview (Vanilla JS, ~5KB core) | Client-agnostic (Flutter, React, Angular renderers) |
201
-
202
- A2UI is an excellent wire format for describing **static snapshots** of a UI. It fits neatly into enterprise ecosystems where Flutter or Angular applications render components.
203
-
204
- cDOM is designed for **dynamic, client-reactive applications** where the UI is a living computation. When your LLM generates a dashboard, you want it to *react* to user input—filter, sort, calculate—without a server round-trip for every interaction.
205
-
206
- And while the current reference implementation is in JavaScript, **nothing prevents cDOM and JPRX from being implemented in other languages like Dart or Swift**. The core concepts—reactive pointers, helper functions, and declarative structure—are universal. You could build a Flutter renderer for cDOM just as easily as Google built one for A2UI.
207
-
208
- ---
209
-
210
- ## Custom Components: Extending the Vocabulary
211
-
212
- A powerful feature of A2UI is **capability negotiation**: the agent queries the client's component catalog before generating UI. This ensures compatibility across different renderers.
213
-
214
- cDOM takes a different approach. There's no formal negotiation protocol, but the ecosystem makes **adding custom components trivial**.
215
-
216
- Libraries like **Lightview** and **Juris.js** allow you to define custom HTML elements declaratively:
217
-
218
- ```javascript
219
- Lightview.define('my-widget', {
220
- template: `<div><slot></slot> - Custom!</div>`,
221
- state: { clicks: 0 }
222
- });
223
- ```
224
-
225
- Once defined, these elements are immediately usable in cDOM:
226
-
227
- ```json
228
- { "my-widget": { "children": ["Hello"] } }
229
- ```
230
-
231
- The philosophy: the **application developer controls the component catalog**, just as in A2UI. The difference is that cDOM skips the negotiation handshake—the LLM uses components it's been trained to expect for that application. If discovery is needed, a JSON manifest of available components can be provided to the LLM as context.
232
-
233
- This trade-off prioritizes **simplicity and low overhead** for applications where the component set is known in advance—which, in my experience, is most applications.
234
-
235
- ---
236
-
237
- ## Why This Matters for the Future of Agentic UI
238
-
239
- I believe the next wave of applications will be **agent-first**. Not chatbots with UI bolted on, but intelligent systems where conversation and application dissolve into one.
240
-
241
- A user might ask:
242
- > "Show me my sales performance for Q4, highlight anything below target, and let me drill down by region."
243
-
244
- An LLM should respond not with a paragraph, but with a **live dashboard**: a chart that filters, a table that sorts, a summary that recalculates. When the user says "focus on EMEA," the agent streams a UI patch that updates the view in place.
245
-
246
- cDOM and JPRX are the foundation for this vision:
247
- * **For Developers**: Write less JavaScript, define relationships, let reactivity handle the rest.
248
- * **For LLMs**: A safe, structured, computable expression language as easy to generate as natural text.
249
- * **For Users**: Rich, instantly reactive interfaces without server round-trip latency.
250
-
251
- ---
252
-
253
- ## Get Started with Lightview
254
-
255
- cDOM and JPRX are part of **Lightview**, my lightweight (~5KB) reactive UI library. It's framework-agnostic, browser-native, and designed for both humans and machines.
256
-
257
- * **Documentation**: [lightview.dev](https://lightview.dev) - Full guides and API reference
258
- * **GitHub**: [github.com/anywhichway/lightview](https://github.com/anywhichway/lightview)
259
- * **npm packages**:
260
- * Lightview (includes cDOM): [`npm install lightview`](https://www.npmjs.com/package/lightview)
261
- * JPRX (standalone parser): [`npm install jprx`](https://www.npmjs.com/package/jprx)
262
-
263
- cDOM is currently in **experimental preview**. I'm actively refining the expression language and helper library based on real-world use cases. I'd love your feedback.
264
-
265
- ---
266
-
267
- ## Conclusion: The Spreadsheet Moment for UI
268
-
269
- Spreadsheets democratized computation. You didn't need to be a programmer to define that `C3 = A1 + B2` and have it update forever.
270
-
271
- cDOM is designed to be that moment for user interfaces. A format where an LLM—or a human—can declare: *this text shows the count; this button increments it; this chart sums the sales*. And the system handles the rest.
272
-
273
- In a world where AI agents are becoming the new developers, the language they speak to the browser matters. I think that language should be safe, reactive, and computational from the ground up.
274
-
275
- **That's cDOM. Welcome to the Computational DOM.**
276
-
277
- ---
278
-
279
- *Simon Y. Blackwell is the creator of Lightview, a lightweight reactive library for building web applications. He believes that the best code is the code you don't have to write, and that LLMs should be first-class citizens in the UI development process.*