91 lines
8.2 KiB
Plaintext
91 lines
8.2 KiB
Plaintext
page Languageanddirectives {
|
|
seo {
|
|
title = "Language and directives"
|
|
description = "Complete WRNexusJS language reference for events, directives, loops, conditionals, data, components, forms, realtime, and native behavior."
|
|
}
|
|
|
|
view {
|
|
<div class="docs-shell">
|
|
<header class="topbar">
|
|
<a class="brand" href="/"><span>W</span> WRNexusJS</a>
|
|
<nav><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="/language">Language</a><a href="/architecture">Architecture</a></nav>
|
|
<button data-wire-theme-toggle class="theme-button" aria-label="Toggle theme">Theme</button>
|
|
</header>
|
|
<main class="page"><article class="documentation prose standalone language-reference"><span class="eyebrow">Complete reference</span><h1>Language and directives</h1><p>This page documents the .wrn language and declarative browser features that span multiple packages.</p>
|
|
<h2 id="file-anatomy">File anatomy</h2><p>A file declares a <code>page</code> or <code>component</code> and can contain metadata, props, state, data, view, style, server functions, APIs, and realtime handlers.</p><pre><code>page Dashboard {
|
|
layout = "default"
|
|
seo { title = "Dashboard" }
|
|
state count = 0
|
|
view { <button @click="count++">{count}</button> }
|
|
style { button { padding: 12px; } }
|
|
}</code></pre>
|
|
<h2 id="state">State and interpolation</h2><p>State is scoped to the nearest generated <code>data-scope</code>. Text expressions update reactively after hydration.</p><pre><code>state count = 0
|
|
state user = { name: "Ada" }
|
|
|
|
view {
|
|
<p>Count: {count}</p>
|
|
<p>{user.name}</p>
|
|
}</code></pre>
|
|
<h2 id="events">Events</h2><p>Any DOM event can use <code>@event="statement"</code>. The compiler emits <code>data-on-event</code>. The expression receives <code>event</code> and can mutate state.</p><div class="table-wrap"><table><thead><tr><th>Syntax</th><th>Purpose</th></tr></thead><tbody><tr><td><code>@click</code></td><td>Pointer or keyboard activation.</td></tr><tr><td><code>@input</code></td><td>Read live field values.</td></tr><tr><td><code>@change</code></td><td>React to committed field changes.</td></tr><tr><td><code>@submit</code></td><td>Handle form submission behavior.</td></tr><tr><td><code>@browser-click</code></td><td>Run only in a browser target.</td></tr><tr><td><code>@mobile-click</code></td><td>Run only in a native/mobile target.</td></tr></tbody></table></div><pre><code><input @input="name = event.target.value">
|
|
<button @click="count++">Add</button>
|
|
<form @submit="submitted = true">...</form></code></pre>
|
|
<h2 id="directives">Reactive data attributes</h2><div class="table-wrap"><table><thead><tr><th>Directive</th><th>Behavior</th></tr></thead><tbody><tr><td><code>data-scope</code></td><td>Declares reactive state for a subtree.</td></tr><tr><td><code>data-text</code></td><td>Synchronizes textContent with an expression.</td></tr><tr><td><code>data-show</code></td><td>Shows or hides an element by truthiness.</td></tr><tr><td><code>data-for</code></td><td>Repeats an element for a client-side list.</td></tr><tr><td><code>data-on-<event></code></td><td>Compiled form of an event binding.</td></tr><tr><td><code>data-component</code></td><td>Mounts a server-rendered component.</td></tr><tr><td><code>data-slot</code></td><td>Fills a named component or layout slot.</td></tr><tr><td><code>data-wrnexus-csr</code></td><td>Connects generated client data fetching.</td></tr></tbody></table></div>
|
|
<h2 id="conditionals">Conditional rendering</h2><h3>Server conditionals</h3><p>Server blocks render only the selected branch into the response.</p><pre><code>{#if user.isAdmin}
|
|
<a href="/admin">Admin</a>
|
|
{:else if user}
|
|
<p>Welcome {user.name}</p>
|
|
{:else}
|
|
<a href="/login">Sign in</a>
|
|
{/if}</code></pre><h3>Client visibility</h3><pre><code><section data-show="open">Visible while open is true</section></code></pre>
|
|
<h2 id="loops">Loops and lists</h2><h3>Server each block</h3><pre><code>{#each users as user, i}
|
|
<p>{i + 1}. {user.name}</p>
|
|
{:empty}
|
|
<p>No users</p>
|
|
{/each}</code></pre><h3>Reactive client loop</h3><pre><code><li data-for="item, i in items">
|
|
<span data-text="item.name"></span>
|
|
<button data-on-click="items = items.filter(x => x !== item)">Remove</button>
|
|
</li></code></pre>
|
|
<h2 id="components">Components, props, and slots</h2><pre><code>component Card {
|
|
props { title = "Card" }
|
|
view {
|
|
<article><h2>{title}</h2><slot></slot></article>
|
|
}
|
|
}
|
|
|
|
<div data-component="card" title="Profile">
|
|
<p>Card content</p>
|
|
</div></code></pre>
|
|
<h2 id="data">Server and client data</h2><p>Use named data bindings for SSR data or client hydration. Secrets and database work stay on the server.</p><pre><code>data users {
|
|
ssr GET "/api/users"
|
|
}
|
|
|
|
view {
|
|
{#each users as user}<p>{user.name}</p>{/each}
|
|
}</code></pre>
|
|
<h2 id="forms">Forms and validation</h2><p>Schema-backed forms validate in the browser and on the server with the same descriptor.</p><pre><code><form data-schema="login" method="post" action="/api/login" data-redirect="/dashboard">
|
|
<input name="email" type="email">
|
|
<span data-error="email"></span>
|
|
<button>Sign in</button>
|
|
<p data-success="Signed in" hidden></p>
|
|
</form></code></pre>
|
|
<h2 id="i18n">Internationalization and themes</h2><pre><code><h1>{t:home.title}</h1>
|
|
<button data-wire-lang-set="fr">Français</button>
|
|
<button data-wire-theme-toggle>Toggle theme</button>
|
|
<button data-wire-theme-set="dark">Dark</button></code></pre>
|
|
<h2 id="realtime">Realtime rooms</h2><pre><code><div data-room="chat" data-room-user="Ada">
|
|
<span data-room-status></span>
|
|
<div data-room-log></div>
|
|
<template data-room-item="message"><p>%user%: %text%</p></template>
|
|
<form data-room-send><input name="text" data-room-reset></form>
|
|
</div></code></pre>
|
|
<h2 id="native">Browser and native directives</h2><pre><code><button data-native-browser="share" data-native-mobile="share"
|
|
data-native-options='{"title":"WRNexusJS"}'>Share</button>
|
|
<nav data-native-only="mobile">Mobile navigation</nav>
|
|
<p data-native-only="browser">Browser instructions</p>
|
|
<button data-native-requires="haptics">Haptic action</button></code></pre>
|
|
<h2 id="other">Other framework attributes</h2><div class="table-wrap"><table><thead><tr><th>Attribute</th><th>Purpose</th></tr></thead><tbody><tr><td><code>data-error</code></td><td>Field validation error destination.</td></tr><tr><td><code>data-success</code></td><td>Successful form message.</td></tr><tr><td><code>data-redirect</code></td><td>Navigation after form success.</td></tr><tr><td><code>data-room-*</code></td><td>Realtime status, templates, sending, and reset behavior.</td></tr><tr><td><code>data-uploader</code></td><td>Config-driven upload widget.</td></tr><tr><td><code>data-wire-theme-*</code></td><td>Theme selection and toggling.</td></tr><tr><td><code>data-wire-lang*</code></td><td>Language selection.</td></tr><tr><td><code>data-native-*</code></td><td>Cross-platform capability and visibility behavior.</td></tr></tbody></table></div></article></main>
|
|
<footer>WRNexusJS 0.2.14 · SSR-first · Bun-native · Documentation generated from published package APIs.</footer>
|
|
</div>
|
|
}
|
|
}
|