lightview 2.3.8 → 2.4.4
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/.gemini/CODE_ANALYSIS_AND_IMPROVEMENT_PLAN.md +56 -0
- package/AI-GUIDANCE.md +259 -0
- package/README.md +35 -0
- package/components/data-display/diff.js +36 -4
- package/docs/api/hypermedia.html +75 -5
- package/docs/api/index.html +3 -3
- package/docs/api/nav.html +0 -16
- package/docs/articles/html-vs-json-partials.md +102 -0
- package/docs/articles/lightview-vs-htmx.md +610 -0
- package/docs/benchmarks/tagged-fragment.js +36 -0
- package/docs/components/chart.html +157 -210
- package/docs/components/component-nav.html +1 -1
- package/docs/components/diff.html +33 -21
- package/docs/components/gallery.html +107 -4
- package/docs/components/index.css +18 -3
- package/docs/components/index.html +20 -9
- package/docs/dom-benchmark.html +644 -0
- package/docs/getting-started/index.html +2 -2
- package/docs/hypermedia/index.html +391 -0
- package/docs/hypermedia/nav.html +17 -0
- package/docs/index.html +128 -18
- package/index.html +59 -10
- package/lightview-all.js +223 -67
- package/lightview-cdom.js +1 -2
- package/lightview-x.js +144 -13
- package/lightview.js +85 -277
- package/package.json +2 -2
- package/src/lightview-cdom.js +1 -5
- package/src/lightview-x.js +158 -27
- package/src/lightview.js +94 -60
- package/docs/articles/calculator-no-javascript-hackernoon.md +0 -283
- package/docs/articles/calculator-no-javascript.md +0 -290
- package/docs/articles/part1-reference.md +0 -236
- package/lightview.js.bak +0 -1
- package/test-xpath.html +0 -63
- package/test_error.txt +0 -0
- package/test_output.txt +0 -0
- package/test_output_full.txt +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# cDOM / JPRX Code Analysis and Improvement Recommendations
|
|
2
|
+
|
|
3
|
+
## 1. Executive Summary
|
|
4
|
+
This document outlines the analysis of the current JPRX (JSON Reactive Path eXpressions) and cDOM implementation within Lightview. While the system is powerful and integral to the framework's reactivity, its core logic (`jprx/parser.js`) has grown into a monolithic module that mixes tokenization, parsing, evaluation, and runtime state management. The primary recommendation is to refactor this into distinct layers to improve maintainability, performance, and testability.
|
|
5
|
+
|
|
6
|
+
## 2. Current State Analysis
|
|
7
|
+
|
|
8
|
+
### 2.1 Code Structure
|
|
9
|
+
* **Monolithic Design**: `jprx/parser.js` is approximately 1,900 lines long. It encapsulates:
|
|
10
|
+
* **Tokenizer**: Regex-based lexer (`tokenize`).
|
|
11
|
+
* **Pratt Parser**: Top-down operator precedence parser.
|
|
12
|
+
* **Evaluator**: `evaluateAST` and `resolvePath` logic.
|
|
13
|
+
* **Runtime Types**: `BindingTarget`, `LazyValue`.
|
|
14
|
+
* **Global Registry**: Storage for helpers and operators.
|
|
15
|
+
* **Coupling**: The parser is tightly coupled with Lightview's specific reactivity model (Signals/Proxies) via direct imports and assumption of `Lightview.state` structure.
|
|
16
|
+
|
|
17
|
+
### 2.2 Performance
|
|
18
|
+
* **Repeated Parsing**: Currently, there is no visible caching mechanism for parsed ASTs. Every time an expression is evaluated (unless manually memoized externally), it goes through the tokenization and parsing steps.
|
|
19
|
+
* **Object Creation**: The heavy use of intermediate objects during AST traversals and resolution could trigger frequent garbage collection in high-frequency updates.
|
|
20
|
+
|
|
21
|
+
### 2.3 DX and Reliability
|
|
22
|
+
* **Error Reporting**: Syntax errors in JPRX expressions often result in generic failures or silent returns, making debugging difficult for the end-user.
|
|
23
|
+
* **Complexity**: Adding new operators or features requires modifying the central file, increasing the risk of regressions.
|
|
24
|
+
|
|
25
|
+
## 3. Improvement Recommendations
|
|
26
|
+
|
|
27
|
+
### Phase 1: Modularization (High Priority)
|
|
28
|
+
Decompose `jprx/parser.js` into focused modules under a `jprx/core/` directory:
|
|
29
|
+
|
|
30
|
+
1. **`tokenization.js`**: Pure functions handling string-to-token conversion.
|
|
31
|
+
2. **`grammar.js`**: Definition of operators, precedence levels, and AST node types.
|
|
32
|
+
3. **`parser.js`**: The Pratt parser implementation that outputs a pure AST.
|
|
33
|
+
4. **`runtime.js`**: The `evaluateAST` logic and `BindingTarget`/`LazyValue` classes.
|
|
34
|
+
5. **`registry.js`**: Singleton or context-based registry for helpers and operators.
|
|
35
|
+
|
|
36
|
+
### Phase 2: Performance Enhancements
|
|
37
|
+
1. **LRU Cache for ASTs**: Implement a Least Recently Used cache for the `tokenize -> parse` pipeline. If an expression string `count + 1` is seen again, serve the cached AST immediately.
|
|
38
|
+
2. **Fast-Path for Simple Paths**: 90% of expressions are likely simple property access (e.g., `user.name`). Implement a proper regex check to bypass the full parser for these cases and use direct traversal.
|
|
39
|
+
3. **Instruction Caching**: For repeated evaluations of the same AST, consider compiling to a closure (similar to how `new Function` works, but safe and sandboxed) if performance bottlenecks appear.
|
|
40
|
+
|
|
41
|
+
### Phase 3: Robustness and Validation
|
|
42
|
+
1. **Fuzz Testing**: Implement grammar-based fuzz testing to ensure the parser does not crash on malformed inputs.
|
|
43
|
+
2. **Strict Mode**: Introduce a strict mode that throws descriptive errors for undefined paths or invalid operations, rather than silently failing.
|
|
44
|
+
3. **Type Safety**: If possible, add JSDoc type definitions to all internal AST nodes to aid tooling and potential future TypeScript migration.
|
|
45
|
+
|
|
46
|
+
## 4. Code Specific Observations
|
|
47
|
+
|
|
48
|
+
* **`BindingTarget` Implementation**: The current "duck-typing" (`isBindingTarget = true`) is practical but could be cleaner using `Symbol.for('jprx.bindingTarget')` to avoid property collision.
|
|
49
|
+
* **Operator Registration**: The dynamic `registerOperator` is powerful but allows overwriting core behavior. Consider locking core operators (math, logic) after initialization.
|
|
50
|
+
* **Reactivity Integration**: The dependency on `Lightview.state` could be abstracted behind an interface (e.g., `IReactiveSource`), allowing JPRX to be used with other state management libraries if desired.
|
|
51
|
+
|
|
52
|
+
## 5. Next Steps
|
|
53
|
+
1. Create the `jprx/core` directory structure.
|
|
54
|
+
2. Move `BindingTarget` and `LazyValue` to a `types.js` file.
|
|
55
|
+
3. Extract the `tokenize` function and unit test it in isolation.
|
|
56
|
+
4. Draft the `AST` cache mechanism.
|
package/AI-GUIDANCE.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Lightview AI Guidance
|
|
2
|
+
|
|
3
|
+
This document is the **definitive guide** for Large Language Models (LLMs) on how to effectively use the Lightview library. It covers all development workflows, particularly emphasizing correct source file usage, hypermedia patterns, and dynamic generation.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Critical: Source Files vs Modules](#source-files)
|
|
7
|
+
2. [The Four UI Syntaxes](#the-four-ui-syntaxes)
|
|
8
|
+
3. [Hypermedia & Lightview X](#hypermedia-lightview-x)
|
|
9
|
+
4. [JPRX & cDOM (AI-Safe Generation)](#jprx-cdom)
|
|
10
|
+
5. [Component System](#component-system)
|
|
11
|
+
6. [Routing & Navigation](#routing-navigation)
|
|
12
|
+
7. [AI Development Strategies](#ai-development-strategies)
|
|
13
|
+
8. [Deep Links & Resources](#deep-links)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<a name="source-files"></a>
|
|
18
|
+
## 1. Critical: Source Files vs Modules
|
|
19
|
+
|
|
20
|
+
**PAY CAREFUL ATTENTION TO FILE TYPES.**
|
|
21
|
+
|
|
22
|
+
* **Standard Scripts (`.js`)**: These files exist in the root and are suitable for direct browser inclusion via script tags or simple bundling.
|
|
23
|
+
* `lightview.js`: The core reactive engine (Signals, State, $, Effect).
|
|
24
|
+
* `lightview-x.js`: The "Extension" module (Hypermedia, src fetching, simple validation, vDOM/oDOM conversion).
|
|
25
|
+
* `lightview-router.js`: The Router implementation.
|
|
26
|
+
* `lightview-cdom.js`: The parser for JPRX and cDOM.
|
|
27
|
+
|
|
28
|
+
* **ES Modules (in subdirectories)**: Files in `jprx/`, `components/`, etc., are ES modules.
|
|
29
|
+
* **Do not** reference these directly in a generic HTML script tag without `type="module"`.
|
|
30
|
+
* **Do** import them in your application logic files (e.g., `import { ... } from './jprx/parser.js'`).
|
|
31
|
+
|
|
32
|
+
**Guidance**: When helping a user set up a new project, prefer importing from the root standard scripts for simplicity, or set up a proper `build.js` if deep module imports are needed.
|
|
33
|
+
|
|
34
|
+
**Note on Syntaxes**:
|
|
35
|
+
- **Tagged API**: Supported in `lightview.js`.
|
|
36
|
+
- **vDOM**: Supported in `lightview.js` (standard `{ tag: ... }` objects).
|
|
37
|
+
- **oDOM**: Requires `lightview-x.js` (converts `{ div: ... }` usage).
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
<a name="the-four-ui-syntaxes"></a>
|
|
42
|
+
## 2. The Four UI Syntaxes
|
|
43
|
+
|
|
44
|
+
Choose the syntax that matches your goal.
|
|
45
|
+
|
|
46
|
+
### A. Tagged API (Best for Logic)
|
|
47
|
+
Javascript functions representing HTML tags. Best for building applications with complex logic.
|
|
48
|
+
```javascript
|
|
49
|
+
const { div, h1, button } = Lightview.tags;
|
|
50
|
+
const count = signal(0);
|
|
51
|
+
|
|
52
|
+
const view = div({ class: "p-4" },
|
|
53
|
+
h1("Counter"),
|
|
54
|
+
button({ onclick: () => count.value++ }, () => `Count: ${count.value}`)
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### B. vDOM (Best for Structured Data)
|
|
59
|
+
Explicit JSON structure. Use this when you need a standard, serializable format.
|
|
60
|
+
```javascript
|
|
61
|
+
const view = {
|
|
62
|
+
tag: "div",
|
|
63
|
+
attributes: { class: "p-4" },
|
|
64
|
+
children: [
|
|
65
|
+
{ tag: "h1", children: ["Counter"] },
|
|
66
|
+
{ tag: "button", attributes: { onclick: () => count.value++ }, children: [() => `Count: ${count.value}`] }
|
|
67
|
+
]
|
|
68
|
+
};
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### C. oDOM (Best for Compact Templates)
|
|
72
|
+
"Object DOM" uses keys as tags. It is significantly more concise. **Preferred for configuration-based UIs.**
|
|
73
|
+
```javascript
|
|
74
|
+
const view = {
|
|
75
|
+
div: {
|
|
76
|
+
class: "p-4",
|
|
77
|
+
children: [
|
|
78
|
+
{ h1: "Counter" },
|
|
79
|
+
{ button: { onclick: "...", children: ["Increment"] } }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### D. Custom Elements (Best for Hybrid Apps)
|
|
86
|
+
Standard HTML tags powered by Lightview. Use these when enhancing an existing HTML page.
|
|
87
|
+
```html
|
|
88
|
+
<lv-button onclick="alert('clicked')">Click Me</lv-button>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
<a name="hypermedia-lightview-x"></a>
|
|
94
|
+
## 3. Hypermedia & Lightview X
|
|
95
|
+
|
|
96
|
+
Lightview X adds powerful **Hypermedia** capabilities to standard HTML elements.
|
|
97
|
+
|
|
98
|
+
### The `src` and `href` Attributes (Hypermedia)
|
|
99
|
+
* **`src`**: Fetches content and replaces the element or its content.
|
|
100
|
+
* **Support**: `.html`, `.json`, `.vdom`, `.odom`, `.cdom`, `.cdomc`
|
|
101
|
+
* **Usage**: `<div src="/components/user-card.vdom"></div>`
|
|
102
|
+
* **`href`**: Non-standard tags (like `div`) with `href` act as "Links".
|
|
103
|
+
* **Behavior**: Clicking them fetches the content at the URL and replaces the element's `src`.
|
|
104
|
+
* **Targeting**: Use `target="#dest:beforeend"` to direct the content elsewhere.
|
|
105
|
+
* **Usage**: `<div href="/api/next-page" target="#content:beforeend">Load More</div>`
|
|
106
|
+
|
|
107
|
+
### Advanced Fetches (`data-method` & `data-body`)
|
|
108
|
+
Customize HTTP requests for `src` and `href` actions.
|
|
109
|
+
|
|
110
|
+
* **`data-method`**: Specify the HTTP verb (e.g., `POST`, `PUT`, `DELETE`). Defaults to `GET`.
|
|
111
|
+
* **`data-body`**: The data to send with the request.
|
|
112
|
+
* **CSS Selector (Default)**: Grabs the data from the DOM.
|
|
113
|
+
* `form`: Serialized as `FormData`.
|
|
114
|
+
* `input`/`select`/`textarea`: Sends the current `value`.
|
|
115
|
+
* `checkbox`/`radio`: Sends `value` only if checked.
|
|
116
|
+
* Other elements: Sends `innerText`.
|
|
117
|
+
* **`javascript:expr`**: Evaluates a Javascript expression (has access to `state` and `signal`).
|
|
118
|
+
* **`json:{...}`**: Sends a literal JSON string (sets `Content-Type: application/json`).
|
|
119
|
+
* **`text:...`**: Sends raw text (sets `Content-Type: text/plain`).
|
|
120
|
+
* **GET Requests**: If the method is `GET`, the data from `data-body` is automatically converted into **URL Query Parameters**.
|
|
121
|
+
|
|
122
|
+
**Usage**:
|
|
123
|
+
```html
|
|
124
|
+
<!-- Post a form -->
|
|
125
|
+
<button href="/api/user/save" data-method="POST" data-body="#user-form">Save</button>
|
|
126
|
+
|
|
127
|
+
<!-- Fetch with query params from an input -->
|
|
128
|
+
<button href="/api/search" data-body="#search-input" target="#results">Search</button>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
* **Template Literals**: Supported in HTML, vDOM, and oDOM strings (e.g., `class="${ val > 10 ? 'red' : 'blue' }"`) via `lightview-x.js`.
|
|
132
|
+
* **Gating**:
|
|
133
|
+
1. **`Lightview.hooks.validateUrl`**: Intercept/block URLs.
|
|
134
|
+
2. **`lv-before`**: Attribute that gates events (e.g., `lv-before="click: throttle(500)"` or custom functions).
|
|
135
|
+
|
|
136
|
+
### Logic in Attributes (`template literals`)
|
|
137
|
+
Lightview X allows embedded `${}` expressions in attributes for simple reactivity
|
|
138
|
+
```javascript
|
|
139
|
+
{
|
|
140
|
+
div: {
|
|
141
|
+
class: "${ count.value > 10 ? 'text-red-500' : 'text-green-500' }",
|
|
142
|
+
children: ["Status"]
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
<a name="jprx-cdom"></a>
|
|
150
|
+
## 4. JPRX & cDOM (Safe Dynamic UI Generation For Humans and AIs)
|
|
151
|
+
|
|
152
|
+
**cDOM (Computed DOM)** and **JPRX (JSON Reactive Expressions)** allow you to build fully reactive UIs using **only JSON**.
|
|
153
|
+
|
|
154
|
+
### JPRX Helper Reference
|
|
155
|
+
JPRX supports a wide range of helpers. AI agents should use these instead of trying to write JS when builing streaming UIs at runtime.
|
|
156
|
+
|
|
157
|
+
| Category | Helpers |
|
|
158
|
+
| :--- | :--- |
|
|
159
|
+
| **Math** | `add`, `subtract`, `multiply`, `divide`, `mod`, `pow`, `abs`, `round`, `ceil`, `floor`, `sqrt`, `negate`, `toPercent` |
|
|
160
|
+
| **Logic** | `and`, `or`, `not`, `if`, `eq`, `neq`, `gt`, `lt`, `gte`, `lte` |
|
|
161
|
+
| **String** | `join`, `concat`, `upper`, `lower`, `trim`, `len`, `split`, `replace`, `capitalize`, `contains` |
|
|
162
|
+
| **Array** | `map`, `filter`, `reduce`, `push`, `pop`, `sort`, `reverse`, `slice`, `find` |
|
|
163
|
+
| **Stats** | `sum`, `avg`, `min`, `max`, `median`, `stdev`, `variance` |
|
|
164
|
+
| **Data** | `lookup(val, searchArr, resultArr)` (VLOOKUP-style) |
|
|
165
|
+
| **State** | `state(val, opts)`, `set(path, val)`, `bind(path)`, `increment`, `decrement`, `toggle` |
|
|
166
|
+
| **DOM** | `xpath(expr)` (Backward-looking only), `move(target, loc)` |
|
|
167
|
+
| **Net** | `fetchHelper(url, opts)`, `mount(url, opts)` |
|
|
168
|
+
|
|
169
|
+
### The "Decentralized Layout" Pattern (AI Strategy)
|
|
170
|
+
1. **Define**: Create a self-contained component with state.
|
|
171
|
+
2. **Move**: Use `=move('#target')` in `onmount` to teleport it.
|
|
172
|
+
3. **Stream**: Determine the update needed, generate the `.cdomc`, and let it patch itself.
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
/* .cdomc format */
|
|
176
|
+
{
|
|
177
|
+
div: {
|
|
178
|
+
id: "widget-1",
|
|
179
|
+
onmount: ["=state({val:0}, {name:'w1', scope:$this})", "=move('#sidebar')"],
|
|
180
|
+
children: [ { p: "Val: =/w1/val" } ]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
<a name="component-system"></a>
|
|
188
|
+
## 5. Component System
|
|
189
|
+
|
|
190
|
+
Built on **DaisyUI** and **Tailwind CSS**.
|
|
191
|
+
|
|
192
|
+
* **Import**: `import { Button } from './components/index.js';`
|
|
193
|
+
* **Init**: `LightviewX.initComponents()` (Shadow DOM).
|
|
194
|
+
* **Theming**: `Lightview.setTheme('dark')` or `localStorage.setItem('lightview-theme', 'dark')`.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
<a name="routing-navigation"></a>
|
|
199
|
+
## 6. Routing & Navigation
|
|
200
|
+
|
|
201
|
+
The `LightviewRouter` uses a pipeline (chain) architecture.
|
|
202
|
+
|
|
203
|
+
### Advanced: Middleware Chains
|
|
204
|
+
You can chain multiple handlers for a single route. This is powerful for authentication or data pre-loading.
|
|
205
|
+
```javascript
|
|
206
|
+
const checkAuth = async (ctx) => {
|
|
207
|
+
const user = await getUser();
|
|
208
|
+
if (!user) {
|
|
209
|
+
LightviewRouter.navigate('/login');
|
|
210
|
+
return null; // Stop chain
|
|
211
|
+
}
|
|
212
|
+
return { ...ctx, user }; // Pass data to next handler
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
router.use(
|
|
216
|
+
'/admin/*',
|
|
217
|
+
checkAuth, // 1. Guard
|
|
218
|
+
'/views/admin.html' // 2. Render
|
|
219
|
+
);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Route Patterns
|
|
223
|
+
* **Static**: `router.use('/about', 'about.html')`
|
|
224
|
+
* **Wildcard**: `router.use('/docs/*', handler)` -> matches `/docs/api/v1`
|
|
225
|
+
* **Parameters**: `router.use('/users/:id', handler)` -> `ctx.params.id`
|
|
226
|
+
* **Replacement**: `router.use('/blog/:slug', '/content/posts/:slug.html')` -> Maps URL params to file path automatically.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
<a name="ai-development-strategies"></a>
|
|
231
|
+
## 7. AI Development Strategies
|
|
232
|
+
|
|
233
|
+
**Scenario A: "I need a full web application."**
|
|
234
|
+
* **Strategy**: Use **Tagged API** + **lightview-router.js**.
|
|
235
|
+
* **Output**: Generate `.js` files.
|
|
236
|
+
|
|
237
|
+
**Scenario B: "I need a dynamic dashboard widget of unknown nature at app development time."**
|
|
238
|
+
* **Strategy**: Use **cDOM/JPRX**.
|
|
239
|
+
* **Output**: Stream `.cdomc` chunks.
|
|
240
|
+
|
|
241
|
+
**Scenario C: "I need a config-driven UI."**
|
|
242
|
+
* **Strategy**: Use **oDOM**.
|
|
243
|
+
* **Output**: Generate `.json` config files.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
<a name="deep-links"></a>
|
|
248
|
+
## 8. Deep Links & Resources
|
|
249
|
+
|
|
250
|
+
* **Documentation Home**: [/docs/index.html](file:///c:/Users/Owner/AntigravityProjects/lightview/docs/index.html)
|
|
251
|
+
* **Core Logic**: [/lightview.js](file:///c:/Users/Owner/AntigravityProjects/lightview/lightview.js)
|
|
252
|
+
* **Extension (Hypermedia)**: [/lightview-x.js](file:///c:/Users/Owner/AntigravityProjects/lightview/lightview-x.js)
|
|
253
|
+
* **Router**: [/lightview-router.js](file:///c:/Users/Owner/AntigravityProjects/lightview/lightview-router.js)
|
|
254
|
+
* **CDOM/JPRX Parser**: [/lightview-cdom.js](file:///c:/Users/Owner/AntigravityProjects/lightview/lightview-cdom.js)
|
|
255
|
+
* **Component Index**: [/components/index.js](file:///c:/Users/Owner/AntigravityProjects/lightview/components/index.js)
|
|
256
|
+
* **JPRX Helpers**: [/jprx/helpers/](file:///c:/Users/Owner/AntigravityProjects/lightview/jprx/helpers/)
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
© 2026 AnyWhichWay LLC.
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ A lightweight reactive UI library with signal-based reactivity and a clean API.
|
|
|
4
4
|
|
|
5
5
|
Access the full documentation and interactive examples at [lightview.dev](https://lightview.dev).
|
|
6
6
|
|
|
7
|
+
LLMs should read [AI-GUIDANCE.md](AI-GUIDANCE.md) for instructions on how to use Lightview.
|
|
8
|
+
|
|
7
9
|
## Modular Architecture
|
|
8
10
|
|
|
9
11
|
**Core Library**: ~7.75KB | **Extended (Hypermedia + Components)**: ~20KB | **Router**: ~3KB
|
|
@@ -25,6 +27,39 @@ Lightview supports multiple ways to build UIs, allowing you to pick the style th
|
|
|
25
27
|
|
|
26
28
|
All syntaxes share the same underlying reactive engine based on **Signals** and **State**.
|
|
27
29
|
|
|
30
|
+
## cDOM & JPRX: AI-Assisted Declarative UIs
|
|
31
|
+
|
|
32
|
+
Lightview includes **cDOM** (Computed DOM) powered by **JPRX** (JSON Pointer Reactive eXpressions)—a fully declarative UI layer that requires **zero custom JavaScript**. Much like **XPath** provides a powerful query language for XML, JPRX provides a reactive, formula-based language for JSON state.
|
|
33
|
+
|
|
34
|
+
### Why This Matters for AI Collaboration
|
|
35
|
+
|
|
36
|
+
Traditional UI development requires AI agents to generate imperative JavaScript code, which introduces security risks (XSS, code injection) and unpredictable behavior. cDOM flips this model:
|
|
37
|
+
|
|
38
|
+
- **Pure Data, No Code**: UIs are defined as JSON structures with reactive expressions—no `eval()`, no `new Function()`, no executable strings.
|
|
39
|
+
- **Safe by Design**: AI agents can generate, modify, and compose UIs without producing potentially harmful code.
|
|
40
|
+
- **Auditable Output**: Every generated UI is a transparent data structure that can be validated, diffed, and sandboxed.
|
|
41
|
+
|
|
42
|
+
### Example: A Reactive Counter (No JavaScript)
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"state": { "count": 0 },
|
|
47
|
+
"div": {
|
|
48
|
+
"children": [
|
|
49
|
+
{ "p": "{$count}" },
|
|
50
|
+
{ "button": { "onclick": "{set('count', add(count, 1))}", "children": ["Increment"] } }
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This JSON is **the entire application**. The `{...}` expressions are JPRX—a sandboxed, spreadsheet-like formula language (inspired by **XPath** and **JSON Pointers**) that resolves paths, calls registered helpers, and triggers reactivity automatically.
|
|
57
|
+
|
|
58
|
+
### Learn More
|
|
59
|
+
|
|
60
|
+
- [cDOM Documentation](https://lightview.dev/docs/cdom)
|
|
61
|
+
- [JPRX Expression Reference](https://lightview.dev/docs/cdom#jprx)
|
|
62
|
+
|
|
28
63
|
## Quick Start
|
|
29
64
|
|
|
30
65
|
### 1. Tagged API (Concise & Expressive)
|
|
@@ -20,7 +20,7 @@ const Diff = (props = {}, ...children) => {
|
|
|
20
20
|
const { div, shadowDOM } = tags;
|
|
21
21
|
|
|
22
22
|
const {
|
|
23
|
-
aspectRatio = 'aspect-
|
|
23
|
+
aspectRatio = 'aspect-video',
|
|
24
24
|
useShadow,
|
|
25
25
|
class: className = '',
|
|
26
26
|
...rest
|
|
@@ -67,7 +67,7 @@ Diff.Item1 = (props = {}, ...children) => {
|
|
|
67
67
|
|
|
68
68
|
if (src) {
|
|
69
69
|
return tags.div({ class: `diff-item-1 ${className}`.trim(), role: 'img', ...rest },
|
|
70
|
-
tags.img({ src, alt })
|
|
70
|
+
tags.img({ src, alt, style: 'width: 100%; height: 100%; object-fit: cover; display: block;' })
|
|
71
71
|
);
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -85,7 +85,7 @@ Diff.Item2 = (props = {}, ...children) => {
|
|
|
85
85
|
|
|
86
86
|
if (src) {
|
|
87
87
|
return tags.div({ class: `diff-item-2 ${className}`.trim(), role: 'img', tabindex: '0', ...rest },
|
|
88
|
-
tags.img({ src, alt })
|
|
88
|
+
tags.img({ src, alt, style: 'width: 100%; height: 100%; object-fit: cover; display: block;' })
|
|
89
89
|
);
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -99,7 +99,15 @@ Diff.Resizer = (props = {}) => {
|
|
|
99
99
|
const { tags } = globalThis.Lightview || {};
|
|
100
100
|
if (!tags) return null;
|
|
101
101
|
|
|
102
|
-
return tags.
|
|
102
|
+
return tags.input({
|
|
103
|
+
type: 'range',
|
|
104
|
+
min: '0',
|
|
105
|
+
max: '100',
|
|
106
|
+
value: '50',
|
|
107
|
+
class: 'diff-resizer',
|
|
108
|
+
oninput: "this.parentElement.style.setProperty('--diff-offset', this.value + '%')",
|
|
109
|
+
...props
|
|
110
|
+
});
|
|
103
111
|
};
|
|
104
112
|
|
|
105
113
|
const tags = globalThis.Lightview.tags;
|
|
@@ -108,4 +116,28 @@ tags['Diff.Item1'] = Diff.Item1;
|
|
|
108
116
|
tags['Diff.Item2'] = Diff.Item2;
|
|
109
117
|
tags['Diff.Resizer'] = Diff.Resizer;
|
|
110
118
|
|
|
119
|
+
// Register as Custom Elements using customElementWrapper
|
|
120
|
+
if (globalThis.LightviewX && typeof customElements !== 'undefined') {
|
|
121
|
+
const { customElementWrapper } = globalThis.LightviewX;
|
|
122
|
+
|
|
123
|
+
if (!customElements.get('lv-diff')) {
|
|
124
|
+
customElements.define('lv-diff', customElementWrapper(Diff, {
|
|
125
|
+
attributeMap: { aspectRatio: String }
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
if (!customElements.get('lv-diff-item1')) {
|
|
129
|
+
customElements.define('lv-diff-item1', customElementWrapper(Diff.Item1, {
|
|
130
|
+
attributeMap: { src: String, alt: String }
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
if (!customElements.get('lv-diff-item2')) {
|
|
134
|
+
customElements.define('lv-diff-item2', customElementWrapper(Diff.Item2, {
|
|
135
|
+
attributeMap: { src: String, alt: String }
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
if (!customElements.get('lv-diff-resizer')) {
|
|
139
|
+
customElements.define('lv-diff-resizer', customElementWrapper(Diff.Resizer, {}));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
111
143
|
export default Diff;
|
package/docs/api/hypermedia.html
CHANGED
|
@@ -70,7 +70,10 @@ Lightview.hooks.validateUrl = () => true;</code></pre>
|
|
|
70
70
|
|
|
71
71
|
<h3 id="vdom-object-dom">vDOM and Object DOM</h3>
|
|
72
72
|
<p>
|
|
73
|
-
Files with <code
|
|
73
|
+
Files with <code>.<a id="vdom" href="/docs/api/elements#vdom">vdom</a></code>,
|
|
74
|
+
<code>.<a id="odom" href="/docs/api/elements#object-dom">odom</a></code> or
|
|
75
|
+
<code>.<a id="cdom" href="/docs/cdom">cdom</a></code> extensions are parsed as JSON and converted to
|
|
76
|
+
elements.
|
|
74
77
|
Any <a href="#template-literals">Template Literals</a> within the JSON values are automatically resolved.
|
|
75
78
|
</p>
|
|
76
79
|
<pre><code>// /api/cards.vdom
|
|
@@ -80,9 +83,76 @@ Lightview.hooks.validateUrl = () => true;</code></pre>
|
|
|
80
83
|
]
|
|
81
84
|
|
|
82
85
|
// Load vDOM
|
|
83
|
-
div({ src: '/api/cards.vdom' })
|
|
86
|
+
div({ src: '/api/cards.vdom' })
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
// Load safe, reactive HTML
|
|
89
|
+
div({ src: '/api/ai-generated.cdom' })
|
|
90
|
+
</code></pre>
|
|
91
|
+
|
|
92
|
+
<h2 id="advanced-fetches">Advanced Fetches (data-method & data-body)</h2>
|
|
93
|
+
<p>
|
|
94
|
+
You can customize the HTTP request method and body for any <code>src</code> or <code>href</code> action
|
|
95
|
+
using <code>data-method</code> and <code>data-body</code>.
|
|
96
|
+
</p>
|
|
97
|
+
|
|
98
|
+
<h3>1. Request Methods</h3>
|
|
99
|
+
<p>Use <code>data-method</code> to specify an HTTP verb. Defaults to <code>GET</code>.</p>
|
|
100
|
+
<pre><code>// Send a DELETE request
|
|
101
|
+
button({
|
|
102
|
+
href: '/api/items/123',
|
|
103
|
+
'data-method': 'DELETE',
|
|
104
|
+
target: '#status-log'
|
|
105
|
+
}, 'Delete Item')</code></pre>
|
|
106
|
+
|
|
107
|
+
<h3>2. Request Bodies</h3>
|
|
108
|
+
<p>Use <code>data-body</code> to send data. If no prefix is used, it is treated as a CSS selector.</p>
|
|
109
|
+
|
|
110
|
+
<h4>CSS Selectors (Default)</h4>
|
|
111
|
+
<p>Grabs data from the DOM based on the element type:</p>
|
|
112
|
+
<ul>
|
|
113
|
+
<li><strong>Forms:</strong> If the selector points to a <code><form></code>, the entire form is
|
|
114
|
+
serialized as <code>FormData</code>.
|
|
115
|
+
</li>
|
|
116
|
+
<li><strong>Checkboxes/Radios:</strong> Only sends the <code>value</code> if the element is
|
|
117
|
+
<code>checked</code>. Otherwise, no data is sent.
|
|
118
|
+
</li>
|
|
119
|
+
<li><strong>Input/Select/Textarea:</strong> Sends the current <code>value</code>.</li>
|
|
120
|
+
<li><strong>Other Elements:</strong> Sends the <code>innerText</code> (e.g., from a <code><div></code>
|
|
121
|
+
or <code><span></code>).
|
|
122
|
+
</li>
|
|
123
|
+
</ul>
|
|
124
|
+
<pre><code><!-- Send the value of an input (Query param search?body=...) -->
|
|
125
|
+
<button href="/api/search" data-body="#search-input" target="#results">Search</button>
|
|
126
|
+
<input id="search-input" type="text">
|
|
127
|
+
|
|
128
|
+
<!-- Send an entire form as POST -->
|
|
129
|
+
<button href="/api/user/update" data-method="POST" data-body="#user-form">Save</button>
|
|
130
|
+
<form id="user-form">
|
|
131
|
+
<input name="email" value="user@example.com">
|
|
132
|
+
</form></code></pre>
|
|
133
|
+
|
|
134
|
+
<h4>Prefixes</h4>
|
|
135
|
+
<p>You can use prefixes to control exactly how the body is constructed:</p>
|
|
136
|
+
<ul>
|
|
137
|
+
<li><code>javascript:</code> - Evaluates an expression (has access to <code>state</code> and
|
|
138
|
+
<code>signal</code>).
|
|
139
|
+
</li>
|
|
140
|
+
<li><code>json:</code> - Sends a literal JSON string (sets <code>Content-Type: application/json</code>).
|
|
141
|
+
</li>
|
|
142
|
+
<li><code>text:</code> - Sends raw text (sets <code>Content-Type: text/plain</code>).</li>
|
|
143
|
+
</ul>
|
|
144
|
+
<pre><code><!-- Dynamic calculation -->
|
|
145
|
+
<button href="/api/log" data-body="javascript:state.user.id">Log ID</button>
|
|
146
|
+
|
|
147
|
+
<!-- Literal JSON -->
|
|
148
|
+
<button href="/api/config" data-method="POST" data-body='json:{"theme": "dark"}'>Set Dark Mode</button></code></pre>
|
|
149
|
+
|
|
150
|
+
<h4>GET Request Handling</h4>
|
|
151
|
+
<p>If the method is <code>GET</code>, the data provided via <code>data-body</code> is automatically converted
|
|
152
|
+
into <strong>URL Query Parameters</strong>. If multiple values are found (like in a form), all are
|
|
153
|
+
appended to the URL.</p>
|
|
154
|
+
|
|
155
|
+
<h2 id="cloning-dom-elements">Cloning DOM Elements</h2>
|
|
86
156
|
<p>
|
|
87
157
|
Use CSS selectors to clone existing elements:
|
|
88
158
|
</p>
|
|
@@ -299,7 +369,7 @@ const app = div({ class: 'app' },
|
|
|
299
369
|
})
|
|
300
370
|
);</code></pre>
|
|
301
371
|
|
|
302
|
-
<h3>Using
|
|
372
|
+
<h3>Using Lightview Syntax</h3>
|
|
303
373
|
<pre><code><div class="app">
|
|
304
374
|
<nav class="sidebar">
|
|
305
375
|
<button href="/pages/dashboard.html" target="#content">📊 Dashboard</button>
|
|
@@ -309,7 +379,7 @@ const app = div({ class: 'app' },
|
|
|
309
379
|
<main id="content" src="/pages/dashboard.html"></main>
|
|
310
380
|
</div></code></pre>
|
|
311
381
|
|
|
312
|
-
<h3>Using HTMX</h3>
|
|
382
|
+
<h3>vs. Using HTMX</h3>
|
|
313
383
|
<pre><code><div class="app">
|
|
314
384
|
<nav class="sidebar">
|
|
315
385
|
<button hx-get="/pages/dashboard.html" hx-target="#content">📊 Dashboard</button>
|
package/docs/api/index.html
CHANGED
|
@@ -96,12 +96,12 @@
|
|
|
96
96
|
</td>
|
|
97
97
|
</tr>
|
|
98
98
|
<tr>
|
|
99
|
-
<td><a href="
|
|
99
|
+
<td><a href="/docs/hypermedia/#fetching-content"><code>src="..."</code></a></td>
|
|
100
100
|
<td>Attribute to automatically fetch HTML or JSON representing HTML and inject it into the element.
|
|
101
101
|
</td>
|
|
102
102
|
</tr>
|
|
103
103
|
<tr>
|
|
104
|
-
<td><a href="
|
|
104
|
+
<td><a href="/docs/hypermedia/#href-navigation"><code>href="..."</code></a></td>
|
|
105
105
|
<td>Attribute for SPA navigation and src injection on any element. Supports targeting content
|
|
106
106
|
before, at the start of, and the end of or after other elements via CSS selectors.</td>
|
|
107
107
|
</tr>
|
|
@@ -165,7 +165,7 @@ const { state } = LightviewX; // Deep state (lightview-x)</code></pre>
|
|
|
165
165
|
Add reactivity to existing HTML. Progressive enhancement made easy.
|
|
166
166
|
</p>
|
|
167
167
|
</a>
|
|
168
|
-
<a href="
|
|
168
|
+
<a href="/docs/hypermedia/" class="feature-card" style="text-decoration: none; color: inherit;">
|
|
169
169
|
<h3 class="feature-title">Hypermedia</h3>
|
|
170
170
|
<p class="feature-description">
|
|
171
171
|
Fetch content with src. HTM-style patterns, built in.
|
package/docs/api/nav.html
CHANGED
|
@@ -54,21 +54,5 @@
|
|
|
54
54
|
Validators</a>
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
57
|
-
<div class="docs-nav-item">
|
|
58
|
-
<a href="./hypermedia.html" class="docs-nav-link">Hypermedia</a>
|
|
59
|
-
<div class="docs-nav-subsection" style="margin-left: 1rem; border-left: 1px solid var(--site-border);">
|
|
60
|
-
<a href="./hypermedia.html#fetching-content" class="docs-nav-link" style="font-size: 0.85em;">Fetching
|
|
61
|
-
Content</a>
|
|
62
|
-
<a href="./hypermedia.html#href-navigation" class="docs-nav-link" style="font-size: 0.85em;">HREF
|
|
63
|
-
Navigation</a>
|
|
64
|
-
<a href="./hypermedia.html#event-gating" class="docs-nav-link" style="font-size: 0.85em;">Event
|
|
65
|
-
Gating</a>
|
|
66
|
-
<a href="./hypermedia.html#template-literals" class="docs-nav-link" style="font-size: 0.85em;">Template
|
|
67
|
-
Literals</a>
|
|
68
|
-
<a href="./hypermedia.html#shadow-dom" class="docs-nav-link" style="font-size: 0.85em;">Shadow DOM</a>
|
|
69
|
-
<a href="./hypermedia.html#htmx-style-apps" class="docs-nav-link" style="font-size: 0.85em;">HTMX-style
|
|
70
|
-
Apps</a>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
57
|
</div>
|
|
74
58
|
</nav>
|