@ equinor/ 聚变反应风格
由 Material-UI 所启发的反应造型库 makeStyles API由JSS所建并被设计为React 19相容. 这个软件包提供了灵活,型式安全的造型解决方案,支持基于主题的造型,动态道具,和范围化风格隔离.
特征
- ✅ 反应 19 兼容性 - 从地上建起来的19回想
- ✅ 类型安全 - 具有智能类型推论的全类型脚本支持
- ✅ 主题集成 - 与融合设计系统的无缝集成
- ✅ 范围化样式 - 防止CSS类名称与
StylesProvider种子 - ✅ 动态样式 - 支持基于正文和主题的造型
- ✅ 业绩 - 缓存样式表和优化JSS实例
- ✅ 嵌入式选择器 - 全力支持伪选者和嵌入规则
安装
npm install @equinor/fusion-react-styles
# or
pnpm add @equinor/fusion-react-styles
# or
yarn add @equinor/fusion-react-styles
同伴依赖关系
- 反应
^18或者说^19
快速启动
import { makeStyles, ThemeProvider, theme } from '@equinor/fusion-react-styles';
const useStyles = makeStyles({
root: {
color: 'blue',
padding: '16px',
},
title: {
fontSize: '24px',
fontWeight: 'bold',
},
}, { name: 'MyComponent' });
function MyComponent() {
const classes = useStyles();
return (
<div className={classes.root}>
<h1 className={classes.title}>Hello World</h1>
</div>
);
}
function App() {
return (
<ThemeProvider theme={theme}>
<MyComponent />
</ThemeProvider>
);
}
核心概念
1. 创建样式
使用 makeStyles 以创建生成 CSS 类名的样式钩。 总是提供 name 选项:
import { makeStyles } from '@equinor/fusion-react-styles';
const useStyles = makeStyles({
root: {
color: 'red',
padding: '16px',
},
button: {
backgroundColor: 'blue',
'&:hover': {
backgroundColor: 'darkblue',
},
},
}, { name: 'MyComponent' });
2. 使用组件样式
调用组件中的钩子以获取类名 :
function Component() {
const classes = useStyles();
return (
<div className={classes.root}>
<button className={classes.button}>Click me</button>
</div>
);
}
3. 有道具的动态样式
样式可以是接收道具的功能. 呼叫钩子时通过道具 :
interface ComponentProps {
color: string;
size: 'small' | 'large';
}
const useStyles = makeStyles({
root: (props: ComponentProps) => ({
color: props.color,
padding: props.size === 'large' ? '24px' : '12px',
}),
}, { name: 'DynamicComponent' });
function Component(props: ComponentProps) {
const classes = useStyles(props);
return <div className={classes.root}>Dynamic styling</div>;
}
4. 基于主题的样式
使用主题函数访问主题值 。 主题属性为 StyleProperty 需要使用 getVariable() 提取 CSS 值的方法 :
import { makeStyles, createStyles, theme } from '@equinor/fusion-react-styles';
const useStyles = makeStyles((themeValue) =>
createStyles({
root: {
color: themeValue.colors.text.static_icons__default.getVariable('color'),
padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
},
button: {
backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
'&:hover': {
backgroundColor: themeValue.colors.ui.background__hover.getVariable('color'),
},
},
}),
{ name: 'ThemedComponent' }
);
重要内容: 主题属性( 颜色、 间隔等 ) 是 StyleProperty 实例 :
- 颜色: 使用
theme.colors.*.getVariable('color')以 CSS 变量字符串获取颜色值 - 间距: 使用
theme.spacing.*.getVariable('padding')以 CSS 变量字符串获取间隔值 - 类型: 使用
theme.typography.*.style.*访问打字属性(例如,theme.typography.heading.h4.style.fontSize(中文(简体) )
示例
const useStyles = makeStyles((themeValue) =>
createStyles({
container: {
// Color property - use getVariable('color')
backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
color: themeValue.colors.text.static_icons__default.getVariable('color'),
// Spacing property - use getVariable('padding')
padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
marginTop: themeValue.spacing.comfortable.small.getVariable('padding'),
// Typography - access style properties directly
fontSize: themeValue.typography.paragraph.body_short.style.fontSize,
fontWeight: themeValue.typography.heading.h4.style.fontWeight,
},
}),
{ name: 'Container' }
);
API 参考
makeStyles(stylesOrCreator, options?)
创建从样式定义生成 CSS 类名的钩子 .
参数:
stylesOrCreator: 样式规则对象或函数(theme) => StyleRulesoptions.name数字 : 需求 用于调试和性能的名称前缀。 没有它,所有实例都共享相同的缓存密钥,引起性能问题.
回返情况: 返回的钩状函数 Record<ClassKey, string> 地点 ClassKey 从您的样式规则中推断出,提供类型安全访问类名.
实例:
// Static styles
const useStyles = makeStyles({
root: { color: 'red' },
}, { name: 'MyComponent' });
// Theme-based styles
const useStyles = makeStyles((theme) => ({
root: {
color: theme.colors.text.static_icons__default.getVariable('color'),
},
}), { name: 'ThemedComponent' });
// Dynamic styles with props
const useStyles = makeStyles({
root: (props: { color: string }) => ({
color: props.color,
}),
}, { name: 'DynamicComponent' });
createStyles(styles?)
用于创建样式规则的类型安全帮助. 改进类密钥的TypeScript推论,允许类型安全访问类名.
import { createStyles, makeStyles } from '@equinor/fusion-react-styles';
const useStyles = makeStyles((theme) =>
createStyles({
root: {
color: theme.colors.text.static_icons__default.getVariable('color'),
},
button: {
padding: theme.spacing.comfortable.medium.getVariable('padding'),
},
}),
{ name: 'Component' }
);
function Component() {
const classes = useStyles();
// TypeScript will error if you try to access classes.foo - it knows the exact keys!
return <div className={classes.root}>...</div>;
}
福利:
- 类型安全类密钥访问 - TypeScript 确切知道存在哪个类密钥
- 更好的 IDEs 自动补全
- 编译时抓取打字符
ThemeProvider
为儿童部分提供主题背景。 支持嵌入主题和主题组成.
道具 :
theme主题对象或函数(outerTheme) => themechildren: 反应节点
示例
import { ThemeProvider, theme } from '@equinor/fusion-react-styles';
function App() {
return (
<ThemeProvider theme={theme}>
<YourApp />
</ThemeProvider>
);
}
// Nested theme composition
function App() {
return (
<ThemeProvider theme={baseTheme}>
<ThemeProvider theme={(outer) => ({ ...outer, custom: true })}>
<YourApp />
</ThemeProvider>
</ThemeProvider>
);
}
useTheme<T>()
从 Hook 访问当前主题 ThemeProvider 上下文.
import { useTheme } from '@equinor/fusion-react-styles';
function Component() {
const theme = useTheme<FusionTheme>();
if (!theme) {
return <div>No theme available</div>;
}
return (
<div style={{
color: theme.colors.text.static_icons__default.getVariable('color'),
}}>
Hello
</div>
);
}
createTheme(customTheme?, baseTheme?)
通过将自定义属性与基准主题合并来创建新主题。 支持为颜色,打字等嵌入属性进行深度合并.
import { createTheme, theme } from '@equinor/fusion-react-styles';
import type { FusionTheme } from '@equinor/fusion-react-styles';
interface ExtendedTheme extends FusionTheme {
app: {
borderRadius: string;
sidebarWidth: string;
};
}
const extendedTheme = createTheme<ExtendedTheme>({
app: {
borderRadius: '12px',
sidebarWidth: '300px',
},
}, theme);
// Use in ThemeProvider
<ThemeProvider theme={extendedTheme}>
<App />
</ThemeProvider>
StylesProvider
创建一个孤立的样式范围来防止CSS类名称相撞. 对微前端和动态加载模块至关重要.
道具 :
seed: 类名的字符串前缀(例如,"my-module"(中文(简体) )generateClassName: 可选自定义类名生成器jss: 可选习俗 JSS 实例children: 反应节点
示例
import { StylesProvider } from '@equinor/fusion-react-styles';
// Main app
<StylesProvider seed="main-app">
<App />
</StylesProvider>
// Dynamically loaded module
<StylesProvider seed="dynamic-module">
<DynamicModule />
</StylesProvider>
createGenerateClassName(seed?)
创建分类名称生成器功能,并带有可选种子前缀用于隔离.
import { createGenerateClassName, StylesProvider } from '@equinor/fusion-react-styles';
const customGenerator = createGenerateClassName('my-app');
function App() {
return (
<StylesProvider generateClassName={customGenerator}>
<YourApp />
</StylesProvider>
);
}
clsx
用于合并类名的实用性. 再次出口 clsx 软件包.
import { clsx } from '@equinor/fusion-react-styles';
const className = clsx(classes.root, isActive && classes.active, 'custom-class');
高级使用
模块隔离的范围化样式
当构建微前端或动态加载模块时,使用 StylesProvider 具有防止CSS相撞的独特种子:
import { StylesProvider, makeStyles, ThemeProvider, theme } from '@equinor/fusion-react-styles';
// Shared styles
const sharedStyles = {
root: { color: 'blue' },
};
// Module A
const useStylesA = makeStyles(sharedStyles, { name: 'ModuleA' });
function ModuleA() {
const classes = useStylesA();
return <div className={classes.root}>Module A</div>;
}
// Module B
const useStylesB = makeStyles(sharedStyles, { name: 'ModuleB' });
function ModuleB() {
const classes = useStylesB();
return <div className={classes.root}>Module B</div>;
}
function App() {
return (
<ThemeProvider theme={theme}>
{/* Each module gets its own scope */}
<StylesProvider seed="module-a">
<ModuleA />
</StylesProvider>
<StylesProvider seed="module-b">
<ModuleB />
</StylesProvider>
</ThemeProvider>
);
}
尽管两个模块都使用相同的样式对象,但它们会生成不同的类名:
- 模块A:
module-a-makeStyles-root-1 - 模块B:
module-b-makeStyles-root-1
嵌入式选择器
完全支持 CSS- in-JS 嵌入选择器 :
import { clsx } from '@equinor/fusion-react-styles';
const useStyles = makeStyles({
root: {
color: 'blue',
'&:hover': {
color: 'red',
},
'& .child': {
padding: '10px',
},
'&$disabled': {
opacity: 0.5,
},
},
disabled: {},
}, { name: 'NestedComponent' });
function Component() {
const classes = useStyles();
const [disabled, setDisabled] = useState(false);
return (
<div className={clsx(classes.root, disabled && classes.disabled)}>
<div className="child">Child element</div>
</div>
);
}
有主题的 Safe 软件
使用 TypeScript 来保证有动态样式和主题的类型安全 :
import { makeStyles, createStyles, theme } from '@equinor/fusion-react-styles';
interface StyleProps {
color: string;
}
const useStyles = makeStyles((themeValue) =>
createStyles({
root: (props: StyleProps) => ({
...themeValue.typography.paragraph.body_short.style,
color: props.color,
padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
backgroundColor: themeValue.colors.ui.background__default.getVariable('color'),
}),
}),
{ name: 'MyComponent' }
);
function Component(props: StyleProps) {
const classes = useStyles(props);
return <div className={classes.root}>Styled component</div>;
}
扩展主题
以自定义属性扩展聚合主题 :
import { createTheme, theme, makeStyles } from '@equinor/fusion-react-styles';
import type { FusionTheme, StyleDefinition } from '@equinor/fusion-react-styles';
interface AppTheme extends StyleDefinition {
app: {
borderRadius: string;
sidebarWidth: string;
};
}
const extendedTheme = createTheme<AppTheme>({
app: {
borderRadius: '12px',
sidebarWidth: '300px',
},
});
// Use extended theme with makeStyles
const useStyles = makeStyles((themeValue: typeof extendedTheme) =>
createStyles({
root: {
borderRadius: themeValue.app.borderRadius,
padding: themeValue.spacing.comfortable.medium.getVariable('padding'),
},
}),
{ name: 'ExtendedThemeComponent' }
);
类型脚本支持
这个包被用TypeScript来写,并提供了完整的类型定义. 所有API都用智能推论完全输入:
自动类型推论
类型推论自动工作,并使用 createStyles 提供更好的类型安全:
// Basic type inference - works, but ClassKey is inferred as string
const useStyles = makeStyles({
root: { color: 'red' },
button: { padding: '10px' },
}, { name: 'Component' });
const classes = useStyles(); // classes: Record<string, string>
// With createStyles - ClassKey is inferred as literal union type
const useStyles = makeStyles((theme) =>
createStyles({
root: {
color: theme.colors.text.static_icons__default.getVariable('color'),
},
button: {
padding: theme.spacing.comfortable.medium.getVariable('padding'),
},
}),
{ name: 'Component' }
);
const classes = useStyles(); // classes: Record<'root' | 'button', string>
// TypeScript will error if you try to access classes.foo - it knows the exact keys!
主题类型
这个 FusionTheme 类型可按自定义属性扩展 :
import type { FusionTheme, StyleDefinition } from '@equinor/fusion-react-styles';
interface MyAppTheme extends StyleDefinition {
customProperty: string;
}
const useStyles = makeStyles((theme: FusionTheme<MyAppTheme>) => ({
root: {
color: theme.colors.text.static_icons__default.getVariable('color'),
custom: theme.customProperty, // Fully typed!
},
}), { name: 'Component' });
类型安全类访问
使用时 createStyles,返回类型是 Record<ClassKey, string> 地点 ClassKey 是您风格键的字面结合 。 该条规定:
- 编译时间安全: 访问未定义类密钥时键入脚本错误
- 更好的自动补全: IDES 确切显示可用的类名
- 重建支持: 重命名类密钥, TypeScript 将捕捉所有用法
从物质UI v4 迁移
此软件包提供了类似的 API @material-ui/styles v4 但为React 19相容性所建. 主要区别:
- 无物质-UI依赖 - 直接使用JSS
- 反应19相容 - 没有兼容性问题
- 改进类型脚本 - 更好的类型推论
- 范围样式 - 加强
StylesProvider基于种子的隔离 - 需要的名称选项 - 总是提供
name内makeStyles绩效选项
大部分代码应该使用最小的修改:
// Before (Material-UI v4)
import { makeStyles } from '@material-ui/styles';
// After (this package)
import { makeStyles } from '@equinor/fusion-react-styles';
// Add name option to makeStyles
const useStyles = makeStyles({ ... }, { name: 'ComponentName' });
反应 19 相容性
这个包与React 19完全兼容,并经过了广泛的测试. 实施中采用了React 19的新API并避免了被贬损的模式.
性能提示
-
总是提供
name选项 - 没有它,所有实例都共享相同的缓存密钥,从而造成不必要的重交和性能问题. -
使用
createStyles为了更好的类型安全 - 虽然是可选的,但它改进了TypeScript推论,提供了更好的自动补全. -
尽可能对样式对象进行纪念 - 如果在组件内部创建样式,则考虑将其移出或记住.
-
借阅样式缓存 - 包会自动缓存基于样式,主题,和名称的样式表,所以相同的样式定义会被再用.
捐款
欢迎捐款! 请读我们的 贡献指南 详细情况.
许可证
公务员制度委员会
相关软件包
@equinor/fusion-web-theme- 融合设计系统主题@equinor/fusion-wc-theme- 融合主题网页组件