Wizard
Wizard держит порядок шагов и текущий value: сверху полоса Steps, ниже содержимое шага из сниппета children, в подвале две кнопки. На первом шаге левая кнопка — отмена (oncancel), на последнем правая — отправка (onapply). В режиме modal мастер живёт в Dialog с заголовком и закрывается после отправки или отмены.
Статус: experimental · в системе с 2026-09 · интерактивность: always (всегда)
Когда использовать
- Создание сущности в несколько экранов: тип, настройки, подтверждение.
- Подключение интеграции с проверкой на последнем шаге.
Не использовать:
- Один экран формы — Steps не нужны.
- Шаги независимы и заполняются в любом порядке — это табы Page Navigation.
Альтернативы:
steps— только индикатор прогрессаform-modal— модальная форма с шагами без логики переходов
Создание кампании
Три шага в потоке страницы: отмена на первом, отправка на последнем.
Новая кампания
<!--
🟢
Создание кампании в три шага (эталон: Vue-легаси structures/stepByStep в
потоке страницы): полоса шагов, содержимое шага, отмена на первом и
отправка на последнем.
-->
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Input from "$lib/ui/Input.svelte";
import Wizard from "$lib/ui/Wizard.svelte";
const steps = [
{ value: "type", label: t("Тип") },
{ value: "settings", label: t("Настройки") },
{ value: "confirm", label: t("Подтверждение") },
];
let value = $state("type");
let name = $state("");
let budget = $state("");
let done = $state(false);
</script>
<div style="width: 480px;">
<Wizard {steps} bind:value title={t("Новая кампания")} onapply={() => (done = true)}>
{#snippet children({ step })}
{#if step.value === "type"}
<Input label={t("Название")} bind:value={name} />
{:else if step.value === "settings"}
<Input label={t("Дневной бюджет, ₽")} bind:value={budget} />
{:else}
<p style="margin: 0; font-size: var(--fs-s);">{t("Кампания «")}{name || t("без названия")}{t("», бюджет")} {budget || "0"} {t("₽ в день.")}</p>
{/if}
{/snippet}
</Wizard>
{#if done}<p aria-live="polite" style="font-size: var(--fs-s);">{t("Отправлено.")}</p>{/if}
</div>
В диалоге
modal: мастер в Dialog с заголовком, закрывается после отправки.
<!--
🟢
Мастер в диалоге (эталон: Vue-легаси stepByStep modal): кнопка открывает
Dialog с шагами, отправка закрывает его.
-->
<script>
import { t } from "$lib/spec/demo-lang.svelte.js";
import Button from "$lib/ui/Button.svelte";
import Input from "$lib/ui/Input.svelte";
import Wizard from "$lib/ui/Wizard.svelte";
const steps = [
{ value: "source", label: t("Источник") },
{ value: "rules", label: t("Правила") },
];
let open = $state(false);
let value = $state("source");
let url = $state("");
</script>
<Button variant="accent" onclick={() => { value = "source"; open = true; }}>{t("Подключить источник")}</Button>
<Wizard {steps} bind:value bind:open modal title={t("Новый источник")} applyLabel={t("Подключить")}>
{#snippet children({ step })}
{#if step.value === "source"}
<Input label={t("Адрес фида")} bind:value={url} />
{:else}
<p style="margin: 0; font-size: var(--fs-s);">{t("Правила отбора применяются после подключения.")}</p>
{/if}
{/snippet}
</Wizard>