@aglyn/shared-ui-theme 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +51 -0
- package/src/index.d.ts +34 -0
- package/src/index.js +50 -0
- package/src/index.js.map +1 -0
- package/src/lib/components/host-theme-provider.d.ts +84 -0
- package/src/lib/components/host-theme-provider.js +146 -0
- package/src/lib/components/host-theme-provider.js.map +1 -0
- package/src/lib/components/theme-css-var-provider.d.ts +44 -0
- package/src/lib/components/theme-css-var-provider.js +79 -0
- package/src/lib/components/theme-css-var-provider.js.map +1 -0
- package/src/lib/console.theme.d.ts +34 -0
- package/src/lib/console.theme.js +598 -0
- package/src/lib/console.theme.js.map +1 -0
- package/src/lib/constants.d.ts +72 -0
- package/src/lib/constants.js +85 -0
- package/src/lib/constants.js.map +1 -0
- package/src/lib/hocs/create-with-emotion-client-cache.d.ts +30 -0
- package/src/lib/hocs/create-with-emotion-client-cache.js +53 -0
- package/src/lib/hocs/create-with-emotion-client-cache.js.map +1 -0
- package/src/lib/hocs/create-with-theme-provider.d.ts +86 -0
- package/src/lib/hocs/create-with-theme-provider.js +231 -0
- package/src/lib/hocs/create-with-theme-provider.js.map +1 -0
- package/src/lib/tenant.theme.d.ts +58 -0
- package/src/lib/tenant.theme.js +282 -0
- package/src/lib/tenant.theme.js.map +1 -0
- package/src/lib/theme.types.d.ts +26 -0
- package/src/lib/theme.types.js +18 -0
- package/src/lib/theme.types.js.map +1 -0
- package/src/lib/util/accent-text.d.ts +187 -0
- package/src/lib/util/accent-text.js +277 -0
- package/src/lib/util/accent-text.js.map +1 -0
- package/src/lib/util/accessible-shade.d.ts +61 -0
- package/src/lib/util/accessible-shade.js +117 -0
- package/src/lib/util/accessible-shade.js.map +1 -0
- package/src/lib/util/color-scheme-hint.d.ts +68 -0
- package/src/lib/util/color-scheme-hint.js +69 -0
- package/src/lib/util/color-scheme-hint.js.map +1 -0
- package/src/lib/util/create-responsive-theme.d.ts +71 -0
- package/src/lib/util/create-responsive-theme.js +287 -0
- package/src/lib/util/create-responsive-theme.js.map +1 -0
- package/src/lib/util/emotion-cache.d.ts +81 -0
- package/src/lib/util/emotion-cache.js +79 -0
- package/src/lib/util/emotion-cache.js.map +1 -0
- package/src/lib/util/generate-component-class-keys.d.ts +41 -0
- package/src/lib/util/generate-component-class-keys.js +53 -0
- package/src/lib/util/generate-component-class-keys.js.map +1 -0
- package/src/lib/util/host-theme.d.ts +92 -0
- package/src/lib/util/host-theme.js +340 -0
- package/src/lib/util/host-theme.js.map +1 -0
- package/src/lib/util/layered-emotion-cache.d.ts +78 -0
- package/src/lib/util/layered-emotion-cache.js +90 -0
- package/src/lib/util/layered-emotion-cache.js.map +1 -0
- package/src/lib/util/merge-sx-props.d.ts +22 -0
- package/src/lib/util/merge-sx-props.js +27 -0
- package/src/lib/util/merge-sx-props.js.map +1 -0
- package/src/lib/util/scheme-route-segment.d.ts +95 -0
- package/src/lib/util/scheme-route-segment.js +101 -0
- package/src/lib/util/scheme-route-segment.js.map +1 -0
- package/src/lib/util/theme-editor-defaults.d.ts +41 -0
- package/src/lib/util/theme-editor-defaults.js +49 -0
- package/src/lib/util/theme-editor-defaults.js.map +1 -0
- package/src/lib/util/theme-editor-fields.d.ts +315 -0
- package/src/lib/util/theme-editor-fields.js +714 -0
- package/src/lib/util/theme-editor-fields.js.map +1 -0
- package/src/lib/util/theme-mode-cookie.d.ts +48 -0
- package/src/lib/util/theme-mode-cookie.js +48 -0
- package/src/lib/util/theme-mode-cookie.js.map +1 -0
- package/src/vendor/emotion.d.ts +18 -0
- package/src/vendor/emotion.js +22 -0
- package/src/vendor/emotion.js.map +1 -0
- package/src/vendor/jss.d.ts +18 -0
- package/src/vendor/jss.js +20 -0
- package/src/vendor/jss.js.map +1 -0
- package/src/vendor/mui.d.ts +282 -0
- package/src/vendor/mui.js +20 -0
- package/src/vendor/mui.js.map +1 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
|
+
import { HOST_THEME_COMPONENT_WHITELIST } from "./host-theme.js";
|
|
18
|
+
/**
|
|
19
|
+
* The host theme editor's field catalog (AGL-2938): every control the editor
|
|
20
|
+
* renders, the range each one accepts, the token it writes, and the write
|
|
21
|
+
* itself.
|
|
22
|
+
*
|
|
23
|
+
* It lives here rather than beside the editor because the editor is not the
|
|
24
|
+
* only thing that changes a site's theme. Anything that proposes a theme
|
|
25
|
+
* change has to offer exactly the controls the editor offers, with the same
|
|
26
|
+
* bounds, and has to write each one the way the editor writes it. A copy of
|
|
27
|
+
* this list anywhere else is a second answer to "what can a theme hold" that
|
|
28
|
+
* drifts from the first the day a control is added, so the editor renders
|
|
29
|
+
* from this module and every other writer reads it.
|
|
30
|
+
*
|
|
31
|
+
* Pure data and pure functions over `HostTheme`: no MUI, no React and no
|
|
32
|
+
* brand theme. What a control resolves to when the site sets nothing is the
|
|
33
|
+
* brand theme's business, in `theme-editor-defaults.ts`.
|
|
34
|
+
*
|
|
35
|
+
* Deliberately NOT re-exported from this library's index: the index reaches
|
|
36
|
+
* every published page, and nothing a visitor renders needs the catalog.
|
|
37
|
+
* Reach it as `@aglyn/shared-ui-theme/util/theme-editor-fields`.
|
|
38
|
+
*/ /**
|
|
39
|
+
* MUI's own toolbar breakpoint. `mixins.toolbar` has to carry this exact
|
|
40
|
+
* query, because the rule it competes with is MUI's `@media (min-width:600px)
|
|
41
|
+
* { min-height: 64px }` (AGL-1242).
|
|
42
|
+
*/ export const TOOLBAR_SM_MIN_WIDTH = 600;
|
|
43
|
+
export const TOOLBAR_SM_QUERY = `@media (min-width:${TOOLBAR_SM_MIN_WIDTH}px)`;
|
|
44
|
+
/** MUI's stock Toolbar heights, shown when the host has set none. */ export const DEFAULT_TOOLBAR_XS = 56;
|
|
45
|
+
export const DEFAULT_TOOLBAR_SM = 64;
|
|
46
|
+
/**
|
|
47
|
+
* `createMixins` spreads `...mixins` AFTER its default, so anything we write
|
|
48
|
+
* REPLACES the stock toolbar wholesale — including its short-landscape rule.
|
|
49
|
+
* Carrying it forward keeps that behavior instead of dropping it silently.
|
|
50
|
+
*/ export const TOOLBAR_LANDSCAPE_QUERY = '@media (min-width:0px)';
|
|
51
|
+
export const TOOLBAR_LANDSCAPE_RULE = {
|
|
52
|
+
'@media (orientation: landscape)': {
|
|
53
|
+
minHeight: 48
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/** Reads a px `minHeight` out of `mixins.toolbar` for one breakpoint. */ export function readToolbarHeight(theme, breakpoint) {
|
|
57
|
+
var _theme_mixins, _toolbar_TOOLBAR_SM_QUERY;
|
|
58
|
+
const toolbar = (_theme_mixins = theme.mixins) == null ? void 0 : _theme_mixins.toolbar;
|
|
59
|
+
if (!toolbar) return undefined;
|
|
60
|
+
const raw = breakpoint === 'xs' ? toolbar.minHeight : (_toolbar_TOOLBAR_SM_QUERY = toolbar[TOOLBAR_SM_QUERY]) == null ? void 0 : _toolbar_TOOLBAR_SM_QUERY.minHeight;
|
|
61
|
+
const value = parseFloat(String(raw != null ? raw : ''));
|
|
62
|
+
return Number.isFinite(value) ? value : undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Builds a COMPLETE `mixins.toolbar`, in the order MUI emits it.
|
|
66
|
+
*
|
|
67
|
+
* Two things this exists to get right, both because `mixins.toolbar` replaces
|
|
68
|
+
* MUI's default wholesale rather than merging into it (AGL-1242):
|
|
69
|
+
*
|
|
70
|
+
* - **Completeness.** Anything omitted is simply gone. Writing only a desktop
|
|
71
|
+
* height left portrait phones with no `min-height` at all, so unset
|
|
72
|
+
* breakpoints fall back to MUI's own 56 / 64.
|
|
73
|
+
* - **Key order.** These land in one CSS rule, so the last matching
|
|
74
|
+
* declaration wins. MUI emits the landscape clause BEFORE the sm height;
|
|
75
|
+
* emitting it after makes a wide landscape window — i.e. every desktop —
|
|
76
|
+
* 48px tall.
|
|
77
|
+
*/ export function buildToolbarMixin(xs, sm) {
|
|
78
|
+
return {
|
|
79
|
+
minHeight: `${xs != null ? xs : DEFAULT_TOOLBAR_XS}px`,
|
|
80
|
+
[TOOLBAR_LANDSCAPE_QUERY]: TOOLBAR_LANDSCAPE_RULE,
|
|
81
|
+
[TOOLBAR_SM_QUERY]: {
|
|
82
|
+
minHeight: `${sm != null ? sm : DEFAULT_TOOLBAR_SM}px`
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Serializes the branches whose KEY ORDER changes what renders.
|
|
88
|
+
*
|
|
89
|
+
* `deepEqual` is order-INsensitive on purpose (AGL-56: Firestore hands the
|
|
90
|
+
* palette back in a different key order than the editor builds it, and a
|
|
91
|
+
* string compare left Save enabled forever), so on its own it cannot see a
|
|
92
|
+
* reorder of `mixins.toolbar` — a change that really does alter the CSS.
|
|
93
|
+
*
|
|
94
|
+
* Deliberately narrow: only `mixins`. `components.*.styleOverrides` are CSS
|
|
95
|
+
* objects too, but widening this would re-expose the AGL-56 failure for every
|
|
96
|
+
* host with component overrides, and order-sensitivity has only actually been
|
|
97
|
+
* demonstrated here.
|
|
98
|
+
*
|
|
99
|
+
* Firestore does NOT hand a map back in the order it was written, and it
|
|
100
|
+
* hands different readers different orders (AGL-3146) — which is why what
|
|
101
|
+
* renders is canonicalized in `hostThemeToThemeOptions` rather than trusted
|
|
102
|
+
* from storage. A freshly-loaded document is still not dirty here, because
|
|
103
|
+
* the draft is seeded from the loaded document itself: both sides of this
|
|
104
|
+
* comparison carry whatever order THIS reader was given.
|
|
105
|
+
*/ export function orderSensitiveKey(theme) {
|
|
106
|
+
var _theme_mixins;
|
|
107
|
+
return JSON.stringify((_theme_mixins = theme.mixins) != null ? _theme_mixins : {});
|
|
108
|
+
}
|
|
109
|
+
export const PALETTE_COLOR_FIELDS = [
|
|
110
|
+
{
|
|
111
|
+
key: 'primary',
|
|
112
|
+
label: 'Primary'
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
key: 'secondary',
|
|
116
|
+
label: 'Secondary'
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
key: 'tertiary',
|
|
120
|
+
label: 'Tertiary'
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
key: 'surface',
|
|
124
|
+
label: 'Surface'
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
key: 'error',
|
|
128
|
+
label: 'Error'
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
key: 'warning',
|
|
132
|
+
label: 'Warning'
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
key: 'info',
|
|
136
|
+
label: 'Info'
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
key: 'success',
|
|
140
|
+
label: 'Success'
|
|
141
|
+
}
|
|
142
|
+
];
|
|
143
|
+
export const SURFACE_COLOR_FIELDS = [
|
|
144
|
+
{
|
|
145
|
+
path: [
|
|
146
|
+
'background',
|
|
147
|
+
'default'
|
|
148
|
+
],
|
|
149
|
+
label: 'Background'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
path: [
|
|
153
|
+
'background',
|
|
154
|
+
'paper'
|
|
155
|
+
],
|
|
156
|
+
label: 'Paper'
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
path: [
|
|
160
|
+
'text',
|
|
161
|
+
'primary'
|
|
162
|
+
],
|
|
163
|
+
label: 'Text'
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
path: [
|
|
167
|
+
'text',
|
|
168
|
+
'secondary'
|
|
169
|
+
],
|
|
170
|
+
label: 'Secondary text'
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
path: [
|
|
174
|
+
'text',
|
|
175
|
+
'disabled'
|
|
176
|
+
],
|
|
177
|
+
label: 'Disabled text'
|
|
178
|
+
}
|
|
179
|
+
];
|
|
180
|
+
/**
|
|
181
|
+
* Pale accent washes (AGL-1244).
|
|
182
|
+
*
|
|
183
|
+
* Separate from {@link PALETTE_COLOR_FIELDS} because a tint is a STRING LEAF,
|
|
184
|
+
* not a `{ main }` record — the palette fields all write `main`, and a tint has
|
|
185
|
+
* none. It rides the same `SurfaceColorPath` machinery as `background`/`text`
|
|
186
|
+
* for exactly that reason, and is listed apart only so the editor can head it
|
|
187
|
+
* "Tints" instead of filing it under "Background & text".
|
|
188
|
+
*/ export const TINT_COLOR_FIELDS = [
|
|
189
|
+
{
|
|
190
|
+
path: [
|
|
191
|
+
'tint',
|
|
192
|
+
'primary'
|
|
193
|
+
],
|
|
194
|
+
label: 'Primary tint'
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
path: [
|
|
198
|
+
'tint',
|
|
199
|
+
'secondary'
|
|
200
|
+
],
|
|
201
|
+
label: 'Secondary tint'
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
path: [
|
|
205
|
+
'tint',
|
|
206
|
+
'tertiary'
|
|
207
|
+
],
|
|
208
|
+
label: 'Tertiary tint'
|
|
209
|
+
}
|
|
210
|
+
];
|
|
211
|
+
/** The one color leaf that is neither a palette color nor a member of a group. */ export const DIVIDER_COLOR_FIELD = {
|
|
212
|
+
key: 'divider',
|
|
213
|
+
label: 'Divider'
|
|
214
|
+
};
|
|
215
|
+
/** Curated Google Fonts choices for the font family selector. */ export const GOOGLE_FONT_OPTIONS = [
|
|
216
|
+
{
|
|
217
|
+
family: 'Inter',
|
|
218
|
+
category: 'sans-serif',
|
|
219
|
+
weights: [
|
|
220
|
+
400,
|
|
221
|
+
500,
|
|
222
|
+
700
|
|
223
|
+
]
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
family: 'Roboto',
|
|
227
|
+
category: 'sans-serif',
|
|
228
|
+
weights: [
|
|
229
|
+
400,
|
|
230
|
+
500,
|
|
231
|
+
700
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
family: 'Open Sans',
|
|
236
|
+
category: 'sans-serif',
|
|
237
|
+
weights: [
|
|
238
|
+
400,
|
|
239
|
+
600,
|
|
240
|
+
700
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
family: 'Lato',
|
|
245
|
+
category: 'sans-serif',
|
|
246
|
+
weights: [
|
|
247
|
+
400,
|
|
248
|
+
700
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
family: 'Montserrat',
|
|
253
|
+
category: 'sans-serif',
|
|
254
|
+
weights: [
|
|
255
|
+
400,
|
|
256
|
+
500,
|
|
257
|
+
700
|
|
258
|
+
]
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
family: 'Poppins',
|
|
262
|
+
category: 'sans-serif',
|
|
263
|
+
weights: [
|
|
264
|
+
400,
|
|
265
|
+
500,
|
|
266
|
+
700
|
|
267
|
+
]
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
family: 'Nunito',
|
|
271
|
+
category: 'sans-serif',
|
|
272
|
+
weights: [
|
|
273
|
+
400,
|
|
274
|
+
600,
|
|
275
|
+
700
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
family: 'Work Sans',
|
|
280
|
+
category: 'sans-serif',
|
|
281
|
+
weights: [
|
|
282
|
+
400,
|
|
283
|
+
500,
|
|
284
|
+
700
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
family: 'Raleway',
|
|
289
|
+
category: 'sans-serif',
|
|
290
|
+
weights: [
|
|
291
|
+
400,
|
|
292
|
+
500,
|
|
293
|
+
700
|
|
294
|
+
]
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
family: 'Merriweather',
|
|
298
|
+
category: 'serif',
|
|
299
|
+
weights: [
|
|
300
|
+
400,
|
|
301
|
+
700
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
family: 'Playfair Display',
|
|
306
|
+
category: 'serif',
|
|
307
|
+
weights: [
|
|
308
|
+
400,
|
|
309
|
+
700
|
|
310
|
+
]
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
family: 'Lora',
|
|
314
|
+
category: 'serif',
|
|
315
|
+
weights: [
|
|
316
|
+
400,
|
|
317
|
+
700
|
|
318
|
+
]
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
family: 'Source Serif 4',
|
|
322
|
+
category: 'serif',
|
|
323
|
+
weights: [
|
|
324
|
+
400,
|
|
325
|
+
700
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
family: 'JetBrains Mono',
|
|
330
|
+
category: 'monospace',
|
|
331
|
+
weights: [
|
|
332
|
+
400,
|
|
333
|
+
700
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
family: 'Bebas Neue',
|
|
338
|
+
category: 'display',
|
|
339
|
+
weights: [
|
|
340
|
+
400
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
];
|
|
344
|
+
export function fontFamilyStack(family, category) {
|
|
345
|
+
const fallback = category === 'monospace' ? 'monospace' : category === 'serif' ? 'serif' : 'sans-serif';
|
|
346
|
+
return `"${family}", ${fallback}`;
|
|
347
|
+
}
|
|
348
|
+
export function getSchemeColor(colors, path) {
|
|
349
|
+
var _colors_group;
|
|
350
|
+
const [group, key] = path;
|
|
351
|
+
return colors == null ? void 0 : (_colors_group = colors[group]) == null ? void 0 : _colors_group[key];
|
|
352
|
+
}
|
|
353
|
+
/* ------------------------------------------------------------------------ *
|
|
354
|
+
* The controls, as one catalog
|
|
355
|
+
* ------------------------------------------------------------------------ */ /** The two color schemes the editor edits, in tab order. */ export const THEME_EDITOR_SCHEMES = [
|
|
356
|
+
'light',
|
|
357
|
+
'dark'
|
|
358
|
+
];
|
|
359
|
+
/** Every color field the editor renders, in the order it renders them. */ export const THEME_COLOR_FIELDS = [
|
|
360
|
+
...PALETTE_COLOR_FIELDS.map(({ key, label })=>({
|
|
361
|
+
token: key,
|
|
362
|
+
label,
|
|
363
|
+
group: 'palette'
|
|
364
|
+
})),
|
|
365
|
+
...SURFACE_COLOR_FIELDS.map(({ path, label })=>({
|
|
366
|
+
token: path.join('.'),
|
|
367
|
+
label,
|
|
368
|
+
group: 'surface'
|
|
369
|
+
})),
|
|
370
|
+
...TINT_COLOR_FIELDS.map(({ path, label })=>({
|
|
371
|
+
token: path.join('.'),
|
|
372
|
+
label,
|
|
373
|
+
group: 'tint'
|
|
374
|
+
})),
|
|
375
|
+
{
|
|
376
|
+
token: DIVIDER_COLOR_FIELD.key,
|
|
377
|
+
label: DIVIDER_COLOR_FIELD.label,
|
|
378
|
+
group: 'divider'
|
|
379
|
+
}
|
|
380
|
+
];
|
|
381
|
+
export const DARK_SCHEME_FIELD = {
|
|
382
|
+
label: 'Dark scheme',
|
|
383
|
+
options: [
|
|
384
|
+
{
|
|
385
|
+
value: 'auto',
|
|
386
|
+
label: 'Follows the visitor'
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
value: 'off',
|
|
390
|
+
label: 'Off — always light'
|
|
391
|
+
}
|
|
392
|
+
]
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* The font select's value for "no font of the site's own": the theme's
|
|
396
|
+
* default stack, with nothing to load.
|
|
397
|
+
*/ export const SYSTEM_FONT_VALUE = '__system__';
|
|
398
|
+
export const FONT_FAMILY_FIELD = {
|
|
399
|
+
label: 'Font family'
|
|
400
|
+
};
|
|
401
|
+
/** The corner radius slider, in px. */ export const BORDER_RADIUS_FIELD = {
|
|
402
|
+
label: 'Border radius',
|
|
403
|
+
min: 0,
|
|
404
|
+
max: 24,
|
|
405
|
+
step: 1
|
|
406
|
+
};
|
|
407
|
+
/** The spacing unit MUI multiplies every `spacing(n)` by, in px. */ export const SPACING_FIELD = {
|
|
408
|
+
label: 'Spacing unit (px)',
|
|
409
|
+
min: 2,
|
|
410
|
+
max: 16,
|
|
411
|
+
step: 1
|
|
412
|
+
};
|
|
413
|
+
/** The two nav heights, either side of MUI's toolbar breakpoint, in px. */ export const TOOLBAR_HEIGHT_FIELDS = {
|
|
414
|
+
xs: {
|
|
415
|
+
label: 'Nav height, mobile (px)',
|
|
416
|
+
min: 40,
|
|
417
|
+
max: 160,
|
|
418
|
+
step: 1
|
|
419
|
+
},
|
|
420
|
+
sm: {
|
|
421
|
+
label: 'Nav height, desktop (px)',
|
|
422
|
+
min: 40,
|
|
423
|
+
max: 160,
|
|
424
|
+
step: 1
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
/** The raw-JSON component overrides, limited to the sanitizer's whitelist. */ export const COMPONENT_OVERRIDES_FIELD = {
|
|
428
|
+
label: 'Component overrides',
|
|
429
|
+
components: HOST_THEME_COMPONENT_WHITELIST
|
|
430
|
+
};
|
|
431
|
+
/**
|
|
432
|
+
* The media queries a component override may scope a style to: either side
|
|
433
|
+
* of MUI's own toolbar breakpoint, the one breakpoint the editor already
|
|
434
|
+
* names. MUI's `down('sm')` stops a twentieth of a pixel short of it.
|
|
435
|
+
*/ export const THEME_EDITOR_MEDIA_QUERIES = {
|
|
436
|
+
mobile: `@media (max-width:${TOOLBAR_SM_MIN_WIDTH - 0.05}px)`,
|
|
437
|
+
desktop: TOOLBAR_SM_QUERY
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Every value-bearing control the editor renders, in the order it renders
|
|
441
|
+
* them. The buttons that act on these values rather than hold one — Copy
|
|
442
|
+
* from light, Reset to default, Discard, Save — are not controls: a reset is
|
|
443
|
+
* a control set back to nothing, and a copy is every color control of one
|
|
444
|
+
* scheme written from the other.
|
|
445
|
+
*/ export const THEME_EDITOR_CONTROLS = [
|
|
446
|
+
{
|
|
447
|
+
id: 'darkScheme',
|
|
448
|
+
label: DARK_SCHEME_FIELD.label,
|
|
449
|
+
kind: 'select',
|
|
450
|
+
perScheme: false,
|
|
451
|
+
options: DARK_SCHEME_FIELD.options.map((option)=>option.value)
|
|
452
|
+
},
|
|
453
|
+
...THEME_COLOR_FIELDS.map(({ token, label })=>({
|
|
454
|
+
id: `color.${token}`,
|
|
455
|
+
label,
|
|
456
|
+
kind: 'color',
|
|
457
|
+
perScheme: true,
|
|
458
|
+
token
|
|
459
|
+
})),
|
|
460
|
+
{
|
|
461
|
+
id: 'fontFamily',
|
|
462
|
+
label: FONT_FAMILY_FIELD.label,
|
|
463
|
+
kind: 'select',
|
|
464
|
+
perScheme: false,
|
|
465
|
+
options: [
|
|
466
|
+
SYSTEM_FONT_VALUE,
|
|
467
|
+
...GOOGLE_FONT_OPTIONS.map((option)=>option.family)
|
|
468
|
+
]
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
id: 'borderRadius',
|
|
472
|
+
label: BORDER_RADIUS_FIELD.label,
|
|
473
|
+
kind: 'number',
|
|
474
|
+
perScheme: false,
|
|
475
|
+
min: BORDER_RADIUS_FIELD.min,
|
|
476
|
+
max: BORDER_RADIUS_FIELD.max,
|
|
477
|
+
step: BORDER_RADIUS_FIELD.step
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
id: 'spacing',
|
|
481
|
+
label: SPACING_FIELD.label,
|
|
482
|
+
kind: 'number',
|
|
483
|
+
perScheme: false,
|
|
484
|
+
min: SPACING_FIELD.min,
|
|
485
|
+
max: SPACING_FIELD.max,
|
|
486
|
+
step: SPACING_FIELD.step
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
id: 'navHeight.xs',
|
|
490
|
+
label: TOOLBAR_HEIGHT_FIELDS.xs.label,
|
|
491
|
+
kind: 'number',
|
|
492
|
+
perScheme: false,
|
|
493
|
+
min: TOOLBAR_HEIGHT_FIELDS.xs.min,
|
|
494
|
+
max: TOOLBAR_HEIGHT_FIELDS.xs.max,
|
|
495
|
+
step: TOOLBAR_HEIGHT_FIELDS.xs.step
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
id: 'navHeight.sm',
|
|
499
|
+
label: TOOLBAR_HEIGHT_FIELDS.sm.label,
|
|
500
|
+
kind: 'number',
|
|
501
|
+
perScheme: false,
|
|
502
|
+
min: TOOLBAR_HEIGHT_FIELDS.sm.min,
|
|
503
|
+
max: TOOLBAR_HEIGHT_FIELDS.sm.max,
|
|
504
|
+
step: TOOLBAR_HEIGHT_FIELDS.sm.step
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
id: 'components',
|
|
508
|
+
label: COMPONENT_OVERRIDES_FIELD.label,
|
|
509
|
+
kind: 'json',
|
|
510
|
+
perScheme: false,
|
|
511
|
+
options: COMPONENT_OVERRIDES_FIELD.components
|
|
512
|
+
}
|
|
513
|
+
];
|
|
514
|
+
/** The catalog entry for a control id. */ export function themeEditorControl(id) {
|
|
515
|
+
const control = THEME_EDITOR_CONTROLS.find((entry)=>entry.id === id);
|
|
516
|
+
if (!control) throw new Error(`unknown theme editor control ${id}`);
|
|
517
|
+
return control;
|
|
518
|
+
}
|
|
519
|
+
/* ------------------------------------------------------------------------ *
|
|
520
|
+
* Reads and writes, exactly as the editor performs them
|
|
521
|
+
* ------------------------------------------------------------------------ */ function setSchemeValue(theme, scheme, update) {
|
|
522
|
+
var _ref;
|
|
523
|
+
var _theme_colorSchemes;
|
|
524
|
+
const colors = (_ref = (_theme_colorSchemes = theme.colorSchemes) == null ? void 0 : _theme_colorSchemes[scheme]) != null ? _ref : {};
|
|
525
|
+
return _extends({}, theme, {
|
|
526
|
+
colorSchemes: _extends({}, theme.colorSchemes, {
|
|
527
|
+
[scheme]: update(colors)
|
|
528
|
+
})
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
/** A color the site set for one scheme; `undefined` when the slot inherits. */ export function readThemeColor(theme, scheme, token) {
|
|
532
|
+
var _theme_colorSchemes, _colors_group;
|
|
533
|
+
const colors = theme == null ? void 0 : (_theme_colorSchemes = theme.colorSchemes) == null ? void 0 : _theme_colorSchemes[scheme];
|
|
534
|
+
if (token === 'divider') return colors == null ? void 0 : colors.divider;
|
|
535
|
+
const [group, key] = token.split('.');
|
|
536
|
+
if (!key) return colors == null ? void 0 : (_colors_group = colors[group]) == null ? void 0 : _colors_group.main;
|
|
537
|
+
return getSchemeColor(colors, [
|
|
538
|
+
group,
|
|
539
|
+
key
|
|
540
|
+
]);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Sets one color for one scheme, or clears it with `undefined` so the slot
|
|
544
|
+
* inherits again. A palette color writes `main` and keeps whatever else its
|
|
545
|
+
* record carries, and clearing it drops the record; a group member that
|
|
546
|
+
* leaves its group empty drops the group.
|
|
547
|
+
*/ export function writeThemeColor(theme, scheme, token, hex) {
|
|
548
|
+
return setSchemeValue(theme, scheme, (colors)=>{
|
|
549
|
+
const next = _extends({}, colors);
|
|
550
|
+
if (token === 'divider') {
|
|
551
|
+
if (hex) next.divider = hex;
|
|
552
|
+
else delete next.divider;
|
|
553
|
+
return next;
|
|
554
|
+
}
|
|
555
|
+
const [group, key] = token.split('.');
|
|
556
|
+
if (!key) {
|
|
557
|
+
const paletteKey = group;
|
|
558
|
+
if (hex) next[paletteKey] = _extends({}, next[paletteKey], {
|
|
559
|
+
main: hex
|
|
560
|
+
});
|
|
561
|
+
else delete next[paletteKey];
|
|
562
|
+
return next;
|
|
563
|
+
}
|
|
564
|
+
const groupKey = group;
|
|
565
|
+
const groupValue = _extends({}, colors[groupKey]);
|
|
566
|
+
if (hex) groupValue[key] = hex;
|
|
567
|
+
else delete groupValue[key];
|
|
568
|
+
const grouped = _extends({}, next, {
|
|
569
|
+
[groupKey]: groupValue
|
|
570
|
+
});
|
|
571
|
+
if (!Object.keys(groupValue).length) delete grouped[groupKey];
|
|
572
|
+
return grouped;
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
/** Replaces one scheme's colors with a copy of the other's. */ export function copyThemeSchemeColors(theme, from, to) {
|
|
576
|
+
var _theme_colorSchemes;
|
|
577
|
+
const source = (_theme_colorSchemes = theme.colorSchemes) == null ? void 0 : _theme_colorSchemes[from];
|
|
578
|
+
if (!source) return theme;
|
|
579
|
+
return _extends({}, theme, {
|
|
580
|
+
colorSchemes: _extends({}, theme.colorSchemes, {
|
|
581
|
+
[to]: JSON.parse(JSON.stringify(source))
|
|
582
|
+
})
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
/** The dark scheme switch as the select shows it. */ export function readDarkScheme(theme) {
|
|
586
|
+
return (theme == null ? void 0 : theme.darkScheme) === 'off' ? 'off' : 'auto';
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Absent means "follows the visitor"; only the opt-out is written, so the
|
|
590
|
+
* saved document stays empty for the common case.
|
|
591
|
+
*/ export function writeDarkScheme(theme, value) {
|
|
592
|
+
const next = _extends({}, theme);
|
|
593
|
+
if (value === 'off') next.darkScheme = 'off';
|
|
594
|
+
else delete next.darkScheme;
|
|
595
|
+
return next;
|
|
596
|
+
}
|
|
597
|
+
/** The font select's value: the site's font, or {@link SYSTEM_FONT_VALUE}. */ export function readFontFamily(theme) {
|
|
598
|
+
var _ref;
|
|
599
|
+
var _theme_fonts_, _theme_fonts;
|
|
600
|
+
return (_ref = theme == null ? void 0 : (_theme_fonts = theme.fonts) == null ? void 0 : (_theme_fonts_ = _theme_fonts[0]) == null ? void 0 : _theme_fonts_.family) != null ? _ref : SYSTEM_FONT_VALUE;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Picks a font from {@link GOOGLE_FONT_OPTIONS}, loading it and naming it as
|
|
604
|
+
* the typography's stack, or {@link SYSTEM_FONT_VALUE} to go back to the
|
|
605
|
+
* theme default. A family outside the curated list changes nothing.
|
|
606
|
+
*/ export function writeFontFamily(theme, value) {
|
|
607
|
+
if (value === SYSTEM_FONT_VALUE) {
|
|
608
|
+
const next = _extends({}, theme);
|
|
609
|
+
delete next.fonts;
|
|
610
|
+
const typography = _extends({}, next.typography);
|
|
611
|
+
delete typography.fontFamily;
|
|
612
|
+
if (Object.keys(typography).length) next.typography = typography;
|
|
613
|
+
else delete next.typography;
|
|
614
|
+
return next;
|
|
615
|
+
}
|
|
616
|
+
const option = GOOGLE_FONT_OPTIONS.find((entry)=>entry.family === value);
|
|
617
|
+
if (!option) return theme;
|
|
618
|
+
return _extends({}, theme, {
|
|
619
|
+
fonts: [
|
|
620
|
+
{
|
|
621
|
+
family: option.family,
|
|
622
|
+
weights: option.weights,
|
|
623
|
+
source: 'google'
|
|
624
|
+
}
|
|
625
|
+
],
|
|
626
|
+
typography: _extends({}, theme.typography, {
|
|
627
|
+
fontFamily: fontFamilyStack(option.family, option.category)
|
|
628
|
+
})
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
/** Sets the corner radius, or clears it with `undefined` so it inherits. */ export function writeBorderRadius(theme, value) {
|
|
632
|
+
if (value !== undefined && Number.isFinite(value)) {
|
|
633
|
+
return _extends({}, theme, {
|
|
634
|
+
shape: _extends({}, theme.shape, {
|
|
635
|
+
borderRadius: value
|
|
636
|
+
})
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
const next = _extends({}, theme);
|
|
640
|
+
const shape = _extends({}, next.shape);
|
|
641
|
+
delete shape.borderRadius;
|
|
642
|
+
if (Object.keys(shape).length) next.shape = shape;
|
|
643
|
+
else delete next.shape;
|
|
644
|
+
return next;
|
|
645
|
+
}
|
|
646
|
+
/** Sets the spacing unit; anything but a positive number clears it. */ export function writeSpacing(theme, value) {
|
|
647
|
+
const next = _extends({}, theme);
|
|
648
|
+
if (value !== undefined && Number.isFinite(value) && value > 0) next.spacing = value;
|
|
649
|
+
else delete next.spacing;
|
|
650
|
+
return next;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Sets one nav height — anything but a positive number clears it — and
|
|
654
|
+
* rebuilds the whole toolbar mixin around both, because `mixins.toolbar`
|
|
655
|
+
* replaces MUI's default rather than merging into it (AGL-1242).
|
|
656
|
+
*/ export function writeToolbarHeight(theme, breakpoint, value) {
|
|
657
|
+
const valid = value !== undefined && Number.isFinite(value) && value > 0;
|
|
658
|
+
const edited = valid ? value : undefined;
|
|
659
|
+
const xs = breakpoint === 'xs' ? edited : readToolbarHeight(theme, 'xs');
|
|
660
|
+
const sm = breakpoint === 'sm' ? edited : readToolbarHeight(theme, 'sm');
|
|
661
|
+
const next = _extends({}, theme);
|
|
662
|
+
if (xs === undefined && sm === undefined) {
|
|
663
|
+
delete next.mixins;
|
|
664
|
+
return next;
|
|
665
|
+
}
|
|
666
|
+
next.mixins = {
|
|
667
|
+
toolbar: buildToolbarMixin(xs, sm)
|
|
668
|
+
};
|
|
669
|
+
return next;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Drops the site's component overrides. With nothing stored the site renders
|
|
673
|
+
* the brand's own component styles, which is what the editor's "Reset to
|
|
674
|
+
* theme defaults" means.
|
|
675
|
+
*/ export function resetComponentOverrides(theme) {
|
|
676
|
+
const next = _extends({}, theme);
|
|
677
|
+
delete next.components;
|
|
678
|
+
return next;
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Sets one leaf inside the site's component overrides and keeps every other
|
|
682
|
+
* override the site has. The stored overrides are deep-merged over the
|
|
683
|
+
* brand's own at render time, so naming one property changes that property
|
|
684
|
+
* and inherits the rest of the component.
|
|
685
|
+
*/ export function writeComponentOverride(theme, leaf) {
|
|
686
|
+
const components = _extends({}, theme.components);
|
|
687
|
+
const entry = _extends({}, components[leaf.component]);
|
|
688
|
+
if (leaf.target === 'defaultProps') {
|
|
689
|
+
entry.defaultProps = _extends({}, entry.defaultProps, {
|
|
690
|
+
[leaf.property]: leaf.value
|
|
691
|
+
});
|
|
692
|
+
} else {
|
|
693
|
+
var _leaf_slot;
|
|
694
|
+
const slot = (_leaf_slot = leaf.slot) != null ? _leaf_slot : 'root';
|
|
695
|
+
const styles = _extends({}, entry.styleOverrides);
|
|
696
|
+
const slotStyles = _extends({}, styles[slot]);
|
|
697
|
+
if (leaf.media) {
|
|
698
|
+
const query = THEME_EDITOR_MEDIA_QUERIES[leaf.media];
|
|
699
|
+
slotStyles[query] = _extends({}, slotStyles[query], {
|
|
700
|
+
[leaf.property]: leaf.value
|
|
701
|
+
});
|
|
702
|
+
} else {
|
|
703
|
+
slotStyles[leaf.property] = leaf.value;
|
|
704
|
+
}
|
|
705
|
+
styles[slot] = slotStyles;
|
|
706
|
+
entry.styleOverrides = styles;
|
|
707
|
+
}
|
|
708
|
+
components[leaf.component] = entry;
|
|
709
|
+
return _extends({}, theme, {
|
|
710
|
+
components
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
//# sourceMappingURL=theme-editor-fields.js.map
|