UNPKG

lightview

Version:

A reactive UI library with features of Bau, Juris, and HTMX plus safe LLM UI generation

178 lines (164 loc) 8.26 kB
<script src="/lightview-router.js?base=/index.html"></script> <div class="docs-layout"> <aside class="docs-sidebar" src="/docs/cdom-nav.html"></aside> <main class="docs-content"> <h1>XPath Navigation in cDOM</h1> <p class="text-secondary" style="font-size: 1.125rem;"> Navigate and derive element properties from the existing DOM structure. </p> <div class="experimental-notice" style="margin: 1.5rem 0; padding: 1.25rem; border-radius: var(--site-radius); background: var(--site-accent-light); border: 1px solid var(--site-warning); color: var(--site-text);"> <div style="display: flex; gap: 0.75rem; align-items: flex-start;"> <span style="font-size: 1.5rem;">🚨</span> <div> <strong style="display: block; margin-bottom: 0.25rem; font-size: 1.1rem;">cDOM vs JPRX</strong> <p style="margin: 0; font-size: 0.95rem; opacity: 0.9;"> Static XPaths are availbale to <strong>cDOM</strong> during the construction phase, whereas <strong>JPRX</strong> has an <code>xpath</code> helper that returns a computed signal. See <a href="/docs/cdom.html#helpers-dom">JPRX documentation</a> on the helper for more info about xpath and reactivity. </p> </div> </div> </div> <h2 id="overview">Overview</h2> <p> cDOM allows elements to derive their properties from the existing DOM tree. This can be done statically for one-time setup or reactively for values that change over time. </p> <ol> <li><strong>Static XPath (<code>#</code> prefix)</strong>: Available to cDOM. Evaluated once during DOM construction.</li> <li><strong>Reactive XPath (<code>=xpath()</code> helper)</strong>: Available to JPRX. Evaluates as an expression and returns a computed signal.</li> </ol> <h2 id="static-xpath">Static XPath (<code>#</code> prefix)</h2> <p> Static XPath expressions are perfect for keeping your definitions <strong>DRY (Don't Repeat Yourself)</strong>. By referencing values like <code>id</code> or <code>class</code> from parent elements, you avoid duplicating data in your cDOM structure. </p> <div id="xpath-live-demo" style="margin: 2rem 0;"> <p class="text-sm font-bold opacity-60 uppercase mb-3">Live Interactive Example</p> <pre><script> examplify(document.currentScript.nextElementSibling, { at: document.currentScript.parentElement, scripts: ['/lightview.js', '/lightview-x.js', '/lightview-cdom.js'], type: 'module', height: '180px', autoRun: true }); </script><code>await import('/lightview-cdom.js'); const { parseJPRX, hydrate } = globalThis.LightviewCDOM; const { $ } = Lightview; const cdom = `{ div: { id: "profile-container", class: "card", "data-theme": "dark", children: [ { h3: "User Profile" }, { button: { id: "7", // XPath #(@id) gets "7" from this button's id // XPath #(../@id) gets "profile-container" from the parent div children: ["Button ", #(@id), " in section ", #(../@id)] }} ] } }`; $('#example').content(hydrate(parseJPRX(cdom)));</code></pre> </div> <h2 id="allowed-axes">Allowed Axes (Backward-Looking Only)</h2> <p> To maintain high performance and safety during construction, cDOM only allows <strong>backward-looking</strong> XPath axes. You can reference nodes that are already constructed (parents, ancestors, earlier siblings). </p> <table class="api-table"> <thead> <tr> <th>Axis</th> <th>Result</th> </tr> </thead> <tbody> <tr> <td><code>self::</code> / <code>.</code></td> <td>The current node.</td> </tr> <tr> <td><code>parent::</code> / <code>..</code></td> <td>The parent element.</td> </tr> <tr> <td><code>ancestor::</code></td> <td>Higher-level ancestors.</td> </tr> <tr> <td><code>preceding-sibling::</code></td> <td>Elements that appear before the current one in the same parent.</td> </tr> </tbody> </table> <p class="text-warning"> <strong>Forbidden:</strong> <code>child::</code>, <code>descendant::</code>, and <code>following::</code> axes are disabled as they could create infinite loops or reference nodes that do not exist yet. </p> <div style="margin-top: 1rem; padding: 1rem; background: var(--site-bg-secondary); border-left: 4px solid var(--site-primary); border-radius: var(--site-radius);"> <p style="margin: 0; font-size: 0.95rem;"> <strong>💡 Need Forward-Looking XPath?</strong> For advanced use cases requiring <code>child::</code>, <code>descendant::</code>, or <code>following::</code> axes, use the reactive <code>=xpath()</code> helper in JPRX instead of static <code>#()</code> in cDOM. The reactive helper evaluates XPath expressions after the DOM is fully constructed and can access any part of the tree. See the <a href="#reactive-xpath">Reactive XPath section</a> below for details. </p> </div> <h2 id="reactive-xpath">Reactive XPath (<code>=xpath()</code>)</h2> <p> If you need an XPath expression to update reactively when attributes elsewhere in the DOM change, or if you need to use <strong>forward-looking axes</strong> (like <code>child::</code>, <code>descendant::</code>, or <code>following::</code>), use the <code>=xpath()</code> helper within a JPRX expression. </p> <p> Unlike static <code>#()</code> expressions which are evaluated once during construction, <code>=xpath()</code> creates a reactive computed signal that re-evaluates whenever its dependencies change, and it has <strong>no axis restrictions</strong> since the DOM is already fully constructed. </p> <div class="code-block"> <pre><code>{ div: { title: "=(xpath('../@data-section'))", class: "=(concat('item ', xpath('../@theme')))" } }</code></pre> </div> <h2 id="cdomc">Concise cDOM (cDOMC) Support</h2> <p> In cDOMC (the shorthand format used in <code>.cdomc</code> files), the parser is <strong>structurally aware</strong> of XPath expressions. You do not need to quote them even if they contain square brackets or spaces. </p> <div class="code-block"> <pre><code>// Clean unquoted syntax in .cdomc files { button: { id: "7", children: [#(../@id)] } } // Support for complex paths with predicates { span: [#(ancestor::div[@data-role='container']/@title)] }</code></pre> </div> <h2 id="safety">Security & Safety</h2> <p> XPath navigation in cDOM is inherently safer than using arbitrary JavaScript for DOM traversal. It provides a restricted, read-only view of the existing structural tree without the risks of code injection or side effects. </p> </main> </div>