初始配色脚本
在 SSR 文档的 React 水合前设置初始配色属性。
本指南覆盖默认 Emotion 环境的 Material UI Core;扩展包与额外示例按清单单独标注。
使用场景与业务边界
这是初始化脚本,不是可见 UI;匹配 Provider 配置、CSP nonce 和存储键,并检查真实服务端 HTML。
原生组成与范围
InitColorSchemeScript
保持 Material UI 原生组合与类型,不替换为 JGuang/Base UI/Radix 同名 API。示例条目不是额外组件。
原生安装与初始化
npm install @mui/material@9.4.0 @emotion/react@11.14.0 @emotion/styled@11.14.1
采用原生 npm 包与 Emotion,不提供虚构的 JGuang UI Registry 地址。将示例放在原生 ThemeProvider 内,按项目选择 CssBaseline 或 ScopedCssBaseline。先检查 React、现有 Provider、锁文件与 SSR 配置;不要覆盖用户文件或忽略 peer 冲突。本批实际验收 React 19.2.8;React 18 及以下须匹配 react-is。完整初始化规则见随附的双语 setup 文档。
关键原生参数
仅解释本指南选出的关键参数,不是平铺的通用 API。原生继承来源、slot 结构、可空值与泛型仍按固定源码保留。
| 所属组件.属性 | 用途说明 | 声明来源 |
|---|---|---|
InitColorSchemeScript.attribute | 初始配色选择器,必须匹配 ThemeProvider 的 colorSchemeSelector。 | InitColorSchemeScript |
InitColorSchemeScript.defaultMode | 没有保存偏好时的原生 light/dark/system 初始模式。 | InitColorSchemeScript |
InitColorSchemeScript.modeStorageKey | 原生模式偏好键,匹配 Provider,并避免其他应用的键。 | InitColorSchemeScript |
InitColorSchemeScript.nonce | 服务端输出初始化脚本使用的 CSP nonce。 | InitColorSchemeScript |
可运行原生示例
下列机器键只选择示例入口,不会作为通用 variant 属性传入每个组件。原生示例 JSX 与数据保持上游原文;JGuang 编写的验收示例明确标注。
- 真实 SSR 与水合,默认浅色 ·
Init-light· JGuang 原生验收代码 - 真实 SSR 与水合,默认深色 ·
Init-dark· JGuang 原生验收代码 - 真实 SSR 与水合,跟随系统 ·
Init-system· JGuang 原生验收代码
真实使用示例
JGuang 编写的原生验收代码,不是上游组件实现。
// JGuang-authored genuine SSR/hydration fixture using Material UI's native APIs.
import { useEffect, useSyncExternalStore } from "react";
import { ThemeProvider, createTheme, useColorScheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import Button from "@mui/material/Button";
import Paper from "@mui/material/Paper";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
export const modeStorageKey = "jguang-material-init-mode";
export const colorSchemeStorageKey = "jguang-material-init-scheme";
const theme = createTheme({ cssVariables: { colorSchemeSelector: "data" }, colorSchemes: { light: true, dark: true } });
export type Mode = "light" | "dark" | "system";
type Props = { defaultMode: Mode; zh: boolean };
const subscribeHydration = () => () => {};
const clientHydrated = () => true;
const serverHydrated = () => false;
function Controls({ defaultMode, zh }: Props) {
const { mode, systemMode, setMode } = useColorScheme();
const hydrated = useSyncExternalStore(subscribeHydration, clientHydrated, serverHydrated);
useEffect(() => {
const report = () => { const root = document.getElementById("root")!; parent.postMessage({ type: "jguang-preview-ready", token: new URLSearchParams(location.search).get("token") ?? "", height: Math.ceil(root.getBoundingClientRect().bottom + window.scrollY) }, location.origin); };
const frame = requestAnimationFrame(report);
const observer = new ResizeObserver(report);
observer.observe(document.getElementById("root")!);
return () => { cancelAnimationFrame(frame); observer.disconnect(); };
}, []);
const reset = () => {
// Remove only this fixture's namespaced preferences, never the website's.
for (const key of [modeStorageKey, `${colorSchemeStorageKey}-light`, `${colorSchemeStorageKey}-dark`]) localStorage.removeItem(key);
location.reload();
};
return <Stack spacing={2}><Typography variant="h5">{zh ? "原生配色初始化与水合" : "Native color initialization and hydration"}</Typography><Paper sx={{ p: 3 }}><Typography>{zh ? "默认模式" : "Default mode"}: {defaultMode}</Typography><Typography role="status" data-hydrated={hydrated ? "true" : "false"} data-native-mode={mode ?? "pending"} data-system-mode={systemMode ?? "pending"}>{zh ? "当前模式" : "Current mode"}: {mode ?? (zh ? "等待水合" : "Awaiting hydration")}</Typography><Stack direction="row" useFlexGap spacing={1} sx={{ mt: 2, flexWrap: "wrap" }}>{(["light", "dark", "system"] as const).map(value => <Button key={value} disabled={!mode} variant={mode === value ? "contained" : "outlined"} onClick={() => setMode(value)}>{zh ? ({ light: "浅色", dark: "深色", system: "跟随系统" })[value] : value}</Button>)}<Button disabled={!hydrated} onClick={reset}>{zh ? "清除演示偏好并刷新" : "Clear demo preference and reload"}</Button></Stack><Typography sx={{ mt: 2 }}>{zh ? "脚本在 React 启动前执行;按钮通过原生 useColorScheme 更新并保存偏好。该工具不是可见 UI 组件,演示面板是 JGuang 编写的验收代码。" : "The native script runs before React starts. Buttons update and persist preferences using useColorScheme. This utility is not a visible UI component; JGuang authored this acceptance panel."}</Typography><input aria-label={zh ? "原生日期" : "Native date"} type="date" defaultValue="2026-01-25" style={{ marginTop: 16 }} /></Paper></Stack>;
}
export default function ColorSchemeApp(props: Props) {
return <ThemeProvider theme={theme} defaultMode={props.defaultMode} modeStorageKey={modeStorageKey} colorSchemeStorageKey={colorSchemeStorageKey} disableTransitionOnChange><CssBaseline enableColorScheme /><Controls {...props} /></ThemeProvider>;
}
示例依赖边界
原生 Core/Emotion 验收代码。
直接导入 Icons/System/Utils 的示例需要匹配 9.4.0 包。局部数据与辅助文件属于示例闭包,不是额外组件。远程图片和模拟操作不提供后端。
固定上游 API 元数据参考
以下表格保留上游元数据,不是重新推断的通用类型体系。条件泛型、继承属性与回调细节以以下源码声明为准。主题默认配置可能覆盖元数据默认值。
InitColorSchemeScript
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
import { InitColorSchemeScript } from '@mui/material';
| 属性 | 必需 | 上游元数据类型/约束 | 元数据默认值 |
|---|---|---|---|
attribute | 否 | string | 'data-mui-color-scheme' |
colorSchemeNode | 否 | string | 'document.documentElement' |
colorSchemeStorageKey | 否 | string | 'mui-color-scheme' |
defaultDarkColorScheme | 否 | string | 'dark' |
defaultLightColorScheme | 否 | string | 'light' |
defaultMode | 否 | 'dark' | 'light' | 'system' | 'system' |
modeStorageKey | 否 | string | 'mui-mode' |
nonce | 否 | string | — |
原生源码声明
声明与 import 从固定源码提取,不平铺联合类型或外部继承。英文注释/类型属于原始源码参考,不代表上游正文已全文翻译。共享类型仍位于原生包中。
vendor/src/InitColorSchemeScript/InitColorSchemeScript.tsx
import PropTypes from 'prop-types';
import SystemInitColorSchemeScript from '@mui/system/InitColorSchemeScript';
export interface InitColorSchemeScriptProps {
/**
* The default mode when the storage is empty (user's first visit).
* @default 'system'
*/
defaultMode?: 'system' | 'light' | 'dark' | undefined;
/**
* The default color scheme to be used in light mode.
* @default 'light'
*/
defaultLightColorScheme?: string | undefined;
/**
* The default color scheme to be used in dark mode.
* @default 'dark'
*/
defaultDarkColorScheme?: string | undefined;
/**
* The node (provided as string) used to attach the color-scheme attribute.
* @default 'document.documentElement'
*/
colorSchemeNode?: string | undefined;
/**
* localStorage key used to store `mode`.
* @default 'mui-mode'
*/
modeStorageKey?: string | undefined;
/**
* localStorage key used to store `colorScheme`.
* @default 'mui-color-scheme'
*/
colorSchemeStorageKey?: string | undefined;
/**
* DOM attribute for applying a color scheme.
* @default 'data-mui-color-scheme'
* @example '.mode-%s' // for class based color scheme
* @example '[data-mode-%s]' // for data-attribute without '='
*/
attribute?: 'class' | 'data' | string | undefined;
/**
* Nonce string to pass to the inline script for CSP headers.
*/
nonce?: string | undefined;
}
安装后验收
执行严格类型检查、生产构建和实际交互。检查键盘标签/焦点、原生支持的禁用/错误/只读语义、深浅色、窄屏和减少动画。按真实宿主数据检查回调,不把复制提示词当作安装完成。初始化工具还需检查服务端 HTML 与无告警水合。
来源与许可
https://github.com/mui/material-ui/tree/809a7717b4c050ba3f69b75300689f07c050a16e
MIT · @mui/material@9.4.0. 保留上游原始内容与许可证。上游完整原文保留于 vendor/docs,不标为全文中文化。