@aglyn/shared-ui-theme 1.0.0-beta.249 → 1.0.0-beta.252

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/shared-ui-theme",
3
- "version": "1.0.0-beta.249",
3
+ "version": "1.0.0-beta.252",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,9 +25,9 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/shared-data-types": "1.0.0-beta.249",
29
- "@aglyn/shared-util-tools": "1.0.0-beta.249",
30
- "@aglyn/shared-util-vendor": "1.0.0-beta.249",
28
+ "@aglyn/shared-data-types": "1.0.0-beta.252",
29
+ "@aglyn/shared-util-tools": "1.0.0-beta.252",
30
+ "@aglyn/shared-util-vendor": "1.0.0-beta.252",
31
31
  "@emotion/cache": "^11.14.0",
32
32
  "@emotion/react": "11.14.0",
33
33
  "@swc/helpers": "0.5.23",
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import type { HostTheme, HostThemeScheme } from '@aglyn/shared-data-types';
7
- import { type ThemeColorToken } from './theme-editor-fields';
7
+ import { type ThemeColorToken, type ThemeComponentLookId } from './theme-editor-fields';
8
8
  /** One control's change; a null value clears it back to the theme's own. */
9
9
  export type ThemeEditorEdit = {
10
10
  control: 'color';
@@ -27,6 +27,12 @@ export type ThemeEditorEdit = {
27
27
  control: 'navHeight';
28
28
  breakpoint: 'xs' | 'sm';
29
29
  value: number | null;
30
+ }
31
+ /** One of the Style components choices; `''` ("Theme default") clears what it wrote. */
32
+ | {
33
+ control: 'componentLook';
34
+ field: ThemeComponentLookId;
35
+ value: string;
30
36
  };
31
37
  /** The most edits one save may carry: every color of both schemes and the rest. */
32
38
  export declare const THEME_EDITOR_EDITS_MAX: number;
@@ -47,6 +53,8 @@ export interface ThemeEditorValues {
47
53
  xs: number | null;
48
54
  sm: number | null;
49
55
  };
56
+ /** Each Style components field's choice: `''` for the theme's own, `'__custom__'` for a value no choice names. */
57
+ componentLooks: Record<string, string>;
50
58
  }
51
59
  export declare function readThemeEditorValues(theme: HostTheme | undefined): ThemeEditorValues;
52
60
  /**
@@ -102,4 +110,22 @@ export declare const THEME_EDITOR_CATALOG: {
102
110
  readonly step: 1;
103
111
  };
104
112
  };
113
+ /** The Style components card: its groups and each field's choices (what a choice stores stays here). */
114
+ readonly componentLooks: {
115
+ readonly groups: readonly {
116
+ group: import("./theme-editor-fields").ThemeComponentLookGroup;
117
+ label: string;
118
+ }[];
119
+ readonly fields: {
120
+ id: ThemeComponentLookId;
121
+ group: import("./theme-editor-fields").ThemeComponentLookGroup;
122
+ label: string;
123
+ kind: "color" | "select";
124
+ options: {
125
+ token?: ThemeColorToken;
126
+ value: string;
127
+ label: string;
128
+ }[];
129
+ }[];
130
+ };
105
131
  };
@@ -2,8 +2,9 @@
2
2
  * @license
3
3
  * Copyright 2026 Aglyn LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
- */ import { BORDER_RADIUS_FIELD, DARK_SCHEME_FIELD, GOOGLE_FONT_OPTIONS, SPACING_FIELD, SYSTEM_FONT_VALUE, THEME_COLOR_FIELDS, THEME_EDITOR_SCHEMES, TOOLBAR_HEIGHT_FIELDS, readDarkScheme, readFontFamily, readThemeColor, readToolbarHeight, writeBorderRadius, writeDarkScheme, writeFontFamily, writeSpacing, writeThemeColor, writeToolbarHeight } from "./theme-editor-fields.js";
6
- /** The most edits one save may carry: every color of both schemes and the rest. */ export const THEME_EDITOR_EDITS_MAX = THEME_COLOR_FIELDS.length * 2 + 8;
5
+ */ import { _ as _extends } from "@swc/helpers/_/_extends";
6
+ import { BORDER_RADIUS_FIELD, DARK_SCHEME_FIELD, GOOGLE_FONT_OPTIONS, SPACING_FIELD, SYSTEM_FONT_VALUE, THEME_COLOR_FIELDS, THEME_COMPONENT_LOOK_FIELDS, THEME_COMPONENT_LOOK_GROUPS, THEME_EDITOR_SCHEMES, THEME_LOOK_DEFAULT, TOOLBAR_HEIGHT_FIELDS, readComponentLook, readDarkScheme, readFontFamily, readThemeColor, readToolbarHeight, themeComponentLookField, writeBorderRadius, writeComponentLook, writeDarkScheme, writeFontFamily, writeSpacing, writeThemeColor, writeToolbarHeight } from "./theme-editor-fields.js";
7
+ /** The most edits one save may carry: every color of both schemes and the rest. */ export const THEME_EDITOR_EDITS_MAX = THEME_COLOR_FIELDS.length * 2 + 8 + THEME_COMPONENT_LOOK_FIELDS.length;
7
8
  const HEX_COLOR = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
8
9
  function readNumber(value, range) {
9
10
  if (value === null || value === undefined || value === '') return null;
@@ -81,6 +82,22 @@ function readNumber(value, range) {
81
82
  value
82
83
  };
83
84
  }
85
+ case 'componentLook':
86
+ {
87
+ var _edit_value;
88
+ const field = THEME_COMPONENT_LOOK_FIELDS.find((entry)=>entry.id === edit['field']);
89
+ if (!field) return 'That is not a component style.';
90
+ const value = (_edit_value = edit['value']) != null ? _edit_value : THEME_LOOK_DEFAULT;
91
+ if (typeof value !== 'string') return 'Pick one of the choices.';
92
+ if (value !== THEME_LOOK_DEFAULT && !field.options.some((option)=>option.value === value)) {
93
+ return 'Pick one of the choices.';
94
+ }
95
+ return {
96
+ control: 'componentLook',
97
+ field: field.id,
98
+ value
99
+ };
100
+ }
84
101
  default:
85
102
  return 'That is not a theme control.';
86
103
  }
@@ -122,6 +139,9 @@ function readNumber(value, range) {
122
139
  var _edit_value3;
123
140
  next = writeToolbarHeight(next, edit.breakpoint, (_edit_value3 = edit.value) != null ? _edit_value3 : undefined);
124
141
  break;
142
+ case 'componentLook':
143
+ next = writeComponentLook(next, themeComponentLookField(edit.field), edit.value);
144
+ break;
125
145
  }
126
146
  }
127
147
  return next;
@@ -148,7 +168,11 @@ export function readThemeEditorValues(theme) {
148
168
  navHeight: {
149
169
  xs: (_readToolbarHeight = readToolbarHeight(safe, 'xs')) != null ? _readToolbarHeight : null,
150
170
  sm: (_readToolbarHeight1 = readToolbarHeight(safe, 'sm')) != null ? _readToolbarHeight1 : null
151
- }
171
+ },
172
+ componentLooks: Object.fromEntries(THEME_COMPONENT_LOOK_FIELDS.map((field)=>[
173
+ field.id,
174
+ readComponentLook(safe, field)
175
+ ]))
152
176
  };
153
177
  }
154
178
  /**
@@ -162,7 +186,22 @@ export function readThemeEditorValues(theme) {
162
186
  fonts: GOOGLE_FONT_OPTIONS,
163
187
  borderRadius: BORDER_RADIUS_FIELD,
164
188
  spacing: SPACING_FIELD,
165
- navHeight: TOOLBAR_HEIGHT_FIELDS
189
+ navHeight: TOOLBAR_HEIGHT_FIELDS,
190
+ /** The Style components card: its groups and each field's choices (what a choice stores stays here). */ componentLooks: {
191
+ groups: THEME_COMPONENT_LOOK_GROUPS,
192
+ fields: THEME_COMPONENT_LOOK_FIELDS.map((field)=>({
193
+ id: field.id,
194
+ group: field.group,
195
+ label: field.label,
196
+ kind: field.kind,
197
+ options: field.options.map((option)=>_extends({
198
+ value: option.value,
199
+ label: option.label
200
+ }, option.token ? {
201
+ token: option.token
202
+ } : {}))
203
+ }))
204
+ }
166
205
  };
167
206
 
168
207
  //# sourceMappingURL=theme-editor-edits.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/theme-editor-edits.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { HostTheme, HostThemeScheme } from '@aglyn/shared-data-types'\nimport {\n BORDER_RADIUS_FIELD,\n DARK_SCHEME_FIELD,\n GOOGLE_FONT_OPTIONS,\n SPACING_FIELD,\n SYSTEM_FONT_VALUE,\n THEME_COLOR_FIELDS,\n THEME_EDITOR_SCHEMES,\n TOOLBAR_HEIGHT_FIELDS,\n readDarkScheme,\n readFontFamily,\n readThemeColor,\n readToolbarHeight,\n writeBorderRadius,\n writeDarkScheme,\n writeFontFamily,\n writeSpacing,\n writeThemeColor,\n writeToolbarHeight,\n type ThemeColorToken,\n} from './theme-editor-fields'\n\n/*\n * THE THEME EDITOR'S CONTROLS AS EDITS (AGL-3668).\n *\n * The console's theme section edits the resolved theme in the browser with\n * the writers in `theme-editor-fields.ts` and saves the difference from the\n * picked theme as the site's override. A native app sends the same controls\n * as named edits instead — one color for one scheme, the font, the radius,\n * the spacing unit, a nav height, the dark scheme — and `/api/hosts/theme`\n * applies them here with those same writers, so both clients make exactly the\n * same theme from the same choice. `readThemeEditorValues` is the other half:\n * what each control currently shows.\n */\n\n/** One control's change; a null value clears it back to the theme's own. */\nexport type ThemeEditorEdit =\n | { control: 'color'; scheme: HostThemeScheme; token: ThemeColorToken; value: string | null }\n | { control: 'darkScheme'; value: 'auto' | 'off' }\n | { control: 'fontFamily'; value: string }\n | { control: 'borderRadius'; value: number | null }\n | { control: 'spacing'; value: number | null }\n | { control: 'navHeight'; breakpoint: 'xs' | 'sm'; value: number | null }\n\n/** The most edits one save may carry: every color of both schemes and the rest. */\nexport const THEME_EDITOR_EDITS_MAX = THEME_COLOR_FIELDS.length * 2 + 8\n\nconst HEX_COLOR = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/\n\nfunction readNumber(\n value: unknown,\n range: { min: number; max: number },\n): number | null | string {\n if (value === null || value === undefined || value === '') return null\n const parsed = typeof value === 'number' ? value : Number(value)\n if (!Number.isFinite(parsed)) return 'Use a number.'\n if (parsed < range.min || parsed > range.max) {\n return `Use a number from ${range.min} to ${range.max}.`\n }\n return parsed\n}\n\n/** One edit from a request body, or why it was refused. */\nexport function readThemeEditorEdit(raw: unknown): ThemeEditorEdit | string {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return 'That change could not be read.'\n const edit = raw as Record<string, unknown>\n switch (edit['control']) {\n case 'color': {\n const scheme = edit['scheme']\n if (!THEME_EDITOR_SCHEMES.includes(scheme as HostThemeScheme)) return 'Pick light or dark.'\n const token = edit['token']\n if (!THEME_COLOR_FIELDS.some((field) => field.token === token)) return 'That is not a theme color.'\n const value = edit['value']\n if (value !== null && value !== undefined && value !== '' && (typeof value !== 'string' || !HEX_COLOR.test(value))) {\n return 'Use a hex color such as #1A73E8.'\n }\n return {\n control: 'color',\n scheme: scheme as HostThemeScheme,\n token: token as ThemeColorToken,\n value: typeof value === 'string' && value ? value : null,\n }\n }\n case 'darkScheme':\n return edit['value'] === 'off' ? { control: 'darkScheme', value: 'off' } : { control: 'darkScheme', value: 'auto' }\n case 'fontFamily': {\n const value = edit['value']\n if (value !== SYSTEM_FONT_VALUE && !GOOGLE_FONT_OPTIONS.some((option) => option.family === value)) {\n return 'Pick a font from the list.'\n }\n return { control: 'fontFamily', value: value as string }\n }\n case 'borderRadius': {\n const value = readNumber(edit['value'], BORDER_RADIUS_FIELD)\n return typeof value === 'string' ? value : { control: 'borderRadius', value }\n }\n case 'spacing': {\n const value = readNumber(edit['value'], SPACING_FIELD)\n return typeof value === 'string' ? value : { control: 'spacing', value }\n }\n case 'navHeight': {\n const breakpoint = edit['breakpoint']\n if (breakpoint !== 'xs' && breakpoint !== 'sm') return 'Pick mobile or desktop.'\n const value = readNumber(edit['value'], TOOLBAR_HEIGHT_FIELDS[breakpoint])\n return typeof value === 'string' ? value : { control: 'navHeight', breakpoint, value }\n }\n default:\n return 'That is not a theme control.'\n }\n}\n\n/** Every edit of a request body, or the first refusal. */\nexport function readThemeEditorEdits(raw: unknown): ThemeEditorEdit[] | string {\n if (!Array.isArray(raw) || raw.length === 0) return 'Nothing to change.'\n if (raw.length > THEME_EDITOR_EDITS_MAX) return 'Too many changes at once.'\n const edits: ThemeEditorEdit[] = []\n for (const entry of raw) {\n const edit = readThemeEditorEdit(entry)\n if (typeof edit === 'string') return edit\n edits.push(edit)\n }\n return edits\n}\n\n/** The theme with [edits] applied, in order, by the editor's own writers. */\nexport function applyThemeEditorEdits(theme: HostTheme, edits: readonly ThemeEditorEdit[]): HostTheme {\n let next = theme\n for (const edit of edits) {\n switch (edit.control) {\n case 'color':\n next = writeThemeColor(next, edit.scheme, edit.token, edit.value ?? undefined)\n break\n case 'darkScheme':\n next = writeDarkScheme(next, edit.value)\n break\n case 'fontFamily':\n next = writeFontFamily(next, edit.value)\n break\n case 'borderRadius':\n next = writeBorderRadius(next, edit.value ?? undefined)\n break\n case 'spacing':\n next = writeSpacing(next, edit.value ?? undefined)\n break\n case 'navHeight':\n next = writeToolbarHeight(next, edit.breakpoint, edit.value ?? undefined)\n break\n }\n }\n return next\n}\n\n/** What each control shows for [theme]; an absent value inherits the platform's. */\nexport interface ThemeEditorValues {\n colors: Record<HostThemeScheme, Record<string, string | null>>\n darkScheme: 'auto' | 'off'\n fontFamily: string\n borderRadius: number | null\n spacing: number | null\n navHeight: { xs: number | null; sm: number | null }\n}\n\nexport function readThemeEditorValues(theme: HostTheme | undefined): ThemeEditorValues {\n const safe = theme ?? {}\n const colors = {} as Record<HostThemeScheme, Record<string, string | null>>\n for (const scheme of THEME_EDITOR_SCHEMES) {\n colors[scheme] = {}\n for (const field of THEME_COLOR_FIELDS) {\n colors[scheme][field.token] = readThemeColor(safe, scheme, field.token) ?? null\n }\n }\n const radius = safe.shape?.borderRadius\n return {\n colors,\n darkScheme: readDarkScheme(safe),\n fontFamily: readFontFamily(safe),\n borderRadius: typeof radius === 'number' && Number.isFinite(radius) ? radius : null,\n spacing: typeof safe.spacing === 'number' ? safe.spacing : null,\n navHeight: {\n xs: readToolbarHeight(safe, 'xs') ?? null,\n sm: readToolbarHeight(safe, 'sm') ?? null,\n },\n }\n}\n\n/**\n * The controls themselves, for a client that draws the editor from data:\n * every color field, the font list, and each number's range and label.\n */\nexport const THEME_EDITOR_CATALOG = {\n schemes: THEME_EDITOR_SCHEMES,\n colors: THEME_COLOR_FIELDS,\n darkScheme: DARK_SCHEME_FIELD,\n systemFont: SYSTEM_FONT_VALUE,\n fonts: GOOGLE_FONT_OPTIONS,\n borderRadius: BORDER_RADIUS_FIELD,\n spacing: SPACING_FIELD,\n navHeight: TOOLBAR_HEIGHT_FIELDS,\n} as const\n"],"names":["BORDER_RADIUS_FIELD","DARK_SCHEME_FIELD","GOOGLE_FONT_OPTIONS","SPACING_FIELD","SYSTEM_FONT_VALUE","THEME_COLOR_FIELDS","THEME_EDITOR_SCHEMES","TOOLBAR_HEIGHT_FIELDS","readDarkScheme","readFontFamily","readThemeColor","readToolbarHeight","writeBorderRadius","writeDarkScheme","writeFontFamily","writeSpacing","writeThemeColor","writeToolbarHeight","THEME_EDITOR_EDITS_MAX","length","HEX_COLOR","readNumber","value","range","undefined","parsed","Number","isFinite","min","max","readThemeEditorEdit","raw","Array","isArray","edit","scheme","includes","token","some","field","test","control","option","family","breakpoint","readThemeEditorEdits","edits","entry","push","applyThemeEditorEdits","theme","next","readThemeEditorValues","safe","colors","radius","shape","borderRadius","darkScheme","fontFamily","spacing","navHeight","xs","sm","THEME_EDITOR_CATALOG","schemes","systemFont","fonts"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/theme-editor-edits.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { HostTheme, HostThemeScheme } from '@aglyn/shared-data-types'\nimport {\n BORDER_RADIUS_FIELD,\n DARK_SCHEME_FIELD,\n GOOGLE_FONT_OPTIONS,\n SPACING_FIELD,\n SYSTEM_FONT_VALUE,\n THEME_COLOR_FIELDS,\n THEME_COMPONENT_LOOK_FIELDS,\n THEME_COMPONENT_LOOK_GROUPS,\n THEME_EDITOR_SCHEMES,\n THEME_LOOK_DEFAULT,\n TOOLBAR_HEIGHT_FIELDS,\n readComponentLook,\n readDarkScheme,\n readFontFamily,\n readThemeColor,\n readToolbarHeight,\n themeComponentLookField,\n writeBorderRadius,\n writeComponentLook,\n writeDarkScheme,\n writeFontFamily,\n writeSpacing,\n writeThemeColor,\n writeToolbarHeight,\n type ThemeColorToken,\n type ThemeComponentLookId,\n} from './theme-editor-fields'\n\n/*\n * THE THEME EDITOR'S CONTROLS AS EDITS (AGL-3668).\n *\n * The console's theme section edits the resolved theme in the browser with\n * the writers in `theme-editor-fields.ts` and saves the difference from the\n * picked theme as the site's override. A native app sends the same controls\n * as named edits instead — one color for one scheme, the font, the radius,\n * the spacing unit, a nav height, the dark scheme — and `/api/hosts/theme`\n * applies them here with those same writers, so both clients make exactly the\n * same theme from the same choice. The Style components card's twelve\n * choices (buttons, form inputs, cards) are the `componentLook` edit.\n * `readThemeEditorValues` is the other half:\n * what each control currently shows.\n */\n\n/** One control's change; a null value clears it back to the theme's own. */\nexport type ThemeEditorEdit =\n | { control: 'color'; scheme: HostThemeScheme; token: ThemeColorToken; value: string | null }\n | { control: 'darkScheme'; value: 'auto' | 'off' }\n | { control: 'fontFamily'; value: string }\n | { control: 'borderRadius'; value: number | null }\n | { control: 'spacing'; value: number | null }\n | { control: 'navHeight'; breakpoint: 'xs' | 'sm'; value: number | null }\n /** One of the Style components choices; `''` (\"Theme default\") clears what it wrote. */\n | { control: 'componentLook'; field: ThemeComponentLookId; value: string }\n\n/** The most edits one save may carry: every color of both schemes and the rest. */\nexport const THEME_EDITOR_EDITS_MAX = THEME_COLOR_FIELDS.length * 2 + 8 + THEME_COMPONENT_LOOK_FIELDS.length\n\nconst HEX_COLOR = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/\n\nfunction readNumber(\n value: unknown,\n range: { min: number; max: number },\n): number | null | string {\n if (value === null || value === undefined || value === '') return null\n const parsed = typeof value === 'number' ? value : Number(value)\n if (!Number.isFinite(parsed)) return 'Use a number.'\n if (parsed < range.min || parsed > range.max) {\n return `Use a number from ${range.min} to ${range.max}.`\n }\n return parsed\n}\n\n/** One edit from a request body, or why it was refused. */\nexport function readThemeEditorEdit(raw: unknown): ThemeEditorEdit | string {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return 'That change could not be read.'\n const edit = raw as Record<string, unknown>\n switch (edit['control']) {\n case 'color': {\n const scheme = edit['scheme']\n if (!THEME_EDITOR_SCHEMES.includes(scheme as HostThemeScheme)) return 'Pick light or dark.'\n const token = edit['token']\n if (!THEME_COLOR_FIELDS.some((field) => field.token === token)) return 'That is not a theme color.'\n const value = edit['value']\n if (value !== null && value !== undefined && value !== '' && (typeof value !== 'string' || !HEX_COLOR.test(value))) {\n return 'Use a hex color such as #1A73E8.'\n }\n return {\n control: 'color',\n scheme: scheme as HostThemeScheme,\n token: token as ThemeColorToken,\n value: typeof value === 'string' && value ? value : null,\n }\n }\n case 'darkScheme':\n return edit['value'] === 'off' ? { control: 'darkScheme', value: 'off' } : { control: 'darkScheme', value: 'auto' }\n case 'fontFamily': {\n const value = edit['value']\n if (value !== SYSTEM_FONT_VALUE && !GOOGLE_FONT_OPTIONS.some((option) => option.family === value)) {\n return 'Pick a font from the list.'\n }\n return { control: 'fontFamily', value: value as string }\n }\n case 'borderRadius': {\n const value = readNumber(edit['value'], BORDER_RADIUS_FIELD)\n return typeof value === 'string' ? value : { control: 'borderRadius', value }\n }\n case 'spacing': {\n const value = readNumber(edit['value'], SPACING_FIELD)\n return typeof value === 'string' ? value : { control: 'spacing', value }\n }\n case 'navHeight': {\n const breakpoint = edit['breakpoint']\n if (breakpoint !== 'xs' && breakpoint !== 'sm') return 'Pick mobile or desktop.'\n const value = readNumber(edit['value'], TOOLBAR_HEIGHT_FIELDS[breakpoint])\n return typeof value === 'string' ? value : { control: 'navHeight', breakpoint, value }\n }\n case 'componentLook': {\n const field = THEME_COMPONENT_LOOK_FIELDS.find((entry) => entry.id === edit['field'])\n if (!field) return 'That is not a component style.'\n const value = edit['value'] ?? THEME_LOOK_DEFAULT\n if (typeof value !== 'string') return 'Pick one of the choices.'\n if (value !== THEME_LOOK_DEFAULT && !field.options.some((option) => option.value === value)) {\n return 'Pick one of the choices.'\n }\n return { control: 'componentLook', field: field.id, value }\n }\n default:\n return 'That is not a theme control.'\n }\n}\n\n/** Every edit of a request body, or the first refusal. */\nexport function readThemeEditorEdits(raw: unknown): ThemeEditorEdit[] | string {\n if (!Array.isArray(raw) || raw.length === 0) return 'Nothing to change.'\n if (raw.length > THEME_EDITOR_EDITS_MAX) return 'Too many changes at once.'\n const edits: ThemeEditorEdit[] = []\n for (const entry of raw) {\n const edit = readThemeEditorEdit(entry)\n if (typeof edit === 'string') return edit\n edits.push(edit)\n }\n return edits\n}\n\n/** The theme with [edits] applied, in order, by the editor's own writers. */\nexport function applyThemeEditorEdits(theme: HostTheme, edits: readonly ThemeEditorEdit[]): HostTheme {\n let next = theme\n for (const edit of edits) {\n switch (edit.control) {\n case 'color':\n next = writeThemeColor(next, edit.scheme, edit.token, edit.value ?? undefined)\n break\n case 'darkScheme':\n next = writeDarkScheme(next, edit.value)\n break\n case 'fontFamily':\n next = writeFontFamily(next, edit.value)\n break\n case 'borderRadius':\n next = writeBorderRadius(next, edit.value ?? undefined)\n break\n case 'spacing':\n next = writeSpacing(next, edit.value ?? undefined)\n break\n case 'navHeight':\n next = writeToolbarHeight(next, edit.breakpoint, edit.value ?? undefined)\n break\n case 'componentLook':\n next = writeComponentLook(next, themeComponentLookField(edit.field), edit.value)\n break\n }\n }\n return next\n}\n\n/** What each control shows for [theme]; an absent value inherits the platform's. */\nexport interface ThemeEditorValues {\n colors: Record<HostThemeScheme, Record<string, string | null>>\n darkScheme: 'auto' | 'off'\n fontFamily: string\n borderRadius: number | null\n spacing: number | null\n navHeight: { xs: number | null; sm: number | null }\n /** Each Style components field's choice: `''` for the theme's own, `'__custom__'` for a value no choice names. */\n componentLooks: Record<string, string>\n}\n\nexport function readThemeEditorValues(theme: HostTheme | undefined): ThemeEditorValues {\n const safe = theme ?? {}\n const colors = {} as Record<HostThemeScheme, Record<string, string | null>>\n for (const scheme of THEME_EDITOR_SCHEMES) {\n colors[scheme] = {}\n for (const field of THEME_COLOR_FIELDS) {\n colors[scheme][field.token] = readThemeColor(safe, scheme, field.token) ?? null\n }\n }\n const radius = safe.shape?.borderRadius\n return {\n colors,\n darkScheme: readDarkScheme(safe),\n fontFamily: readFontFamily(safe),\n borderRadius: typeof radius === 'number' && Number.isFinite(radius) ? radius : null,\n spacing: typeof safe.spacing === 'number' ? safe.spacing : null,\n navHeight: {\n xs: readToolbarHeight(safe, 'xs') ?? null,\n sm: readToolbarHeight(safe, 'sm') ?? null,\n },\n componentLooks: Object.fromEntries(\n THEME_COMPONENT_LOOK_FIELDS.map((field) => [field.id, readComponentLook(safe, field)]),\n ),\n }\n}\n\n/**\n * The controls themselves, for a client that draws the editor from data:\n * every color field, the font list, and each number's range and label.\n */\nexport const THEME_EDITOR_CATALOG = {\n schemes: THEME_EDITOR_SCHEMES,\n colors: THEME_COLOR_FIELDS,\n darkScheme: DARK_SCHEME_FIELD,\n systemFont: SYSTEM_FONT_VALUE,\n fonts: GOOGLE_FONT_OPTIONS,\n borderRadius: BORDER_RADIUS_FIELD,\n spacing: SPACING_FIELD,\n navHeight: TOOLBAR_HEIGHT_FIELDS,\n /** The Style components card: its groups and each field's choices (what a choice stores stays here). */\n componentLooks: {\n groups: THEME_COMPONENT_LOOK_GROUPS,\n fields: THEME_COMPONENT_LOOK_FIELDS.map((field) => ({\n id: field.id,\n group: field.group,\n label: field.label,\n kind: field.kind,\n options: field.options.map((option) => ({\n value: option.value,\n label: option.label,\n ...(option.token ? { token: option.token } : {}),\n })),\n })),\n },\n} as const\n"],"names":["BORDER_RADIUS_FIELD","DARK_SCHEME_FIELD","GOOGLE_FONT_OPTIONS","SPACING_FIELD","SYSTEM_FONT_VALUE","THEME_COLOR_FIELDS","THEME_COMPONENT_LOOK_FIELDS","THEME_COMPONENT_LOOK_GROUPS","THEME_EDITOR_SCHEMES","THEME_LOOK_DEFAULT","TOOLBAR_HEIGHT_FIELDS","readComponentLook","readDarkScheme","readFontFamily","readThemeColor","readToolbarHeight","themeComponentLookField","writeBorderRadius","writeComponentLook","writeDarkScheme","writeFontFamily","writeSpacing","writeThemeColor","writeToolbarHeight","THEME_EDITOR_EDITS_MAX","length","HEX_COLOR","readNumber","value","range","undefined","parsed","Number","isFinite","min","max","readThemeEditorEdit","raw","Array","isArray","edit","scheme","includes","token","some","field","test","control","option","family","breakpoint","find","entry","id","options","readThemeEditorEdits","edits","push","applyThemeEditorEdits","theme","next","readThemeEditorValues","safe","colors","radius","shape","borderRadius","darkScheme","fontFamily","spacing","navHeight","xs","sm","componentLooks","Object","fromEntries","map","THEME_EDITOR_CATALOG","schemes","systemFont","fonts","groups","fields","group","label","kind"],"mappings":"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"}