@lilydesignsystem/web-components-picker-bar 0.1.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.
@@ -0,0 +1,97 @@
1
+ import { ThemePickerProps } from '@lilydesignsystem/web-components-theme-picker';
2
+ import { LocalePickerProps } from '@lilydesignsystem/web-components-locale-picker';
3
+ import { TextSizePickerProps } from '@lilydesignsystem/web-components-text-size-picker';
4
+ import { ShareTarget, SharePickerProps } from '@lilydesignsystem/web-components-share-picker';
5
+
6
+ /**
7
+ * `<lily-picker-bar>` — Lily Design System HTML helper.
8
+ *
9
+ * See `./spec/index.md` for the canonical contract. This file implements
10
+ * the custom-element class but does NOT register it. The `index.ts`
11
+ * barrel registers it on import.
12
+ *
13
+ * A thin composition wrapper: it renders `<lily-theme-picker>`,
14
+ * `<lily-locale-picker>`, `<lily-text-size-picker>`, and
15
+ * `<lily-share-picker>` — each depended on as a real npm package, not
16
+ * vendored — in that fixed order, with two catalog-specific defaults
17
+ * pre-wired (§5.1, §5.2 of the spec). It owns no interaction of its
18
+ * own: no listbox, no keyboard handling, no applied/persisted state.
19
+ */
20
+
21
+ /**
22
+ * All 45 Lily reference theme slugs (see `themes/` at the repo root),
23
+ * sorted alphabetically except the United Kingdom and United States
24
+ * government/public-sector themes, which sort last as one alphabetical
25
+ * group of their own. Mirrors `<lily-theme-picker>`'s own title-casing
26
+ * of each slug, so no `theme-labels` override is needed for these to
27
+ * read well.
28
+ */
29
+ declare const DEFAULT_THEMES: string[];
30
+ /**
31
+ * The seven-step text-size scale. Each slug title-cases to exactly the
32
+ * requested label ("largest" → "Largest", …) via `<lily-text-size-picker>`'s
33
+ * own default `labelFor`, so no `size-labels` override is needed either.
34
+ */
35
+ declare const DEFAULT_SIZES: string[];
36
+ /** Accessible names for the four pickers. Required — no English default. */
37
+ type PickerBarLabels = {
38
+ /** Accessible name for the theme picker's button and listbox. */
39
+ theme: string;
40
+ /** Accessible name for the locale picker's button and listbox. */
41
+ locale: string;
42
+ /** Accessible name for the text-size picker's button and listbox. */
43
+ textSize: string;
44
+ /** Accessible name for the share picker's button and list. */
45
+ share: string;
46
+ };
47
+ /** Mirrors the observed attributes / properties for typing convenience. */
48
+ type PickerBarProps = {
49
+ /** Property-only — see `spec/index.md` §4.3. Required, no default. */
50
+ labels: PickerBarLabels;
51
+ themesUrl: string;
52
+ themes?: string[];
53
+ /** Property-only extra `<lily-theme-picker>` config, applied after the bar's own. */
54
+ themeProps?: Partial<Omit<ThemePickerProps, "themesUrl" | "themes" | "label">>;
55
+ locales: string[];
56
+ /** Property-only extra `<lily-locale-picker>` config, applied after the bar's own. */
57
+ localeProps?: Partial<Omit<LocalePickerProps, "locales" | "label">>;
58
+ sizes?: string[];
59
+ /** Property-only extra `<lily-text-size-picker>` config, applied after the bar's own. */
60
+ textSizeProps?: Partial<Omit<TextSizePickerProps, "sizes" | "label">>;
61
+ /** Property-only — `ShareTarget.href` is a function. */
62
+ shareTargets?: ShareTarget[];
63
+ /** Property-only extra `<lily-share-picker>` config, applied after the bar's own. */
64
+ shareProps?: Partial<Omit<SharePickerProps, "targets" | "label">>;
65
+ class?: string;
66
+ };
67
+ /** Custom-element class implementing `<lily-picker-bar>`. */
68
+ declare class PickerBar extends HTMLElement {
69
+ #private;
70
+ static get observedAttributes(): string[];
71
+ get themesUrl(): string;
72
+ set themesUrl(v: string);
73
+ get themes(): string[];
74
+ set themes(v: string[]);
75
+ get locales(): string[];
76
+ set locales(v: string[]);
77
+ get sizes(): string[];
78
+ set sizes(v: string[]);
79
+ /** Property-only. No English default — see `spec/index.md` §4.3. */
80
+ get labels(): PickerBarLabels;
81
+ set labels(v: PickerBarLabels);
82
+ /** Property-only — `ShareTarget.href` is a function. */
83
+ get shareTargets(): ShareTarget[];
84
+ set shareTargets(v: ShareTarget[]);
85
+ get themeProps(): Partial<ThemePickerProps>;
86
+ set themeProps(v: Partial<ThemePickerProps>);
87
+ get localeProps(): Partial<LocalePickerProps>;
88
+ set localeProps(v: Partial<LocalePickerProps>);
89
+ get textSizeProps(): Partial<TextSizePickerProps>;
90
+ set textSizeProps(v: Partial<TextSizePickerProps>);
91
+ get shareProps(): Partial<SharePickerProps>;
92
+ set shareProps(v: Partial<SharePickerProps>);
93
+ connectedCallback(): void;
94
+ attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
95
+ }
96
+
97
+ export { DEFAULT_SIZES, DEFAULT_THEMES, PickerBar, type PickerBarLabels, type PickerBarProps };
package/dist/index.js ADDED
@@ -0,0 +1,264 @@
1
+ // lily-design-system-web-components-picker-bar/picker-bar.ts
2
+ import "@lilydesignsystem/web-components-theme-picker";
3
+ import "@lilydesignsystem/web-components-locale-picker";
4
+ import "@lilydesignsystem/web-components-text-size-picker";
5
+ import "@lilydesignsystem/web-components-share-picker";
6
+ var DEFAULT_THEMES = [
7
+ "abyss",
8
+ "acid",
9
+ "adobe-spectrum",
10
+ "aqua",
11
+ "autumn",
12
+ "black",
13
+ "bumblebee",
14
+ "business",
15
+ "caramellatte",
16
+ "cmyk",
17
+ "coffee",
18
+ "corporate",
19
+ "cupcake",
20
+ "cyberpunk",
21
+ "dark",
22
+ "dim",
23
+ "dracula",
24
+ "emerald",
25
+ "fantasy",
26
+ "forest",
27
+ "garden",
28
+ "halloween",
29
+ "lemonade",
30
+ "light",
31
+ "lofi",
32
+ "luxury",
33
+ "mozilla-protocol",
34
+ "night",
35
+ "nord",
36
+ "pastel",
37
+ "retro",
38
+ "silk",
39
+ "sunset",
40
+ "synthwave",
41
+ "valentine",
42
+ "winter",
43
+ "wireframe",
44
+ "united-kingdom-government-digital-service",
45
+ "united-kingdom-national-health-service-england-for-patients",
46
+ "united-kingdom-national-health-service-england-for-practitioners",
47
+ "united-kingdom-national-health-service-scotland-for-patients",
48
+ "united-kingdom-national-health-service-scotland-for-practitioners",
49
+ "united-kingdom-national-health-service-wales-for-patients",
50
+ "united-kingdom-national-health-service-wales-for-practitioners",
51
+ "united-states-web-design-system"
52
+ ];
53
+ var DEFAULT_SIZES = [
54
+ "largest",
55
+ "larger",
56
+ "large",
57
+ "normal",
58
+ "small",
59
+ "smaller",
60
+ "smallest"
61
+ ];
62
+ var DEFAULT_LABELS = {
63
+ theme: "",
64
+ locale: "",
65
+ textSize: "",
66
+ share: ""
67
+ };
68
+ function parseCsv(s) {
69
+ return s.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
70
+ }
71
+ var PickerBar = class extends HTMLElement {
72
+ static get observedAttributes() {
73
+ return ["themes-url", "themes", "locales", "sizes", "class"];
74
+ }
75
+ #themes = [...DEFAULT_THEMES];
76
+ #locales = [];
77
+ #sizes = [...DEFAULT_SIZES];
78
+ #labels = { ...DEFAULT_LABELS };
79
+ #shareTargets = [];
80
+ #themeProps = {};
81
+ #localeProps = {};
82
+ #textSizeProps = {};
83
+ #shareProps = {};
84
+ #built = false;
85
+ #rootEl = null;
86
+ #themeEl = null;
87
+ #localeEl = null;
88
+ #textSizeEl = null;
89
+ #shareEl = null;
90
+ // ---- Property accessors ----
91
+ get themesUrl() {
92
+ return this.getAttribute("themes-url") ?? "";
93
+ }
94
+ set themesUrl(v) {
95
+ this.setAttribute("themes-url", v);
96
+ }
97
+ get themes() {
98
+ return [...this.#themes];
99
+ }
100
+ set themes(v) {
101
+ this.#themes = Array.isArray(v) && v.length > 0 ? v.slice() : [...DEFAULT_THEMES];
102
+ const csv = this.#themes.join(",");
103
+ if (this.getAttribute("themes") !== csv) {
104
+ this.setAttribute("themes", csv);
105
+ return;
106
+ }
107
+ if (this.#themeEl) this.#themeEl.themes = this.#themes;
108
+ }
109
+ get locales() {
110
+ return [...this.#locales];
111
+ }
112
+ set locales(v) {
113
+ this.#locales = Array.isArray(v) ? v.slice() : [];
114
+ const csv = this.#locales.join(",");
115
+ if (this.getAttribute("locales") !== csv) {
116
+ this.setAttribute("locales", csv);
117
+ return;
118
+ }
119
+ if (this.#localeEl) this.#localeEl.locales = this.#locales;
120
+ }
121
+ get sizes() {
122
+ return [...this.#sizes];
123
+ }
124
+ set sizes(v) {
125
+ this.#sizes = Array.isArray(v) && v.length > 0 ? v.slice() : [...DEFAULT_SIZES];
126
+ const csv = this.#sizes.join(",");
127
+ if (this.getAttribute("sizes") !== csv) {
128
+ this.setAttribute("sizes", csv);
129
+ return;
130
+ }
131
+ if (this.#textSizeEl) this.#textSizeEl.sizes = this.#sizes;
132
+ }
133
+ /** Property-only. No English default — see `spec/index.md` §4.3. */
134
+ get labels() {
135
+ return { ...this.#labels };
136
+ }
137
+ set labels(v) {
138
+ this.#labels = v ?? { ...DEFAULT_LABELS };
139
+ if (this.#themeEl) this.#themeEl.label = this.#labels.theme;
140
+ if (this.#localeEl) this.#localeEl.label = this.#labels.locale;
141
+ if (this.#textSizeEl) this.#textSizeEl.label = this.#labels.textSize;
142
+ if (this.#shareEl) this.#shareEl.label = this.#labels.share;
143
+ }
144
+ /** Property-only — `ShareTarget.href` is a function. */
145
+ get shareTargets() {
146
+ return [...this.#shareTargets];
147
+ }
148
+ set shareTargets(v) {
149
+ this.#shareTargets = Array.isArray(v) ? v.slice() : [];
150
+ if (this.#shareEl) this.#shareEl.targets = this.#shareTargets;
151
+ }
152
+ get themeProps() {
153
+ return { ...this.#themeProps };
154
+ }
155
+ set themeProps(v) {
156
+ this.#themeProps = v ?? {};
157
+ if (this.#themeEl) Object.assign(this.#themeEl, this.#themeProps);
158
+ }
159
+ get localeProps() {
160
+ return { ...this.#localeProps };
161
+ }
162
+ set localeProps(v) {
163
+ this.#localeProps = v ?? {};
164
+ if (this.#localeEl) Object.assign(this.#localeEl, this.#localeProps);
165
+ }
166
+ get textSizeProps() {
167
+ return { ...this.#textSizeProps };
168
+ }
169
+ set textSizeProps(v) {
170
+ this.#textSizeProps = v ?? {};
171
+ if (this.#textSizeEl) Object.assign(this.#textSizeEl, this.#textSizeProps);
172
+ }
173
+ get shareProps() {
174
+ return { ...this.#shareProps };
175
+ }
176
+ set shareProps(v) {
177
+ this.#shareProps = v ?? {};
178
+ if (this.#shareEl) Object.assign(this.#shareEl, this.#shareProps);
179
+ }
180
+ // ---- Lifecycle ----
181
+ connectedCallback() {
182
+ const themesAttr = this.getAttribute("themes");
183
+ if (themesAttr !== null) this.#themes = parseCsv(themesAttr);
184
+ const localesAttr = this.getAttribute("locales");
185
+ if (localesAttr !== null) this.#locales = parseCsv(localesAttr);
186
+ const sizesAttr = this.getAttribute("sizes");
187
+ if (sizesAttr !== null) this.#sizes = parseCsv(sizesAttr);
188
+ this.#build();
189
+ }
190
+ attributeChangedCallback(name, _old, value) {
191
+ switch (name) {
192
+ case "themes-url":
193
+ if (this.#themeEl) this.#themeEl.themesUrl = this.themesUrl;
194
+ break;
195
+ case "themes":
196
+ this.#themes = value === null ? [...DEFAULT_THEMES] : parseCsv(value);
197
+ if (this.#themeEl) this.#themeEl.themes = this.#themes;
198
+ break;
199
+ case "locales":
200
+ this.#locales = value === null ? [] : parseCsv(value);
201
+ if (this.#localeEl) this.#localeEl.locales = this.#locales;
202
+ break;
203
+ case "sizes":
204
+ this.#sizes = value === null ? [...DEFAULT_SIZES] : parseCsv(value);
205
+ if (this.#textSizeEl) this.#textSizeEl.sizes = this.#sizes;
206
+ break;
207
+ case "class":
208
+ if (this.#rootEl) {
209
+ this.#rootEl.className = `picker-bar ${value ?? ""}`.trim();
210
+ }
211
+ break;
212
+ default:
213
+ break;
214
+ }
215
+ }
216
+ // ---- Rendering (built once; later changes update the existing children in place) ----
217
+ #build() {
218
+ if (this.#built) return;
219
+ this.#built = true;
220
+ const extraClass = this.getAttribute("class") ?? "";
221
+ const root = document.createElement("div");
222
+ root.className = `picker-bar ${extraClass}`.trim();
223
+ this.replaceChildren(root);
224
+ const themeEl = document.createElement("lily-theme-picker");
225
+ themeEl.label = this.#labels.theme;
226
+ themeEl.themesUrl = this.themesUrl;
227
+ themeEl.themes = this.#themes;
228
+ Object.assign(themeEl, this.#themeProps);
229
+ root.appendChild(themeEl);
230
+ const localeEl = document.createElement("lily-locale-picker");
231
+ localeEl.label = this.#labels.locale;
232
+ localeEl.locales = this.#locales;
233
+ Object.assign(localeEl, this.#localeProps);
234
+ root.appendChild(localeEl);
235
+ const textSizeEl = document.createElement(
236
+ "lily-text-size-picker"
237
+ );
238
+ textSizeEl.label = this.#labels.textSize;
239
+ textSizeEl.sizes = this.#sizes;
240
+ textSizeEl.defaultValue = "normal";
241
+ Object.assign(textSizeEl, this.#textSizeProps);
242
+ root.appendChild(textSizeEl);
243
+ const shareEl = document.createElement("lily-share-picker");
244
+ shareEl.label = this.#labels.share;
245
+ shareEl.targets = this.#shareTargets;
246
+ Object.assign(shareEl, this.#shareProps);
247
+ root.appendChild(shareEl);
248
+ this.#rootEl = root;
249
+ this.#themeEl = themeEl;
250
+ this.#localeEl = localeEl;
251
+ this.#textSizeEl = textSizeEl;
252
+ this.#shareEl = shareEl;
253
+ }
254
+ };
255
+
256
+ // lily-design-system-web-components-picker-bar/index.ts
257
+ if (typeof customElements !== "undefined" && !customElements.get("lily-picker-bar")) {
258
+ customElements.define("lily-picker-bar", PickerBar);
259
+ }
260
+ export {
261
+ DEFAULT_SIZES,
262
+ DEFAULT_THEMES,
263
+ PickerBar
264
+ };
package/index.md ADDED
@@ -0,0 +1,128 @@
1
+ # Lily Design System™ — `<lily-picker-bar>`
2
+
3
+ A single page-header row that composes four of the Lily
4
+ [`*-picker` helpers](../index.md) — theme, locale, text size, and
5
+ share — with two catalog-wide defaults pre-wired, so you can drop one
6
+ custom element into a header instead of assembling and configuring
7
+ four.
8
+
9
+ `<lily-motion-picker>` and `<lily-date-time-picker>` are not part of
10
+ the bar: motion has no natural spot next to the other three header
11
+ preferences, and `<lily-date-time-picker>` is a form control, not a
12
+ header control.
13
+
14
+ ## Install
15
+
16
+ ```sh
17
+ npm install @lilydesignsystem/web-components-picker-bar
18
+ ```
19
+
20
+ `@lilydesignsystem/web-components-theme-picker`, `-locale-picker`,
21
+ `-text-size-picker`, and `-share-picker` install automatically as
22
+ regular dependencies — `<lily-picker-bar>` is a thin wrapper around
23
+ them, not a reimplementation.
24
+
25
+ ## Usage
26
+
27
+ ```html
28
+ <script type="module">
29
+ import "@lilydesignsystem/web-components-picker-bar";
30
+ </script>
31
+
32
+ <lily-picker-bar id="header-picker-bar" themes-url="/assets/themes/"></lily-picker-bar>
33
+
34
+ <script type="module">
35
+ const bar = document.getElementById("header-picker-bar");
36
+ bar.labels = {
37
+ theme: "Theme",
38
+ locale: "Language",
39
+ textSize: "Text size",
40
+ share: "Share",
41
+ };
42
+ bar.locales = ["en", "cy", "gd", "ga"];
43
+ bar.shareTargets = [
44
+ {
45
+ id: "email",
46
+ label: "Email",
47
+ href: (url, title) => `mailto:?subject=${title}&body=${url}`,
48
+ },
49
+ ];
50
+ </script>
51
+ ```
52
+
53
+ `labels`, `locales`, and `shareTargets` are property-only (§4.3 of the
54
+ spec) — objects and functions cannot be expressed as HTML attributes
55
+ — so set them from script, before or after the element connects.
56
+ `themes-url` (required) and `class` are plain attributes and can be
57
+ written directly in HTML, as shown above.
58
+
59
+ That's a complete, working header row: 45 themes, four locales, the
60
+ seven-step text-size scale, and one share destination plus
61
+ copy-to-URL if you add `bar.shareProps = { copyLabel: "Copy link" }`.
62
+
63
+ ## Defaults
64
+
65
+ - **`themes`** defaults to `DEFAULT_THEMES` — all 45 Lily reference
66
+ theme slugs, alphabetical, with the 8 United Kingdom / United States
67
+ government themes moved to their own alphabetical group at the
68
+ bottom. Set `bar.themes = [...]` (or the `themes="a,b,c"` attribute)
69
+ to override.
70
+ - **`sizes`** defaults to `DEFAULT_SIZES` — the seven-step scale
71
+ `largest`, `larger`, `large`, `normal`, `small`, `smaller`,
72
+ `smallest` — and the text-size picker starts on `normal`. Set
73
+ `bar.sizes = [...]` (and `bar.textSizeProps = { defaultValue: "…" }`
74
+ if you want a different starting point) to override.
75
+
76
+ Both are exported as named constants:
77
+
78
+ ```js
79
+ import { DEFAULT_THEMES, DEFAULT_SIZES } from "@lilydesignsystem/web-components-picker-bar";
80
+ ```
81
+
82
+ ## Passing extra properties to one picker
83
+
84
+ Each wrapped picker takes a `*Props` bag for anything beyond what
85
+ `<lily-picker-bar>` lifts to the top level — persistence, initial
86
+ value, detection, a `*Labels` override map, a custom glyph:
87
+
88
+ ```js
89
+ bar.themeProps = { storageKey: "lily-theme", detectFromSystem: true };
90
+ bar.localeProps = { storageKey: "lily-locale", detectFromNavigator: true };
91
+ bar.textSizeProps = { storageKey: "lily-text-size" };
92
+ bar.shareProps = { copyLabel: "Copy link", copiedLabel: "Copied" };
93
+ ```
94
+
95
+ Anything in a `*Props` bag wins over `<lily-picker-bar>`'s own default
96
+ for that picker.
97
+
98
+ ## Styling
99
+
100
+ `<lily-picker-bar>` renders no CSS of its own class beyond the
101
+ `picker-bar` root wrapper — style each child through its own
102
+ package's class hooks (`theme-picker`, `locale-picker`,
103
+ `text-size-picker`, `share-picker`; see each package's own `index.md`).
104
+ A typical header layout:
105
+
106
+ ```css
107
+ .picker-bar {
108
+ display: flex;
109
+ gap: var(--theme-space-sm, 0.5rem);
110
+ align-items: center;
111
+ }
112
+ ```
113
+
114
+ ## Accessibility
115
+
116
+ Every accessible name comes from `labels` — there is no English
117
+ default, because a set of names this catalog invented is exactly the
118
+ case the rest of Lily's i18n rule exists for. Each wrapped picker
119
+ keeps its own WAI-ARIA APG contract unchanged; see that picker's own
120
+ `index.md`.
121
+
122
+ ## Full contract
123
+
124
+ See [`spec/index.md`](./spec/index.md).
125
+
126
+ ---
127
+
128
+ Lily™ and Lily Design System™ are trademarks.
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@lilydesignsystem/web-components-picker-bar",
3
+ "version": "0.1.0",
4
+ "engines": {
5
+ "node": "=26"
6
+ },
7
+ "description": "Lily Design System - HTML custom element picker bar: composes lily-theme-picker, lily-locale-picker, lily-text-size-picker, and lily-share-picker into one page-header row.",
8
+ "type": "module",
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "index.md",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "prepublishOnly": "cd .. && npm run build"
25
+ },
26
+ "dependencies": {
27
+ "@lilydesignsystem/web-components-theme-picker": "^0.1.0",
28
+ "@lilydesignsystem/web-components-locale-picker": "^0.1.0",
29
+ "@lilydesignsystem/web-components-text-size-picker": "^0.1.0",
30
+ "@lilydesignsystem/web-components-share-picker": "^0.1.0"
31
+ },
32
+ "keywords": [
33
+ "lily",
34
+ "design",
35
+ "system",
36
+ "html",
37
+ "picker",
38
+ "picker-bar",
39
+ "theme",
40
+ "locale",
41
+ "text-size",
42
+ "share"
43
+ ],
44
+ "author": "Joel Parker Henderson <joel@joelparkerhenderson.com>",
45
+ "license": "MIT OR Apache-2.0 OR GPL-2.0-only OR GPL-3.0-only OR BSD-3-Clause",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/LilyDesignSystem/lily-design-system-web-components-helpers.git",
49
+ "directory": "lily-design-system-web-components-picker-bar"
50
+ },
51
+ "homepage": "https://lilydesignsystem.com/",
52
+ "bugs": {
53
+ "url": "https://github.com/LilyDesignSystem/lily-design-system/issues"
54
+ }
55
+ }