Svelte (runes)
Svelte 5.7+ runes adapter — setLayerClient, useStack().current, callFor.
@stainless-code/svelte-layers (package root) binds stacks to Svelte 5 runes via createSubscriber. Most core symbols are re-exported. Core’s headless createLayer is createLayerHandle; the wired handle is createLayer.
Install
npm install @stainless-code/svelte-layerspnpm add @stainless-code/svelte-layersyarn add @stainless-code/svelte-layersbun add @stainless-code/svelte-layersPeer: svelte >=3.0.0 (runes entry requires Svelte 5.7+ for createSubscriber)
For Svelte 3–4 or store-based projects, use Svelte (store).
Client
Call setLayerClient() in a parent component (creates a LayerClient when omitted). Descendants read it with useLayerClient():
<script>
import { setLayerClient } from "@stainless-code/svelte-layers";
setLayerClient();
</script>
Render a stack
useStack({ stack }) returns a SvelteStack with .current (the selected snapshot) and .callFor(state) (the call context). Iterate in your markup:
<script>
import { useStack } from "@stainless-code/svelte-layers";
const stack = useStack({ stack: "confirm" });
</script>
{#each stack.current as state (state.id)}
{@const call = stack.callFor(state)}
{#if call}
<Confirm {call} payload={state.payload} />
{/if}
{/each}
useStack({ stack }).current + callFor is the headless equivalent of useStackHandles — no separate export.
Confirm dialog
<script lang="ts">
import {
createLayer,
layerOptions,
setLayerClient,
useStack,
} from "@stainless-code/svelte-layers";
type ConfirmPayload = { title: string };
type ConfirmResponse = boolean;
setLayerClient();
const confirmStack = useStack({ stack: "confirm" });
const confirm = layerOptions<ConfirmPayload, ConfirmResponse>({
stack: "confirm",
key: ["confirm", "remove"],
});
const c = createLayer(confirm);
async function remove() {
await c.open({ title: "Remove item?" });
}
</script>
{#each confirmStack.current as state (state.id)}
{@const call = confirmStack.callFor(state)}
{#if call}
<div role="dialog">
<h2>{state.payload.title}</h2>
<button onclick={() => void call.end(true)}>Yes</button>
<button onclick={() => void call.end(false)}>No</button>
</div>
{/if}
{/each}
<button onclick={remove}>Remove</button>
Primitives
Options bag plus optional trailing LayerClient. Drive with createLayer(options); observe with createLayerState({ key, … }). Queued counterparts: createQueuedStack, createLayerQueuedState.
| Export | Role |
|---|---|
setLayerClient(client?) |
Provide a LayerClient via Svelte context |
useLayerClient() |
Read the nearest context client |
useStack({ stack?, select?, compare? }, client?) |
SvelteStack with .current and .callFor(state) |
createLayer(options, client?) |
Drive — wired handle + open() / dismiss() + reactive state / queued / top |
createLayerState({ key, stack?, select?, compare? }, client?) |
Observe — SvelteStack whose .current is mounted same-key LayerState[] |
createLayerQueuedState({ key, stack?, select?, compare? }, client?) |
Observe — queued same-key layers |
Ergonomic APIs
| Export | Role |
|---|---|
useMutationFlow(call) |
pending getter (reactive via createSubscriber); run(fn).orEnd(response) |
useLayerGroup(call, options?) |
Child stack — render {#each group.stack.current} + group.stack.callFor(s) |
No shipped outlet or subscribe components — render with useStack().current + callFor in your markup.
Learn more
- Svelte (store) —
Readablestores for Svelte 3+ - Lifecycle · Adapter parity