@lilydesignsystem/nunjucks-picker-bar 0.4.0 → 0.5.0

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,166 @@
1
+ # Lily Design System™ — Nunjucks 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).** Pass `labels.timeZone` and `timeZoneProps: { locale, options }`, where `options = timeZoneOptions({ locale })` from `@lilydesignsystem/nunjucks-time-zone-picker` is built where the page is built (and `names` there for CLDR 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 macro that composes five of the Lily
8
+ [`*-picker` helpers](../index.md) in this catalog — search, theme,
9
+ locale, text size, and share, in that order — with two catalog-wide
10
+ defaults pre-wired, so you can call one macro instead of assembling
11
+ 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/nunjucks-picker-bar
21
+ ```
22
+
23
+ `@lilydesignsystem/nunjucks-search-picker`, `-theme-picker`,
24
+ `-locale-picker`, `-text-size-picker`, and `-share-picker` install
25
+ automatically as
26
+ regular dependencies — `pickerBar` is a thin wrapper around them, not
27
+ a reimplementation.
28
+
29
+ Point your Nunjucks `Environment` at `node_modules` so the macro's
30
+ cross-package imports resolve:
31
+
32
+ ```js
33
+ import nunjucks from "nunjucks";
34
+ const env = nunjucks.configure(["views", "node_modules"], { autoescape: true });
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ```njk
40
+ {% from "lily-design-system-nunjucks-picker-bar/dist/picker-bar.njk" import pickerBar %}
41
+
42
+ {{ pickerBar({
43
+ labels: {
44
+ search: "Search this site",
45
+ searchInput: "Search terms",
46
+ searchSubmit: "Search",
47
+ theme: "Theme",
48
+ locale: "Language",
49
+ textSize: "Text size",
50
+ share: "Share"
51
+ },
52
+ themesUrl: "/assets/themes/",
53
+ locales: ["en", "cy", "gd", "ga"],
54
+ shareTargets: [
55
+ { id: "email", label: "Email", href: "mailto:?subject=Check this out&body=https://example.com" }
56
+ ]
57
+ }) }}
58
+ ```
59
+
60
+ Then load `picker-bar.client.js` once and call `autoInit()`:
61
+
62
+ ```html
63
+ <script type="module">
64
+ import { autoInit } from "/path/to/picker-bar.client.js";
65
+ autoInit();
66
+ </script>
67
+ ```
68
+
69
+ That's a complete, working header row: a site search (a search for
70
+ `foo` goes to `/?foo`), 45 themes, four locales, the
71
+ seven-step text-size scale, and one share destination plus copy-to-URL
72
+ if you add `shareProps: { copyLabel: "Copy link" }`.
73
+
74
+ Note the [`share-picker` deviation](../lily-design-system-nunjucks-share-picker/index.md):
75
+ `href` in `shareTargets` is an already-resolved string, not a
76
+ function — a Nunjucks macro cannot call an arbitrary JS function.
77
+
78
+ ## Defaults
79
+
80
+ - **`themes`** defaults to `DEFAULT_THEMES` — all 45 Lily reference
81
+ theme slugs, alphabetical, with the 8 United Kingdom / United States
82
+ government themes moved to their own alphabetical group at the
83
+ bottom. Pass your own `themes` array to override.
84
+ - **`sizes`** defaults to `DEFAULT_SIZES` — the seven-step scale
85
+ `largest`, `larger`, `large`, `normal`, `small`, `smaller`,
86
+ `smallest` — and the text-size picker starts on `normal`. Pass your
87
+ own `sizes` array (and `textSizeProps: { defaultValue: "…" }` if
88
+ you want a different starting point) to override.
89
+
90
+ Both are exported from the client.js module too:
91
+
92
+ ```js
93
+ import { DEFAULT_THEMES, DEFAULT_SIZES } from "@lilydesignsystem/nunjucks-picker-bar";
94
+ ```
95
+
96
+ ## Passing extra params to one picker
97
+
98
+ Each wrapped picker takes a `*Props` object for anything beyond what
99
+ `pickerBar` lifts to the top level — persistence, initial value,
100
+ detection, a `*Labels` override map, an `id`:
101
+
102
+ ```njk
103
+ {{ pickerBar({
104
+ labels: {
105
+ search: "Search this site", searchInput: "Search terms", searchSubmit: "Search",
106
+ theme: "Theme", locale: "Language", textSize: "Text size", share: "Share"
107
+ },
108
+ themesUrl: "/assets/themes/",
109
+ locales: ["en", "cy"],
110
+ searchProps: { action: "/search", placeholder: "Search…" },
111
+ themeProps: { storageKey: "lily-theme", detectFromSystem: true },
112
+ localeProps: { storageKey: "lily-locale", detectFromNavigator: true },
113
+ textSizeProps: { storageKey: "lily-text-size" },
114
+ shareProps: { copyLabel: "Copy link", copiedLabel: "Copied" }
115
+ }) }}
116
+ ```
117
+
118
+ `search-picker`'s function-valued options — `navigate` (default
119
+ `location.assign`) and `onSearch` — cannot pass through a macro, so
120
+ hand them to the client instead:
121
+
122
+ ```js
123
+ autoInit({ searchProps: { navigate: (href) => router.go(href) } });
124
+ ```
125
+
126
+ Unlike the Svelte canonical, `pickerBar` cannot route a custom glyph to
127
+ one specific picker (a Nunjucks macro call accepts only one
128
+ `{% call %}` block) — compose the five macros directly if you need
129
+ that.
130
+
131
+ ## Styling
132
+
133
+ `pickerBar` renders no CSS of its own beyond the `picker-bar` root
134
+ wrapper — style each child through its own package's class hooks
135
+ (`search-picker`, `theme-picker`, `locale-picker`, `text-size-picker`,
136
+ `share-picker`;
137
+ see each package's own `index.md`). A typical header layout:
138
+
139
+ ```css
140
+ .picker-bar {
141
+ display: flex;
142
+ gap: var(--theme-space-sm, 0.5rem);
143
+ align-items: center;
144
+ }
145
+ ```
146
+
147
+ ## Accessibility
148
+
149
+ Every accessible name comes from `labels` — `search`, `searchInput`,
150
+ and `searchSubmit` name the search picker's button and landmark, field,
151
+ and `⏎` button; `theme`, `locale`, `textSize`, `share` the others —
152
+ and there is no English
153
+ default, because a set of names this catalog invented is exactly the
154
+ case the rest of Lily's i18n rule exists for. Each wrapped picker keeps
155
+ its own WAI-ARIA APG contract unchanged; see that picker's own
156
+ `index.md`. As with every helper in this catalog, none of the five is
157
+ operable until its client.js has run — see each package's own
158
+ `docs/ssr.md`.
159
+
160
+ ## Full contract
161
+
162
+ See [`spec/index.md`](./spec/index.md).
163
+
164
+ ---
165
+
166
+ Lily™ and Lily Design System™ are trademarks.
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ import { initLocalePicker } from '@lilydesignsystem/nunjucks-locale-picker';
8
8
  export { autoInit as autoInitLocalePicker } from '@lilydesignsystem/nunjucks-locale-picker';
9
9
  import { initTextSizePicker } from '@lilydesignsystem/nunjucks-text-size-picker';
10
10
  export { autoInit as autoInitTextSizePicker } from '@lilydesignsystem/nunjucks-text-size-picker';
11
+ import { initTimeZonePicker } from '@lilydesignsystem/nunjucks-time-zone-picker';
11
12
  import { initSharePicker } from '@lilydesignsystem/nunjucks-share-picker';
12
13
  export { autoInit as autoInitSharePicker } from '@lilydesignsystem/nunjucks-share-picker';
13
14
 
@@ -115,7 +116,7 @@ const DEFAULT_SIZES = [
115
116
  * rendered one.
116
117
  *
117
118
  * @param {HTMLElement} root
118
- * @param {{linkProps?: object, searchProps?: object, themeProps?: object, localeProps?: object, textSizeProps?: object, shareProps?: object}=} opts
119
+ * @param {{linkProps?: object, searchProps?: object, themeProps?: object, localeProps?: object, timeZoneProps?: object, textSizeProps?: object, shareProps?: object}=} opts
119
120
  */
120
121
  function initPickerBar(root, opts = {}) {
121
122
  if (!root) {
@@ -124,6 +125,7 @@ function initPickerBar(root, opts = {}) {
124
125
  search: null,
125
126
  theme: null,
126
127
  locale: null,
128
+ timeZone: null,
127
129
  textSize: null,
128
130
  share: null,
129
131
  };
@@ -133,6 +135,7 @@ function initPickerBar(root, opts = {}) {
133
135
  searchProps = {},
134
136
  themeProps = {},
135
137
  localeProps = {},
138
+ timeZoneProps = {},
136
139
  textSizeProps = {},
137
140
  shareProps = {},
138
141
  } = opts;
@@ -141,6 +144,7 @@ function initPickerBar(root, opts = {}) {
141
144
  const searchRoot = root.querySelector("[data-lily-search-picker-root]");
142
145
  const themeRoot = root.querySelector("[data-lily-theme-picker-root]");
143
146
  const localeRoot = root.querySelector("[data-lily-locale-picker-root]");
147
+ const timeZoneRoot = root.querySelector("[data-lily-time-zone-picker-root]");
144
148
  const textSizeRoot = root.querySelector(
145
149
  "[data-lily-text-size-picker-root]",
146
150
  );
@@ -151,6 +155,7 @@ function initPickerBar(root, opts = {}) {
151
155
  search: searchRoot ? initSearchPicker(searchRoot, searchProps) : null,
152
156
  theme: themeRoot ? initThemePicker(themeRoot, themeProps) : null,
153
157
  locale: localeRoot ? initLocalePicker(localeRoot, localeProps) : null,
158
+ timeZone: timeZoneRoot ? initTimeZonePicker(timeZoneRoot, timeZoneProps) : null,
154
159
  textSize: textSizeRoot
155
160
  ? initTextSizePicker(textSizeRoot, textSizeProps)
156
161
  : null,
@@ -161,7 +166,7 @@ function initPickerBar(root, opts = {}) {
161
166
  /**
162
167
  * Find every `[data-lily-picker-bar-root]` and wire it.
163
168
  *
164
- * @param {{linkProps?: object, searchProps?: object, themeProps?: object, localeProps?: object, textSizeProps?: object, shareProps?: object}=} opts
169
+ * @param {{linkProps?: object, searchProps?: object, themeProps?: object, localeProps?: object, timeZoneProps?: object, textSizeProps?: object, shareProps?: object}=} opts
165
170
  * @returns {Array<ReturnType<typeof initPickerBar>>}
166
171
  */
167
172
  function autoInit(opts = {}) {
package/dist/index.js CHANGED
@@ -19,6 +19,10 @@ import {
19
19
  initTextSizePicker,
20
20
  autoInit as autoInitTextSizePicker
21
21
  } from "@lilydesignsystem/nunjucks-text-size-picker";
22
+ import {
23
+ initTimeZonePicker,
24
+ autoInit as autoInitTimeZonePicker
25
+ } from "@lilydesignsystem/nunjucks-time-zone-picker";
22
26
  import {
23
27
  initSharePicker,
24
28
  autoInit as autoInitSharePicker
@@ -98,6 +102,7 @@ function initPickerBar(root, opts = {}) {
98
102
  search: null,
99
103
  theme: null,
100
104
  locale: null,
105
+ timeZone: null,
101
106
  textSize: null,
102
107
  share: null
103
108
  };
@@ -107,6 +112,7 @@ function initPickerBar(root, opts = {}) {
107
112
  searchProps = {},
108
113
  themeProps = {},
109
114
  localeProps = {},
115
+ timeZoneProps = {},
110
116
  textSizeProps = {},
111
117
  shareProps = {}
112
118
  } = opts;
@@ -114,6 +120,7 @@ function initPickerBar(root, opts = {}) {
114
120
  const searchRoot = root.querySelector("[data-lily-search-picker-root]");
115
121
  const themeRoot = root.querySelector("[data-lily-theme-picker-root]");
116
122
  const localeRoot = root.querySelector("[data-lily-locale-picker-root]");
123
+ const timeZoneRoot = root.querySelector("[data-lily-time-zone-picker-root]");
117
124
  const textSizeRoot = root.querySelector(
118
125
  "[data-lily-text-size-picker-root]"
119
126
  );
@@ -123,6 +130,7 @@ function initPickerBar(root, opts = {}) {
123
130
  search: searchRoot ? initSearchPicker(searchRoot, searchProps) : null,
124
131
  theme: themeRoot ? initThemePicker(themeRoot, themeProps) : null,
125
132
  locale: localeRoot ? initLocalePicker(localeRoot, localeProps) : null,
133
+ timeZone: timeZoneRoot ? initTimeZonePicker(timeZoneRoot, timeZoneProps) : null,
126
134
  textSize: textSizeRoot ? initTextSizePicker(textSizeRoot, textSizeProps) : null,
127
135
  share: shareRoot ? initSharePicker(shareRoot, shareProps) : null
128
136
  };
@@ -30,6 +30,7 @@
30
30
  {% from "lily-design-system-nunjucks-theme-picker/dist/theme-picker.njk" import themePicker %}
31
31
  {% from "lily-design-system-nunjucks-locale-picker/dist/locale-picker.njk" import localePicker %}
32
32
  {% from "lily-design-system-nunjucks-text-size-picker/dist/text-size-picker.njk" import textSizePicker %}
33
+ {% from "lily-design-system-nunjucks-time-zone-picker/dist/time-zone-picker.njk" import timeZonePicker %}
33
34
  {% from "lily-design-system-nunjucks-share-picker/dist/share-picker.njk" import sharePicker %}
34
35
  {#
35
36
  All 57 Lily reference theme slugs (see `themes/` at the repo root),
@@ -73,7 +74,7 @@
73
74
  {#
74
75
  Params (single `opts` object):
75
76
  labels — object, required: { link?, search, searchInput,
76
- searchSubmit, theme, locale, textSize, share }.
77
+ searchSubmit, theme, locale, timeZone?, textSize, share }.
77
78
  `link` names the link picker's button and list and is
78
79
  needed only when `links` is supplied.
79
80
  The seven accessible names: `search` names the
@@ -95,6 +96,11 @@
95
96
  no catalog default exists.
96
97
  themes — array<string>. Defaults to DEFAULT_THEMES (above).
97
98
  sizes — array<string>. Defaults to DEFAULT_SIZES (above).
99
+ timeZoneProps — object. The time-zone picker, rendered after the locale picker only when this has `locale`
100
+ and `options` AND `labels.timeZone` is set. `options` is built where the page is built with
101
+ `timeZoneOptions({ locale, zones?, date?, labelFor?, names? })` from
102
+ @lilydesignsystem/nunjucks-time-zone-picker (a macro cannot call `Intl`); the rest are
103
+ time-zone-picker opts (date, value, defaultValue, storageKey, name, id, classes, attributes).
98
104
  shareTargets — array<object>. Forwarded to share-picker's `targets`
99
105
  (default []). See share-picker.njk for the object
100
106
  shape — `href` is an already-resolved string, not a
@@ -148,6 +154,7 @@
148
154
  {%- set searchProps = opts.searchProps | default({}) -%}
149
155
  {%- set themeProps = opts.themeProps | default({}) -%}
150
156
  {%- set localeProps = opts.localeProps | default({}) -%}
157
+ {%- set timeZoneProps = opts.timeZoneProps | default({}) -%}
151
158
  {%- set textSizeProps = opts.textSizeProps | default({}) -%}
152
159
  {%- set shareProps = opts.shareProps | default({}) -%}
153
160
  <div
@@ -206,6 +213,21 @@
206
213
  classes: localeProps.classes,
207
214
  attributes: localeProps.attributes
208
215
  }) }}
216
+ {%- if opts.labels.timeZone and timeZoneProps.locale and timeZoneProps.options %}
217
+ {{ timeZonePicker({
218
+ label: opts.labels.timeZone,
219
+ locale: timeZoneProps.locale,
220
+ options: timeZoneProps.options,
221
+ date: timeZoneProps.date,
222
+ value: timeZoneProps.value,
223
+ defaultValue: timeZoneProps.defaultValue,
224
+ storageKey: timeZoneProps.storageKey,
225
+ name: timeZoneProps.name,
226
+ id: timeZoneProps.id,
227
+ classes: timeZoneProps.classes,
228
+ attributes: timeZoneProps.attributes
229
+ }) }}
230
+ {%- endif %}
209
231
  {{ textSizePicker({
210
232
  label: opts.labels.textSize,
211
233
  sizes: sizes,
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).** Pass `labels.timeZone` and `timeZoneProps: { locale, options }`, where `options = timeZoneOptions({ locale })` from `@lilydesignsystem/nunjucks-time-zone-picker` is built where the page is built (and `names` there for CLDR 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 macro that composes five of the Lily
6
8
  [`*-picker` helpers](../index.md) in this catalog — search, theme,
7
9
  locale, text size, and share, in that order — with two catalog-wide
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@lilydesignsystem/nunjucks-picker-bar",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "engines": {
5
- "node": "=26"
5
+ "node": ">=26"
6
6
  },
7
- "description": "Lily Design System Nunjucks 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 Nunjucks 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",
@@ -33,14 +33,15 @@
33
33
  "@lilydesignsystem/nunjucks-theme-picker": "^0.2.0",
34
34
  "@lilydesignsystem/nunjucks-locale-picker": "^0.2.0",
35
35
  "@lilydesignsystem/nunjucks-text-size-picker": "^0.2.0",
36
+ "@lilydesignsystem/nunjucks-time-zone-picker": "^0.1.0",
36
37
  "@lilydesignsystem/nunjucks-share-picker": "^0.2.0"
37
38
  },
38
39
  "devDependencies": {
39
40
  "jsdom": "^30.1.1",
40
41
  "nunjucks": "^3.2.4",
41
- "tsup": "^8.5.1",
42
+ "tsup": "^9.0.0",
42
43
  "typescript": "^5.9.3",
43
- "vitest": "^5.0.3"
44
+ "vitest": "^5.0.4"
44
45
  },
45
46
  "keywords": [
46
47
  "lily",