Помощници за предпочитания
Седем малки пакета на фреймуърк, всеки от които притежава една потребителска задача от начало до край, плюс лента, която събира пет от тях. Вече се запознахте с theme-picker; ето locale-picker, text-size-picker и motion-picker (предпочитания), share-picker и search-picker (действия), date-time-picker (стойност на форма) и picker-bar.
Какво ще изградите
Панел с настройки, в който потребителите избират език и размер на текста — избори, които важат за целия документ, запазват се между посещенията и ви струват два компонента и няколко реда CSS. Около 15 минути.
Преди да започнете
Първо завършете ръководството за фреймуърка за вашия стек. Примерите по-долу са на Svelte; помощниците за React, Vue, Angular, HTML, Nunjucks и Blazor съответстват договор по договор.
Формата, която споделят
- Headless бутон-икона, който отваря WAI-ARIA APG listbox (или, за date-time-picker, диалог за избор на дата) — без роден
<select>, така че всеки фреймуърк получава еднакво поведение на клавиатурата и стилови куки. - Една класова кука на пакет (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker), нула доставен CSS. - Безопасно за SSR: записите в DOM стават само в жизнения цикъл mount/effect.
- Чисто за i18n: всеки низ, видим за потребителя, е prop.
- Налично за Svelte (каноничен), React, Vue, Angular, персонализиран HTML елемент, Nunjucks и Blazor — един и същ договор във всеки.
theme-picker, locale-picker и text-size-picker притежават всеки по едно потребителско
предпочитание от начало до край (избор, прилагане към DOM, незадължително
localStorage запазване чрез prop-а storageKey
). share-picker и date-time-picker са различни по вид: share-picker притежава действие — не прилага нищо към документа и не запазва нищо — а date-time-picker притежава
стойност на форма, защото датата във форма са данни, а не предпочитание.
locale-picker — език и посока
Позволява на потребителя да избере локал, после записва lang и
dir върху корена на документа, така че вашата i18n библиотека, вашият CSS и помощните технологии да го следват. RTL се открива автоматично за арабски, иврит и други писмености отдясно наляво. Занимава се само със сигнализиране — преводът е работа на вашата 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"
/>
Опциите се означават от вградена таблица с имена на локали (презаписва се чрез localeLabels), всяка опция носи собствен атрибут
lang , за да произнасят екранните четци „Français“ на френски, а кодовете с долна черта като en_US
се преобразуват без загуби към BCP 47 и обратно en-US. Свържете
onChange (или обвързаната стойност) с i18next, Paraglide, vue-i18n или каквото използвате.
text-size-picker — размер, контролиран от читателя
Победа за достъпността за минути: помощникът задава
data-text-size="{slug}" върху корена на документа, а вашият CSS съпоставя всяка стойност с размер.
<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%; }
Оразмерете оформлението си в rem и цялото приложение се мащабира според избора на потребителя. Етикетите се образуват от слъговете с главна буква („X Large“) или се презаписват с sizeLabels.
Проверете работата си: изберете „Large“ от селектора и текстът на страницата расте. Презаредете — още е голям: изборът е запазен в
localStorage. Превключете селектора на език на арабски и
dir="rtl" се задава автоматично върху документа.
share-picker — изпратете тази страница
Бутон с един глиф, който отваря родния лист за споделяне на устройството, където има такъв, а иначе се връща към списък с дестинации, които вие доставяте, плюс действие за копиране на URL. Не доставя URL адреси на социални мрежи — кои мрежи принадлежат на вашия продукт е ваше решение, не на дизайн системата.
<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 по подразбиране е location.href, така че обичайният случай не изисква свързване. Наложете път с strategy="list" или
strategy="native" когато ви трябва последователно поведение между платформите за тестове или снимки на екрана.
date-time-picker — дата, час или и двете
Текстово поле, в което можете да пишете, плюс бутон-икона, който отваря диалог за избор на дата по WAI-ARIA APG. Правилен за локала по конструкция — имената на месеците, имената на дните, първият ден от седмицата и 12- или 24-часовият часовник идват от Intl — а стойността винаги е сортируем ISO низ без часова зона: "2026-03-15" за
mode="date", "09:30" за
mode="time", "2026-03-15T09:30" за
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",
}}
/>
ISO стойността е идентична с това, което <input type="date">
изпраща, така че можете да смените родния контрол вътре или вън, без да пипате бекенда.
motion-picker — уважавайте намаленото движение
Помощникът задава data-motion="{slug}" върху корена на документа. Първата му стойност идва от настройката
prefers-reduced-motion на операционната система на посетителя — винаги, без флаг за включване, защото движението е реална нужда от достъпност (WCAG 2.3.3). Вашият CSS и скриптове решават какво да се потисне.
<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 — поле за търсене, което не пречи
Бутон-икона, който отваря поле за търсене. Натискането на Return или на бутона ⏎ до полето навигира с обикновена GET заявка към
/?<text> (текстът се подрязва и се кодира като URI; празна заявка не води никъде). Трите му достъпни имена са задължителни, защото помощникът не доставя английски.
<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 променя пътя (/search?foo), а
navigate задържа навигацията вътре в приложението; без него помощникът извиква location.assign.
picker-bar — целият ред на заглавката наведнъж
picker-bar рендира търсене, тема, локал, размер на текста и споделяне в един ред, с пълния набор референтни теми и седемстепенната скала за текст предварително свързани. Всяко достъпно име идва в един задължителен
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}
/>
Достигнете всеки обвит селектор с searchProps,
themeProps, localeProps,
textSizeProps и shareProps.
Подсказките са вградени
Всеки селектор показва етикета си в подсказка, когато показалецът почива върху бутона му или бутонът има фокус от клавиатурата. Подсказката остава, докато показалецът се премества върху нея, Escape я затваря, където и да е фокусът, и никога не се показва, докато изскачащият прозорец на селектора е отворен. Носи същия текст като достъпното име на бутона, така че няма какво да се конфигурира и няма какво да се превежда два пъти; референтните теми я стилизират.
Панел с настройки на едно място
Четирите помощника за предпочитания се комбинират естествено:
<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>
Проверено: фрагментите за locale-picker, text-size-picker, share-picker, date-time-picker и комбинирания панел бяха компилирани поотделно спрямо публикуваните 0.1.1 пакети, чрез
svelte/server (2026-08-29); фрагментите за motion-picker, search-picker и picker-bar бяха рендирани спрямо собствените компоненти на пакетите на 2026-10-06.
Откъде да ги вземете
# 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-
Всеки пакет има собствен spec, тестове, съпоставени към клаузите на spec-а, изпълними примери (включително модели с бисквитки за SSR) и конвейер за изграждане и публикуване. Пакетите за Svelte са каноничните; при съмнение техните договори печелят.
Следващи стъпки
- Каталог на компонентите — пълната справка за 571-те компонента.
- Помощ — отстраняване на неизправности и често задавани въпроси.
- Защо Lily — и как да подкрепите проекта.
Въпроси по пътя? Страницата за помощ е пълна с отговори — а ако някоя стъпка може да е по-ясна, кажете ни и с радост ще подобрим ръководството.