Допоміжні засоби налаштувань

Сім невеликих пакетів на фреймворк, кожен повністю відповідає за одне завдання користувача, плюс панель, що збирає п’ять із них. Ви вже знайомі з 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 відповідають їм контракт за контрактом.

Форма, яку вони розділяють

  • «Безголова» кнопка-значок, що відкриває список вибору WAI-ARIA APG (або, для date-time-picker, діалог вибору дати) — жодного нативного <select>, тож кожен фреймворк отримує однакову поведінку клавіатури та гачки стилізації.
  • Один клас-гачок на пакет (.locale-picker, .text-size-picker, .share-picker, .date-time-picker), нуль CSS у постачанні.
  • Безпечно для SSR: записи в DOM відбуваються лише в життєвому циклі mount/effect.
  • Чисто щодо i18n: кожен рядок, який бачить користувач, є властивістю.
  • Доступно для Svelte (канонічно), React, Vue, Angular, кастомного елемента HTML, Nunjucks і Blazor — той самий контракт у кожному.

theme-picker, locale-picker і text-size-picker повністю володіють кожен одним налаштуванням користувача (вибір, застосування до DOM, необов’язкова localStorage стійкість 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-

Кожен пакет має власну специфікацію, тести, зіставлені з пунктами специфікації, запускні приклади (зокрема шаблони cookie для SSR) і конвеєр збирання та публікації. Пакети Svelte — канонічні; у разі сумнівів перемагають їхні контракти.

Наступні кроки

Питання по дорозі? сторінка допомоги повна відповідей — а якщо якийсь крок може бути зрозумілішим, повідомте нам і ми із задоволенням покращимо посібник.