lightview 2.3.7 → 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/cdom.html +6 -5
- 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/1769196538097-package.json +0 -43
- package/build_tmp/lightview-router.js +0 -185
- package/build_tmp/lightview-x.js +0 -1608
- package/build_tmp/lightview.js +0 -932
- 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,391 @@
|
|
|
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/hypermedia/nav.html" data-preserve-scroll="docs-nav"></aside>
|
|
6
|
+
|
|
7
|
+
<main class="docs-content">
|
|
8
|
+
<h1>Hypermedia</h1>
|
|
9
|
+
<p>
|
|
10
|
+
HTMX-style patterns, built right in. Load HTML fragments, fetch vDOM/Object DOM, clone templates - all with
|
|
11
|
+
the
|
|
12
|
+
<code>src</code> and <code>href</code> attributes.
|
|
13
|
+
<em>Requires lightview-x.js</em>
|
|
14
|
+
</p>
|
|
15
|
+
<p>
|
|
16
|
+
If you look at the source for the navigation to the left, you will see that this page is built using a
|
|
17
|
+
hypermedia approach.
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<h2 id="fetching-content">Fetching Content</h2>
|
|
21
|
+
<h3 id="html">HTML</h3>
|
|
22
|
+
<p>
|
|
23
|
+
Point <code>src</code> at an HTML file and Lightview loads it as children:
|
|
24
|
+
</p>
|
|
25
|
+
<pre><code><!-- Load HTML partials into specific elements -->
|
|
26
|
+
<div>
|
|
27
|
+
<header src="/partials/nav.html"></header>
|
|
28
|
+
<main src="/partials/content.html"></main>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<!-- The HTML is fetched, parsed, and made reactive automatically! --></code></pre>
|
|
32
|
+
|
|
33
|
+
<p>
|
|
34
|
+
By default, Lightview enforces a <strong>Same-Domain security policy</strong> for all remote fetches.
|
|
35
|
+
Content can only be fetched from the same domain or its subdomains. External domains are blocked to prevent
|
|
36
|
+
Cross-Site Scripting (XSS) and unauthorized data ingestion. Different ports on the same host (e.g.,
|
|
37
|
+
localhost:3000 and localhost:4000) are <strong>allowed</strong> by default.
|
|
38
|
+
</p>
|
|
39
|
+
<p>
|
|
40
|
+
<strong>Relative Paths:</strong> Any URL that does not specify a protocol (e.g., <code>./data.html</code>,
|
|
41
|
+
<code>/api/user</code>) is automatically considered valid. This ensures reliability in sandboxed
|
|
42
|
+
environments (like iframes) where the global origin might be reported as <code>null</code>.
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<h4>Controlling Access with validateUrl</h4>
|
|
46
|
+
<p>
|
|
47
|
+
You can customize or disable this security policy using the <code>validateUrl</code> hook. This hook is
|
|
48
|
+
checked before any <code>src</code> fetch or non-standard <code>href</code> navigation.
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<pre><code>// Allow specific external CDNs
|
|
52
|
+
Lightview.hooks.validateUrl = (url) => {
|
|
53
|
+
const target = new URL(url, location.origin);
|
|
54
|
+
const allowed = ['trusted-api.com', 'cdn.content.org', 'localhost'];
|
|
55
|
+
return allowed.includes(target.hostname) || target.hostname.endsWith('.mysite.com');
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Disable security (Not recommended for production)
|
|
59
|
+
Lightview.hooks.validateUrl = () => true;</code></pre>
|
|
60
|
+
|
|
61
|
+
<h4>Dangerous Protocol Blocking</h4>
|
|
62
|
+
<p>
|
|
63
|
+
Lightview automatically blocks dangerous URI protocols in <code>src</code> and <code>href</code> attributes,
|
|
64
|
+
including <code>javascript:</code>, <code>vbscript:</code>, and certain <code>data:</code> types. If a
|
|
65
|
+
dangerous protocol is detected, the action is cancelled and a warning is logged to the console.
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
<h3 id="vdom-object-dom">vDOM and Object DOM</h3>
|
|
69
|
+
<p>
|
|
70
|
+
Files with <code>.<a id="vdom" href="/docs/api/elements#vdom">vdom</a></code>,
|
|
71
|
+
<code>.<a id="odom" href="/docs/api/elements#object-dom">odom</a></code> or
|
|
72
|
+
<code>.<a id="cdom" href="/docs/cdom">cdom</a></code> extensions are parsed as JSON and converted to
|
|
73
|
+
elements.
|
|
74
|
+
Any <a href="#template-literals">Template Literals</a> within the JSON values are automatically resolved.
|
|
75
|
+
</p>
|
|
76
|
+
<pre><code>// /api/cards.vdom
|
|
77
|
+
[
|
|
78
|
+
{ "tag": "div", "attributes": { "class": "card" }, "children": ["Card 1"] },
|
|
79
|
+
{ "tag": "div", "attributes": { "class": "card" }, "children": ["Card 2"] }
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
// Load vDOM
|
|
83
|
+
div({ src: '/api/cards.vdom' })
|
|
84
|
+
|
|
85
|
+
// Load safe, reactive HTML
|
|
86
|
+
div({ src: '/api/ai-generated.cdom' })
|
|
87
|
+
</code></pre>
|
|
88
|
+
|
|
89
|
+
<h2 id="advanced-fetches">Advanced Fetches (data-method & data-body)</h2>
|
|
90
|
+
<p>
|
|
91
|
+
You can customize the HTTP request method and body for any <code>src</code> or <code>href</code> action
|
|
92
|
+
using <code>data-method</code> and <code>data-body</code>.
|
|
93
|
+
</p>
|
|
94
|
+
|
|
95
|
+
<h3>1. Request Methods</h3>
|
|
96
|
+
<p>Use <code>data-method</code> to specify an HTTP verb. Defaults to <code>GET</code>.</p>
|
|
97
|
+
<pre><code><!-- Send a DELETE request -->
|
|
98
|
+
<button href="/api/items/123" data-method="DELETE" target="#status-log">
|
|
99
|
+
Delete Item
|
|
100
|
+
</button></code></pre>
|
|
101
|
+
|
|
102
|
+
<h3>2. Request Bodies</h3>
|
|
103
|
+
<p>Use <code>data-body</code> to send data. The prefixes <code>css:</code>, <code>json:</code>, and
|
|
104
|
+
<code>text:</code> can be used to control exactly how the body is constructed. If no prefix is used, it is
|
|
105
|
+
treated as a CSS selector.</p>
|
|
106
|
+
|
|
107
|
+
<h4>CSS Selectors (Default)</h4>
|
|
108
|
+
<p>Grabs data from the DOM based on the element type:</p>
|
|
109
|
+
<ul>
|
|
110
|
+
<li><strong>Forms:</strong> If the selector points to a <code><form></code>, the entire form is
|
|
111
|
+
serialized as <code>FormData</code>.
|
|
112
|
+
</li>
|
|
113
|
+
<li><strong>Checkboxes/Radios:</strong> Only sends the <code>value</code> if the element is
|
|
114
|
+
<code>checked</code>. Otherwise, no data is sent.
|
|
115
|
+
</li>
|
|
116
|
+
<li><strong>Input/Select/Textarea:</strong> Sends the current <code>value</code>.</li>
|
|
117
|
+
<li><strong>Other Elements:</strong> Sends the <code>innerText</code> (e.g., from a <code><div></code>
|
|
118
|
+
or <code><span></code>).
|
|
119
|
+
</li>
|
|
120
|
+
</ul>
|
|
121
|
+
<pre><code><!-- Send the value of an input (Query param search?body=...) -->
|
|
122
|
+
<button href="/api/search" data-body="#search-input" target="#results">Search</button>
|
|
123
|
+
<input id="search-input" type="text">
|
|
124
|
+
|
|
125
|
+
<!-- Send an entire form as POST -->
|
|
126
|
+
<button href="/api/user/update" data-method="POST" data-body="#user-form">Save</button>
|
|
127
|
+
<form id="user-form">
|
|
128
|
+
<input name="email" value="user@example.com">
|
|
129
|
+
</form></code></pre>
|
|
130
|
+
|
|
131
|
+
<h4>Prefixes</h4>
|
|
132
|
+
<p>You can use prefixes to control exactly how the body is constructed:</p>
|
|
133
|
+
<ul>
|
|
134
|
+
<li><code>javascript:</code> - Evaluates an expression (has access to <code>state</code> and
|
|
135
|
+
<code>signal</code>).
|
|
136
|
+
</li>
|
|
137
|
+
<li><code>json:</code> - Sends a literal JSON string (sets <code>Content-Type: application/json</code>).
|
|
138
|
+
</li>
|
|
139
|
+
<li><code>text:</code> - Sends raw text (sets <code>Content-Type: text/plain</code>).</li>
|
|
140
|
+
</ul>
|
|
141
|
+
<pre><code><!-- Dynamic calculation -->
|
|
142
|
+
<button href="/api/log" data-body="javascript:state.user.id">Log ID</button>
|
|
143
|
+
|
|
144
|
+
<!-- Literal JSON -->
|
|
145
|
+
<button href="/api/config" data-method="POST" data-body='json:{"theme": "dark"}'>Set Dark Mode</button></code></pre>
|
|
146
|
+
|
|
147
|
+
<h4>GET Request Handling</h4>
|
|
148
|
+
<p>If the method is <code>GET</code>, the data provided via <code>data-body</code> is automatically converted
|
|
149
|
+
into <strong>URL Query Parameters</strong>. If multiple values are found (like in a form), all are
|
|
150
|
+
appended to the URL.</p>
|
|
151
|
+
|
|
152
|
+
<h2 id="cloning-dom-elements">Cloning DOM Elements</h2>
|
|
153
|
+
<p>
|
|
154
|
+
Use CSS selectors to clone existing elements:
|
|
155
|
+
</p>
|
|
156
|
+
<pre><code>// Clone a template
|
|
157
|
+
div({ src: '#my-template' })
|
|
158
|
+
|
|
159
|
+
// Clone multiple elements
|
|
160
|
+
div({ src: '.card-template' })</code></pre>
|
|
161
|
+
<pre><code><!-- Hidden template in HTML -->
|
|
162
|
+
<template id="my-template">
|
|
163
|
+
<div class="modal">
|
|
164
|
+
<h2>Modal Title</h2>
|
|
165
|
+
<p>Modal content here</p>
|
|
166
|
+
</div>
|
|
167
|
+
</template></code></pre>
|
|
168
|
+
|
|
169
|
+
<h2 id="href-navigation">HREF Navigation</h2>
|
|
170
|
+
<p>
|
|
171
|
+
Add <code>href</code> to any element to make it interactive. The behavior depends on the <code>target</code>
|
|
172
|
+
attribute:
|
|
173
|
+
</p>
|
|
174
|
+
<p><strong>Note:</strong> The same <a href="#fetching-content">src Fetch Security</a> controls (same-domain
|
|
175
|
+
policy
|
|
176
|
+
and protocol
|
|
177
|
+
blocking) apply to all interactive <code>href</code> navigations.</p>
|
|
178
|
+
|
|
179
|
+
<h3>1. Self-Loading (Default)</h3>
|
|
180
|
+
<p>If no target is specified, clicking sets the element's own <code>src</code> to the <code>href</code> value:
|
|
181
|
+
</p>
|
|
182
|
+
<pre><code>// Loads content into itself on click
|
|
183
|
+
button({ href: '/partials/data.html' }, 'Load Data')</code></pre>
|
|
184
|
+
|
|
185
|
+
<h3>2. Browser Navigation</h3>
|
|
186
|
+
<p>Use standard underscore targets for window navigation:</p>
|
|
187
|
+
<pre><code>// Opens new tab
|
|
188
|
+
button({ href: 'https://example.com', target: '_blank' }, 'Open External')
|
|
189
|
+
|
|
190
|
+
// Navigates current page
|
|
191
|
+
div({ href: '/home', target: '_self' }, 'Go Home')</code></pre>
|
|
192
|
+
|
|
193
|
+
<h3>3. Targeting Other Elements</h3>
|
|
194
|
+
<p>Use a CSS selector as the target to load content into other elements:</p>
|
|
195
|
+
<pre><code>// Loads content into element with id="main"
|
|
196
|
+
button({ href: '/pages/about.html', target: '#main' }, 'Load About Page')
|
|
197
|
+
|
|
198
|
+
div({ id: 'main' }) // Content appears here</code></pre>
|
|
199
|
+
|
|
200
|
+
<h3>4. Positioning Content</h3>
|
|
201
|
+
<p>Control where content is inserted using the <code>location</code> attribute or a target suffix.</p>
|
|
202
|
+
<p><strong>Supported locations:</strong> <code>innerhtml</code> (default), <code>outerhtml</code>,
|
|
203
|
+
<code>beforebegin</code>, <code>afterbegin</code>, <code>beforeend</code>, <code>afterend</code>,
|
|
204
|
+
<code>shadow</code>.
|
|
205
|
+
</p>
|
|
206
|
+
|
|
207
|
+
<pre><code>// Option A: Suffix syntax for href (Target Selector:Location)
|
|
208
|
+
button({
|
|
209
|
+
href: '/partials/item.html',
|
|
210
|
+
target: '#list:beforeend' // Append to list
|
|
211
|
+
}, 'Add Item')
|
|
212
|
+
|
|
213
|
+
// Option B: Explicit attribute on target for src
|
|
214
|
+
div({
|
|
215
|
+
src: '/partials/banner.html',
|
|
216
|
+
location: 'afterbegin'
|
|
217
|
+
})</code></pre>
|
|
218
|
+
|
|
219
|
+
<p><strong>Smart Replacement:</strong> Lightview tracks inserted content. Fetching the same content to the same
|
|
220
|
+
location is a no-op. Fetching different content replaces the previous content at that specific location.</p>
|
|
221
|
+
|
|
222
|
+
<h3>5. Hash Scrolling</h3>
|
|
223
|
+
<p>If an <code>href</code> or <code>src</code> includes a hash (e.g., <code>/page.html#section-1</code>),
|
|
224
|
+
Lightview will automatically
|
|
225
|
+
attempt to scroll to the element with that ID after the content is loaded and injected. This works for both
|
|
226
|
+
standard document targets and Shadow DOM targets (where it searches within the specific
|
|
227
|
+
<code>shadowRoot</code>).
|
|
228
|
+
</p>
|
|
229
|
+
<pre><code>// Scrolls to #details within the loaded content
|
|
230
|
+
button({ href: '/api/items.html#details', target: '#content' }, 'View Details')</code></pre>
|
|
231
|
+
|
|
232
|
+
<h2 id="event-gating">Declarative Event Gating (lv-before)</h2>
|
|
233
|
+
<p>
|
|
234
|
+
The <code>lv-before</code> attribute provides a declarative way to intercept, filter, and modify events
|
|
235
|
+
<em>before</em> they reach your standard handlers (like <code>onclick</code>) or trigger native browser
|
|
236
|
+
behavior.
|
|
237
|
+
</p>
|
|
238
|
+
<div class="alert alert-info">
|
|
239
|
+
<p>
|
|
240
|
+
<strong>Important:</strong> Custom gating functions must be defined in the <code>globalThis</code> scope
|
|
241
|
+
(e.g., <code>window.myGate = ...</code>) to be accessible to the declarative parser.
|
|
242
|
+
</p>
|
|
243
|
+
</div>
|
|
244
|
+
|
|
245
|
+
<h3>1. Selection & Exclusions</h3>
|
|
246
|
+
<p>You must specify which events to gate by name, or use <code>*</code> to gate all common (sensible) UI and
|
|
247
|
+
form events. You can
|
|
248
|
+
also exclude specific events:</p>
|
|
249
|
+
<pre><code><!-- Gate only clicks -->
|
|
250
|
+
<button lv-before="click myGate()">Click Me</button>
|
|
251
|
+
|
|
252
|
+
<!-- Gate all common events EXCEPT keyboard events -->
|
|
253
|
+
<div lv-before="* !keydown !keyup logInteraction()">...</div></code></pre>
|
|
254
|
+
|
|
255
|
+
<h3>2. Rate Limiting (Throttle & Debounce)</h3>
|
|
256
|
+
<p>Lightview-X provides built-in "Gate Modifiers" for common timing patterns. These return <code>true</code>
|
|
257
|
+
only when the timing condition is met, effectively filtering the event stream.</p>
|
|
258
|
+
<pre><code><!-- Prevent button spam (only 1 click per second) -->
|
|
259
|
+
<button lv-before="click throttle(1000)" onclick="saveData()">Save</button>
|
|
260
|
+
|
|
261
|
+
<!-- Wait for 500ms of silence before processing input -->
|
|
262
|
+
<input lv-before="input debounce(500)" oninput="search(this.value)"></code></pre>
|
|
263
|
+
|
|
264
|
+
<h3>3. Sequence & Async Pipelines</h3>
|
|
265
|
+
<p>You can chain multiple gates in a space-separated list. They execute sequentially and can be asynchronous.
|
|
266
|
+
If any function returns <code>false</code>, <code>null</code>, or <code>undefined</code>, the entire event
|
|
267
|
+
is aborted.</p>
|
|
268
|
+
<p><strong>Parsing Note:</strong> Expressions are fundamentally space-separated. However, spaces within single
|
|
269
|
+
quotes (<code>'</code>), double quotes (<code>"</code>), or parentheses (<code>()</code>) are preserved.
|
|
270
|
+
This allows you to pass strings with spaces to your gate functions, such as confirmation messages.</p>
|
|
271
|
+
<pre><code><!-- Chained: Throttled first, then a confirmation -->
|
|
272
|
+
<button lv-before="click throttle(2000) confirm('Really delete?')"
|
|
273
|
+
onclick="doDelete()">Delete</button></code></pre>
|
|
274
|
+
|
|
275
|
+
<h3>4. Context & Arguments</h3>
|
|
276
|
+
<p>Inside an <code>lv-before</code> expression, <code>this</code> refers to the current element. You can pass
|
|
277
|
+
the
|
|
278
|
+
native
|
|
279
|
+
<code>event</code> object, as well as <code>state</code> and <code>signal</code> registries, to your
|
|
280
|
+
custom gate functions.
|
|
281
|
+
</p>
|
|
282
|
+
<pre><code><!-- Pass event to a custom logic function -->
|
|
283
|
+
<button lv-before="click validateClick(event)" onclick="proceed()">...</button></code></pre>
|
|
284
|
+
|
|
285
|
+
<h2 id="template-literals">Template Literals</h2>
|
|
286
|
+
<p>
|
|
287
|
+
External HTML, <code>.vdom</code> and <code>.odom</code> files, can reference named signals or state with
|
|
288
|
+
template syntax:
|
|
289
|
+
</p>
|
|
290
|
+
<pre><code>// main.js - Register named signals and state
|
|
291
|
+
const count = signal(0, 'count');
|
|
292
|
+
const userName = signal('Guest', 'userName');
|
|
293
|
+
const userPrefs = state({ theme: 'dark', lang: 'en' }, 'userPrefs');
|
|
294
|
+
|
|
295
|
+
// Load template that uses them
|
|
296
|
+
div({ src: '/partials/dashboard.html' })
|
|
297
|
+
div({ src: '/partials/dashboard.vdom' })
|
|
298
|
+
div({ src: '/partials/dashboard.odom' })</code></pre>
|
|
299
|
+
|
|
300
|
+
<pre><code><!-- /partials/dashboard.html -->
|
|
301
|
+
<div class="dashboard">
|
|
302
|
+
<h1>Welcome, ${signal.get('userName').value}!</h1>
|
|
303
|
+
<p>You have ${signal.get('count').value} notifications.</p>
|
|
304
|
+
<p>Theme: ${state.get('userPrefs').theme}</p>
|
|
305
|
+
</div></code></pre>
|
|
306
|
+
|
|
307
|
+
<pre><code>// /partials/dashboard.vdom (JSON Array)
|
|
308
|
+
[
|
|
309
|
+
{
|
|
310
|
+
"tag": "div",
|
|
311
|
+
"attributes": { "class": "dashboard" },
|
|
312
|
+
"children": [
|
|
313
|
+
{ "tag": "h1", "children": ["Welcome, ${signal.get('userName').value}!"] },
|
|
314
|
+
{ "tag": "p", "children": ["Theme: ${state.get('userPrefs').theme}"] }
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
]</code></pre>
|
|
318
|
+
|
|
319
|
+
<pre><code>// /partials/dashboard.odom (Object DOM)
|
|
320
|
+
{
|
|
321
|
+
"div": {
|
|
322
|
+
"class": "dashboard",
|
|
323
|
+
"children": [
|
|
324
|
+
{ "h1": { "children": ["Welcome, ${signal.get('userName').value}!"] } },
|
|
325
|
+
{ "p": { "children": ["Theme: ${state.get('userPrefs').theme}"] } }
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
}</code></pre>
|
|
329
|
+
|
|
330
|
+
<h2 id="shadow-dom">Shadow DOM</h2>
|
|
331
|
+
<p>
|
|
332
|
+
Load content into shadow DOM for style isolation using <code>location="shadow"</code> or the
|
|
333
|
+
<code>:shadow</code> suffix:
|
|
334
|
+
</p>
|
|
335
|
+
<pre><code>// Option A: location attribute
|
|
336
|
+
div({ src: '/components/widget.html', location: 'shadow' })
|
|
337
|
+
|
|
338
|
+
// Option B: target suffix
|
|
339
|
+
button({ href: '/components/widget.html', target: '#container:shadow' }, 'Load Widget')</code></pre>
|
|
340
|
+
|
|
341
|
+
<h2 id="htmx-style-apps">HTMX-style Apps</h2>
|
|
342
|
+
<p>
|
|
343
|
+
Combine <code>src</code> and <code>href</code> for hypermedia-driven UIs. You can use <code>lv-before</code>
|
|
344
|
+
for confirmation or validation before navigation.
|
|
345
|
+
</p>
|
|
346
|
+
|
|
347
|
+
<h3>Using Tag Functions</h3>
|
|
348
|
+
<pre><code>const { tags } = Lightview;
|
|
349
|
+
const { div, nav, button, main } = tags;
|
|
350
|
+
|
|
351
|
+
const app = div({ class: 'app' },
|
|
352
|
+
nav({ class: 'sidebar' },
|
|
353
|
+
button({
|
|
354
|
+
href: '/pages/dashboard.html',
|
|
355
|
+
target: '#content'
|
|
356
|
+
}, '📊 Dashboard'),
|
|
357
|
+
button({
|
|
358
|
+
href: '/pages/settings.html',
|
|
359
|
+
target: '#content',
|
|
360
|
+
'lv-before': "click confirm('Go to settings?')" // Event gate
|
|
361
|
+
}, '⚙️ Settings')
|
|
362
|
+
),
|
|
363
|
+
main({
|
|
364
|
+
id: 'content',
|
|
365
|
+
src: '/pages/dashboard.html' // Initial content
|
|
366
|
+
})
|
|
367
|
+
);</code></pre>
|
|
368
|
+
|
|
369
|
+
<h3>Using Ligthview Plain HTML</h3>
|
|
370
|
+
<pre><code><div class="app">
|
|
371
|
+
<nav class="sidebar">
|
|
372
|
+
<button href="/pages/dashboard.html" target="#content">📊 Dashboard</button>
|
|
373
|
+
<button href="/pages/settings.html" target="#content"
|
|
374
|
+
lv-before="click confirm('Go to settings?')">⚙️ Settings</button>
|
|
375
|
+
</nav>
|
|
376
|
+
<main id="content" src="/pages/dashboard.html"></main>
|
|
377
|
+
</div></code></pre>
|
|
378
|
+
|
|
379
|
+
<h3>vs. Using HTMX</h3>
|
|
380
|
+
<pre><code><div class="app">
|
|
381
|
+
<nav class="sidebar">
|
|
382
|
+
<button hx-get="/pages/dashboard.html" hx-target="#content">📊 Dashboard</button>
|
|
383
|
+
<button hx-get="/pages/settings.html" hx-target="#content"
|
|
384
|
+
hx-confirm="Go to settings?">⚙️ Settings</button>
|
|
385
|
+
</nav>
|
|
386
|
+
<main id="content" hx-get="/pages/dashboard.html" hx-trigger="load"></main>
|
|
387
|
+
</div></code></pre>
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
</main>
|
|
391
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<nav data-preserve-scroll="docs-nav" class="docs-nav">
|
|
2
|
+
<div class="docs-nav-section">
|
|
3
|
+
<div class="docs-nav-title">Hypermedia</div>
|
|
4
|
+
<a href="#fetching-content" class="docs-nav-link">Fetching Content</a>
|
|
5
|
+
<div class="docs-nav-subsection" style="margin-left: 1rem; border-left: 1px solid var(--site-border);">
|
|
6
|
+
<a href="#html" class="docs-nav-link" style="font-size: 0.85em;">HTML</a>
|
|
7
|
+
<a href="#vdom-object-dom" class="docs-nav-link" style="font-size: 0.85em;">vDOM & oDOM</a>
|
|
8
|
+
</div>
|
|
9
|
+
<a href="#advanced-fetches" class="docs-nav-link">Advanced Fetches</a>
|
|
10
|
+
<a href="#cloning-dom-elements" class="docs-nav-link">Cloning DOM Elements</a>
|
|
11
|
+
<a href="#href-navigation" class="docs-nav-link">HREF Navigation</a>
|
|
12
|
+
<a href="#event-gating" class="docs-nav-link">Event Gating (lv-before)</a>
|
|
13
|
+
<a href="#template-literals" class="docs-nav-link">Template Literals</a>
|
|
14
|
+
<a href="#shadow-dom" class="docs-nav-link">Shadow DOM</a>
|
|
15
|
+
<a href="#htmx-style-apps" class="docs-nav-link">HTMX-style Apps</a>
|
|
16
|
+
</div>
|
|
17
|
+
</nav>
|
package/docs/index.html
CHANGED
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
<p class="hero-tagline">Reactive UI's done light</p>
|
|
10
10
|
<p class="hero-description">
|
|
11
11
|
More power. Less energy.
|
|
12
|
+
<br>
|
|
13
|
+
<a id="link-hero-ai-safe" href="#ai-safe"
|
|
14
|
+
style="color: var(--site-primary); font-size: 1.25rem; font-weight: 700; text-decoration: none; display: inline-block; margin-top: 0.5rem; border-bottom: 2px solid var(--site-primary); padding-bottom: 2px;">AI
|
|
15
|
+
Safe</a>
|
|
12
16
|
</p>
|
|
13
17
|
<div class="hero-actions">
|
|
14
|
-
<a href="./getting-started/" class="btn btn-primary btn-lg">Get Started</a>
|
|
18
|
+
<a id="link-hero-get-started" href="./getting-started/" class="btn btn-primary btn-lg">Get Started</a>
|
|
15
19
|
</div>
|
|
16
20
|
<div class="hero-stats">
|
|
17
21
|
<div class="hero-stat">
|
|
@@ -40,76 +44,182 @@
|
|
|
40
44
|
</p>
|
|
41
45
|
</div>
|
|
42
46
|
<div class="feature-grid">
|
|
43
|
-
<
|
|
47
|
+
<div class="feature-card">
|
|
44
48
|
<div class="feature-icon">
|
|
45
49
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
|
|
46
50
|
<circle cx="12" cy="12" r="10" />
|
|
47
51
|
<path d="M12 6v6l4 2" />
|
|
48
52
|
</svg>
|
|
49
53
|
</div>
|
|
50
|
-
<h3 class="feature-title">Signals and Object
|
|
54
|
+
<h3><a id="link-feature-signals" href="./api/signals.html" class="feature-title">Signals and Object
|
|
55
|
+
State Reactivity</a></h3>
|
|
51
56
|
<p class="feature-description">
|
|
52
57
|
Fine-grained reactivity with signals and obejct state. Updates propagate automatically—no virtual
|
|
53
58
|
DOM diffing needed. As a bonus, session and local storage are also supported.
|
|
54
59
|
</p>
|
|
55
|
-
</
|
|
56
|
-
<
|
|
60
|
+
</div>
|
|
61
|
+
<div class="feature-card">
|
|
57
62
|
<div class="feature-icon">
|
|
58
63
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
|
|
59
64
|
<rect x="3" y="3" width="18" height="18" rx="2" />
|
|
60
65
|
<path d="M3 9h18M9 21V9" />
|
|
61
66
|
</svg>
|
|
62
67
|
</div>
|
|
63
|
-
<h3 class="feature-title">Multiple Syntaxes</
|
|
68
|
+
<h3><a id="link-feature-elements" href="./api/elements.html" class="feature-title">Multiple Syntaxes</a>
|
|
69
|
+
</h3>
|
|
64
70
|
<p class="feature-description">
|
|
65
71
|
Tagged API, vDOM, Object DOM, HTML. Pick your style—they all work together.
|
|
66
72
|
</p>
|
|
67
|
-
</
|
|
68
|
-
<
|
|
73
|
+
</div>
|
|
74
|
+
<div class="feature-card">
|
|
69
75
|
<div class="feature-icon">
|
|
70
76
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
|
|
71
77
|
<path
|
|
72
78
|
d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.66 0 3-4 3-9s-1.34-9-3-9m0 18c-1.66 0-3-4-3-9s1.34-9 3-9" />
|
|
73
79
|
</svg>
|
|
74
80
|
</div>
|
|
75
|
-
<h3 class="feature-title">Hypermedia
|
|
81
|
+
<h3><a id="link-feature-hypermedia" href="/docs/hypermedia/" class="feature-title">Hypermedia
|
|
82
|
+
Ready</a></h3>
|
|
76
83
|
<p class="feature-description">
|
|
77
84
|
Fetch HTML, vDOM, or Object DOM with the <code>src</code> attribute. HTMX-like patterns for
|
|
78
85
|
<code>src</code> and <code>href</code> built right
|
|
79
86
|
in.
|
|
80
87
|
</p>
|
|
81
|
-
</
|
|
82
|
-
<
|
|
88
|
+
</div>
|
|
89
|
+
<div class="feature-card">
|
|
83
90
|
<div class="feature-icon">
|
|
84
91
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
|
|
85
92
|
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
|
86
93
|
</svg>
|
|
87
94
|
</div>
|
|
88
|
-
<h3 class="feature-title">Component
|
|
95
|
+
<h3><a id="link-feature-components" href="./components/index.html" class="feature-title">Component
|
|
96
|
+
Library</a></h3>
|
|
89
97
|
<p class="feature-description">
|
|
90
98
|
Beautiful, accessible components ready to use. Buttons, modals, forms, charts, and more.
|
|
91
99
|
</p>
|
|
92
|
-
</
|
|
93
|
-
<
|
|
100
|
+
</div>
|
|
101
|
+
<div class="feature-card">
|
|
94
102
|
<div class="feature-icon">
|
|
95
103
|
<svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
|
|
96
104
|
<path
|
|
97
105
|
d="M14.7 6.3a1 1 0 000 1.4l1.6 1.6a1 1 0 001.4 0l3.77-3.77a6 6 0 01-7.94 7.94l-6.91 6.91a2.12 2.12 0 01-3-3l6.91-6.91a6 6 0 017.94-7.94l-3.76 3.76z" />
|
|
98
106
|
</svg>
|
|
99
107
|
</div>
|
|
100
|
-
<h3 class="feature-title">Zero Build
|
|
108
|
+
<h3><a id="link-feature-zerobuild" href="./getting-started/index.html" class="feature-title">Zero Build
|
|
109
|
+
Step</a></h3>
|
|
101
110
|
<p class="feature-description">
|
|
102
111
|
No bundler required. Drop in a script tag and start building. Works everywhere.
|
|
103
112
|
</p>
|
|
104
|
-
</
|
|
113
|
+
</div>
|
|
105
114
|
|
|
106
115
|
</div>
|
|
107
116
|
</div>
|
|
108
117
|
</section>
|
|
109
118
|
|
|
119
|
+
<!-- AI Catch Section -->
|
|
120
|
+
<section class="section" id="ai-safe">
|
|
121
|
+
<div class="section-content"
|
|
122
|
+
style="background: linear-gradient(135deg, #1a1c2c 0%, #4a1942 100%); color: white; border-radius: 2rem; padding: 4rem 2rem; border: 1px solid rgba(255, 255, 255, 0.1); box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); position: relative; overflow: hidden;">
|
|
123
|
+
<!-- Glowing background elements -->
|
|
124
|
+
<div
|
|
125
|
+
style="position: absolute; top: -20%; left: -10%; width: 50%; height: 140%; background: radial-gradient(circle, rgba(138, 43, 226, 0.2) 0%, transparent 70%); filter: blur(60px); pointer-events: none;">
|
|
126
|
+
</div>
|
|
127
|
+
<div
|
|
128
|
+
style="position: absolute; bottom: -20%; right: -10%; width: 50%; height: 140%; background: radial-gradient(circle, rgba(255, 20, 147, 0.15) 0%, transparent 70%); filter: blur(60px); pointer-events: none;">
|
|
129
|
+
</div>
|
|
110
130
|
|
|
131
|
+
<div style="position: relative; z-index: 1;">
|
|
132
|
+
<div class="section-header">
|
|
133
|
+
<h2 class="section-title" style="color: white; font-size: 2.5rem;">The AI-Safe UI Engine</h2>
|
|
134
|
+
<p class="section-subtitle" style="color: rgba(255, 255, 255, 0.85); max-width: 800px; margin: 0 auto;">
|
|
135
|
+
Lightview's <strong>cDOM</strong> and <strong>JPRX</strong> are purpose-built for the era of
|
|
136
|
+
AI-driven development, providing a safe, standard-based foundation for agentic UI generation.
|
|
137
|
+
</p>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div
|
|
141
|
+
style="display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 2.5rem; margin-top: 3.5rem;">
|
|
142
|
+
<div
|
|
143
|
+
style="background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 1.5rem; padding: 2.5rem; transition: transform 0.3s ease;">
|
|
144
|
+
<div
|
|
145
|
+
style="width: 48px; height: 48px; background: rgba(138, 43, 226, 0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem;">
|
|
146
|
+
<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="#a78bfa" stroke-width="2">
|
|
147
|
+
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
|
|
148
|
+
</svg>
|
|
149
|
+
</div>
|
|
150
|
+
<h3 style="color: white; font-size: 1.5rem; margin-bottom: 1rem;">Execution Safety</h3>
|
|
151
|
+
<p style="color: rgba(255, 255, 255, 0.75); line-height: 1.6;">AI-generated UIs usually require
|
|
152
|
+
risky JavaScript strings. cDOM creates reactive interfaces using <strong>pure JSON
|
|
153
|
+
data</strong> and <a id="link-ai-safe-cdom-helpers" href="/docs/cdom.html#helpers"
|
|
154
|
+
style="color: #a78bfa; text-decoration: underline; font-weight: 600;">over 50 built-in
|
|
155
|
+
functions</a> that bring spreadsheet-like
|
|
156
|
+
functionality to the DOM. No <code>eval()</code>, no <code>new Function()</code>, and <strong>no
|
|
157
|
+
access to global JavaScript context</strong>. When used in conjunction with <a
|
|
158
|
+
id="link-ai-safe-hypermedia" href="/docs/hypermedia/"
|
|
159
|
+
style="color: #a78bfa; text-decoration: underline; font-weight: 600;">Lightview hypermedia
|
|
160
|
+
support</a>, it strictly limits security exposure.</p>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div
|
|
164
|
+
style="background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 1.5rem; padding: 2.5rem; transition: transform 0.3s ease;">
|
|
165
|
+
<div
|
|
166
|
+
style="width: 48px; height: 48px; background: rgba(255, 20, 147, 0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem;">
|
|
167
|
+
<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="#fb7185" stroke-width="2">
|
|
168
|
+
<path d="M7 21h10M12 21V3m0 0l-5 5m5-5l5 5" />
|
|
169
|
+
</svg>
|
|
170
|
+
</div>
|
|
171
|
+
<h3 style="color: white; font-size: 1.5rem; margin-bottom: 1rem;">Standards-First Design</h3>
|
|
172
|
+
<p style="color: rgba(255, 255, 255, 0.75); line-height: 1.6;"><a id="link-ai-safe-cdom"
|
|
173
|
+
href="/docs/cdom.html"
|
|
174
|
+
style="color: #fb7185; text-decoration: underline; font-weight: 600;">cDOM</a>
|
|
175
|
+
(Computational DOM) and <a id="link-ai-safe-jprx" href="/docs/cdom.html#JPRX"
|
|
176
|
+
style="color: #fb7185; text-decoration: underline; font-weight: 600;">JPRX</a> (JSON Pointer
|
|
177
|
+
Reactive eXpressions) built based on <a id="link-ai-safe-json-pointers"
|
|
178
|
+
href="https://datatracker.ietf.org/doc/html/rfc6901" target="_blank"
|
|
179
|
+
style="color: #fb7185; text-decoration: underline; font-weight: 600;">JSON
|
|
180
|
+
Pointers</a> (RFC 6901), <a id="link-ai-safe-json-schema" href="https://json-schema.org/"
|
|
181
|
+
target="_blank" style="color: #fb7185; text-decoration: underline; font-weight: 600;">JSON
|
|
182
|
+
Schema</a>, and
|
|
183
|
+
<a id="link-ai-safe-xpath" href="https://www.w3.org/TR/xpath/" target="_blank"
|
|
184
|
+
style="color: #fb7185; text-decoration: underline; font-weight: 600;">XPath</a>. AI agents
|
|
185
|
+
describe complex relationships through proven standards and path languages, not imperative
|
|
186
|
+
logic.
|
|
187
|
+
</p>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div
|
|
191
|
+
style="background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 1.5rem; padding: 2.5rem; transition: transform 0.3s ease;">
|
|
192
|
+
<div
|
|
193
|
+
style="width: 48px; height: 48px; background: rgba(56, 189, 248, 0.2); border-radius: 12px; display: flex; align-items: center; justify-content: center; margin-bottom: 1.5rem;">
|
|
194
|
+
<svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="#38bdf8" stroke-width="2">
|
|
195
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
|
|
196
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
197
|
+
<line x1="16" y1="13" x2="8" y2="13"></line>
|
|
198
|
+
<line x1="16" y1="17" x2="8" y2="17"></line>
|
|
199
|
+
<polyline points="10 9 9 9 8 9"></polyline>
|
|
200
|
+
</svg>
|
|
201
|
+
</div>
|
|
202
|
+
<h3 style="color: white; font-size: 1.5rem; margin-bottom: 1rem;">Context for Agents</h3>
|
|
203
|
+
<p style="color: rgba(255, 255, 255, 0.75); line-height: 1.6;">
|
|
204
|
+
Accelerate development by pointing your AI assistant to the
|
|
205
|
+
<a id="link-ai-safe-guidance" href="/AI-GUIDANCE.md" target="_blank"
|
|
206
|
+
style="color: #38bdf8; text-decoration: underline; font-weight: 600;">AI Guidance
|
|
207
|
+
Manual</a>.
|
|
208
|
+
A definitive implementation guide optimized for LLM consumption.
|
|
209
|
+
</p>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div style="text-align: center; margin-top: 4rem;">
|
|
214
|
+
<a id="link-ai-safe-cta" href="/docs/cdom.html" class="btn btn-primary btn-lg"
|
|
215
|
+
style="background: white; color: #1a1c2c; border: none; font-weight: 600;">
|
|
216
|
+
Unleash the Power of cDOM
|
|
217
|
+
</a>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
</section>
|
|
111
222
|
|
|
112
|
-
<!-- Call to Action -->
|
|
113
223
|
<section class="section">
|
|
114
224
|
<div class="section-content">
|
|
115
225
|
<div class="section-header">
|
|
@@ -119,7 +229,7 @@
|
|
|
119
229
|
</p>
|
|
120
230
|
</div>
|
|
121
231
|
<div style="text-align: center;">
|
|
122
|
-
<a href="/docs/getting-started/" class="btn btn-primary btn-lg">Enlighten Your UI</a>
|
|
232
|
+
<a id="link-footer-cta" href="/docs/getting-started/" class="btn btn-primary btn-lg">Enlighten Your UI</a>
|
|
123
233
|
</div>
|
|
124
234
|
</div>
|
|
125
235
|
</section>
|