@lilydesignsystem/html-picker-bar 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # Lily Design System™ — HTML PickerBar
2
+
3
+ > **Link picker (0.3.0).** Pass `links` (and `labels.link`) to add a `link-picker` — a home icon opening the page links your app defines — as the leftmost icon. It renders only when both are given.
4
+
5
+ > **Time zone picker (0.5.0).** Set `labels.timeZone` and `timeZoneProps = { locale: "fr" }` (plus any `<time-zone-picker>` property, e.g. `names`) to add a `time-zone-picker` — time zones by UTC offset with their full names — right after the locale picker. It renders only when both the label and the locale are given. To name the text sizes in the reader's language pass `sizeLabels` through the text-size props (`textSizeLabels(pack)` / `LocaleTranslations.TextSizeLabels(locale)` from the locale-translations package).
6
+
7
+ A single page-header custom element, `<picker-bar>`, that composes five
8
+ of the Lily [`*-picker` helpers](../index.md) — search, theme, locale,
9
+ text size, and share, in that order — with two catalog-wide defaults
10
+ pre-wired, so you can drop one element into a header instead of
11
+ assembling and configuring five.
12
+
13
+ `motion-picker` and `date-time-picker` are not part of the bar: motion
14
+ has no natural spot next to the other three header preferences, and
15
+ `date-time-picker` is a form control, not a header control.
16
+
17
+ ## Install
18
+
19
+ ```sh
20
+ npm install @lilydesignsystem/html-picker-bar
21
+ ```
22
+
23
+ `@lilydesignsystem/html-search-picker`, `-theme-picker`,
24
+ `-locale-picker`, `-text-size-picker`, and `-share-picker` install automatically as
25
+ regular dependencies — `<picker-bar>` is a thin wrapper around them,
26
+ not a reimplementation.
27
+
28
+ ## Usage
29
+
30
+ ```js
31
+ import "@lilydesignsystem/html-picker-bar";
32
+
33
+ const bar = document.createElement("picker-bar");
34
+ bar.labels = {
35
+ search: "Search this site",
36
+ searchInput: "Search terms",
37
+ searchSubmit: "Search",
38
+ theme: "Theme",
39
+ locale: "Language",
40
+ textSize: "Text size",
41
+ share: "Share",
42
+ };
43
+ bar.themesUrl = "/assets/themes/";
44
+ bar.locales = ["en", "cy", "gd", "ga"];
45
+ bar.shareTargets = [
46
+ {
47
+ id: "email",
48
+ label: "Email",
49
+ href: (url, title) => `mailto:?subject=${title}&body=${url}`,
50
+ },
51
+ ];
52
+ document.querySelector("header").appendChild(bar);
53
+ ```
54
+
55
+ Or in markup, for the parts that fit plain attributes:
56
+
57
+ ```html
58
+ <script type="module" src="/node_modules/lily-design-system-html-picker-bar/dist/index.js"></script>
59
+ <picker-bar themes-url="/assets/themes/" locales="en,cy,gd,ga"></picker-bar>
60
+ <script type="module">
61
+ document.querySelector("picker-bar").labels = {
62
+ search: "Search this site",
63
+ searchInput: "Search terms",
64
+ searchSubmit: "Search",
65
+ theme: "Theme",
66
+ locale: "Language",
67
+ textSize: "Text size",
68
+ share: "Share",
69
+ };
70
+ </script>
71
+ ```
72
+
73
+ Search sends a query for `foo` to `/?foo` by default. `labels` carries
74
+ seven names: three for search (`search` names its button and search
75
+ landmark, `searchInput` the field, `searchSubmit` the `⏎` button) and
76
+ one for each other picker.
77
+
78
+ `labels` has to be set as a JS property (no honest attribute encoding
79
+ exists for an object), same as `shareTargets` — see
80
+ `<date-time-picker>`'s `labels` and `<share-picker>`'s `targets` for the
81
+ same pattern elsewhere in this catalog.
82
+
83
+ ## Defaults
84
+
85
+ - **`themes`** defaults to `DEFAULT_THEMES` — all 45 Lily reference
86
+ theme slugs, alphabetical, with the 8 United Kingdom / United States
87
+ government themes moved to their own alphabetical group at the
88
+ bottom. Set your own `themes` attribute (comma-separated) or
89
+ `.themes` property (array) to override.
90
+ - **`sizes`** defaults to `DEFAULT_SIZES` — the seven-step scale
91
+ `largest`, `larger`, `large`, `normal`, `small`, `smaller`,
92
+ `smallest` — and the text-size picker starts on `normal`. Set your
93
+ own `sizes` to override (and `textSizeProps = { defaultValue: "…" }`
94
+ for a different starting point).
95
+
96
+ Both are exported as named constants:
97
+
98
+ ```js
99
+ import { DEFAULT_THEMES, DEFAULT_SIZES } from "@lilydesignsystem/html-picker-bar";
100
+ ```
101
+
102
+ ## Passing extra configuration to one picker
103
+
104
+ Each wrapped picker takes a `*Props` bag — a property, not an
105
+ attribute — for anything beyond what `<picker-bar>` lifts to the top
106
+ level: persistence, initial value, detection, a `*Labels` override map.
107
+
108
+ ```js
109
+ bar.searchProps = { action: "/search", placeholder: "Search…", navigate: (href) => router.push(href) };
110
+ bar.themeProps = { storageKey: "lily-theme", detectFromSystem: true };
111
+ bar.localeProps = { storageKey: "lily-locale", detectFromNavigator: true };
112
+ bar.textSizeProps = { storageKey: "lily-text-size" };
113
+ bar.shareProps = { copyLabel: "Copy link", copiedLabel: "Copied" };
114
+ ```
115
+
116
+ Set these **before** appending `bar` to the document — they apply to
117
+ the wrapped picker's element instance before it connects, so
118
+ persistence and initial-value resolution see them on first mount, the
119
+ same as if you had configured that picker directly.
120
+
121
+ ## Reading a wrapped picker directly
122
+
123
+ After `<picker-bar>` has rendered (i.e. once it's connected to the
124
+ document), each wrapped element is available as a read-only property:
125
+
126
+ ```js
127
+ bar.searchPicker; // the <search-picker> instance
128
+ bar.themePicker; // the <theme-picker> instance
129
+ bar.localePicker; // the <locale-picker> instance
130
+ bar.textSizePicker; // the <text-size-picker> instance
131
+ bar.sharePicker; // the <share-picker> instance
132
+ ```
133
+
134
+ Useful for attaching a `themechange` listener, reading `.value`, or any
135
+ other post-mount interaction — the elements are real, unmodified
136
+ instances of their own packages.
137
+
138
+ ## Styling
139
+
140
+ `<picker-bar>` renders no CSS of its own beyond the `picker-bar` root
141
+ wrapper class — style each child through its own package's class hooks
142
+ (`search-picker`, `theme-picker`, `locale-picker`, `text-size-picker`,
143
+ `share-picker`;
144
+ see each package's own `index.md`). A typical header layout:
145
+
146
+ ```css
147
+ .picker-bar {
148
+ display: flex;
149
+ gap: var(--theme-space-sm, 0.5rem);
150
+ align-items: center;
151
+ }
152
+ ```
153
+
154
+ ## Accessibility
155
+
156
+ Every accessible name comes from `labels` — there is no English
157
+ default, because a set of names this catalog invented is exactly the
158
+ case the rest of Lily's i18n rule exists for. Each wrapped picker keeps
159
+ its own WAI-ARIA APG contract unchanged; see that picker's own `index.md`.
160
+
161
+ ## Full contract
162
+
163
+ See [`spec/index.md`](./spec/index.md).
164
+
165
+ ---
166
+
167
+ Lily™ and Lily Design System™ are trademarks.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import { LinkItem, LinkPickerProps, LinkPicker } from '@lilydesignsystem/html-li
2
2
  import { SearchPickerProps, SearchPicker } from '@lilydesignsystem/html-search-picker';
3
3
  import { ThemePickerProps, ThemePicker } from '@lilydesignsystem/html-theme-picker';
4
4
  import { LocalePickerProps, LocalePicker } from '@lilydesignsystem/html-locale-picker';
5
+ import { TimeZonePickerProps, TimeZonePicker } from '@lilydesignsystem/html-time-zone-picker';
5
6
  import { TextSizePickerProps, TextSizePicker } from '@lilydesignsystem/html-text-size-picker';
6
7
  import { ShareTarget, SharePickerProps, SharePicker } from '@lilydesignsystem/html-share-picker';
7
8
  export { ShareTarget } from '@lilydesignsystem/html-share-picker';
@@ -55,6 +56,11 @@ type PickerBarLabels = {
55
56
  locale: string;
56
57
  /** Accessible name for the text-size picker's button and listbox. */
57
58
  textSize: string;
59
+ /**
60
+ * Accessible name for the time-zone picker's button and listbox. Needed only when
61
+ * `timeZoneProps.locale` is supplied; the time-zone picker renders only when both are present.
62
+ */
63
+ timeZone?: string;
58
64
  /** Accessible name for the share picker's button and list. */
59
65
  share: string;
60
66
  };
@@ -71,6 +77,7 @@ type LinkPickerExtra = Partial<Omit<LinkPickerProps, "label" | "links">>;
71
77
  type SearchPickerExtra = Partial<Omit<SearchPickerProps, "label" | "inputLabel" | "submitLabel">>;
72
78
  type ThemePickerExtra = Partial<Omit<ThemePickerProps, "label" | "themesUrl" | "themes">>;
73
79
  type LocalePickerExtra = Partial<Omit<LocalePickerProps, "label" | "locales">>;
80
+ type TimeZonePickerExtra = Partial<Omit<TimeZonePickerProps, "label">>;
74
81
  type TextSizePickerExtra = Partial<Omit<TextSizePickerProps, "label" | "sizes">>;
75
82
  type SharePickerExtra = Partial<Omit<SharePickerProps, "label" | "targets">>;
76
83
  /** Mirrors the observed attributes / properties for typing convenience. */
@@ -85,6 +92,8 @@ type PickerBarProps = {
85
92
  themeProps?: ThemePickerExtra;
86
93
  locales: string[];
87
94
  localeProps?: LocalePickerExtra;
95
+ /** `locale` (the language that names and sorts the zones) is required for the time-zone picker, after the locale picker, to render. */
96
+ timeZoneProps?: TimeZonePickerExtra;
88
97
  sizes?: string[];
89
98
  textSizeProps?: TextSizePickerExtra;
90
99
  shareTargets?: ShareTarget[];
@@ -117,6 +126,8 @@ declare class PickerBar extends HTMLElement {
117
126
  set themeProps(v: ThemePickerExtra);
118
127
  get localeProps(): LocalePickerExtra;
119
128
  set localeProps(v: LocalePickerExtra);
129
+ get timeZoneProps(): TimeZonePickerExtra;
130
+ set timeZoneProps(v: TimeZonePickerExtra);
120
131
  get textSizeProps(): TextSizePickerExtra;
121
132
  set textSizeProps(v: TextSizePickerExtra);
122
133
  get shareProps(): SharePickerExtra;
@@ -129,6 +140,8 @@ declare class PickerBar extends HTMLElement {
129
140
  get themePicker(): ThemePicker | null;
130
141
  /** The rendered `<locale-picker>` instance, once connected. */
131
142
  get localePicker(): LocalePicker | null;
143
+ /** The rendered `<time-zone-picker>` instance, once connected (null without a label and locale). */
144
+ get timeZonePicker(): TimeZonePicker | null;
132
145
  /** The rendered `<text-size-picker>` instance, once connected. */
133
146
  get textSizePicker(): TextSizePicker | null;
134
147
  /** The rendered `<share-picker>` instance, once connected. */
@@ -137,4 +150,5 @@ declare class PickerBar extends HTMLElement {
137
150
  attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
138
151
  }
139
152
 
140
- export { DEFAULT_SIZES, DEFAULT_THEMES, type LocalePickerExtra, PickerBar, type PickerBarLabels, type PickerBarProps, type SearchPickerExtra, type SharePickerExtra, type TextSizePickerExtra, type ThemePickerExtra };
153
+ export { DEFAULT_SIZES, DEFAULT_THEMES, PickerBar };
154
+ export type { LocalePickerExtra, PickerBarLabels, PickerBarProps, SearchPickerExtra, SharePickerExtra, TextSizePickerExtra, ThemePickerExtra, TimeZonePickerExtra };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import "@lilydesignsystem/html-link-picker";
3
3
  import "@lilydesignsystem/html-search-picker";
4
4
  import "@lilydesignsystem/html-theme-picker";
5
5
  import "@lilydesignsystem/html-locale-picker";
6
+ import "@lilydesignsystem/html-time-zone-picker";
6
7
  import "@lilydesignsystem/html-text-size-picker";
7
8
  import "@lilydesignsystem/html-share-picker";
8
9
  var DEFAULT_THEMES = [
@@ -100,6 +101,7 @@ var PickerBar = class extends HTMLElement {
100
101
  #searchProps = {};
101
102
  #themeProps = {};
102
103
  #localeProps = {};
104
+ #timeZoneProps = {};
103
105
  #textSizeProps = {};
104
106
  #shareProps = {};
105
107
  // Rendered-DOM references. Null until #render() has run.
@@ -108,6 +110,7 @@ var PickerBar = class extends HTMLElement {
108
110
  #searchPickerEl = null;
109
111
  #themePickerEl = null;
110
112
  #localePickerEl = null;
113
+ #timeZonePickerEl = null;
111
114
  #textSizePickerEl = null;
112
115
  #sharePickerEl = null;
113
116
  // ---- Property accessors ----
@@ -202,6 +205,13 @@ var PickerBar = class extends HTMLElement {
202
205
  this.#localeProps = v ?? {};
203
206
  this.#render();
204
207
  }
208
+ get timeZoneProps() {
209
+ return this.#timeZoneProps;
210
+ }
211
+ set timeZoneProps(v) {
212
+ this.#timeZoneProps = v ?? {};
213
+ this.#render();
214
+ }
205
215
  get textSizeProps() {
206
216
  return this.#textSizeProps;
207
217
  }
@@ -232,6 +242,10 @@ var PickerBar = class extends HTMLElement {
232
242
  get localePicker() {
233
243
  return this.#localePickerEl;
234
244
  }
245
+ /** The rendered `<time-zone-picker>` instance, once connected (null without a label and locale). */
246
+ get timeZonePicker() {
247
+ return this.#timeZonePickerEl;
248
+ }
235
249
  /** The rendered `<text-size-picker>` instance, once connected. */
236
250
  get textSizePicker() {
237
251
  return this.#textSizePickerEl;
@@ -304,6 +318,14 @@ var PickerBar = class extends HTMLElement {
304
318
  localeEl.locales = this.#locales;
305
319
  Object.assign(localeEl, this.#localeProps);
306
320
  root.appendChild(localeEl);
321
+ let timeZoneEl = null;
322
+ if (this.#labels.timeZone && this.#timeZoneProps.locale) {
323
+ timeZoneEl = document.createElement("time-zone-picker");
324
+ timeZoneEl.locale = this.#timeZoneProps.locale;
325
+ Object.assign(timeZoneEl, this.#timeZoneProps);
326
+ timeZoneEl.label = this.#labels.timeZone;
327
+ root.appendChild(timeZoneEl);
328
+ }
307
329
  const textSizeEl = document.createElement(
308
330
  "text-size-picker"
309
331
  );
@@ -322,6 +344,7 @@ var PickerBar = class extends HTMLElement {
322
344
  this.#searchPickerEl = searchEl;
323
345
  this.#themePickerEl = themeEl;
324
346
  this.#localePickerEl = localeEl;
347
+ this.#timeZonePickerEl = timeZoneEl;
325
348
  this.#textSizePickerEl = textSizeEl;
326
349
  this.#sharePickerEl = shareEl;
327
350
  }
package/index.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > **Link picker (0.3.0).** Pass `links` (and `labels.link`) to add a `link-picker` — a home icon opening the page links your app defines — as the leftmost icon. It renders only when both are given.
4
4
 
5
+ > **Time zone picker (0.5.0).** Set `labels.timeZone` and `timeZoneProps = { locale: "fr" }` (plus any `<time-zone-picker>` property, e.g. `names`) to add a `time-zone-picker` — time zones by UTC offset with their full names — right after the locale picker. It renders only when both the label and the locale are given. To name the text sizes in the reader's language pass `sizeLabels` through the text-size props (`textSizeLabels(pack)` / `LocaleTranslations.TextSizeLabels(locale)` from the locale-translations package).
6
+
5
7
  A single page-header custom element, `<picker-bar>`, that composes five
6
8
  of the Lily [`*-picker` helpers](../index.md) — search, theme, locale,
7
9
  text size, and share, in that order — with two catalog-wide defaults
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@lilydesignsystem/html-picker-bar",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "engines": {
5
- "node": "=26"
5
+ "node": ">=26"
6
6
  },
7
- "description": "Lily Design System HTML picker bar: composes link-picker (optional), search-picker, theme-picker, locale-picker, text-size-picker, and share-picker into one page-header row. Headless, SSR-safe, no CSS.",
7
+ "description": "Lily Design System HTML picker bar: composes link-picker (optional), search-picker, theme-picker, locale-picker, time-zone-picker (optional), text-size-picker, and share-picker into one page-header row. Headless, SSR-safe, no CSS.",
8
8
  "type": "module",
9
9
  "main": "./dist/index.js",
10
10
  "module": "./dist/index.js",
@@ -27,18 +27,19 @@
27
27
  "prepublishOnly": "npm run build"
28
28
  },
29
29
  "dependencies": {
30
- "@lilydesignsystem/html-link-picker": "^0.1.0",
31
- "@lilydesignsystem/html-search-picker": "^0.1.0",
32
- "@lilydesignsystem/html-theme-picker": "^0.2.0",
33
- "@lilydesignsystem/html-locale-picker": "^0.2.0",
34
- "@lilydesignsystem/html-text-size-picker": "^0.2.0",
35
- "@lilydesignsystem/html-share-picker": "^0.2.0"
30
+ "@lilydesignsystem/html-link-picker": "^0.2.0",
31
+ "@lilydesignsystem/html-locale-picker": "^0.3.1",
32
+ "@lilydesignsystem/html-search-picker": "^0.2.0",
33
+ "@lilydesignsystem/html-share-picker": "^0.3.0",
34
+ "@lilydesignsystem/html-text-size-picker": "^0.3.0",
35
+ "@lilydesignsystem/html-theme-picker": "^0.3.0",
36
+ "@lilydesignsystem/html-time-zone-picker": "^0.1.0"
36
37
  },
37
38
  "devDependencies": {
38
- "jsdom": "^30.1.1",
39
- "tsup": "^8.5.1",
39
+ "jsdom": "^30.1.3",
40
+ "tsup": "^9.0.0",
40
41
  "typescript": "^5.9.3",
41
- "vitest": "^5.0.3"
42
+ "vitest": "^5.0.5"
42
43
  },
43
44
  "keywords": [
44
45
  "lily",