Ajutoare pentru preferințe

Șapte pachete mici pe framework, fiecare deținând o sarcină a utilizatorului de la cap la coadă, plus o bară care le reunește pe cinci dintre ele. Ai întâlnit deja theme-picker; iată locale-picker, text-size-picker și motion-picker (preferințe), share-picker și search-picker (acțiuni), date-time-picker (o valoare de formular) și picker-bar.

Ce vei construi

Un panou de setări în care utilizatorii aleg limba și dimensiunea textului — alegeri care se aplică întregului document, persistă între vizite și te costă două componente și câteva rânduri de CSS. Aproximativ 15 minute.

Înainte să începi

Termină mai întâi tutorialul frameworkului pentru stiva ta. Exemplele de mai jos sunt în Svelte; ajutoarele pentru React, Vue, Angular, HTML, Nunjucks și Blazor corespund contract cu contract.

Forma pe care o împart

  • Un buton-pictogramă headless care deschide un listbox WAI-ARIA APG (sau, pentru date-time-picker, un dialog de alegere a datei) — fără <select>nativ, astfel încât fiecare framework primește același comportament al tastaturii și aceleași cârlige de stil.
  • Un cârlig de clasă pe pachet (.locale-picker, .text-size-picker, .share-picker, .date-time-picker), zero CSS livrat.
  • Sigur pentru SSR: scrierile în DOM au loc doar în ciclul de viață mount/effect.
  • Curat pentru i18n: fiecare șir vizibil utilizatorului este un prop.
  • Disponibil pentru Svelte (canonic), React, Vue, Angular, element personalizat HTML, Nunjucks și Blazor — același contract în fiecare.

theme-picker, locale-picker și text-size-picker dețin fiecare câte o preferință a utilizatorului de la cap la coadă (selecție, aplicare în DOM, localStorage persistență opțională prin prop-ul storageKey ). share-picker și date-time-picker sunt de alt fel: share-picker deține o acțiune — nu aplică nimic documentului și nu persistă nimic — iar date-time-picker deține o valoare de formular, deoarece o dată dintr-un formular este informație, nu o preferință.

locale-picker — limbă și direcție

Lasă utilizatorul să aleagă o localizare, apoi scrie lang și dir pe rădăcina documentului, astfel încât biblioteca ta i18n, CSS-ul tău și tehnologiile asistive să o urmeze. RTL este detectat automat pentru araba, ebraica și alte scrieri de la dreapta la stânga. Se concentrează strict pe semnalizare — biblioteca ta i18n se ocupă de traducere.

<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"
/>

Opțiunile sunt etichetate dintr-un tabel încorporat de nume de localizări (se poate suprascrie prin localeLabels), fiecare opțiune poartă propriul atribut lang ca cititoarele de ecran să pronunțe „Français” în franceză, iar codurile cu liniuță de subliniere precum en_US se convertesc fără pierderi în BCP 47 și înapoi en-US. Conectează onChange (sau valoarea legată) la i18next, Paraglide, vue-i18n sau orice folosești.

text-size-picker — dimensiune controlată de cititor

Un câștig de accesibilitate care durează minute: ajutorul setează data-text-size="{slug}" pe rădăcina documentului, iar CSS-ul tău mapează fiecare valoare la o dimensiune.

<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%; }

Dimensionează-ți aspectul în rem iar întreaga aplicație se scalează cu alegerea utilizatorului. Etichetele sunt formate din slug-uri cu majusculă inițială („X Large”) sau suprascrise cu sizeLabels.

Verifică-ți munca: alege „Large” din selector, iar textul paginii crește. Reîncarcă — tot mare e: alegerea a fost salvată persistent în localStorage. Comută selectorul de limbă pe arabă și dir="rtl" este setat automat pe document.

share-picker — trimite această pagină

Un buton cu un singur glif care deschide foaia de partajare nativă a dispozitivului acolo unde există, iar altfel revine la o listă de destinații pe care o furnizezi tu, plus o acțiune de copiere a URL-ului. Nu livrează niciun URL de rețea socială — ce rețele se potrivesc produsului tău este decizia ta, nu a sistemului de design.

<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 are valoarea implicită location.href, deci cazul obișnuit nu necesită nicio conectare. Forțează o cale cu strategy="list" sau strategy="native" când ai nevoie de comportament consecvent între platforme pentru teste sau capturi de ecran.

date-time-picker — o dată, o oră sau ambele

Un câmp de text în care poți tasta, plus un buton-pictogramă care deschide un dialog de alegere a datei WAI-ARIA APG. Corect local prin construcție — numele lunilor, numele zilelor, prima zi a săptămânii și ceasul de 12 sau 24 de ore vin toate din Intl — iar valoarea este întotdeauna un șir ISO sortabil și fără fus orar: "2026-03-15" pentru mode="date", "09:30" pentru mode="time", "2026-03-15T09:30" pentru 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",
  }}
/>

Valoarea ISO este identică cu ceea ce trimite <input type="date"> astfel încât poți schimba controlul nativ cu cel al bibliotecii sau invers fără a atinge backend-ul.

motion-picker — respectă mișcarea redusă

Ajutorul setează data-motion="{slug}" pe rădăcina documentului. Prima lui valoare provine din setarea prefers-reduced-motion a sistemului de operare al vizitatorului — întotdeauna, fără indicator de activare, deoarece mișcarea este o nevoie reală de accesibilitate (WCAG 2.3.3). CSS-ul și scripturile tale decid ce se suprimă.

<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 — o casetă de căutare care nu stă în cale

Un buton-pictogramă care deschide un câmp de căutare. Apăsarea tastei Return sau a butonului ⏎ de lângă câmp navighează printr-o cerere GET obișnuită către /?<text> (textul este tăiat de spații și codat URI; o interogare goală nu duce nicăieri). Cele trei nume accesibile ale sale sunt obligatorii, deoarece ajutorul nu livrează engleză.

<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 schimbă calea (/search?foo), iar navigate păstrează navigarea în aplicație; fără el ajutorul apelează location.assign.

picker-bar — tot rândul antetului deodată

picker-bar randează căutarea, tema, localizarea, dimensiunea textului și partajarea într-un singur rând, cu setul complet de teme de referință și scara de text în șapte trepte preconectate. Fiecare nume accesibil vine într-un singur obiect labels obligatoriu.

<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}
/>

Ajungi la orice selector învelit cu searchProps, themeProps, localeProps, textSizeProps și shareProps.

Baloanele explicative vin încorporate

Fiecare selector își arată eticheta într-un balon explicativ când cursorul se oprește pe butonul său sau butonul are focalizare de tastatură. Balonul rămâne cât timp cursorul se mută pe el, Escape îl închide oriunde ar fi focalizarea și nu apare niciodată cât timp fereastra pop-up a selectorului este deschisă. Poartă același text ca numele accesibil al butonului, deci nu e nimic de configurat și nimic de tradus de două ori; temele de referință îl stilizează.

Un panou de setări într-un singur loc

Cele patru ajutoare pentru preferințe se compun firesc:

<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>

Verificat: fragmentele pentru locale-picker, text-size-picker, share-picker, date-time-picker și panoul combinat au fost compilate individual față de pachetele publicate 0.1.1 , prin svelte/server (2026-08-29); fragmentele pentru motion-picker, search-picker și picker-bar au fost randate față de componentele proprii ale pachetelor la 2026-10-06.

De unde le obții

# 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-

Fiecare pachet are propriul spec, teste asociate clauzelor spec-ului, exemple executabile (inclusiv tipare de cookie-uri pentru SSR) și o conductă de build + publicare. Pachetele Svelte sunt canonice; la îndoială, contractele lor câștigă.

Pașii următori

Întrebări pe parcurs? Pagina de ajutor este plină de răspunsuri — iar dacă un pas poate fi mai clar, spune-ne și vom îmbunătăți cu plăcere tutorialul.