@aglyn/shared-ui-theme 1.0.0-beta.250 → 1.0.0-beta.253
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.
|
|
3
|
+
"version": "1.0.0-beta.253",
|
|
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.
|
|
29
|
-
"@aglyn/shared-util-tools": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-util-vendor": "1.0.0-beta.
|
|
28
|
+
"@aglyn/shared-data-types": "1.0.0-beta.253",
|
|
29
|
+
"@aglyn/shared-util-tools": "1.0.0-beta.253",
|
|
30
|
+
"@aglyn/shared-util-vendor": "1.0.0-beta.253",
|
|
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 {
|
|
6
|
-
|
|
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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"}
|