@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.
Files changed (78) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +51 -0
  4. package/src/index.d.ts +34 -0
  5. package/src/index.js +50 -0
  6. package/src/index.js.map +1 -0
  7. package/src/lib/components/host-theme-provider.d.ts +84 -0
  8. package/src/lib/components/host-theme-provider.js +146 -0
  9. package/src/lib/components/host-theme-provider.js.map +1 -0
  10. package/src/lib/components/theme-css-var-provider.d.ts +44 -0
  11. package/src/lib/components/theme-css-var-provider.js +79 -0
  12. package/src/lib/components/theme-css-var-provider.js.map +1 -0
  13. package/src/lib/console.theme.d.ts +34 -0
  14. package/src/lib/console.theme.js +598 -0
  15. package/src/lib/console.theme.js.map +1 -0
  16. package/src/lib/constants.d.ts +72 -0
  17. package/src/lib/constants.js +85 -0
  18. package/src/lib/constants.js.map +1 -0
  19. package/src/lib/hocs/create-with-emotion-client-cache.d.ts +30 -0
  20. package/src/lib/hocs/create-with-emotion-client-cache.js +53 -0
  21. package/src/lib/hocs/create-with-emotion-client-cache.js.map +1 -0
  22. package/src/lib/hocs/create-with-theme-provider.d.ts +86 -0
  23. package/src/lib/hocs/create-with-theme-provider.js +231 -0
  24. package/src/lib/hocs/create-with-theme-provider.js.map +1 -0
  25. package/src/lib/tenant.theme.d.ts +58 -0
  26. package/src/lib/tenant.theme.js +282 -0
  27. package/src/lib/tenant.theme.js.map +1 -0
  28. package/src/lib/theme.types.d.ts +26 -0
  29. package/src/lib/theme.types.js +18 -0
  30. package/src/lib/theme.types.js.map +1 -0
  31. package/src/lib/util/accent-text.d.ts +187 -0
  32. package/src/lib/util/accent-text.js +277 -0
  33. package/src/lib/util/accent-text.js.map +1 -0
  34. package/src/lib/util/accessible-shade.d.ts +61 -0
  35. package/src/lib/util/accessible-shade.js +117 -0
  36. package/src/lib/util/accessible-shade.js.map +1 -0
  37. package/src/lib/util/color-scheme-hint.d.ts +68 -0
  38. package/src/lib/util/color-scheme-hint.js +69 -0
  39. package/src/lib/util/color-scheme-hint.js.map +1 -0
  40. package/src/lib/util/create-responsive-theme.d.ts +71 -0
  41. package/src/lib/util/create-responsive-theme.js +287 -0
  42. package/src/lib/util/create-responsive-theme.js.map +1 -0
  43. package/src/lib/util/emotion-cache.d.ts +81 -0
  44. package/src/lib/util/emotion-cache.js +79 -0
  45. package/src/lib/util/emotion-cache.js.map +1 -0
  46. package/src/lib/util/generate-component-class-keys.d.ts +41 -0
  47. package/src/lib/util/generate-component-class-keys.js +53 -0
  48. package/src/lib/util/generate-component-class-keys.js.map +1 -0
  49. package/src/lib/util/host-theme.d.ts +92 -0
  50. package/src/lib/util/host-theme.js +340 -0
  51. package/src/lib/util/host-theme.js.map +1 -0
  52. package/src/lib/util/layered-emotion-cache.d.ts +78 -0
  53. package/src/lib/util/layered-emotion-cache.js +90 -0
  54. package/src/lib/util/layered-emotion-cache.js.map +1 -0
  55. package/src/lib/util/merge-sx-props.d.ts +22 -0
  56. package/src/lib/util/merge-sx-props.js +27 -0
  57. package/src/lib/util/merge-sx-props.js.map +1 -0
  58. package/src/lib/util/scheme-route-segment.d.ts +95 -0
  59. package/src/lib/util/scheme-route-segment.js +101 -0
  60. package/src/lib/util/scheme-route-segment.js.map +1 -0
  61. package/src/lib/util/theme-editor-defaults.d.ts +41 -0
  62. package/src/lib/util/theme-editor-defaults.js +49 -0
  63. package/src/lib/util/theme-editor-defaults.js.map +1 -0
  64. package/src/lib/util/theme-editor-fields.d.ts +315 -0
  65. package/src/lib/util/theme-editor-fields.js +714 -0
  66. package/src/lib/util/theme-editor-fields.js.map +1 -0
  67. package/src/lib/util/theme-mode-cookie.d.ts +48 -0
  68. package/src/lib/util/theme-mode-cookie.js +48 -0
  69. package/src/lib/util/theme-mode-cookie.js.map +1 -0
  70. package/src/vendor/emotion.d.ts +18 -0
  71. package/src/vendor/emotion.js +22 -0
  72. package/src/vendor/emotion.js.map +1 -0
  73. package/src/vendor/jss.d.ts +18 -0
  74. package/src/vendor/jss.js +20 -0
  75. package/src/vendor/jss.js.map +1 -0
  76. package/src/vendor/mui.d.ts +282 -0
  77. package/src/vendor/mui.js +20 -0
  78. package/src/vendor/mui.js.map +1 -0
@@ -0,0 +1,340 @@
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 { objectDeepMergeReplaceArrays } from "@aglyn/shared-util-vendor";
18
+ /**
19
+ * Components a host theme may override. Persisted overrides are plain JSON;
20
+ * anything outside this list is dropped by {@link sanitizeHostTheme} so a
21
+ * tampered document can't restyle console-internal or portal-critical
22
+ * components.
23
+ */ export const HOST_THEME_COMPONENT_WHITELIST = [
24
+ 'MuiAppBar',
25
+ 'MuiAvatar',
26
+ 'MuiBadge',
27
+ 'MuiButton',
28
+ 'MuiButtonBase',
29
+ 'MuiCard',
30
+ 'MuiCardContent',
31
+ 'MuiCheckbox',
32
+ 'MuiChip',
33
+ 'MuiCircularProgress',
34
+ 'MuiDivider',
35
+ 'MuiIconButton',
36
+ 'MuiLinearProgress',
37
+ 'MuiLink',
38
+ 'MuiList',
39
+ 'MuiListItem',
40
+ 'MuiMenu',
41
+ 'MuiPaper',
42
+ 'MuiRadio',
43
+ 'MuiSlider',
44
+ 'MuiSwitch',
45
+ 'MuiTab',
46
+ 'MuiTabs',
47
+ 'MuiTextField',
48
+ 'MuiToolbar',
49
+ 'MuiTooltip',
50
+ 'MuiTypography'
51
+ ];
52
+ const componentWhitelist = new Set(HOST_THEME_COMPONENT_WHITELIST);
53
+ function pickPaletteColor(color) {
54
+ if (!(color == null ? void 0 : color.main)) return undefined;
55
+ const picked = {
56
+ main: color.main
57
+ };
58
+ if (color.light) picked.light = color.light;
59
+ if (color.dark) picked.dark = color.dark;
60
+ if (color.contrastText) picked.contrastText = color.contrastText;
61
+ return picked;
62
+ }
63
+ function schemeColorsToPaletteOptions(scheme, colors) {
64
+ var _colors_background, _colors_background1, _colors_text, _colors_text1, _colors_text2, _colors_tint, _colors_tint1, _colors_tint2;
65
+ const palette = {
66
+ mode: scheme
67
+ };
68
+ if (!colors) return palette;
69
+ const colorKeys = [
70
+ 'primary',
71
+ 'secondary',
72
+ 'tertiary',
73
+ 'surface',
74
+ 'error',
75
+ 'warning',
76
+ 'info',
77
+ 'success'
78
+ ];
79
+ for (const key of colorKeys){
80
+ const color = pickPaletteColor(colors[key]);
81
+ if (color) palette[key] = color;
82
+ }
83
+ if (((_colors_background = colors.background) == null ? void 0 : _colors_background.default) || ((_colors_background1 = colors.background) == null ? void 0 : _colors_background1.paper)) {
84
+ palette.background = _extends({}, colors.background.default && {
85
+ default: colors.background.default
86
+ }, colors.background.paper && {
87
+ paper: colors.background.paper
88
+ });
89
+ }
90
+ if (((_colors_text = colors.text) == null ? void 0 : _colors_text.primary) || ((_colors_text1 = colors.text) == null ? void 0 : _colors_text1.secondary) || ((_colors_text2 = colors.text) == null ? void 0 : _colors_text2.disabled)) {
91
+ palette.text = _extends({}, colors.text.primary && {
92
+ primary: colors.text.primary
93
+ }, colors.text.secondary && {
94
+ secondary: colors.text.secondary
95
+ }, colors.text.disabled && {
96
+ disabled: colors.text.disabled
97
+ });
98
+ }
99
+ // Tints are string leaves, not a PaletteColor, so they pass through the
100
+ // same "copy what was set" path as `background`/`text` rather than
101
+ // `pickPaletteColor` — which requires a `main` a tint does not have
102
+ // (AGL-1244).
103
+ if (((_colors_tint = colors.tint) == null ? void 0 : _colors_tint.primary) || ((_colors_tint1 = colors.tint) == null ? void 0 : _colors_tint1.secondary) || ((_colors_tint2 = colors.tint) == null ? void 0 : _colors_tint2.tertiary)) {
104
+ palette.tint = _extends({}, colors.tint.primary && {
105
+ primary: colors.tint.primary
106
+ }, colors.tint.secondary && {
107
+ secondary: colors.tint.secondary
108
+ }, colors.tint.tertiary && {
109
+ tertiary: colors.tint.tertiary
110
+ });
111
+ }
112
+ if (colors.divider) palette.divider = colors.divider;
113
+ return palette;
114
+ }
115
+ function sanitizeComponents(components) {
116
+ if (!components) return undefined;
117
+ const sanitized = {};
118
+ for (const [key, override] of Object.entries(components)){
119
+ if (!componentWhitelist.has(key) || !override) continue;
120
+ const entry = {};
121
+ if (override.defaultProps) entry.defaultProps = override.defaultProps;
122
+ if (override.styleOverrides) entry.styleOverrides = override.styleOverrides;
123
+ if (Object.keys(entry).length) sanitized[key] = entry;
124
+ }
125
+ return Object.keys(sanitized).length ? sanitized : undefined;
126
+ }
127
+ /**
128
+ * Strips unknown component overrides and empty branches from a persisted
129
+ * host theme. Returns a new object; the input is never mutated.
130
+ */ export function sanitizeHostTheme(theme) {
131
+ var _theme_mixins;
132
+ if (!theme) return {};
133
+ const sanitized = _extends({}, theme);
134
+ const components = sanitizeComponents(theme.components);
135
+ if (components) sanitized.components = components;
136
+ else delete sanitized.components;
137
+ // `mixins.toolbar` must be a CSS object; a scalar would reach
138
+ // `createTheme` and throw while building the Toolbar variant.
139
+ if (isPlainObject((_theme_mixins = theme.mixins) == null ? void 0 : _theme_mixins.toolbar)) {
140
+ sanitized.mixins = {
141
+ toolbar: theme.mixins.toolbar
142
+ };
143
+ } else {
144
+ delete sanitized.mixins;
145
+ }
146
+ // Absent already means "follows the visitor", so only the opt-out is worth
147
+ // persisting; anything else (a stale `'auto'`, junk) is dropped.
148
+ if (theme.darkScheme !== 'off') delete sanitized.darkScheme;
149
+ return sanitized;
150
+ }
151
+ /** An `@media` key that names a `min-width`, and the width it names. */ const MIN_WIDTH_AT_RULE = /^@media\b[^{]*\bmin-width\s*:\s*(\d+(?:\.\d+)?)\s*px/;
152
+ /**
153
+ * Re-orders breakpoint at-rules ascending, so STORED key order cannot decide
154
+ * which rule wins (AGL-3146).
155
+ *
156
+ * Two `min-width` rules of equal specificity both match a wide window, so the
157
+ * later one wins — which makes key order a rendering decision. Firestore does
158
+ * not preserve it: one stored toolbar mixin came back sm, landscape, base to
159
+ * the server reader and landscape, base, sm to the browser, so aglyn.com's
160
+ * nav drew 48px live and 72px on the besigner canvas from a single saved
161
+ * document. The editor and the page disagreed about a value neither of them
162
+ * had changed.
163
+ *
164
+ * Ascending is the order MUI writes its own breakpoint styles in and the
165
+ * order the theme editor writes a toolbar mixin in: the wider query is the
166
+ * more specific answer, so it belongs last.
167
+ *
168
+ * Only two things move. Plain declarations are hoisted ahead of the blocks,
169
+ * keeping their order among themselves — which is where the style engine
170
+ * emits them anyway, since a nested block becomes a rule of its own after the
171
+ * base one, and where the shorthand/longhand hazard lives. Breakpoint rules
172
+ * are sorted into the slots the blocks already occupy, so a nested selector
173
+ * or a condition naming no width never changes position against one another.
174
+ *
175
+ * Returns its input by identity when no order changes, which is every theme
176
+ * with at most one breakpoint rule per object.
177
+ */ export function orderMediaWidths(value) {
178
+ if (Array.isArray(value)) {
179
+ let moved = false;
180
+ const next = value.map((entry)=>{
181
+ const ordered = orderMediaWidths(entry);
182
+ if (ordered !== entry) moved = true;
183
+ return ordered;
184
+ });
185
+ return moved ? next : value;
186
+ }
187
+ if (!isPlainObject(value)) return value;
188
+ const source = value;
189
+ const keys = Object.keys(source);
190
+ const declarations = keys.filter((key)=>!isPlainObject(source[key]));
191
+ const blocks = keys.filter((key)=>isPlainObject(source[key]));
192
+ const widthSlots = [];
193
+ const widths = [];
194
+ blocks.forEach((key, index)=>{
195
+ const match = MIN_WIDTH_AT_RULE.exec(key);
196
+ if (!match) return;
197
+ widthSlots.push(index);
198
+ widths.push({
199
+ key,
200
+ width: Number.parseFloat(match[1])
201
+ });
202
+ });
203
+ // A stable sort, so two rules at the same width keep the order they were
204
+ // stored in — there is nothing to prefer between them.
205
+ const sorted = [
206
+ ...widths
207
+ ].sort((a, b)=>a.width - b.width);
208
+ widthSlots.forEach((slot, position)=>{
209
+ blocks[slot] = sorted[position].key;
210
+ });
211
+ const order = [
212
+ ...declarations,
213
+ ...blocks
214
+ ];
215
+ let moved = order.some((key, index)=>key !== keys[index]);
216
+ const next = {};
217
+ for (const key of order){
218
+ const child = orderMediaWidths(source[key]);
219
+ if (child !== source[key]) moved = true;
220
+ next[key] = child;
221
+ }
222
+ return moved ? next : value;
223
+ }
224
+ /**
225
+ * Converts a persisted {@link HostTheme} document into MUI `ThemeOptions`
226
+ * for one color scheme. The result is meant to be passed through
227
+ * `createResponsiveTheme` (or `createTheme`) by the consumer; shade and
228
+ * contrast-text derivation for partial palettes is MUI's job, so only
229
+ * explicitly set values are forwarded.
230
+ */ export function hostThemeToThemeOptions(theme, scheme) {
231
+ var _sanitized_colorSchemes, _sanitized_shape, _sanitized_mixins;
232
+ const sanitized = sanitizeHostTheme(theme);
233
+ const options = {
234
+ palette: schemeColorsToPaletteOptions(scheme, (_sanitized_colorSchemes = sanitized.colorSchemes) == null ? void 0 : _sanitized_colorSchemes[scheme])
235
+ };
236
+ const { typography } = sanitized;
237
+ if ((typography == null ? void 0 : typography.fontFamily) || (typography == null ? void 0 : typography.variants)) {
238
+ // HostThemeTypographyVariant is a sanitized subset of MUI's
239
+ // TypographyStyleOptions; the missing index signature is by design.
240
+ options.typography = _extends({}, typography.fontFamily && {
241
+ fontFamily: typography.fontFamily
242
+ }, typography.variants);
243
+ }
244
+ if (typeof ((_sanitized_shape = sanitized.shape) == null ? void 0 : _sanitized_shape.borderRadius) === 'number') {
245
+ options.shape = {
246
+ borderRadius: sanitized.shape.borderRadius
247
+ };
248
+ }
249
+ if (typeof sanitized.spacing === 'number') {
250
+ options.spacing = sanitized.spacing;
251
+ }
252
+ if (sanitized.components) {
253
+ options.components = sanitized.components;
254
+ }
255
+ // Toolbar height is only reachable here (AGL-1242). MUI derives the
256
+ // Toolbar's `regular` variant style from `mixins.toolbar` and applies it
257
+ // AFTER `components.MuiToolbar.styleOverrides`, so the slot override loses
258
+ // every time — its nested media queries do not even emit.
259
+ if ((_sanitized_mixins = sanitized.mixins) == null ? void 0 : _sanitized_mixins.toolbar) {
260
+ options.mixins = {
261
+ toolbar: sanitized.mixins.toolbar
262
+ };
263
+ }
264
+ // Every surface that renders a site's theme arrives here — the tenant's
265
+ // provider, the besigner canvas, Preview, the theme editor — so this is
266
+ // where a stored document stops being able to resolve differently for
267
+ // different readers (AGL-3146).
268
+ return orderMediaWidths(options);
269
+ }
270
+ /**
271
+ * Layers a host's overrides ONTO a base set of theme options (AGL-1180).
272
+ *
273
+ * `hostThemeToThemeOptions` deliberately emits only what the host explicitly
274
+ * set, so building a theme from it alone leaves every other slot to MUI's
275
+ * stock palette. Consumers used to switch — console theme when the document
276
+ * was empty, host document when it was not — which meant setting a single
277
+ * value (the spec's own example is `{ spacing: 8 }`) silently repainted
278
+ * secondary, tertiary, surface, info, success, warning, error, background
279
+ * and paper in MUI blue/purple. Merging instead of switching keeps the brand
280
+ * as the floor no matter how much the host customizes.
281
+ *
282
+ * `palette` merges one level deep so overriding `primary` cannot drop
283
+ * `secondary`. Within a single colour the override replaces the whole record
284
+ * — MUI derives shades and contrast text from `main`, which is exactly the
285
+ * partial-palette behaviour the converter is written for.
286
+ */ export function mergeThemeOptions(base, overrides) {
287
+ var _base_components, _overrides_components;
288
+ const merged = _extends({}, base, overrides);
289
+ // Palette merges ONE level: overriding a colour replaces its whole record
290
+ // so MUI re-derives light/dark/contrastText from the new `main`, which is
291
+ // the partial-palette behaviour the converter is written for. Overriding
292
+ // `primary` still must not disturb `secondary`, hence the level.
293
+ merged.palette = _extends({}, base.palette, overrides.palette);
294
+ merged.shape = _extends({}, base.shape, overrides.shape);
295
+ // Same reasoning as `palette`: setting `toolbar` must not drop any other
296
+ // mixin the base defines.
297
+ merged.mixins = _extends({}, base.mixins, overrides.mixins);
298
+ // `typography` is an object in every base we ship, but MUI's type also
299
+ // allows a function of the palette — merging into that would silently drop
300
+ // the base, so prefer the override wholesale in that case.
301
+ if (isPlainObject(base.typography) && isPlainObject(overrides.typography)) {
302
+ merged.typography = objectDeepMergeReplaceArrays(base.typography, overrides.typography);
303
+ }
304
+ // Components merge DEEPLY. A host override names one component, and often
305
+ // one property inside it — `MuiButton.defaultProps.color`. A shallow merge
306
+ // would swap out the entire `MuiButton` entry and take the brand's
307
+ // `styleOverrides` with it, and those styles are frequently FUNCTIONS of
308
+ // the theme that JSON cannot express, so the editor could not put them
309
+ // back even in principle. Deep-merging means you override the leaf you
310
+ // named and inherit everything else, functions included.
311
+ merged.components = objectDeepMergeReplaceArrays((_base_components = base.components) != null ? _base_components : {}, (_overrides_components = overrides.components) != null ? _overrides_components : {});
312
+ return merged;
313
+ }
314
+ /** Plain data object — not an array, function, or class instance. */ function isPlainObject(value) {
315
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
316
+ }
317
+ /** True when the document customizes anything, i.e. consumers should build a theme from it rather than using their default. */ export function hasHostTheme(theme) {
318
+ return !!theme && Object.keys(theme).length > 0;
319
+ }
320
+ /**
321
+ * Builds a Google Fonts CSS2 stylesheet URL for the theme's loadable fonts.
322
+ * Returns undefined when nothing needs loading (system/absent fonts).
323
+ */ export function getGoogleFontsUrl(fonts) {
324
+ const families = (fonts != null ? fonts : []).filter((font)=>{
325
+ var _font_source;
326
+ return font.family && ((_font_source = font.source) != null ? _font_source : 'google') === 'google';
327
+ }).map((font)=>{
328
+ var _font_weights;
329
+ const family = font.family.trim().replace(/\s+/g, '+');
330
+ const weights = ((_font_weights = font.weights) == null ? void 0 : _font_weights.length) ? `:wght@${[
331
+ ...font.weights
332
+ ].sort((a, b)=>a - b).join(';')}` : '';
333
+ return `family=${family}${weights}`;
334
+ });
335
+ if (!families.length) return undefined;
336
+ return `https://fonts.googleapis.com/css2?${families.join('&')}&display=swap`;
337
+ }
338
+ export default hostThemeToThemeOptions;
339
+
340
+ //# sourceMappingURL=host-theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/host-theme.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n HostTheme,\n HostThemeComponentOverride,\n HostThemeFont,\n HostThemePaletteColor,\n HostThemeScheme,\n HostThemeSchemeColors,\n} from '@aglyn/shared-data-types'\nimport { objectDeepMergeReplaceArrays } from '@aglyn/shared-util-vendor'\nimport type { PaletteOptions, ThemeOptions } from '../../vendor/mui'\n\n/**\n * Components a host theme may override. Persisted overrides are plain JSON;\n * anything outside this list is dropped by {@link sanitizeHostTheme} so a\n * tampered document can't restyle console-internal or portal-critical\n * components.\n */\nexport const HOST_THEME_COMPONENT_WHITELIST = [\n 'MuiAppBar',\n 'MuiAvatar',\n 'MuiBadge',\n 'MuiButton',\n 'MuiButtonBase',\n 'MuiCard',\n 'MuiCardContent',\n 'MuiCheckbox',\n 'MuiChip',\n 'MuiCircularProgress',\n 'MuiDivider',\n 'MuiIconButton',\n 'MuiLinearProgress',\n 'MuiLink',\n 'MuiList',\n 'MuiListItem',\n 'MuiMenu',\n 'MuiPaper',\n 'MuiRadio',\n 'MuiSlider',\n 'MuiSwitch',\n 'MuiTab',\n 'MuiTabs',\n 'MuiTextField',\n 'MuiToolbar',\n 'MuiTooltip',\n 'MuiTypography',\n] as const\n\nexport type HostThemeComponentKey =\n (typeof HOST_THEME_COMPONENT_WHITELIST)[number]\n\nconst componentWhitelist: ReadonlySet<string> = new Set(\n HOST_THEME_COMPONENT_WHITELIST,\n)\n\nfunction pickPaletteColor(color: HostThemePaletteColor | undefined) {\n if (!color?.main) return undefined\n const picked: HostThemePaletteColor = { main: color.main }\n if (color.light) picked.light = color.light\n if (color.dark) picked.dark = color.dark\n if (color.contrastText) picked.contrastText = color.contrastText\n return picked\n}\n\nfunction schemeColorsToPaletteOptions(\n scheme: HostThemeScheme,\n colors: HostThemeSchemeColors | undefined,\n): PaletteOptions {\n const palette: PaletteOptions = { mode: scheme }\n if (!colors) return palette\n\n const colorKeys = [\n 'primary',\n 'secondary',\n 'tertiary',\n 'surface',\n 'error',\n 'warning',\n 'info',\n 'success',\n ] as const\n for (const key of colorKeys) {\n const color = pickPaletteColor(colors[key])\n if (color) (palette as Record<string, unknown>)[key] = color\n }\n\n if (colors.background?.default || colors.background?.paper) {\n palette.background = {\n ...(colors.background.default && { default: colors.background.default }),\n ...(colors.background.paper && { paper: colors.background.paper }),\n }\n }\n if (\n colors.text?.primary ||\n colors.text?.secondary ||\n colors.text?.disabled\n ) {\n palette.text = {\n ...(colors.text.primary && { primary: colors.text.primary }),\n ...(colors.text.secondary && { secondary: colors.text.secondary }),\n ...(colors.text.disabled && { disabled: colors.text.disabled }),\n }\n }\n // Tints are string leaves, not a PaletteColor, so they pass through the\n // same \"copy what was set\" path as `background`/`text` rather than\n // `pickPaletteColor` — which requires a `main` a tint does not have\n // (AGL-1244).\n if (colors.tint?.primary || colors.tint?.secondary || colors.tint?.tertiary) {\n palette.tint = {\n ...(colors.tint.primary && { primary: colors.tint.primary }),\n ...(colors.tint.secondary && { secondary: colors.tint.secondary }),\n ...(colors.tint.tertiary && { tertiary: colors.tint.tertiary }),\n }\n }\n if (colors.divider) palette.divider = colors.divider\n\n return palette\n}\n\nfunction sanitizeComponents(\n components: Record<string, HostThemeComponentOverride> | undefined,\n) {\n if (!components) return undefined\n const sanitized: Record<string, HostThemeComponentOverride> = {}\n for (const [key, override] of Object.entries(components)) {\n if (!componentWhitelist.has(key) || !override) continue\n const entry: HostThemeComponentOverride = {}\n if (override.defaultProps) entry.defaultProps = override.defaultProps\n if (override.styleOverrides) entry.styleOverrides = override.styleOverrides\n if (Object.keys(entry).length) sanitized[key] = entry\n }\n return Object.keys(sanitized).length ? sanitized : undefined\n}\n\n/**\n * Strips unknown component overrides and empty branches from a persisted\n * host theme. Returns a new object; the input is never mutated.\n */\nexport function sanitizeHostTheme(theme: HostTheme | undefined): HostTheme {\n if (!theme) return {}\n const sanitized: HostTheme = { ...theme }\n const components = sanitizeComponents(theme.components)\n if (components) sanitized.components = components\n else delete sanitized.components\n // `mixins.toolbar` must be a CSS object; a scalar would reach\n // `createTheme` and throw while building the Toolbar variant.\n if (isPlainObject(theme.mixins?.toolbar)) {\n sanitized.mixins = { toolbar: theme.mixins.toolbar }\n } else {\n delete sanitized.mixins\n }\n // Absent already means \"follows the visitor\", so only the opt-out is worth\n // persisting; anything else (a stale `'auto'`, junk) is dropped.\n if (theme.darkScheme !== 'off') delete sanitized.darkScheme\n return sanitized\n}\n\n/** An `@media` key that names a `min-width`, and the width it names. */\nconst MIN_WIDTH_AT_RULE = /^@media\\b[^{]*\\bmin-width\\s*:\\s*(\\d+(?:\\.\\d+)?)\\s*px/\n\n/**\n * Re-orders breakpoint at-rules ascending, so STORED key order cannot decide\n * which rule wins (AGL-3146).\n *\n * Two `min-width` rules of equal specificity both match a wide window, so the\n * later one wins — which makes key order a rendering decision. Firestore does\n * not preserve it: one stored toolbar mixin came back sm, landscape, base to\n * the server reader and landscape, base, sm to the browser, so aglyn.com's\n * nav drew 48px live and 72px on the besigner canvas from a single saved\n * document. The editor and the page disagreed about a value neither of them\n * had changed.\n *\n * Ascending is the order MUI writes its own breakpoint styles in and the\n * order the theme editor writes a toolbar mixin in: the wider query is the\n * more specific answer, so it belongs last.\n *\n * Only two things move. Plain declarations are hoisted ahead of the blocks,\n * keeping their order among themselves — which is where the style engine\n * emits them anyway, since a nested block becomes a rule of its own after the\n * base one, and where the shorthand/longhand hazard lives. Breakpoint rules\n * are sorted into the slots the blocks already occupy, so a nested selector\n * or a condition naming no width never changes position against one another.\n *\n * Returns its input by identity when no order changes, which is every theme\n * with at most one breakpoint rule per object.\n */\nexport function orderMediaWidths<T>(value: T): T {\n if (Array.isArray(value)) {\n let moved = false\n const next = value.map((entry) => {\n const ordered = orderMediaWidths(entry)\n if (ordered !== entry) moved = true\n return ordered\n })\n return (moved ? next : value) as T\n }\n if (!isPlainObject(value)) return value\n\n const source = value as Record<string, unknown>\n const keys = Object.keys(source)\n const declarations = keys.filter((key) => !isPlainObject(source[key]))\n const blocks = keys.filter((key) => isPlainObject(source[key]))\n const widthSlots: number[] = []\n const widths: Array<{ key: string; width: number }> = []\n blocks.forEach((key, index) => {\n const match = MIN_WIDTH_AT_RULE.exec(key)\n if (!match) return\n widthSlots.push(index)\n widths.push({ key, width: Number.parseFloat(match[1]) })\n })\n // A stable sort, so two rules at the same width keep the order they were\n // stored in — there is nothing to prefer between them.\n const sorted = [...widths].sort((a, b) => a.width - b.width)\n widthSlots.forEach((slot, position) => {\n blocks[slot] = sorted[position].key\n })\n\n const order = [...declarations, ...blocks]\n let moved = order.some((key, index) => key !== keys[index])\n const next: Record<string, unknown> = {}\n for (const key of order) {\n const child = orderMediaWidths(source[key])\n if (child !== source[key]) moved = true\n next[key] = child\n }\n return (moved ? next : value) as T\n}\n\n/**\n * Converts a persisted {@link HostTheme} document into MUI `ThemeOptions`\n * for one color scheme. The result is meant to be passed through\n * `createResponsiveTheme` (or `createTheme`) by the consumer; shade and\n * contrast-text derivation for partial palettes is MUI's job, so only\n * explicitly set values are forwarded.\n */\nexport function hostThemeToThemeOptions(\n theme: HostTheme | undefined,\n scheme: HostThemeScheme,\n): ThemeOptions {\n const sanitized = sanitizeHostTheme(theme)\n const options: ThemeOptions = {\n palette: schemeColorsToPaletteOptions(\n scheme,\n sanitized.colorSchemes?.[scheme],\n ),\n }\n\n const { typography } = sanitized\n if (typography?.fontFamily || typography?.variants) {\n // HostThemeTypographyVariant is a sanitized subset of MUI's\n // TypographyStyleOptions; the missing index signature is by design.\n options.typography = {\n ...(typography.fontFamily && { fontFamily: typography.fontFamily }),\n ...typography.variants,\n } as ThemeOptions['typography']\n }\n\n if (typeof sanitized.shape?.borderRadius === 'number') {\n options.shape = { borderRadius: sanitized.shape.borderRadius }\n }\n if (typeof sanitized.spacing === 'number') {\n options.spacing = sanitized.spacing\n }\n if (sanitized.components) {\n options.components = sanitized.components as ThemeOptions['components']\n }\n // Toolbar height is only reachable here (AGL-1242). MUI derives the\n // Toolbar's `regular` variant style from `mixins.toolbar` and applies it\n // AFTER `components.MuiToolbar.styleOverrides`, so the slot override loses\n // every time — its nested media queries do not even emit.\n if (sanitized.mixins?.toolbar) {\n options.mixins = { toolbar: sanitized.mixins.toolbar }\n }\n\n // Every surface that renders a site's theme arrives here — the tenant's\n // provider, the besigner canvas, Preview, the theme editor — so this is\n // where a stored document stops being able to resolve differently for\n // different readers (AGL-3146).\n return orderMediaWidths(options)\n}\n\n/**\n * Layers a host's overrides ONTO a base set of theme options (AGL-1180).\n *\n * `hostThemeToThemeOptions` deliberately emits only what the host explicitly\n * set, so building a theme from it alone leaves every other slot to MUI's\n * stock palette. Consumers used to switch — console theme when the document\n * was empty, host document when it was not — which meant setting a single\n * value (the spec's own example is `{ spacing: 8 }`) silently repainted\n * secondary, tertiary, surface, info, success, warning, error, background\n * and paper in MUI blue/purple. Merging instead of switching keeps the brand\n * as the floor no matter how much the host customizes.\n *\n * `palette` merges one level deep so overriding `primary` cannot drop\n * `secondary`. Within a single colour the override replaces the whole record\n * — MUI derives shades and contrast text from `main`, which is exactly the\n * partial-palette behaviour the converter is written for.\n */\nexport function mergeThemeOptions(\n base: ThemeOptions,\n overrides: ThemeOptions,\n): ThemeOptions {\n const merged: ThemeOptions = { ...base, ...overrides }\n\n // Palette merges ONE level: overriding a colour replaces its whole record\n // so MUI re-derives light/dark/contrastText from the new `main`, which is\n // the partial-palette behaviour the converter is written for. Overriding\n // `primary` still must not disturb `secondary`, hence the level.\n merged.palette = { ...base.palette, ...overrides.palette }\n merged.shape = { ...base.shape, ...overrides.shape }\n // Same reasoning as `palette`: setting `toolbar` must not drop any other\n // mixin the base defines.\n merged.mixins = { ...base.mixins, ...overrides.mixins }\n\n // `typography` is an object in every base we ship, but MUI's type also\n // allows a function of the palette — merging into that would silently drop\n // the base, so prefer the override wholesale in that case.\n if (\n isPlainObject(base.typography) &&\n isPlainObject(overrides.typography)\n ) {\n merged.typography = objectDeepMergeReplaceArrays(\n base.typography,\n overrides.typography,\n ) as ThemeOptions['typography']\n }\n\n // Components merge DEEPLY. A host override names one component, and often\n // one property inside it — `MuiButton.defaultProps.color`. A shallow merge\n // would swap out the entire `MuiButton` entry and take the brand's\n // `styleOverrides` with it, and those styles are frequently FUNCTIONS of\n // the theme that JSON cannot express, so the editor could not put them\n // back even in principle. Deep-merging means you override the leaf you\n // named and inherit everything else, functions included.\n merged.components = objectDeepMergeReplaceArrays(\n base.components ?? {},\n overrides.components ?? {},\n ) as ThemeOptions['components']\n\n return merged\n}\n\n/** Plain data object — not an array, function, or class instance. */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === 'object' && value !== null && !Array.isArray(value)\n )\n}\n\n/** True when the document customizes anything, i.e. consumers should build a theme from it rather than using their default. */\nexport function hasHostTheme(theme: HostTheme | undefined): theme is HostTheme {\n return !!theme && Object.keys(theme).length > 0\n}\n\n/**\n * Builds a Google Fonts CSS2 stylesheet URL for the theme's loadable fonts.\n * Returns undefined when nothing needs loading (system/absent fonts).\n */\nexport function getGoogleFontsUrl(fonts: Array<HostThemeFont> | undefined) {\n const families = (fonts ?? [])\n .filter((font) => font.family && (font.source ?? 'google') === 'google')\n .map((font) => {\n const family = font.family.trim().replace(/\\s+/g, '+')\n const weights = font.weights?.length\n ? `:wght@${[...font.weights].sort((a, b) => a - b).join(';')}`\n : ''\n return `family=${family}${weights}`\n })\n if (!families.length) return undefined\n return `https://fonts.googleapis.com/css2?${families.join('&')}&display=swap`\n}\n\nexport default hostThemeToThemeOptions\n"],"names":["objectDeepMergeReplaceArrays","HOST_THEME_COMPONENT_WHITELIST","componentWhitelist","Set","pickPaletteColor","color","main","undefined","picked","light","dark","contrastText","schemeColorsToPaletteOptions","scheme","colors","palette","mode","colorKeys","key","background","default","paper","text","primary","secondary","disabled","tint","tertiary","divider","sanitizeComponents","components","sanitized","override","Object","entries","has","entry","defaultProps","styleOverrides","keys","length","sanitizeHostTheme","theme","isPlainObject","mixins","toolbar","darkScheme","MIN_WIDTH_AT_RULE","orderMediaWidths","value","Array","isArray","moved","next","map","ordered","source","declarations","filter","blocks","widthSlots","widths","forEach","index","match","exec","push","width","Number","parseFloat","sorted","sort","a","b","slot","position","order","some","child","hostThemeToThemeOptions","options","colorSchemes","typography","fontFamily","variants","shape","borderRadius","spacing","mergeThemeOptions","base","overrides","merged","hasHostTheme","getGoogleFontsUrl","fonts","families","font","family","trim","replace","weights","join"],"mappings":"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"}
@@ -0,0 +1,78 @@
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
+ */
17
+ import { type CreateEmotionCacheOptions, type EmotionCache } from '../../vendor/emotion';
18
+ /**
19
+ * An emotion cache whose output is wrapped in `@layer mui`, for surfaces that
20
+ * cannot use `AppRouterCacheProvider` (AGL-2486).
21
+ *
22
+ * ## Why this exists: "what you see is not what you publish"
23
+ *
24
+ * `enableCssLayer` is NOT an emotion option. It is implemented by
25
+ * `AppRouterCacheProvider` monkey-patching `cache.insert` to wrap the
26
+ * serialized styles string (`appRouterV13.mjs`), and that patch is the only
27
+ * code in the dependency tree that emits `@layer mui`. So every surface that
28
+ * builds its own cache with plain `createEmotionCache` is UNLAYERED, however
29
+ * carefully its options were copied.
30
+ *
31
+ * The besigner canvas was exactly that surface. Measured 2026-08-23 against
32
+ * rendered CSS on both halves:
33
+ *
34
+ * - published tenant (`northwind-coffee.aglyn.app`): 72 `@layer mui` blocks,
35
+ * ZERO unlayered `.mui-*` rules;
36
+ * - besigner canvas shadow root: ZERO layer blocks, 183 unlayered `.msd-*`
37
+ * rules.
38
+ *
39
+ * Component defaults and author `sx` share one cache, so they enter or skip
40
+ * the layer TOGETHER and their relative order survives either way — that part
41
+ * was never broken. What diverged is CSS that never passes through the
42
+ * emotion cache at all, principally a Custom HTML component's `css` attribute
43
+ * (`custom-html.tsx` renders it as a raw `<style>`). Against a fully layered
44
+ * document that CSS wins UNCONDITIONALLY, regardless of specificity, because
45
+ * an unlayered normal declaration beats every layered one. Against the
46
+ * unlayered canvas it merely competes on specificity. Measured on the same
47
+ * two surfaces with a rule of specificity 0-0-1 pitched against an emotion
48
+ * rule of 0-1-0: it won on the published page and lost on the canvas.
49
+ *
50
+ * That is a divergence in the product's central claim — "publish exactly what
51
+ * you designed" — so the canvas is layered to match the published document
52
+ * rather than the published document unlayered to match the canvas. Layering
53
+ * the tenant is what lets site and plugin CSS override MUI without a
54
+ * specificity war (see `emotion-cache.ts`); that behaviour is the intended
55
+ * one and it is the editor that has to agree with it.
56
+ *
57
+ * ## Notes for whoever touches this next
58
+ *
59
+ * - Cascade layers are scoped to a TREE CONTEXT. A `@layer mui` inside a
60
+ * shadow root is a different layer from the document's, with its own
61
+ * ordering, so reusing the name across the boundary is safe — and it has to
62
+ * be the same name anyway, since the point is to reproduce the published
63
+ * cascade exactly.
64
+ * - The `^@layer\s+[^{]*$` guard is MUI's, kept verbatim: a bare `@layer a, b;`
65
+ * ORDERING statement must not be wrapped in a layer block, or it stops
66
+ * declaring an order and starts declaring an empty nested layer.
67
+ * - `!important` inverts layer precedence (a layered important declaration
68
+ * beats an unlayered one). The canvas's `.aglyn-hidden` override in
69
+ * `viewport-frame.component.tsx` is an important declaration that goes
70
+ * through this cache, whereas the tenant ships its `.aglyn-hidden` rule from
71
+ * a non-emotion `<style>`. Those two were already deliberately different
72
+ * rules (AGL-592, the canvas reveals hidden panels while selected), so this
73
+ * does not make an agreeing pair disagree.
74
+ * - `cache.compat` is deliberately NOT set here. `AppRouterCacheProvider` sets
75
+ * it for its streaming-SSR `flush()` registry, which this client-only
76
+ * shadow-root cache has no equivalent of.
77
+ */
78
+ export declare function createLayeredEmotionCache(options: CreateEmotionCacheOptions): EmotionCache;
@@ -0,0 +1,90 @@
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 { createEmotionCache } from "../../vendor/emotion.js";
17
+ import { MUI_CSS_LAYER_NAME } from "./emotion-cache.js";
18
+ /**
19
+ * An emotion cache whose output is wrapped in `@layer mui`, for surfaces that
20
+ * cannot use `AppRouterCacheProvider` (AGL-2486).
21
+ *
22
+ * ## Why this exists: "what you see is not what you publish"
23
+ *
24
+ * `enableCssLayer` is NOT an emotion option. It is implemented by
25
+ * `AppRouterCacheProvider` monkey-patching `cache.insert` to wrap the
26
+ * serialized styles string (`appRouterV13.mjs`), and that patch is the only
27
+ * code in the dependency tree that emits `@layer mui`. So every surface that
28
+ * builds its own cache with plain `createEmotionCache` is UNLAYERED, however
29
+ * carefully its options were copied.
30
+ *
31
+ * The besigner canvas was exactly that surface. Measured 2026-08-23 against
32
+ * rendered CSS on both halves:
33
+ *
34
+ * - published tenant (`northwind-coffee.aglyn.app`): 72 `@layer mui` blocks,
35
+ * ZERO unlayered `.mui-*` rules;
36
+ * - besigner canvas shadow root: ZERO layer blocks, 183 unlayered `.msd-*`
37
+ * rules.
38
+ *
39
+ * Component defaults and author `sx` share one cache, so they enter or skip
40
+ * the layer TOGETHER and their relative order survives either way — that part
41
+ * was never broken. What diverged is CSS that never passes through the
42
+ * emotion cache at all, principally a Custom HTML component's `css` attribute
43
+ * (`custom-html.tsx` renders it as a raw `<style>`). Against a fully layered
44
+ * document that CSS wins UNCONDITIONALLY, regardless of specificity, because
45
+ * an unlayered normal declaration beats every layered one. Against the
46
+ * unlayered canvas it merely competes on specificity. Measured on the same
47
+ * two surfaces with a rule of specificity 0-0-1 pitched against an emotion
48
+ * rule of 0-1-0: it won on the published page and lost on the canvas.
49
+ *
50
+ * That is a divergence in the product's central claim — "publish exactly what
51
+ * you designed" — so the canvas is layered to match the published document
52
+ * rather than the published document unlayered to match the canvas. Layering
53
+ * the tenant is what lets site and plugin CSS override MUI without a
54
+ * specificity war (see `emotion-cache.ts`); that behaviour is the intended
55
+ * one and it is the editor that has to agree with it.
56
+ *
57
+ * ## Notes for whoever touches this next
58
+ *
59
+ * - Cascade layers are scoped to a TREE CONTEXT. A `@layer mui` inside a
60
+ * shadow root is a different layer from the document's, with its own
61
+ * ordering, so reusing the name across the boundary is safe — and it has to
62
+ * be the same name anyway, since the point is to reproduce the published
63
+ * cascade exactly.
64
+ * - The `^@layer\s+[^{]*$` guard is MUI's, kept verbatim: a bare `@layer a, b;`
65
+ * ORDERING statement must not be wrapped in a layer block, or it stops
66
+ * declaring an order and starts declaring an empty nested layer.
67
+ * - `!important` inverts layer precedence (a layered important declaration
68
+ * beats an unlayered one). The canvas's `.aglyn-hidden` override in
69
+ * `viewport-frame.component.tsx` is an important declaration that goes
70
+ * through this cache, whereas the tenant ships its `.aglyn-hidden` rule from
71
+ * a non-emotion `<style>`. Those two were already deliberately different
72
+ * rules (AGL-592, the canvas reveals hidden panels while selected), so this
73
+ * does not make an agreeing pair disagree.
74
+ * - `cache.compat` is deliberately NOT set here. `AppRouterCacheProvider` sets
75
+ * it for its streaming-SSR `flush()` registry, which this client-only
76
+ * shadow-root cache has no equivalent of.
77
+ */ export function createLayeredEmotionCache(options) {
78
+ const cache = createEmotionCache(options);
79
+ const prevInsert = cache.insert;
80
+ cache.insert = (...args)=>{
81
+ const serialized = args[1];
82
+ if (!serialized.styles.match(/^@layer\s+[^{]*$/)) {
83
+ serialized.styles = `@layer ${MUI_CSS_LAYER_NAME} {${serialized.styles}}`;
84
+ }
85
+ return prevInsert(...args);
86
+ };
87
+ return cache;
88
+ }
89
+
90
+ //# sourceMappingURL=layered-emotion-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/layered-emotion-cache.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n createEmotionCache,\n type CreateEmotionCacheOptions,\n type EmotionCache,\n} from '../../vendor/emotion'\nimport { MUI_CSS_LAYER_NAME } from './emotion-cache'\n\n/**\n * An emotion cache whose output is wrapped in `@layer mui`, for surfaces that\n * cannot use `AppRouterCacheProvider` (AGL-2486).\n *\n * ## Why this exists: \"what you see is not what you publish\"\n *\n * `enableCssLayer` is NOT an emotion option. It is implemented by\n * `AppRouterCacheProvider` monkey-patching `cache.insert` to wrap the\n * serialized styles string (`appRouterV13.mjs`), and that patch is the only\n * code in the dependency tree that emits `@layer mui`. So every surface that\n * builds its own cache with plain `createEmotionCache` is UNLAYERED, however\n * carefully its options were copied.\n *\n * The besigner canvas was exactly that surface. Measured 2026-08-23 against\n * rendered CSS on both halves:\n *\n * - published tenant (`northwind-coffee.aglyn.app`): 72 `@layer mui` blocks,\n * ZERO unlayered `.mui-*` rules;\n * - besigner canvas shadow root: ZERO layer blocks, 183 unlayered `.msd-*`\n * rules.\n *\n * Component defaults and author `sx` share one cache, so they enter or skip\n * the layer TOGETHER and their relative order survives either way — that part\n * was never broken. What diverged is CSS that never passes through the\n * emotion cache at all, principally a Custom HTML component's `css` attribute\n * (`custom-html.tsx` renders it as a raw `<style>`). Against a fully layered\n * document that CSS wins UNCONDITIONALLY, regardless of specificity, because\n * an unlayered normal declaration beats every layered one. Against the\n * unlayered canvas it merely competes on specificity. Measured on the same\n * two surfaces with a rule of specificity 0-0-1 pitched against an emotion\n * rule of 0-1-0: it won on the published page and lost on the canvas.\n *\n * That is a divergence in the product's central claim — \"publish exactly what\n * you designed\" — so the canvas is layered to match the published document\n * rather than the published document unlayered to match the canvas. Layering\n * the tenant is what lets site and plugin CSS override MUI without a\n * specificity war (see `emotion-cache.ts`); that behaviour is the intended\n * one and it is the editor that has to agree with it.\n *\n * ## Notes for whoever touches this next\n *\n * - Cascade layers are scoped to a TREE CONTEXT. A `@layer mui` inside a\n * shadow root is a different layer from the document's, with its own\n * ordering, so reusing the name across the boundary is safe — and it has to\n * be the same name anyway, since the point is to reproduce the published\n * cascade exactly.\n * - The `^@layer\\s+[^{]*$` guard is MUI's, kept verbatim: a bare `@layer a, b;`\n * ORDERING statement must not be wrapped in a layer block, or it stops\n * declaring an order and starts declaring an empty nested layer.\n * - `!important` inverts layer precedence (a layered important declaration\n * beats an unlayered one). The canvas's `.aglyn-hidden` override in\n * `viewport-frame.component.tsx` is an important declaration that goes\n * through this cache, whereas the tenant ships its `.aglyn-hidden` rule from\n * a non-emotion `<style>`. Those two were already deliberately different\n * rules (AGL-592, the canvas reveals hidden panels while selected), so this\n * does not make an agreeing pair disagree.\n * - `cache.compat` is deliberately NOT set here. `AppRouterCacheProvider` sets\n * it for its streaming-SSR `flush()` registry, which this client-only\n * shadow-root cache has no equivalent of.\n */\nexport function createLayeredEmotionCache(\n options: CreateEmotionCacheOptions,\n): EmotionCache {\n const cache = createEmotionCache(options)\n const prevInsert = cache.insert\n cache.insert = (...args: Parameters<EmotionCache['insert']>) => {\n const serialized = args[1]\n if (!serialized.styles.match(/^@layer\\s+[^{]*$/)) {\n serialized.styles = `@layer ${MUI_CSS_LAYER_NAME} {${serialized.styles}}`\n }\n return prevInsert(...args)\n }\n return cache\n}\n"],"names":["createEmotionCache","MUI_CSS_LAYER_NAME","createLayeredEmotionCache","options","cache","prevInsert","insert","args","serialized","styles","match"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,kBAAkB,QAGb,0BAAsB;AAC7B,SAASC,kBAAkB,QAAQ,qBAAiB;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2DC,GACD,OAAO,SAASC,0BACdC,OAAkC;IAElC,MAAMC,QAAQJ,mBAAmBG;IACjC,MAAME,aAAaD,MAAME,MAAM;IAC/BF,MAAME,MAAM,GAAG,CAAC,GAAGC;QACjB,MAAMC,aAAaD,IAAI,CAAC,EAAE;QAC1B,IAAI,CAACC,WAAWC,MAAM,CAACC,KAAK,CAAC,qBAAqB;YAChDF,WAAWC,MAAM,GAAG,CAAC,OAAO,EAAER,mBAAmB,EAAE,EAAEO,WAAWC,MAAM,CAAC,CAAC,CAAC;QAC3E;QACA,OAAOJ,cAAcE;IACvB;IACA,OAAOH;AACT"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 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
+ */
17
+ import type { SxProps } from '@mui/system';
18
+ import type { Theme as DefaultTheme } from '../../vendor/mui';
19
+ type MaybeSxProps<Theme extends object> = SxProps<Theme> | boolean | null | undefined;
20
+ export declare function useMergeSxProps<Theme extends DefaultTheme>(...sxProps: MaybeSxProps<Theme>[]): SxProps<Theme>;
21
+ export declare function mergeSxProps<Theme extends DefaultTheme>(...sxProps: MaybeSxProps<Theme>[]): SxProps<Theme>;
22
+ export default mergeSxProps;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 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 { useMemo } from "react";
17
+ export function useMergeSxProps(...sxProps) {
18
+ return useMemo(()=>mergeSxProps(...sxProps), [
19
+ sxProps
20
+ ]);
21
+ }
22
+ export function mergeSxProps(...sxProps) {
23
+ return sxProps.flat(2);
24
+ }
25
+ export default mergeSxProps;
26
+
27
+ //# sourceMappingURL=merge-sx-props.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/merge-sx-props.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2023 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SxProps } from '@mui/system'\nimport { useMemo } from 'react'\nimport type { Theme as DefaultTheme } from '../../vendor/mui'\n\ntype MaybeSxProps<Theme extends object> = SxProps<Theme> | boolean | null | undefined\n\nexport function useMergeSxProps<Theme extends DefaultTheme>(\n ...sxProps: MaybeSxProps<Theme>[]\n): SxProps<Theme> {\n return useMemo(() => mergeSxProps(...sxProps), [sxProps])\n}\n\nexport function mergeSxProps<Theme extends DefaultTheme>(\n ...sxProps: MaybeSxProps<Theme>[]\n): SxProps<Theme> {\n return sxProps.flat(2) as SxProps<Theme>\n}\n\nexport default mergeSxProps\n"],"names":["useMemo","useMergeSxProps","sxProps","mergeSxProps","flat"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAGD,SAASA,OAAO,QAAQ,QAAO;AAK/B,OAAO,SAASC,gBACd,GAAGC,OAA8B;IAEjC,OAAOF,QAAQ,IAAMG,gBAAgBD,UAAU;QAACA;KAAQ;AAC1D;AAEA,OAAO,SAASC,aACd,GAAGD,OAA8B;IAEjC,OAAOA,QAAQE,IAAI,CAAC;AACtB;AAEA,eAAeD,aAAY"}