Pomocniki preferencji
Siedem małych pakietów na framework, z których każdy posiada jedno zadanie użytkownika od początku do końca, plus pasek łączący pięć z nich. Znasz już theme-picker; oto locale-picker, text-size-picker i motion-picker (preferencje), share-picker i search-picker (akcje), date-time-picker (wartość formularza) oraz picker-bar.
Co zbudujesz
Panel ustawień, w którym użytkownicy wybierają język i rozmiar tekstu — wybory, które obowiązują w całym dokumencie, utrzymują się między wizytami i kosztują cię dwa komponenty oraz kilka linijek CSS. Około 15 minut.
Zanim zaczniesz
Najpierw ukończ samouczek frameworka dla swojego stosu. Poniższe przykłady są w Svelte; pomocniki dla Reacta, Vue, Angulara, HTML, Nunjucks i Blazora odpowiadają im kontrakt po kontrakcie.
Kształt, który współdzielą
- Bezstylowy przycisk-ikona otwierający listbox WAI-ARIA APG (albo, dla date-time-picker, okno wyboru daty) — bez natywnego
<select>, więc każdy framework dostaje to samo działanie klawiatury i te same haczyki stylów. - Jeden haczyk klasy na pakiet (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker), zero dostarczanego CSS. - Bezpieczny dla SSR: zapisy do DOM zachodzą tylko w cyklu życia mount/effect.
- Czysty pod i18n: każdy widoczny dla użytkownika napis jest propsem.
- Dostępne dla Svelte (kanoniczny), Reacta, Vue, Angulara, elementu niestandardowego HTML, Nunjucks i Blazora — ten sam kontrakt w każdym.
theme-picker, locale-picker i text-size-picker posiadają każdy jedną
preferencję użytkownika od początku do końca (wybór, zastosowanie do DOM, opcjonalna
localStorage trwałość przez props storageKey
). share-picker i date-time-picker są innego rodzaju: share-picker posiada akcję — nie stosuje niczego do dokumentu i niczego nie zapisuje — a date-time-picker posiada
wartość formularza, ponieważ data w formularzu to dane, a nie preferencja.
locale-picker — język i kierunek
Pozwala użytkownikowi wybrać ustawienia regionalne, a następnie zapisuje lang i
dir w korzeniu dokumentu, aby twoja biblioteka i18n, CSS i technologie wspomagające podążały za nim. RTL jest wykrywany automatycznie dla arabskiego, hebrajskiego i innych pism pisanych od prawej do lewej. Zajmuje się wyłącznie sygnalizowaniem — tłumaczenie obsługuje twoja biblioteka i18n.
<script>
import LocalePicker from "@lilydesignsystem/svelte-locale-picker";
let locale = $state("en-US");
</script>
<LocalePicker
label="Language"
locales={["en-US", "fr", "ar", "he", "ja"]}
bind:value={locale}
storageKey="my-app-locale"
/>
Opcje są podpisywane z wbudowanej tabeli nazw ustawień regionalnych (można nadpisać przez localeLabels), każda opcja ma własny atrybut
lang , aby czytniki ekranu wymawiały „Français” po francusku, a kody z podkreśleniem, takie jak en_US
są bezstratnie konwertowane do BCP 47 i z powrotem en-US. Podłącz
onChange (lub związaną wartość) do i18next, Paraglide, vue-i18n lub czegokolwiek używasz.
text-size-picker — rozmiar kontrolowany przez czytelnika
Zysk dla dostępności w kilka minut: pomocnik ustawia
data-text-size="{slug}" na korzeniu dokumentu, a twój CSS mapuje każdą wartość na rozmiar.
<script>
import TextSizePicker from "@lilydesignsystem/svelte-text-size-picker";
</script>
<TextSizePicker
label="Text size"
sizes={["small", "medium", "large", "x-large"]}
storageKey="my-app-text-size"
/>
:root[data-text-size="small"] { font-size: 87.5%; }
:root[data-text-size="medium"] { font-size: 100%; }
:root[data-text-size="large"] { font-size: 112.5%; }
:root[data-text-size="x-large"] { font-size: 125%; }
Zwymiaruj układ w rem a cała aplikacja skaluje się wraz z wyborem użytkownika. Etykiety powstają ze slugów z wielkiej litery („X Large”) lub są nadpisywane przez sizeLabels.
Sprawdź swoją pracę: wybierz „Large” w selektorze, a tekst strony rośnie. Odśwież — nadal jest duży: wybór został zapisany w
localStorage. Przełącz selektor języka na arabski, a
dir="rtl" zostanie ustawione na dokumencie automatycznie.
share-picker — wyślij tę stronę
Przycisk z jednym glifem, który otwiera natywny arkusz udostępniania urządzenia, jeśli taki istnieje, a w przeciwnym razie przechodzi na listę celów, które podasz, plus akcję kopiowania adresu URL. Nie dostarcza żadnych adresów URL sieci społecznościowych — które sieci pasują do twojego produktu, to twoja decyzja, a nie systemu projektowego.
<script>
import SharePicker from "@lilydesignsystem/svelte-share-picker";
const targets = [
{ id: "mastodon", label: "Mastodon",
href: (url, title) => `https://mastodon.social/share?text=${encodeURIComponent(title)}%20${encodeURIComponent(url)}` },
{ id: "email", label: "Email",
href: (url, title) => `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`, newTab: false },
];
</script>
<SharePicker
label="Share this page"
title="An article worth reading"
{targets}
copyLabel="Copy link"
copiedLabel="Link copied"
/>
url domyślnie ma wartość location.href, więc typowy przypadek nie wymaga okablowania. Wymuś ścieżkę przez strategy="list" lub
strategy="native" gdy potrzebujesz spójnego działania na różnych platformach do testów lub zrzutów ekranu.
date-time-picker — data, godzina lub oba
Pole tekstowe, w którym można pisać, plus przycisk-ikona otwierający okno wyboru daty WAI-ARIA APG. Poprawny regionalnie z założenia — nazwy miesięcy, nazwy dni tygodnia, pierwszy dzień tygodnia oraz zegar 12- lub 24-godzinny pochodzą z Intl — a wartość jest zawsze sortowalnym ciągiem ISO bez strefy czasowej: "2026-03-15" dla
mode="date", "09:30" dla
mode="time", "2026-03-15T09:30" dla
mode="datetime".
<script>
import DateTimePicker from "@lilydesignsystem/svelte-date-time-picker";
let appointment = $state("");
</script>
<DateTimePicker
inputId="appointment"
name="appointment"
label="Choose an appointment date"
locale="en-GB"
bind:value={appointment}
labels={{
previousYear: "Previous year",
previousMonth: "Previous month",
nextMonth: "Next month",
nextYear: "Next year",
confirm: "OK",
cancel: "Cancel",
}}
/>
Wartość ISO jest identyczna z tą, którą <input type="date">
wysyła, więc możesz wymienić natywną kontrolkę, nie dotykając backendu.
motion-picker — szanuj ograniczony ruch
Pomocnik ustawia data-motion="{slug}" na korzeniu dokumentu. Jego pierwsza wartość pochodzi z ustawienia
prefers-reduced-motion systemu operacyjnego odwiedzającego — zawsze, bez flagi włączającej, ponieważ ruch jest realną potrzebą dostępności (WCAG 2.3.3). Twój CSS i skrypty decydują, co zostanie stłumione.
<script>
import MotionPicker from "@lilydesignsystem/svelte-motion-picker";
</script>
<MotionPicker
label="Motion"
motions={["no-preference", "reduce"]}
storageKey="my-app-motion"
/>
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important;
}
search-picker — wyszukiwarka, która nie przeszkadza
Przycisk-ikona otwierający pole wyszukiwania. Naciśnięcie Return lub przycisku ⏎ obok pola nawiguje zwykłym żądaniem GET do
/?<text> (tekst jest przycinany i kodowany jako URI; puste zapytanie donikąd nie prowadzi). Jego trzy dostępne nazwy są wymagane, ponieważ pomocnik nie dostarcza angielskiego.
<script>
import SearchPicker from "@lilydesignsystem/svelte-search-picker";
import { goto } from "$app/navigation";
</script>
<SearchPicker
label="Search this site"
inputLabel="Search terms"
submitLabel="Search"
placeholder="Search…"
action="/search"
navigate={(href) => goto(href)}
/>
action zmienia ścieżkę (/search?foo), a
navigate zatrzymuje nawigację wewnątrz aplikacji; bez niego pomocnik wywołuje location.assign.
picker-bar — cały wiersz nagłówka naraz
picker-bar renderuje wyszukiwanie, motyw, język, rozmiar tekstu i udostępnianie w jednym wierszu, z pełnym zestawem motywów referencyjnych i siedmiostopniową skalą tekstu podłączonymi z góry. Każda dostępna nazwa przychodzi w jednym wymaganym obiekcie
labels .
<script>
import PickerBar from "@lilydesignsystem/svelte-picker-bar";
</script>
<PickerBar
labels={{
search: "Search", searchInput: "Search terms", searchSubmit: "Search",
theme: "Theme", locale: "Language", textSize: "Text size", share: "Share",
}}
themesUrl="/themes/"
locales={["en", "fr", "es"]}
shareTargets={targets}
/>
Dotrzyj do dowolnego opakowanego selektora przez searchProps,
themeProps, localeProps,
textSizeProps i shareProps.
Podpowiedzi są wbudowane
Każdy selektor pokazuje swoją etykietę w podpowiedzi, gdy wskaźnik spoczywa na jego przycisku lub przycisk ma fokus klawiatury. Podpowiedź pozostaje, gdy wskaźnik przesuwa się na nią, Escape zamyka ją niezależnie od tego, gdzie jest fokus, i nigdy nie pojawia się, gdy okno podręczne selektora jest otwarte. Niesie ten sam tekst co dostępna nazwa przycisku, więc nie ma nic do konfigurowania ani do dwukrotnego tłumaczenia; stylizują ją motywy referencyjne.
Panel ustawień w jednym miejscu
Cztery pomocniki preferencji składają się naturalnie:
<fieldset class="fieldset">
<legend>Preferences</legend>
<ThemePicker label="Theme" themesUrl="/themes/" themes={themes} storageKey="pref-theme" />
<LocalePicker label="Language" locales={locales} storageKey="pref-locale" />
<TextSizePicker label="Text size" sizes={sizes} storageKey="pref-text-size" />
<MotionPicker label="Motion" motions={motions} storageKey="pref-motion" />
</fieldset>
Zweryfikowano: fragmenty locale-picker, text-size-picker, share-picker, date-time-picker i połączonego panelu zostały skompilowane osobno względem opublikowanych 0.1.1 pakietów, przez
svelte/server (2026-08-29); fragmenty motion-picker, search-picker i picker-bar zostały wyrenderowane względem własnych komponentów pakietów 2026-10-06.
Gdzie je zdobyć
# one directory per package in the monorepo, e.g.
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-svelte-theme-picker
# or lily-design-system-react-theme-picker, -vue- / -angular- / -html- / -web-components- / -nunjucks- / -blazor-
Każdy pakiet ma własny spec, testy odwzorowane na klauzule specu, uruchamialne przykłady (w tym wzorce ciasteczek SSR) oraz potok budowania i publikacji. Pakiety Svelte są kanoniczne; w razie wątpliwości ich kontrakty wygrywają.
Następne kroki
- Katalog komponentów — pełna dokumentacja 571 komponentów.
- Pomoc — rozwiązywanie problemów i FAQ.
- Dlaczego Lily — i jak wesprzeć projekt.
Pytania po drodze? Strona pomocy jest pełna odpowiedzi — a jeśli jakiś krok mógłby być jaśniejszy, daj nam znać a chętnie ulepszymy samouczek.