Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ export default () => (
);
```

The SVG is decorative by default. When using it as the progress indicator itself, provide progress semantics and an accessible name with standard SVG/ARIA props:

```tsx | pure
<Line
percent={42}
role="progressbar"
aria-label="Upload progress"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={42}
/>
```

## Examples

Run the local dumi site:
Expand Down Expand Up @@ -88,6 +101,8 @@ Then open `http://localhost:8000`.
| `styles` | Partial<Record<'root' \| 'rail' \| 'track', React.CSSProperties>> | - | Semantic styles for internal slots. |
| `transition` | string | - | CSS transition for track updates. |

Standard SVG attributes, including `role` and `aria-*`, are forwarded to the root SVG.

## Development

```bash
Expand Down
15 changes: 15 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@ export default () => (
);
```

SVG 默认作为装饰元素。当 SVG 本身作为进度指示器时,可通过标准 SVG/ARIA 属性提供进度语义和无障碍名称:

```tsx | pure
<Line
percent={42}
role="progressbar"
aria-label="上传进度"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={42}
/>
```

## 示例

运行本地 dumi 站点:
Expand Down Expand Up @@ -88,6 +101,8 @@ npm start
| `styles` | Partial<Record<'root' \| 'rail' \| 'track', React.CSSProperties>> | - | 内部插槽的语义化样式。 |
| `transition` | string | - | 用于跟踪更新的 CSS 过渡。 |

标准 SVG 属性(包括 `role` 和 `aria-*`)会透传到根 SVG。

## 本地开发

```bash
Expand Down
2 changes: 2 additions & 0 deletions src/Line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ const Line: React.FC<ProgressProps> = (props) => {

return (
<svg
id={id}
className={clsx(`${prefixCls}-line`, className)}
viewBox={viewBoxString}
preserveAspectRatio="none"
style={style}
role="presentation"
{...restProps}
>
<path
Expand Down
7 changes: 6 additions & 1 deletion src/interface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
export type SemanticName = 'root' | 'rail' | 'track';

export interface ProgressProps {
export interface ProgressProps extends Omit<
React.SVGAttributes<SVGSVGElement>,
'strokeWidth' | 'strokeLinecap'
> {
id?: string;
/** Component geometry width, rather than the root SVG stroke-width attribute. */
Comment thread
coderabbitai[bot] marked this conversation as resolved.
strokeWidth?: number;
railWidth?: number;
className?: string;
Expand All @@ -10,6 +14,7 @@ export interface ProgressProps {
percent?: number | number[];
strokeColor?: StrokeColorType;
railColor?: string;
/** Component path line cap, rather than the root SVG stroke-linecap attribute. */
strokeLinecap?: StrokeLinecapType;
prefixCls?: string;
style?: React.CSSProperties;
Expand Down
5 changes: 5 additions & 0 deletions tests/__snapshots__/index.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ exports[`Progress Diff Line should match snapshot 1`] = `
<svg
class="rc-progress-line"
preserveAspectRatio="none"
role="presentation"
viewBox="0 0 100 1"
>
<path
Expand All @@ -347,6 +348,7 @@ exports[`Progress Diff Line should match snapshot 1`] = `
<svg
class="rc-progress-line"
preserveAspectRatio="none"
role="presentation"
viewBox="0 0 100 1"
>
<path
Expand All @@ -373,6 +375,7 @@ exports[`Progress Diff Line should match snapshot 1`] = `
<svg
class="rc-progress-line"
preserveAspectRatio="none"
role="presentation"
viewBox="0 0 100 1"
>
<path
Expand Down Expand Up @@ -402,6 +405,7 @@ exports[`Progress Line change with animation 1`] = `
<svg
class="rc-progress-line"
preserveAspectRatio="none"
role="presentation"
viewBox="0 0 100 1"
>
<path
Expand Down Expand Up @@ -430,6 +434,7 @@ exports[`Progress Line change with animation 2`] = `
<svg
class="rc-progress-line"
preserveAspectRatio="none"
role="presentation"
viewBox="0 0 100 1"
>
<path
Expand Down
48 changes: 47 additions & 1 deletion tests/semantic.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,54 @@
import React from 'react';
import { render } from '@testing-library/react';
import { Circle, type ProgressProps } from '../src';
import { Circle, Line, type ProgressProps } from '../src';

describe('Semantic', () => {
it('hides decorative SVGs and supports explicit progress semantics', () => {
const { container } = render(
<>
<Line percent={25} />
<Circle
percent={50}
role="progressbar"
aria-label="Upload progress"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={50}
/>
</>,
);

const [line, circle] = container.querySelectorAll('svg');
expect(line).toHaveAttribute('role', 'presentation');
expect(circle).toHaveAttribute('role', 'progressbar');
expect(circle).toHaveAccessibleName('Upload progress');
expect(circle).toHaveAttribute('aria-valuemin', '0');
expect(circle).toHaveAttribute('aria-valuemax', '100');
expect(circle).toHaveAttribute('aria-valuenow', '50');
});

it('supports explicit progress semantics for lines', () => {
const { container } = render(
<Line
id="download-progress"
percent={25}
role="progressbar"
aria-label="Download progress"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={25}
/>,
);

const line = container.querySelector('svg');
expect(line).toHaveAttribute('id', 'download-progress');
expect(line).toHaveAttribute('role', 'progressbar');
expect(line).toHaveAccessibleName('Download progress');
expect(line).toHaveAttribute('aria-valuemin', '0');
expect(line).toHaveAttribute('aria-valuemax', '100');
expect(line).toHaveAttribute('aria-valuenow', '25');
});

describe('Circle', () => {
function test(
name: string,
Expand Down
Loading