如何在Storybook中实现Button组件Variant联动ColorVariant的动态控制
问题描述
我有一个React TypeScript Button组件,通过泛型实现了主Variant(normal、fill、outline)和ColorVariant的类型联动——选择不同主Variant时,ColorVariant只能选对应允许的值。但用Storybook Autodocs生成文档时,系统识别不了这个联动逻辑:Variant只显示normal选项,ColorVariant仅显示primary选项,而且无法根据选中的Variant动态切换可选值。
解决方案
要实现Storybook里的动态联动,需要调整组件类型适配Storybook的类型推断,同时利用Storybook的argTypes和controls钩子来动态更新选项。
步骤1:优化组件类型(适配Storybook)
Storybook对泛型组件的类型支持有限,我们可以导出一个包含所有可能Props组合的类型,帮助Storybook识别完整参数:
// 在Button组件文件中添加 export type ButtonAllProps = { [T in keyof typeof variants]: ButtonProps<T>; }[keyof typeof variants];
步骤2:重构Storybook配置
修改Storybook的meta配置,添加动态联动逻辑,确保所有主Variant都显示,且ColorVariant随Variant切换:
import type { Meta, StoryObj } from '@storybook/react'; import { Button, variants, colorVariants } from './Button'; // 提取组件的实际Props类型,避免泛型干扰Storybook识别 type ButtonProps = typeof Button extends React.ComponentType<infer P> ? P : never; const meta: Meta<ButtonProps> = { component: Button, tags: ['autodocs'], // 默认参数 args: { height: 48, width: 100, radiusVariant: 4, children: 'Button!', variant: 'normal', colorVariant: 'primary', }, argTypes: { variant: { control: 'select', // 显示所有主Variant选项 options: Object.keys(variants) as Array<keyof typeof variants>, description: '主变体类型', }, colorVariant: { control: 'select', // 初始选项对应normal的ColorVariant options: Object.keys(colorVariants.normal) as Array<keyof typeof colorVariants['normal']>, description: '颜色变体,随主变体变化', }, }, // 核心:实现Variant切换时ColorVariant的动态更新 parameters: { controls: { onChange: (args: ButtonProps, changedArg: keyof ButtonProps) => { if (changedArg === 'variant') { const selectedVariant = args.variant as keyof typeof variants; // 更新ColorVariant的可选值为当前主Variant对应的选项 meta.argTypes.colorVariant.options = Object.keys(colorVariants[selectedVariant]) as Array<any>; // 重置ColorVariant为当前主Variant的第一个可选值 args.colorVariant = Object.keys(colorVariants[selectedVariant])[0] as any; } return args; }, }, }, }; export default meta; type Story = StoryObj<ButtonProps>; // 可选:定义各个主变体的快捷故事,方便快速查看效果 export const Normal: Story = { args: { variant: 'normal', colorVariant: 'primary', }, parameters: { backgrounds: { default: 'dawn' }, }, }; export const Fill: Story = { args: { variant: 'fill', colorVariant: 'primary', }, }; export const Outline: Story = { args: { variant: 'outline', colorVariant: 'primary', }, };
关键逻辑说明
- 类型适配:通过
ButtonProps别名提取组件的实际Props类型,解决泛型导致Storybook无法识别完整参数的问题。 - 全Variant展示:直接用
Object.keys(variants)作为Variant的选项列表,确保所有主Variant都显示在下拉菜单中。 - 动态联动:利用
controls.onChange钩子,当Variant改变时,自动更新ColorVariant的可选选项,并重置为当前主Variant的第一个有效值。
效果验证
- 在Storybook的Controls面板中,切换Variant下拉选项,ColorVariant的可选值会自动同步为对应主Variant允许的选项。
- Autodocs会正确展示所有主Variant选项,且ColorVariant的描述会明确其随主变体变化的特性。
内容的提问来源于stack exchange,提问作者Saman
相关产品推荐
相关产品推荐

