From 28d5508b4963e51ad816e2d3ebdedd0e7a04afd8 Mon Sep 17 00:00:00 2001 From: Yangfan Wu <39647285+wyf027@users.noreply.github.com> Date: Wed, 8 Jul 2026 08:38:06 +0800 Subject: [PATCH 1/3] feat(ui): support Progress custom format --- .../ui/src/components/data/Progress/Progress.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/ui/src/components/data/Progress/Progress.tsx b/packages/ui/src/components/data/Progress/Progress.tsx index 5d8fd08..d678777 100644 --- a/packages/ui/src/components/data/Progress/Progress.tsx +++ b/packages/ui/src/components/data/Progress/Progress.tsx @@ -1,10 +1,11 @@ -import { forwardRef, type HTMLAttributes } from 'react' +import { forwardRef, type HTMLAttributes, type ReactNode } from 'react' import { cn } from '../../../utils/cn' export interface ProgressProps extends HTMLAttributes { percent: number status?: 'normal' | 'success' | 'exception' showInfo?: boolean + format?: (percent: number) => ReactNode } export const Progress = forwardRef(function Progress( @@ -13,6 +14,7 @@ export const Progress = forwardRef(function Progr percent, status = 'normal', showInfo = true, + format, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-valuetext': ariaValueText, @@ -22,6 +24,9 @@ export const Progress = forwardRef(function Progr ) { const safePercent = Math.max(0, Math.min(100, percent)) const accessibleLabel = ariaLabel ?? (ariaLabelledBy ? undefined : 'Progress') + const info = format ? format(safePercent) : `${safePercent}%` + const formattedValueText = + typeof info === 'string' || typeof info === 'number' ? String(info) : `${safePercent}%` return (
(function Progr aria-valuemin={0} aria-valuemax={100} aria-valuenow={safePercent} - aria-valuetext={ariaValueText ?? `${safePercent}%`} + aria-valuetext={ariaValueText ?? formattedValueText} >
(function Progr style={{ width: `${safePercent}%` }} />
- {showInfo ? ( -
{safePercent}%
- ) : null} + {showInfo ?
{info}
: null}
) -}) +}) \ No newline at end of file From 62ff69f334ab35ecc7d3da41ab81d2436aa1ad62 Mon Sep 17 00:00:00 2001 From: Yangfan Wu <39647285+wyf027@users.noreply.github.com> Date: Wed, 8 Jul 2026 08:38:26 +0800 Subject: [PATCH 2/3] test(ui): cover Progress custom format --- .../data/Progress/Progress.test.tsx | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/components/data/Progress/Progress.test.tsx b/packages/ui/src/components/data/Progress/Progress.test.tsx index 4e2354d..64fc6c6 100644 --- a/packages/ui/src/components/data/Progress/Progress.test.tsx +++ b/packages/ui/src/components/data/Progress/Progress.test.tsx @@ -25,6 +25,31 @@ describe('Progress', () => { expect(screen.getByText('100%')).toBeInTheDocument() }) + it('uses custom formatted text for visible and accessible value text', () => { + render( `${value} days`} />) + + const progress = screen.getByRole('progressbar', { name: 'Progress' }) + + expect(progress).toHaveAttribute('aria-valuenow', '75') + expect(progress).toHaveAttribute('aria-valuetext', '75 days') + expect(screen.getByText('75 days')).toBeInTheDocument() + }) + + it('keeps explicit value text when custom formatted content is visual only', () => { + render( + {value} days} + aria-valuetext="75 days remaining" + />, + ) + + const progress = screen.getByRole('progressbar', { name: 'Progress' }) + + expect(progress).toHaveAttribute('aria-valuetext', '75 days remaining') + expect(screen.getByText('75 days')).toBeInTheDocument() + }) + it('supports external labelling and custom value text', () => { render(
@@ -44,4 +69,4 @@ describe('Progress', () => { expect(progress).toHaveAttribute('aria-valuetext', '64 percent complete') expect(screen.queryByText('64%')).not.toBeInTheDocument() }) -}) +}) \ No newline at end of file From 6b4c78d5a4875490678d2495bb37156573cb21c4 Mon Sep 17 00:00:00 2001 From: Yangfan Wu <39647285+wyf027@users.noreply.github.com> Date: Wed, 8 Jul 2026 08:38:41 +0800 Subject: [PATCH 3/3] docs(ui): document Progress format --- docs/components/progress.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/components/progress.md b/docs/components/progress.md index 7b5f7e4..78f07fc 100644 --- a/docs/components/progress.md +++ b/docs/components/progress.md @@ -7,11 +7,11 @@ @@ -20,6 +20,8 @@ Progress 默认渲染为 `role="progressbar"`,并根据 `percent` 同步 `aria-valuemin`、`aria-valuemax`、`aria-valuenow` 和 `aria-valuetext`。当页面中有多个进度条时,建议通过 `aria-label` 或 `aria-labelledby` 提供可区分名称。 +`format` 会自定义可见进度文本;当 `format` 返回字符串或数字时,该内容也会作为默认 `aria-valuetext`。如果格式化结果是复杂节点,或需要让屏幕阅读器读取更完整的上下文,请显式传入 `aria-valuetext`。 + ## API | 属性 | 说明 | 类型 | 默认值 | @@ -27,6 +29,7 @@ Progress 默认渲染为 `role="progressbar"`,并根据 `percent` 同步 `aria | percent | 百分比 | `number` | - | | status | 状态 | `'normal' \| 'success' \| 'exception'` | `'normal'` | | showInfo | 显示百分比文字 | `boolean` | `true` | +| format | 自定义进度文本 | `(percent: number) => ReactNode` | - | | aria-label | 进度条可访问名称 | `string` | `'Progress'` | | aria-labelledby | 使用外部标签命名进度条 | `string` | - | | aria-valuetext | 自定义屏幕阅读器读取的进度文本 | `string` | `${percent}%` |