עוזרי העדפות

שבע חבילות קטנות לכל מסגרת, שכל אחת מהן מחזיקה במשימת משתמש אחת מקצה לקצה, בצירוף סרגל שמרכיב חמש מהן. כבר פגשתם את 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 וכל האפליקציה משתנה בקנה מידה עם בחירת המשתמש. התוויות נכתבות באות רישית מתוך ה-slug (“X Large”) או נעקפות באמצעות sizeLabels.

בדקו את העבודה שלכם: בחרו “Large” מהבורר, וטקסט העמוד גדל. טענו מחדש — הוא עדיין גדול: הבחירה נשמרה ב- localStorage. החליפו את בורר השפה לערבית ו- dir="rtl" מוגדר על המסמך אוטומטית.

share-picker — שלחו את העמוד הזה

כפתור בעל סימן יחיד שפותח את חלון השיתוף המקורי של המכשיר היכן שקיים, ואחרת חוזר לרשימת יעדים שאתם מספקים, בתוספת פעולת העתקת הכתובת. הוא אינו שולח כתובות של רשתות חברתיות — אילו רשתות שייכות למוצר שלכם זו החלטה שלכם, לא של מערכת העיצוב.

<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"> שולח, כך שתוכלו להחליף את הפקד המקורי פנימה והחוצה בלי לגעת ב-backend.

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.

כלי עזר מובנים (tooltips)

כל בורר מציג את התווית שלו ב-tooltip כשהסמן נח על הכפתור שלו או כשיש לכפתור מיקוד מקלדת. ה-tooltip נשאר כשהסמן עובר אליו, 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 הן הקנוניות; במקרה של ספק החוזים שלהן גוברים.

השלבים הבאים

שאלות בדרך? עמוד העזרה מלא בתשובות — ואם שלב יכול להיות ברור יותר, ספרו לנו ונשמח לשפר את המדריך.