- UI组件
- 图表库
- 前端
【免费下载链接】tremor
React components to build charts and dashboards
导读
本文以 Divider 组件的 changelog 为骨架,系统讲解 Tremor Raw 中Divider分隔线组件的完整技术细节:它的版本演进(0.0.1 → 0.0.2)、API 设计、样式体系、暗色模式支持、tremor-id约定,以及 Playwright 测试与 Storybook 示例的实战用法。读完本文,你将能独立使用并二次定制Divider,也能理解 Tremor Raw 组件库统一的演进与质量保障方式。
Tremor 是一套基于 Tailwind CSS 与 Radix UI 构建的 React 组件库,用于快速搭建图表与数据看板(见 README.md)。Divider正是其中用于内容分区的轻量组件之一。
一、changelog 全貌:一次 Typo、一次架构修复、一次全局约定
Divider的变更记录非常简短,但信息密度不低:
# Tremor Divider Changelog ## 0.0.2 ### Changes - Chore: Add `tremor-id` - Fix: Supertype divider ## 0.0.1 ### Changes - Fix: Typo逐条拆解:
| 版本 | 变更类型 | 变更内容 | 对应源码证据 |
|---|---|---|---|
| 0.0.1 | Fix | 修复拼写错误 | 早期版本遗留问题,当前版本已无此问题 |
| 0.0.2 | Chore | 为组件根节点添加tremor-id="tremor-raw"属性 | Divider.tsx |
| 0.0.2 | Fix | 修复 "Supertype divider"(组件泛型/父类型相关修复) | Divider.tsx 采用React.ComponentPropsWithoutRef<"div">类型 |
这三条记录恰好勾勒出组件从"能用"到"规范"的演进路径:先修正文案笔误,再修复类型设计,最后接入全库统一的tremor-id标记规范。其中tremor-id并非 Divider 独有——它是 Tremor Raw 所有组件的统一约定,可在 Accordion、Badge、BarList、Card 等组件源码中看到完全相同的写法,并在 CategoryBar 的测试 中通过toHaveAttribute("tremor-id", "tremor-raw")被断言验证。这为自动化测试、主题注入与第三方样式定位提供了稳定的选择器锚点。
二、源码解剖:一个 59 行的 forwardRef 组件
当前版本的Divider实现在 src/components/Divider/Divider.tsx,共 59 行,核心结构如下:
// Tremor Divider [v0.0.2] import React from "react" import { cx } from "../../utils/cx" type DividerProps = React.ComponentPropsWithoutRef<"div"> const Divider = React.forwardRef<HTMLDivElement, DividerProps>( ({ className, children, ...props }, forwardedRef) => ( <div ref={forwardedRef} className={cx( // base "mx-auto my-6 flex w-full items-center justify-between gap-3 text-sm", // text color "text-gray-500 dark:text-gray-500", className, )} tremor-id="tremor-raw" {...props} > {children ? ( <> <div className={cx( // base "h-[1px] w-full", // background color "bg-gray-200 dark:bg-gray-800", )} /> <div className="whitespace-nowrap text-inherit">{children}</div> <div className={cx( // base "h-[1px] w-full", // background color "bg-gray-200 dark:bg-gray-800", )} /> </> ) : ( <div className={cx( // base "h-[1px] w-full", // background color "bg-gray-200 dark:bg-gray-800", )} /> )} </div> ), ) Divider.displayName = "Divider" export { Divider }2.1 类型设计:与 HTML 原生 div 完全对齐
DividerProps = React.ComponentPropsWithoutRef<"div">意味着组件接受原生<div>元素的全部合法属性(id、data-*、事件处理器等),并通过{...props}透传到根节点。这正是 changelog 中 "Supertype divider" 修复的落点:Divider不再使用自定义的属性白名单,而是直接以div的 Props 作为超类型,任何原生属性都能无缝传入,配合forwardRef实现 ref 透传,在表单、动画库等需要直接操作 DOM 节点的场景中毫无阻碍。
2.2 双形态渲染:有子元素与无子元素
组件的渲染逻辑取决于是否传入children:
- 无子元素:渲染一条
h-[1px] w-full bg-gray-200 dark:bg-gray-800的水平细线,铺满整行; - 有子元素:渲染"左线 + 内容 + 右线"三段结构,内容区域通过
whitespace-nowrap text-inherit保持单行不换行并继承父级文字颜色,两边的线各占剩余宽度的一半,从而让文本/图标/按钮居中显示。
这种条件渲染配合gap-3保证内容与线段之间始终保持 0.75rem 的间距,text-sm则为内容设置了基准字号。
2.3 样式合并机制:cx 的妙用
所有类名都经过cx()处理,其实现在 src/utils/cx.ts:
import clsx, { type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" export function cx(...args: ClassValue[]) { return twMerge(clsx(...args)) }cx先由clsx合并条件类名,再由tailwind-merge去重冲突的 Tailwind 类(如用户传入的text-lg会正确覆盖默认的text-sm),因此通过className自定义样式时无需担心与内置类冲突,且传入的className优先级最高(排在cx参数最后)。
2.4 暗色模式与主题变量
组件内置暗色适配:文字色text-gray-500 dark:text-gray-500,线条色bg-gray-200 dark:bg-gray-800。结合 tailwind.config.js 中配置的dark:变体,只需在应用根节点切换dark类即可整体切换配色,无需修改组件代码。这也是 Tremor Raw 全部组件遵循的设计一致性。
三、实战用法:四种 Story 场景
Storybook 示例位于 src/components/Divider/divider.stories.tsx,覆盖了组件的典型应用形态:
3.1 基础分隔线
<Divider />最简单的形态,渲染一条通栏细线,用于大段内容之间的视觉分隔,默认上下外边距为my-6。
3.2 图标与文本居中分隔
<div className="w-96"> <Divider /> <Divider> <RiCalendar2Line className="h-5 w-5" /> </Divider> <Divider>Standard</Divider> <Divider> <span className="px-4">With little bit more space</span> </Divider> </div>这是"带内容的 Divider"最典型的用法:在统计数字、卡片区块之间插入带文字或图标的分隔线,比纯线段更有信息表达力。
3.3 仪表盘详情区块示例
<> <p className="text-sm text-gray-500 dark:text-gray-500">Tickets Sold</p> <p className="text-3xl font-semibold text-gray-900 dark:text-gray-50"> 1,587 </p> <Divider>Details</Divider> <p className="mt-2 text-sm leading-7 text-gray-500 dark:text-gray-500"> {/* 长文本说明内容 */} </p> </>展示了数据看板中"标题 → 关键指标 → 分隔线 → 详情说明"的经典段落结构,分隔线在此处承担了小标题的作用。
3.4 嵌入交互组件
<Divider> <Button variant="secondary" className="rounded-full"> Show more </Button> </Divider>children可以是任意 React 节点,甚至可以放入 Button 这类交互组件,形成"展开更多"式的行动分隔条。
四、质量保障:Playwright 测试用例
组件配套的端到端测试位于 src/components/Divider/divider.spec.ts,通过 Playwright 驱动 Storybook 运行:
test.describe("Expect divider", () => { test("to be rendered", async ({ page }) => { await page.goto("http://localhost:6006/?path=/story/ui-divider--default") await expect( page .frameLocator('iframe[title="storybook-preview-iframe"]') .locator("#storybook-root div") .nth(1), ).toBeVisible() }) })测试覆盖三条关键路径:
- 默认渲染:
DefaultStory 下组件可见; - 图标子元素渲染:
WithChildrenStory 下通过getByRole("img")断言图标元素可见; - 文本子元素渲染:通过
getByText("Standard")断言文本内容正确输出。
测试的 Story 名称(ui-divider--default、ui-divider--with-children)与 divider.stories.tsx 中title: "ui/Divider"及 Story 导出名一一对应,体现"Storybook 即测试夹具"的研发模式。运行方式见 package.json:pnpm storybook启动 Storybook(端口 6006),pnpm test:all依次执行 Vitest 单元测试与 Playwright 端到端测试。
五、如何在本仓库运行与查看 Divider
- 安装依赖:在仓库根目录执行
pnpm install(依赖清单见 package.json); - 启动 Storybook:
pnpm storybook,浏览器访问http://localhost:6006,在左侧面板选择ui/Divider即可交互查看全部 Story; - 运行测试:先启动 Storybook,再执行
pnpm exec playwright test src/components/Divider/divider.spec.ts,即可单独验证 Divider 的三个测试用例。
结语
从 src/components/Divider/changelog.md 的三条记录出发,我们完整还原了 Tremor RawDivider组件的技术全貌:它的版本足迹(Typo 修复 → Supertype 修复 →tremor-id约定)、59 行的精简实现、双形态渲染逻辑、基于cx的样式合并体系、暗色模式适配,以及 Playwright + Storybook 驱动的测试保障。理解这一个组件,也就理解了 Tremor Raw 整个组件库的设计语言与工程规范——小而专注,规范统一,测试完备。
- UI组件
- 图表库
- 前端
【免费下载链接】tremor
React components to build charts and dashboards
相关推荐
Civitai 前端仓库 TypeScript 编码规范实战:从 global.md 规则到源码实践
Civitai 前端仓库 TypeScript 编码规范实战:从 global.md 规则到源码实践 导读 本文围绕当前仓库根目录下的编码规范文件 .vscod
UI组件图表库前端TanStack Form 的 BaseFormOptions:defaultValues 与 onSubmitMeta 如何驱动表单初始化与提交元数据流
TanStack Form 的 BaseFormOptions:defaultValues 与 onSubmitMeta 如何驱动表单初始化与提交元数据流 本篇
UI组件图表库前端Tremor ProgressCircle 环形进度组件深度解析:从 changelog 看组件演进与 SVG 源码实现
Tremor ProgressCircle 环形进度组件深度解析:从 changelog 看组件演进与 SVG 源码实现 环形进度(Progress Circl
UI组件图表库前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考