Archived
143137e2b4
Counter.el defines Counter, CounterPair, and App components with {#if}
conditionals, event handlers, and child component composition.
render.js (generated by elc-ui --target=server) is the Node.js render
script the server calls. app.js (generated by elc-ui --target=web) is the
compiled browser module. hydrate.js attaches the runtime to the
server-rendered DOM without replacing it.
index.html shows the integration point with instructions for injecting
server output and the two CLI commands needed to regenerate both targets.
89 lines
2.4 KiB
EmacsLisp
89 lines
2.4 KiB
EmacsLisp
// ssr-counter/Counter.el
|
|
//
|
|
// A counter component that demonstrates:
|
|
// - State with initial value
|
|
// - {#if} conditional rendering
|
|
// - {#each} list rendering
|
|
// - Interpolation
|
|
// - Event binding
|
|
// - SSR + client hydration
|
|
//
|
|
// Run `node render.js Counter` to see the server-rendered HTML.
|
|
// Open index.html in a browser to see the full SSR + hydration lifecycle.
|
|
|
|
component Counter {
|
|
props {
|
|
initialValue: Int = 0
|
|
label: String = "Counter"
|
|
}
|
|
|
|
state {
|
|
count: Int = 0
|
|
history: String = ""
|
|
}
|
|
|
|
fn increment() -> Void {
|
|
count = count + 1
|
|
history = history + "+" + count + " "
|
|
}
|
|
|
|
fn decrement() -> Void {
|
|
count = count - 1
|
|
history = history + "-" + count + " "
|
|
}
|
|
|
|
fn reset() -> Void {
|
|
count = 0
|
|
history = ""
|
|
}
|
|
|
|
template {
|
|
<div class="counter">
|
|
<h2 class="counter-label">{label}</h2>
|
|
<div class="count-display">
|
|
<span class={count > 0 ? "count positive" : count < 0 ? "count negative" : "count zero"}>
|
|
{count}
|
|
</span>
|
|
</div>
|
|
<div class="buttons">
|
|
<button class="btn btn-decrement" on:click={() => decrement()}>-</button>
|
|
<button class="btn btn-reset" on:click={() => reset()}>reset</button>
|
|
<button class="btn btn-increment" on:click={() => increment()}>+</button>
|
|
</div>
|
|
{#if history != ""}
|
|
<div class="history">
|
|
<span class="history-label">history:</span>
|
|
<code>{history}</code>
|
|
</div>
|
|
{/if}
|
|
{#if count == 0}
|
|
<p class="hint">Press + or - to begin.</p>
|
|
{/if}
|
|
</div>
|
|
}
|
|
}
|
|
|
|
component CounterPair {
|
|
template {
|
|
<div class="counter-pair">
|
|
<Counter label="Left" />
|
|
<Counter label="Right" />
|
|
</div>
|
|
}
|
|
}
|
|
|
|
component App {
|
|
template {
|
|
<div class="app">
|
|
<header class="app-header">
|
|
<h1>el-ui SSR + Hydration</h1>
|
|
<p class="subtitle">Server-rendered, client-hydrated with spreading activation</p>
|
|
</header>
|
|
<main class="app-main">
|
|
<Counter label="Main Counter" />
|
|
<CounterPair />
|
|
</main>
|
|
</div>
|
|
}
|
|
}
|