@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 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/create-responsive-theme.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2024 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 CssVarsThemeOptions,\n extendTheme as muiExtendTheme,\n} from '@mui/material/styles'\nimport {\n createTheme,\n darken,\n getContrastRatio,\n lighten,\n type PaletteColor,\n type PaletteOptions,\n responsiveFontSizes,\n type Theme,\n type ThemeOptions,\n} from '../../vendor/mui'\nimport {\n accessibleShade,\n contrastRatio,\n meetsContrast,\n type ShadeDirection,\n} from './accessible-shade'\n\nenum ContrastText {\n LIGHT = 'rgba(0, 0, 0, 0.87)',\n DARK = '#FFFFFF',\n}\n\ntype TonalOffset = number | { light?: number; dark?: number }\n\nfunction resolveTonalOffsets(tonalOffset: TonalOffset | undefined) {\n const offsetObj = typeof tonalOffset === 'number' ? undefined : tonalOffset\n const offsetNum = typeof tonalOffset === 'number' ? tonalOffset : undefined\n return {\n light: offsetObj?.light ?? offsetNum ?? 0.2,\n dark: offsetObj?.dark ?? (offsetNum ?? 0.2) * 1.5,\n }\n}\n\nfunction getContrastTextColor(background: string, contrastThreshold: number) {\n return getContrastRatio(background, ContrastText.DARK) >= (contrastThreshold ?? 3)\n ? ContrastText.DARK\n : ContrastText.LIGHT\n}\nfunction addShade(paletteColor: PaletteColor, shade: string, variant: string | undefined, tonalOffset: TonalOffset) {\n // Custom palette colors (tertiary, surface) are optional in host themes.\n if (!paletteColor?.main) return\n const { light: tonalOffsetLight, dark: tonalOffsetDark } =\n resolveTonalOffsets(tonalOffset)\n const indexed = paletteColor as unknown as Record<string, string>\n\n if (!indexed[shade]) {\n // eslint-disable-next-line no-prototype-builtins\n if (paletteColor.hasOwnProperty(variant)) {\n indexed[shade] = indexed[variant]\n } else if (shade === 'light') {\n paletteColor.light = lighten(paletteColor.main, tonalOffsetLight)\n } else if (shade === 'dark') {\n paletteColor.dark = darken(paletteColor.main, tonalOffsetDark)\n } else if (shade === 'contrastText') {\n paletteColor.contrastText = getContrastTextColor(\n paletteColor.main,\n tonalOffsetDark,\n )\n }\n }\n}\nfunction addShadeVariants(paletteColor: PaletteColor, tonalOffset?: TonalOffset) {\n addShade(paletteColor, 'dark', undefined, tonalOffset)\n addShade(paletteColor, 'light', undefined, tonalOffset)\n addShade(paletteColor, 'contrastText', undefined, tonalOffset)\n}\n\n/**\n * Colour families whose shades act as FOREGROUNDS — the `dark` slot carries\n * \"accessible accent text\" (AGL-1293 put the marketing brand blue there), so\n * its derivation must clear AA against the scheme's real backgrounds.\n *\n * `surface` is deliberately absent: its `light`/`dark` are surface STEPS\n * (panel fills, borders — see the designer's box styler), and walking them to\n * text contrast would repaint layout chrome, not fix any text.\n */\nconst FOREGROUND_COLOR_KEYS = [\n 'primary',\n 'secondary',\n 'tertiary',\n 'error',\n 'warning',\n 'info',\n 'success',\n] as const\n\n/** `contrastText` IS a text pairing wherever it lives, so `surface` joins here. */\nconst CONTRAST_TEXT_COLOR_KEYS = [...FOREGROUND_COLOR_KEYS, 'surface'] as const\n\n/**\n * Post-`createTheme` pass making DERIVED shades scheme- and AA-aware\n * (AGL-1297). Fixed tonal offsets derive `dark = darken(main, 0.3)` no\n * matter the scheme, which (a) misses 4.5:1 on real off-white surfaces and\n * (b) points the wrong way entirely in dark mode, where the accessible\n * direction for a foreground shade is LIGHTER.\n *\n * Invariants:\n * - Only slots ABSENT from the caller's `palette` input are ever touched;\n * an explicitly authored shade passes through byte-identical (the\n * marketing host's hand-set `primary.dark` values depend on this).\n * - A derived value that already clears 4.5:1 against both\n * `background.default` and `background.paper` is kept byte-identical, so\n * themes that were fine yesterday do not shift.\n * - A failing derived `dark` is re-seeded at the tonal offset from `main`\n * in the scheme's foreground direction (darken in light, lighten in\n * dark), then walked in HSL lightness until it clears the bar.\n * - A light-scheme `light` is a background TINT — its ramp direction points\n * away from the text bar by design — so it keeps the tonal derivation.\n * In dark schemes `light` is foreground-capable and gets the same walk.\n * - Derived `contrastText` keeps the threshold choice unless that pairing\n * is below 4.5:1 against `main`; then it walks toward the pole with more\n * contrast headroom.\n */\nfunction ensureAccessibleShades(\n theme: Theme,\n inputPalette: PaletteOptions | undefined,\n) {\n const { palette } = theme\n const backgrounds = [\n palette.background?.default,\n palette.background?.paper,\n ].filter((background): background is string => typeof background === 'string')\n if (!backgrounds.length) return\n const mode: 'light' | 'dark' = palette.mode === 'dark' ? 'dark' : 'light'\n const foregroundDirection: ShadeDirection =\n mode === 'dark' ? 'lighten' : 'darken'\n const tonalOffsetDark = resolveTonalOffsets(palette.tonalOffset).dark\n const providedColors = inputPalette as\n | Record<string, unknown>\n | undefined\n\n for (const key of CONTRAST_TEXT_COLOR_KEYS) {\n const color = (palette as unknown as Record<string, PaletteColor>)[key]\n if (!color || typeof color.main !== 'string') continue\n const provided = providedColors?.[key]\n // A ColorPartial ramp (`{ 50…900 }`) is an author-owned scale — MUI maps\n // its shades straight across, so nothing in it counts as derived.\n if (provided && typeof provided === 'object' && !('main' in provided)) {\n continue\n }\n // Read with brackets, not dots: these keys come from an index signature,\n // and `json-editor` compiles this file under\n // `noPropertyAccessFromIndexSignature` (paths resolve to source, so a\n // consumer's flags check its dependencies). Dot access reds that build\n // while this project's own stays green — AGL-1323.\n const explicit = (provided ?? {}) as Record<string, unknown>\n const isForeground = (FOREGROUND_COLOR_KEYS as readonly string[]).includes(\n key,\n )\n\n try {\n if (\n isForeground &&\n !explicit['dark'] &&\n typeof color.dark === 'string' &&\n !meetsContrast(color.dark, backgrounds)\n ) {\n const seed =\n mode === 'dark' ? lighten(color.main, tonalOffsetDark) : color.dark\n color.dark = accessibleShade(seed, backgrounds, foregroundDirection)\n }\n if (\n isForeground &&\n mode === 'dark' &&\n !explicit['light'] &&\n typeof color.light === 'string' &&\n !meetsContrast(color.light, backgrounds)\n ) {\n color.light = accessibleShade(color.light, backgrounds, 'lighten')\n }\n if (\n !explicit['contrastText'] &&\n typeof color.contrastText === 'string' &&\n !meetsContrast(color.contrastText, [color.main])\n ) {\n const textDirection: ShadeDirection =\n contrastRatio('#fff', color.main) >= contrastRatio('#000', color.main)\n ? 'lighten'\n : 'darken'\n color.contrastText = accessibleShade(\n color.contrastText,\n [color.main],\n textDirection,\n )\n }\n } catch {\n // Unparseable colour (CSS variable, color-mix()): leave the derived\n // value alone rather than failing theme creation.\n }\n }\n}\n\n/**\n * MUI's own default `responsiveFontSizes` variant list, spelled out because\n * passing `variants` replaces it rather than extending it.\n */\nconst RAMPED_MUI_VARIANTS = [\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'subtitle1',\n 'subtitle2',\n 'body1',\n 'body2',\n 'caption',\n 'button',\n 'overline',\n] as const\n\n/**\n * The brand's custom display rungs, which MUI cannot know about.\n *\n * Only variants whose size genuinely needs to shrink belong here. `lede`,\n * `bodyCompact` and `micro` are body-scale text that reads the same at every\n * width and are deliberately absent.\n */\nconst RAMPED_DISPLAY_VARIANTS = ['displayXl'] as const\n\nexport type CreateResponsiveThemeOptions = {\n themeOptions?: ThemeOptions\n responsiveFontSizesOptions?: Parameters<typeof responsiveFontSizes>[1]\n}\n\n/**\n * START EXAMPLE – OVERRIDE DEFAULT PROPS ↓\n * ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄\n * ```typescript\n * const theme = createMuiTheme({\n * props: {\n * // Name of the component ⚛️\n * MuiButtonBase: {\n * // The default props to change\n * disableRipple: true, // No more ripple, on the whole application 💣!\n * },\n * },\n * })\n * ```\n * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n * END EXAMPLE – OVERRIDE DEFAULT PROPS ↑\n *\n * START EXAMPLE – OVERRIDE DEFAULT STYLES ↓\n * ⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄⌄\n * ```typescript\n * const theme = createMuiTheme({\n * overrides: {\n * // Style sheet name ⚛️\n * MuiButton: {\n * // Name of the rule\n * text: {\n * // Some CSS\n * color: 'white',\n * },\n * },\n * MuiCssBaseline: {\n * '@global': {\n * html: {\n * WebkitFontSmoothing: 'auto',\n * },\n * },\n * },\n * },\n * })\n * ```\n * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n * END EXAMPLE – OVERRIDE DEFAULT STYLES ↑\n *\n * @param {ThemeOptions} options\n * @returns {Theme}\n */\nexport function createResponsiveTheme(\n options: CreateResponsiveThemeOptions,\n): Theme {\n const { themeOptions, responsiveFontSizesOptions } = options\n let theme = createTheme(themeOptions)\n addShadeVariants(theme.palette.tertiary, theme.palette.tonalOffset)\n addShadeVariants(theme.palette.surface, theme.palette.tonalOffset)\n // `tint` is deliberately absent from BOTH shade passes (AGL-1244). It is a\n // group of string leaves rather than a PaletteColor — no `main` to ramp\n // from, no `contrastText` to pair — so `addShadeVariants` would no-op and\n // `ensureAccessibleShades` (which keys off `CONTRAST_TEXT_COLOR_KEYS`) never\n // sees it. Both correct: a 90%-desaturated wash is authored, not derived,\n // and walking it to a text-contrast bar would repaint the fill.\n // Scheme- and AA-aware repair of DERIVED shades only (AGL-1297); explicit\n // palette values pass through byte-identical.\n ensureAccessibleShades(theme, themeOptions?.palette)\n\n theme = responsiveFontSizes(theme, {\n // Override to include `xs` and `xl` - default: ['sm', 'md', 'lg']\n breakpoints: ['xs', 'sm', 'md', 'lg', 'xl'],\n // MUI only ramps the variants it ships, so a CUSTOM display variant would\n // keep its desktop size on a phone — `displayXl` at 72px on a 375px\n // screen. Passing `variants` REPLACES MUI's default list, so the defaults\n // are spelled out here and ours appended; drop one and that variant\n // silently stops scaling.\n variants: [...RAMPED_MUI_VARIANTS, ...RAMPED_DISPLAY_VARIANTS],\n ...responsiveFontSizesOptions,\n })\n\n return theme\n}\n\nexport function createResponsiveCssVarTheme(\n light: Theme,\n dark: Theme,\n options?: CssVarsThemeOptions,\n) {\n const { palette: lightPalette, ...lightTheme } = light\n const { palette: darkPalette } = dark\n\n return muiExtendTheme({\n ...lightTheme,\n // Allow setMode() to work by driving the color scheme via a CSS class on\n // <html> instead of the OS-level @media query (the default 'media' selector\n // makes setMode() a no-op because media queries can't be overridden in JS).\n colorSchemeSelector: 'class',\n ...options,\n colorSchemes: {\n ...options?.colorSchemes,\n light: { palette: lightPalette, ...((options?.colorSchemes?.light ?? {}) as object) },\n dark: { palette: darkPalette, ...((options?.colorSchemes?.dark ?? {}) as object) },\n },\n })\n}\n\nexport default createResponsiveTheme\n"],"names":["extendTheme","muiExtendTheme","createTheme","darken","getContrastRatio","lighten","responsiveFontSizes","accessibleShade","contrastRatio","meetsContrast","ContrastText","resolveTonalOffsets","tonalOffset","offsetObj","undefined","offsetNum","light","dark","getContrastTextColor","background","contrastThreshold","addShade","paletteColor","shade","variant","main","tonalOffsetLight","tonalOffsetDark","indexed","hasOwnProperty","contrastText","addShadeVariants","FOREGROUND_COLOR_KEYS","CONTRAST_TEXT_COLOR_KEYS","ensureAccessibleShades","theme","inputPalette","palette","backgrounds","default","paper","filter","length","mode","foregroundDirection","providedColors","key","color","provided","explicit","isForeground","includes","seed","textDirection","RAMPED_MUI_VARIANTS","RAMPED_DISPLAY_VARIANTS","createResponsiveTheme","options","themeOptions","responsiveFontSizesOptions","tertiary","surface","breakpoints","variants","createResponsiveCssVarTheme","lightPalette","lightTheme","darkPalette","colorSchemeSelector","colorSchemes"],"mappings":"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"}
@@ -0,0 +1,81 @@
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
+ /**
18
+ * The one emotion cache key every App Router surface renders under (AGL-1266).
19
+ *
20
+ * Why a shared constant rather than each app's own literal — or, as it was,
21
+ * nobody's literal at all:
22
+ *
23
+ * Emotion's class name is `${cache.key}-${hash}`. The hash is a function of
24
+ * the STYLES, the key is a function of WHICH CACHE rendered them. So two
25
+ * renders of identical styles under two different caches produce
26
+ * `css-13b992c` and `mui-13b992c` — same hash, different prefix — and React
27
+ * throws away the entire server tree at hydration over the difference. That is
28
+ * AGL-1266: every tenant page re-rendered on the client, discarding the whole
29
+ * point of the tenant's SSR/ISR.
30
+ *
31
+ * Three separate defaults were in play, none of them written down:
32
+ *
33
+ * - `AppRouterCacheProvider` (@mui/material-nextjs) defaults to `mui`.
34
+ * - `StyledEngineProvider` (@mui/styled-engine) picks `mui` when
35
+ * `enableCssLayer` is on and `css` when it is off — so flipping one
36
+ * boolean silently renames every class on that surface.
37
+ * - Emotion itself falls back to `css`. This is the dangerous one: on the
38
+ * server, `withEmotionCache` sees a null cache context and quietly
39
+ * CREATES `createCache({ key: 'css' })` rather than failing (see
40
+ * `@emotion/react`'s non-browser branch). A server tree that loses the
41
+ * provider therefore renders perfectly — in the wrong key, unlayered, and
42
+ * with no error anywhere.
43
+ *
44
+ * Naming the key in one place means the layouts cannot drift from each other,
45
+ * and `emotion-cache.spec.ts` pins the fallback so the silent branch above is
46
+ * a documented, tested fact rather than something the next person rediscovers
47
+ * from a hydration diff.
48
+ *
49
+ * Deliberately dependency-free: this module is imported by App Router root
50
+ * layouts, which are Server Components, so it must not drag React, emotion or
51
+ * the theme HOCs into the RSC graph (AGL-405).
52
+ */
53
+ export declare const EMOTION_CACHE_KEY = "mui";
54
+ /**
55
+ * The exact options both root layouts hand `AppRouterCacheProvider`.
56
+ *
57
+ * `enableCssLayer` wraps MUI's rules in `@layer mui`, which is what lets site
58
+ * and plugin CSS override them without a specificity war. It travels WITH the
59
+ * key on purpose: the layered and unlayered caches must never share a key, or
60
+ * an unlayered `.mui-xxx` rule wins over the layered one with the same hash.
61
+ */
62
+ export declare const APP_EMOTION_CACHE_OPTIONS: {
63
+ readonly key: "mui";
64
+ readonly enableCssLayer: true;
65
+ };
66
+ /**
67
+ * The layer `enableCssLayer` actually emits.
68
+ *
69
+ * It is NOT configurable: `AppRouterCacheProvider` hard-codes the string when
70
+ * it patches `cache.insert`. Naming it here lets a surface that cannot use
71
+ * that provider — the besigner canvas's shadow-root cache, via
72
+ * `createLayeredEmotionCache` — reproduce the SAME layer rather than invent a
73
+ * parallel one, which would order differently and put the editor back out of
74
+ * step with the published page (AGL-2486). `emotion-cache.spec.ts` pins the
75
+ * value against MUI's own source so an upstream rename cannot drift past us.
76
+ *
77
+ * Kept in this module because it is a plain string: this file is imported by
78
+ * App Router root layouts, which are Server Components, so it must stay free
79
+ * of React, emotion and the theme HOCs (AGL-405).
80
+ */
81
+ export declare const MUI_CSS_LAYER_NAME = "mui";
@@ -0,0 +1,79 @@
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
+ * The one emotion cache key every App Router surface renders under (AGL-1266).
18
+ *
19
+ * Why a shared constant rather than each app's own literal — or, as it was,
20
+ * nobody's literal at all:
21
+ *
22
+ * Emotion's class name is `${cache.key}-${hash}`. The hash is a function of
23
+ * the STYLES, the key is a function of WHICH CACHE rendered them. So two
24
+ * renders of identical styles under two different caches produce
25
+ * `css-13b992c` and `mui-13b992c` — same hash, different prefix — and React
26
+ * throws away the entire server tree at hydration over the difference. That is
27
+ * AGL-1266: every tenant page re-rendered on the client, discarding the whole
28
+ * point of the tenant's SSR/ISR.
29
+ *
30
+ * Three separate defaults were in play, none of them written down:
31
+ *
32
+ * - `AppRouterCacheProvider` (@mui/material-nextjs) defaults to `mui`.
33
+ * - `StyledEngineProvider` (@mui/styled-engine) picks `mui` when
34
+ * `enableCssLayer` is on and `css` when it is off — so flipping one
35
+ * boolean silently renames every class on that surface.
36
+ * - Emotion itself falls back to `css`. This is the dangerous one: on the
37
+ * server, `withEmotionCache` sees a null cache context and quietly
38
+ * CREATES `createCache({ key: 'css' })` rather than failing (see
39
+ * `@emotion/react`'s non-browser branch). A server tree that loses the
40
+ * provider therefore renders perfectly — in the wrong key, unlayered, and
41
+ * with no error anywhere.
42
+ *
43
+ * Naming the key in one place means the layouts cannot drift from each other,
44
+ * and `emotion-cache.spec.ts` pins the fallback so the silent branch above is
45
+ * a documented, tested fact rather than something the next person rediscovers
46
+ * from a hydration diff.
47
+ *
48
+ * Deliberately dependency-free: this module is imported by App Router root
49
+ * layouts, which are Server Components, so it must not drag React, emotion or
50
+ * the theme HOCs into the RSC graph (AGL-405).
51
+ */ export const EMOTION_CACHE_KEY = 'mui';
52
+ /**
53
+ * The exact options both root layouts hand `AppRouterCacheProvider`.
54
+ *
55
+ * `enableCssLayer` wraps MUI's rules in `@layer mui`, which is what lets site
56
+ * and plugin CSS override them without a specificity war. It travels WITH the
57
+ * key on purpose: the layered and unlayered caches must never share a key, or
58
+ * an unlayered `.mui-xxx` rule wins over the layered one with the same hash.
59
+ */ export const APP_EMOTION_CACHE_OPTIONS = {
60
+ key: EMOTION_CACHE_KEY,
61
+ enableCssLayer: true
62
+ };
63
+ /**
64
+ * The layer `enableCssLayer` actually emits.
65
+ *
66
+ * It is NOT configurable: `AppRouterCacheProvider` hard-codes the string when
67
+ * it patches `cache.insert`. Naming it here lets a surface that cannot use
68
+ * that provider — the besigner canvas's shadow-root cache, via
69
+ * `createLayeredEmotionCache` — reproduce the SAME layer rather than invent a
70
+ * parallel one, which would order differently and put the editor back out of
71
+ * step with the published page (AGL-2486). `emotion-cache.spec.ts` pins the
72
+ * value against MUI's own source so an upstream rename cannot drift past us.
73
+ *
74
+ * Kept in this module because it is a plain string: this file is imported by
75
+ * App Router root layouts, which are Server Components, so it must stay free
76
+ * of React, emotion and the theme HOCs (AGL-405).
77
+ */ export const MUI_CSS_LAYER_NAME = 'mui';
78
+
79
+ //# sourceMappingURL=emotion-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/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\n/**\n * The one emotion cache key every App Router surface renders under (AGL-1266).\n *\n * Why a shared constant rather than each app's own literal — or, as it was,\n * nobody's literal at all:\n *\n * Emotion's class name is `${cache.key}-${hash}`. The hash is a function of\n * the STYLES, the key is a function of WHICH CACHE rendered them. So two\n * renders of identical styles under two different caches produce\n * `css-13b992c` and `mui-13b992c` — same hash, different prefix — and React\n * throws away the entire server tree at hydration over the difference. That is\n * AGL-1266: every tenant page re-rendered on the client, discarding the whole\n * point of the tenant's SSR/ISR.\n *\n * Three separate defaults were in play, none of them written down:\n *\n * - `AppRouterCacheProvider` (@mui/material-nextjs) defaults to `mui`.\n * - `StyledEngineProvider` (@mui/styled-engine) picks `mui` when\n * `enableCssLayer` is on and `css` when it is off — so flipping one\n * boolean silently renames every class on that surface.\n * - Emotion itself falls back to `css`. This is the dangerous one: on the\n * server, `withEmotionCache` sees a null cache context and quietly\n * CREATES `createCache({ key: 'css' })` rather than failing (see\n * `@emotion/react`'s non-browser branch). A server tree that loses the\n * provider therefore renders perfectly — in the wrong key, unlayered, and\n * with no error anywhere.\n *\n * Naming the key in one place means the layouts cannot drift from each other,\n * and `emotion-cache.spec.ts` pins the fallback so the silent branch above is\n * a documented, tested fact rather than something the next person rediscovers\n * from a hydration diff.\n *\n * Deliberately dependency-free: this module is imported by App Router root\n * layouts, which are Server Components, so it must not drag React, emotion or\n * the theme HOCs into the RSC graph (AGL-405).\n */\nexport const EMOTION_CACHE_KEY = 'mui'\n\n/**\n * The exact options both root layouts hand `AppRouterCacheProvider`.\n *\n * `enableCssLayer` wraps MUI's rules in `@layer mui`, which is what lets site\n * and plugin CSS override them without a specificity war. It travels WITH the\n * key on purpose: the layered and unlayered caches must never share a key, or\n * an unlayered `.mui-xxx` rule wins over the layered one with the same hash.\n */\nexport const APP_EMOTION_CACHE_OPTIONS = {\n key: EMOTION_CACHE_KEY,\n enableCssLayer: true,\n} as const\n\n/**\n * The layer `enableCssLayer` actually emits.\n *\n * It is NOT configurable: `AppRouterCacheProvider` hard-codes the string when\n * it patches `cache.insert`. Naming it here lets a surface that cannot use\n * that provider — the besigner canvas's shadow-root cache, via\n * `createLayeredEmotionCache` — reproduce the SAME layer rather than invent a\n * parallel one, which would order differently and put the editor back out of\n * step with the published page (AGL-2486). `emotion-cache.spec.ts` pins the\n * value against MUI's own source so an upstream rename cannot drift past us.\n *\n * Kept in this module because it is a plain string: this file is imported by\n * App Router root layouts, which are Server Components, so it must stay free\n * of React, emotion and the theme HOCs (AGL-405).\n */\nexport const MUI_CSS_LAYER_NAME = 'mui'\n"],"names":["EMOTION_CACHE_KEY","APP_EMOTION_CACHE_OPTIONS","key","enableCssLayer","MUI_CSS_LAYER_NAME"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,OAAO,MAAMA,oBAAoB,MAAK;AAEtC;;;;;;;CAOC,GACD,OAAO,MAAMC,4BAA4B;IACvCC,KAAKF;IACLG,gBAAgB;AAClB,EAAU;AAEV;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,qBAAqB,MAAK"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 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
+ type PFX = 'Aglyn';
18
+ type Sep = '-';
19
+ export type ElementClass<ClassKey extends string, Prefix extends string = PFX> = `${Prefix}${Sep}${ClassKey}`;
20
+ export type GlobalClassKey = keyof typeof globalClassKey;
21
+ export type GlobalElementClass<ClassKey extends GlobalClassKey = GlobalClassKey> = ElementClass<ClassKey>;
22
+ export type ComponentClass<ClassKey extends string, Prefix extends string> = ClassKey extends GlobalClassKey ? GlobalElementClass<ClassKey> : ElementClass<ClassKey, Prefix>;
23
+ export type ClassKeyMap<ClassKey extends string, Prefix extends string> = {
24
+ [P in ClassKey]: ComponentClass<P, Prefix>;
25
+ };
26
+ export declare const globalClassKey: {
27
+ active: `${string}-active`;
28
+ checked: `${string}-checked`;
29
+ completed: `${string}-completed`;
30
+ disabled: `${string}-disabled`;
31
+ error: `${string}-error`;
32
+ expanded: `${string}-expanded`;
33
+ focused: `${string}-focused`;
34
+ focusVisible: `${string}-focusVisible`;
35
+ hovered: `${string}-hovered`;
36
+ required: `${string}-required`;
37
+ selected: `${string}-selected`;
38
+ wrapper: `${string}-wrapper`;
39
+ };
40
+ export declare function generateComponentClassKeys<ClassKey extends string | GlobalClassKey, Prefix extends string>(componentName: Prefix, classKeys: ClassKey[]): ClassKeyMap<ClassKey, Prefix>;
41
+ export default generateComponentClassKeys;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2022 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
+ */ const pfx = 'Aglyn';
17
+ const sep = '-';
18
+ export const globalClassKey = {
19
+ active: makeClassKey('active'),
20
+ checked: makeClassKey('checked'),
21
+ completed: makeClassKey('completed'),
22
+ disabled: makeClassKey('disabled'),
23
+ error: makeClassKey('error'),
24
+ expanded: makeClassKey('expanded'),
25
+ focused: makeClassKey('focused'),
26
+ focusVisible: makeClassKey('focusVisible'),
27
+ hovered: makeClassKey('hovered'),
28
+ required: makeClassKey('required'),
29
+ selected: makeClassKey('selected'),
30
+ wrapper: makeClassKey('wrapper')
31
+ };
32
+ function makeClassKey(key, pre) {
33
+ if (pre) return `${pre}${sep}${key}`;
34
+ return `${pfx}${sep}${key}`;
35
+ }
36
+ function generateComponentClass(key, componentName) {
37
+ if (key in globalClassKey) {
38
+ return globalClassKey[key];
39
+ }
40
+ return makeClassKey(key, componentName);
41
+ }
42
+ export function generateComponentClassKeys(componentName, classKeys) {
43
+ const result = {};
44
+ classKeys.forEach((key)=>{
45
+ Object.assign(result, {
46
+ [key]: generateComponentClass(key, componentName)
47
+ });
48
+ });
49
+ return result;
50
+ }
51
+ export default generateComponentClassKeys;
52
+
53
+ //# sourceMappingURL=generate-component-class-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/shared/ui/theme/src/lib/util/generate-component-class-keys.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2022 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\ntype PFX = 'Aglyn'\ntype Sep = '-'\nexport type ElementClass<\n ClassKey extends string,\n Prefix extends string = PFX\n> = `${Prefix}${Sep}${ClassKey}`\nexport type GlobalClassKey = keyof typeof globalClassKey\nexport type GlobalElementClass<ClassKey extends GlobalClassKey = GlobalClassKey> =\n ElementClass<ClassKey>\nexport type ComponentClass<\n ClassKey extends string,\n Prefix extends string\n> = ClassKey extends GlobalClassKey ? GlobalElementClass<ClassKey> : ElementClass<ClassKey, Prefix>\n\nexport type ClassKeyMap<ClassKey extends string, Prefix extends string> = {\n [P in ClassKey]: ComponentClass<P, Prefix>\n}\n\nconst pfx: PFX = 'Aglyn'\nconst sep: Sep = '-'\n\nexport const globalClassKey = {\n active: makeClassKey('active'),\n checked: makeClassKey('checked'),\n completed: makeClassKey('completed'),\n disabled: makeClassKey('disabled'),\n error: makeClassKey('error'),\n expanded: makeClassKey('expanded'),\n focused: makeClassKey('focused'),\n focusVisible: makeClassKey('focusVisible'),\n hovered: makeClassKey('hovered'),\n required: makeClassKey('required'),\n selected: makeClassKey('selected'),\n wrapper: makeClassKey('wrapper'),\n}\n\nfunction makeClassKey<ClassKey extends string, Prefix extends string>(key: ClassKey, pre?: Prefix) {\n if (pre) return `${pre}${sep}${key}` as ElementClass<ClassKey, Prefix>\n return `${pfx}${sep}${key}` as ElementClass<ClassKey, PFX>\n}\n\nfunction generateComponentClass<ClassKey extends string, Prefix extends string>(\n key: ClassKey,\n componentName: Prefix\n) {\n if (key in globalClassKey) {\n return globalClassKey[key as GlobalClassKey] as ComponentClass<ClassKey, PFX>\n }\n return makeClassKey(key, componentName) as ComponentClass<ClassKey, Prefix>\n}\n\nexport function generateComponentClassKeys<\n ClassKey extends string | GlobalClassKey,\n Prefix extends string\n>(componentName: Prefix, classKeys: ClassKey[]) {\n const result = {} as ClassKeyMap<ClassKey, Prefix>\n\n classKeys.forEach((key) => {\n Object.assign(result, { [key]: generateComponentClass(key, componentName) })\n })\n\n return result\n}\n\nexport default generateComponentClassKeys\n"],"names":["pfx","sep","globalClassKey","active","makeClassKey","checked","completed","disabled","error","expanded","focused","focusVisible","hovered","required","selected","wrapper","key","pre","generateComponentClass","componentName","generateComponentClassKeys","classKeys","result","forEach","Object","assign"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAoBD,MAAMA,MAAW;AACjB,MAAMC,MAAW;AAEjB,OAAO,MAAMC,iBAAiB;IAC5BC,QAAQC,aAAa;IACrBC,SAASD,aAAa;IACtBE,WAAWF,aAAa;IACxBG,UAAUH,aAAa;IACvBI,OAAOJ,aAAa;IACpBK,UAAUL,aAAa;IACvBM,SAASN,aAAa;IACtBO,cAAcP,aAAa;IAC3BQ,SAASR,aAAa;IACtBS,UAAUT,aAAa;IACvBU,UAAUV,aAAa;IACvBW,SAASX,aAAa;AACxB,EAAC;AAED,SAASA,aAA6DY,GAAa,EAAEC,GAAY;IAC/F,IAAIA,KAAK,OAAO,GAAGA,MAAMhB,MAAMe,KAAK;IACpC,OAAO,GAAGhB,MAAMC,MAAMe,KAAK;AAC7B;AAEA,SAASE,uBACPF,GAAa,EACbG,aAAqB;IAErB,IAAIH,OAAOd,gBAAgB;QACzB,OAAOA,cAAc,CAACc,IAAsB;IAC9C;IACA,OAAOZ,aAAaY,KAAKG;AAC3B;AAEA,OAAO,SAASC,2BAGdD,aAAqB,EAAEE,SAAqB;IAC5C,MAAMC,SAAS,CAAC;IAEhBD,UAAUE,OAAO,CAAC,CAACP;QACjBQ,OAAOC,MAAM,CAACH,QAAQ;YAAE,CAACN,IAAI,EAAEE,uBAAuBF,KAAKG;QAAe;IAC5E;IAEA,OAAOG;AACT;AAEA,eAAeF,2BAA0B"}
@@ -0,0 +1,92 @@
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 { HostTheme, HostThemeFont, HostThemeScheme } from '@aglyn/shared-data-types';
18
+ import type { ThemeOptions } from '../../vendor/mui';
19
+ /**
20
+ * Components a host theme may override. Persisted overrides are plain JSON;
21
+ * anything outside this list is dropped by {@link sanitizeHostTheme} so a
22
+ * tampered document can't restyle console-internal or portal-critical
23
+ * components.
24
+ */
25
+ export declare const HOST_THEME_COMPONENT_WHITELIST: readonly ["MuiAppBar", "MuiAvatar", "MuiBadge", "MuiButton", "MuiButtonBase", "MuiCard", "MuiCardContent", "MuiCheckbox", "MuiChip", "MuiCircularProgress", "MuiDivider", "MuiIconButton", "MuiLinearProgress", "MuiLink", "MuiList", "MuiListItem", "MuiMenu", "MuiPaper", "MuiRadio", "MuiSlider", "MuiSwitch", "MuiTab", "MuiTabs", "MuiTextField", "MuiToolbar", "MuiTooltip", "MuiTypography"];
26
+ export type HostThemeComponentKey = (typeof HOST_THEME_COMPONENT_WHITELIST)[number];
27
+ /**
28
+ * Strips unknown component overrides and empty branches from a persisted
29
+ * host theme. Returns a new object; the input is never mutated.
30
+ */
31
+ export declare function sanitizeHostTheme(theme: HostTheme | undefined): HostTheme;
32
+ /**
33
+ * Re-orders breakpoint at-rules ascending, so STORED key order cannot decide
34
+ * which rule wins (AGL-3146).
35
+ *
36
+ * Two `min-width` rules of equal specificity both match a wide window, so the
37
+ * later one wins — which makes key order a rendering decision. Firestore does
38
+ * not preserve it: one stored toolbar mixin came back sm, landscape, base to
39
+ * the server reader and landscape, base, sm to the browser, so aglyn.com's
40
+ * nav drew 48px live and 72px on the besigner canvas from a single saved
41
+ * document. The editor and the page disagreed about a value neither of them
42
+ * had changed.
43
+ *
44
+ * Ascending is the order MUI writes its own breakpoint styles in and the
45
+ * order the theme editor writes a toolbar mixin in: the wider query is the
46
+ * more specific answer, so it belongs last.
47
+ *
48
+ * Only two things move. Plain declarations are hoisted ahead of the blocks,
49
+ * keeping their order among themselves — which is where the style engine
50
+ * emits them anyway, since a nested block becomes a rule of its own after the
51
+ * base one, and where the shorthand/longhand hazard lives. Breakpoint rules
52
+ * are sorted into the slots the blocks already occupy, so a nested selector
53
+ * or a condition naming no width never changes position against one another.
54
+ *
55
+ * Returns its input by identity when no order changes, which is every theme
56
+ * with at most one breakpoint rule per object.
57
+ */
58
+ export declare function orderMediaWidths<T>(value: T): T;
59
+ /**
60
+ * Converts a persisted {@link HostTheme} document into MUI `ThemeOptions`
61
+ * for one color scheme. The result is meant to be passed through
62
+ * `createResponsiveTheme` (or `createTheme`) by the consumer; shade and
63
+ * contrast-text derivation for partial palettes is MUI's job, so only
64
+ * explicitly set values are forwarded.
65
+ */
66
+ export declare function hostThemeToThemeOptions(theme: HostTheme | undefined, scheme: HostThemeScheme): ThemeOptions;
67
+ /**
68
+ * Layers a host's overrides ONTO a base set of theme options (AGL-1180).
69
+ *
70
+ * `hostThemeToThemeOptions` deliberately emits only what the host explicitly
71
+ * set, so building a theme from it alone leaves every other slot to MUI's
72
+ * stock palette. Consumers used to switch — console theme when the document
73
+ * was empty, host document when it was not — which meant setting a single
74
+ * value (the spec's own example is `{ spacing: 8 }`) silently repainted
75
+ * secondary, tertiary, surface, info, success, warning, error, background
76
+ * and paper in MUI blue/purple. Merging instead of switching keeps the brand
77
+ * as the floor no matter how much the host customizes.
78
+ *
79
+ * `palette` merges one level deep so overriding `primary` cannot drop
80
+ * `secondary`. Within a single colour the override replaces the whole record
81
+ * — MUI derives shades and contrast text from `main`, which is exactly the
82
+ * partial-palette behaviour the converter is written for.
83
+ */
84
+ export declare function mergeThemeOptions(base: ThemeOptions, overrides: ThemeOptions): ThemeOptions;
85
+ /** True when the document customizes anything, i.e. consumers should build a theme from it rather than using their default. */
86
+ export declare function hasHostTheme(theme: HostTheme | undefined): theme is HostTheme;
87
+ /**
88
+ * Builds a Google Fonts CSS2 stylesheet URL for the theme's loadable fonts.
89
+ * Returns undefined when nothing needs loading (system/absent fonts).
90
+ */
91
+ export declare function getGoogleFontsUrl(fonts: Array<HostThemeFont> | undefined): string;
92
+ export default hostThemeToThemeOptions;