ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Storybook 侧边栏 renderLabel 配置:自定义 Sidebar 中 Story 与分组名称的显示逻辑

Storybook 侧边栏 renderLabel 配置:自定义 Sidebar 中 Story 与分组名称的显示逻辑 Storybook 侧边栏 renderLabel 配置自定义 Sidebar 中 Story 与分组名称的显示逻辑【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook本篇技术指南围绕 Storybook 中addons.setConfig的sidebar.renderLabel配置项展开讲解如何在 Manager 侧对侧边栏Sidebar中 Story 名称、组件名、分组名和根节点Roots的显示文本进行自定义。文中给出的配置用于解决 CSF 3.0 auto-title 机制在 Storybook 6.5 后不再对自动生成的标题做大小写转换不再调用 Lodash 的startCase带来的命名差异读完后你将掌握renderLabel回调的参数结构、源码中的生效链路以及如何将其用于恢复旧版标题样式或实现任意自定义展示逻辑。背景CSF 3.0 auto-title 与 6.5 的命名规则变化Storybook 的侧边栏默认按 CSF 文件的title字段将 stories 分组展示。自 Storybook 6.4 引入 CSF 3.0 起title可以从 metadefault export中省略由 Storybook 依据 story 文件的物理路径自动推断这就是 auto-title 机制。从 Storybook 6.5 开始自动生成的标题不再依赖 Lodash 的startCase做单词大写转换而是保留文件名的原始大小写。例如6.5 之前components/MyComponent.stories.js的自动标题经过 startCase 处理6.5 之后文件名大小写被原样保留components/My Component会被定义为components/MyComponent。官方侧边栏配置文档docs/configure/user-interface/sidebar-and-urls.mdx在 “Auto-title filename case” 一节中明确说明如果你需要回退到旧的 startCase 命名模式可以添加下面这段 Manager 配置对应代码片段 docs/_snippets/storybook-manager-render-label-stories.md配置示例在 manager.js 中注册 renderLabel将以下配置写入.storybook/manager.js这是 Manager 运行时的配置文件在 Browser 端的 Manager 上下文加载import { addons } from storybook/manager-api; import startCase from lodash/startCase.js; addons.setConfig({ sidebar: { renderLabel: ({ name, type }) (type story ? name : startCase(name)), }, });配置要点配置项说明addons.setConfigManager 端 API用于在 Manager 上下文中设置全局配置来自storybook/manager-apisidebar.renderLabel一个回调函数接收侧边栏条目entry和 API 对象返回值将替代默认的name用于渲染({ name, type })回调参数解构name是条目名称type是条目类型story、docs、component、group、root等type story ? name : startCase(name)策略Story 叶子节点保持原始名称其余节点根、分组、组件统一转换为 Start Case 大写样式注意事项示例中使用了lodash/startCase.js因此项目需要安装lodash依赖或使用等价的大写转换函数替代。该配置只影响显示文本不改变 story 的id、URL 链接或分组结构renderLabel返回的文本不会反写回item.name。renderLabel对所有类型的侧边栏条目统一生效见下文源码分析因此回调内通常需要按type区分处理。源码解析renderLabel 从配置到渲染的完整链路1. 配置声明API_SidebarOptionsrenderLabel是sidebar配置对象的合法选项其类型定义位于 code/core/src/types/modules/api.tsexport interface API_SidebarOptionsAPI any { showRoots?: boolean; filters?: Recordstring, API_FilterFunction; collapsedRoots?: string[]; renderLabel?: (item: API_HashEntry, api: API) any; }可以看到回调签名为(item: API_HashEntry, api: API) any第一个参数是完整的侧边栏条目对象第二个参数是 Manager 的 API 实例可用于读取状态等返回任意可渲染值。每个侧边栏条目类型Root / Group / Component / Story / Docs都继承自API_BaseEntry其中声明了可选的renderLabel字段见 code/core/src/types/modules/api-stories.tsexport interface API_BaseEntry { id: StoryId; depth: number; name: string; tags: Tag[]; refId?: string; renderLabel?: (item: API_HashEntry, api: any) any; }2. 配置注入transformStoryIndexToStoriesHash在 code/core/src/manager-api/lib/stories.ts 中Manager 将 story 索引转换为侧边栏哈希IndexHash时会从当前配置中取出renderLabelconst { sidebar {} } provider.getConfig(); const { showRoots, collapsedRoots [], renderLabel } sidebar;随后在transformStoryIndexToStoriesHash内构建每一层节点时这个renderLabel会被挂到所有条目上Root 节点acc[id] merge(... { type: root, ..., renderLabel, ... })stories.tsComponent 节点与 Group 节点同样带上renderLabelstories.tsStory / Docs 叶子条目renderLabel作为最终哈希条目的字段写入stories.ts。这解释了为什么配置里的renderLabel既能作用于 Story也能作用于组件、分组和根节点——它是在索引转换阶段被统一分发的而非按类型单独注册。3. 渲染消费Tree.tsx 中的调用与兜底侧边栏树的渲染组件 code/core/src/manager/components/sidebar/Tree.tsx 在多种节点上调用该回调且都带有兜底逻辑Story/Docs 叶子节点Tree.tsx{(item.renderLabel as (i: typeof item, api: API) React.ReactNode)?.(item, api) || item.name}Root 根节点Tree.tsx{item.renderLabel?.(item, api) || item.name}Group/Component 折叠行也存在同样的调用点Tree.tsx、Tree.tsx。两个关键行为||兜底如果回调返回 falsy 值undefined、null、侧边栏会回退到默认的item.name。因此renderLabel可以安全地只处理部分类型其余类型返回undefined即可保持原样。返回 ReactNode从 Tree.tsx 的 JSX 用法看返回值直接作为 React 子节点渲染因此不仅可以返回字符串还可以返回带样式的 JSX如加图标、加 badge 的节点名。移动端导航组件 code/core/src/manager/components/mobile/navigation/MobileNavigation.tsx 同样消费renderLabel意味着该配置在窄屏/移动视图下同样生效。renderLabel 回调参数详解回调的第一个参数item是API_HashEntry从 code/core/src/types/modules/api-stories.ts 的类型定义看可读取的常用字段包括字段可用条件说明name所有类型条目原始名称来自 title 按/拆分后的段落type所有类型root|group|component|story|docs另有subtype: test的测试条目id所有类型条目 ID叶子条目的id即 story 的iddepth所有类型层级深度根为 0title/importPathstory/docs完整组件标题与来源文件路径tags所有类型条目 tags含dev、test等childrenroot/group/component子条目 ID 列表第二个参数api是 Manager 的 API 实例可用于读取当前状态如 filters、当前选中的 story从而做出状态相关的展示。更多用法从恢复 startCase 到完全自定义官方示例只覆盖了“恢复 6.5 之前的 startCase 标题”这一场景但同一机制支持任意展示逻辑例如import { addons } from storybook/manager-api; addons.setConfig({ sidebar: { renderLabel: (item) { // 只对分组/组件/根做转换Story 保持原名 if (item.type story) { return undefined; // 返回 falsy 时自动回退到 item.name } return item.name.toUpperCase(); }, }, });由于 Tree.tsx 中的|| item.name兜底对不需要自定义的类型直接返回undefined即可无需在每个分支中重复写原始名称。适用前提与限制该配置属于Manager 配置必须放在.storybook/manager.js或等价的 manager 入口中通过addons.setConfig注册它不是preview配置写在preview.js中不会生效。renderLabel只改变侧边栏展示文本不影响storyid生成、URL 路由与 permalinks改名需求若需保留链接稳定性应使用显式id与story.name参见 sidebar-and-urls.mdx 的 “Permalink to stories” 一节。示例中的startCase行为依赖lodash依赖仓库源码中code/core/__mocks__/lodash-es等 mock 表明核心测试对 lodash 生态有约定用法但业务项目自行引入lodash是示例代码的隐含前提。从源码结构看renderLabel在索引转换阶段被一次性挂到所有条目上stories.ts后续 story 索引更新如 filters 变化会重新构建哈希因此回调函数本身应保持无副作用避免依赖闭包内可变状态。小结sidebar.renderLabel是 Storybook 提供的一个轻量但通用的侧边栏定制钩子配置在 manager.js 中声明经transformStoryIndexToStoriesHashcode/core/src/manager-api/lib/stories.ts分发到 Root、Group、Component 与 Story 每一层条目最终在 Tree.tsx 等渲染点被调用并带回退。典型用途是恢复 6.5 之前 auto-title 的 startCase 命名风格也可以扩展为任意的展示层自定义逻辑同时不触碰 story 的id与 URL 语义。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进