Skip to content

Commit 2a2dc57

Browse files
authored
feat(tag): add variant prop with filled, soft, solid, and outlined styles (#83)
1 parent 50d2c30 commit 2a2dc57

9 files changed

Lines changed: 298 additions & 101 deletions

File tree

.changeset/feat-tag-variant.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tiny-design/react": minor
3+
---
4+
5+
feat(tag): add `variant` prop with `filled`, `soft`, `solid`, and `outlined` styles

apps/docs/src/routers.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ export const getGuideMenu = (s: SiteLocale): RouterItem[] => {
171171
{
172172
title: s.guideMenu.groups.ai,
173173
children: [
174-
{ title: s.guideMenu.mcpServer, route: 'mcp-server', component: pick(guide.mcpServer, isZh), tag: <Tag color="info">New</Tag> },
175-
{ title: s.guideMenu.cli, route: 'cli', component: pick(guide.cli, isZh), tag: <Tag color="info">New</Tag> },
174+
{ title: s.guideMenu.mcpServer, route: 'mcp-server', component: pick(guide.mcpServer, isZh), tag: <Tag variant='soft' color="info">New</Tag> },
175+
{ title: s.guideMenu.cli, route: 'cli', component: pick(guide.cli, isZh), tag: <Tag variant='soft' color="info">New</Tag> },
176176
],
177177
},
178178
{
@@ -257,7 +257,7 @@ export const getComponentMenu = (s: SiteLocale): RouterItem[] => {
257257
{ title: 'Timeline', route: 'timeline', component: pick(c.timeline, z) },
258258
{ title: 'Tooltip', route: 'tooltip', component: pick(c.tooltip, z) },
259259
{ title: 'Tree', route: 'tree', component: pick(c.tree, z) },
260-
{ title: 'Chart', route: 'chart', component: pick(c.chart, z), tag: <Tag color="info">New</Tag> },
260+
{ title: 'Chart', route: 'chart', component: pick(c.chart, z), tag: <Tag variant='soft' color="info">New</Tag> },
261261
],
262262
},
263263
{

packages/react/src/tag/__tests__/tag.test.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,36 @@ describe('<Tag />', () => {
3737
container.firstChild && fireEvent.click(container.firstChild);
3838
expect(fn).toHaveBeenCalledTimes(1);
3939
});
40+
41+
// Variant tests
42+
it('should apply filled variant class by default for preset color', () => {
43+
const { container } = render(<Tag color="blue">Blue</Tag>);
44+
expect(container.firstChild).toHaveClass('ty-tag_blue');
45+
expect(container.firstChild).not.toHaveClass('ty-tag_blue-solid');
46+
expect(container.firstChild).not.toHaveClass('ty-tag_blue-outlined');
47+
});
48+
49+
it('should apply solid variant class', () => {
50+
const { container } = render(<Tag color="blue" variant="solid">Blue</Tag>);
51+
expect(container.firstChild).toHaveClass('ty-tag_blue-solid');
52+
expect(container.firstChild).not.toHaveClass('ty-tag_blue');
53+
});
54+
55+
it('should apply soft variant class', () => {
56+
const { container } = render(<Tag color="blue" variant="soft">Blue</Tag>);
57+
expect(container.firstChild).toHaveClass('ty-tag_blue-soft');
58+
expect(container.firstChild).not.toHaveClass('ty-tag_blue');
59+
});
60+
61+
it('should apply outlined variant class', () => {
62+
const { container } = render(<Tag color="blue" variant="outlined">Blue</Tag>);
63+
expect(container.firstChild).toHaveClass('ty-tag_blue-outlined');
64+
expect(container.firstChild).not.toHaveClass('ty-tag_blue');
65+
});
66+
67+
it('should not apply variant class without color', () => {
68+
const { container } = render(<Tag variant="solid">Tag</Tag>);
69+
expect(container.firstChild).toHaveClass('ty-tag');
70+
expect(container.firstChild).not.toHaveClass('ty-tag_solid');
71+
});
4072
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { Tag, Typography } from '@tiny-design/react';
2+
3+
const colors = ['blue', 'green', 'orange', 'red', 'purple'] as const;
4+
const statusColors = ['success', 'warning', 'info', 'danger'] as const;
5+
6+
export default function VariantDemo() {
7+
return (
8+
<>
9+
<Typography.Heading level={6} style={{ marginBottom: 16 }}>
10+
Filled (default):
11+
</Typography.Heading>
12+
<div>
13+
{colors.map((color) => (
14+
<Tag key={color} color={color}>{color}</Tag>
15+
))}
16+
</div>
17+
18+
<Typography.Heading level={6} style={{ margin: '16px 0' }}>
19+
Soft:
20+
</Typography.Heading>
21+
<div>
22+
{colors.map((color) => (
23+
<Tag key={color} color={color} variant="soft">{color}</Tag>
24+
))}
25+
</div>
26+
27+
<Typography.Heading level={6} style={{ margin: '16px 0' }}>
28+
Solid:
29+
</Typography.Heading>
30+
<div>
31+
{colors.map((color) => (
32+
<Tag key={color} color={color} variant="solid">{color}</Tag>
33+
))}
34+
</div>
35+
36+
<Typography.Heading level={6} style={{ margin: '16px 0' }}>
37+
Outlined:
38+
</Typography.Heading>
39+
<div>
40+
{colors.map((color) => (
41+
<Tag key={color} color={color} variant="outlined">{color}</Tag>
42+
))}
43+
</div>
44+
45+
<Typography.Heading level={6} style={{ margin: '16px 0' }}>
46+
Status (solid):
47+
</Typography.Heading>
48+
<div>
49+
{statusColors.map((color) => (
50+
<Tag key={color} color={color} variant="solid">{color}</Tag>
51+
))}
52+
</div>
53+
54+
<Typography.Heading level={6} style={{ margin: '16px 0' }}>
55+
Custom color variants:
56+
</Typography.Heading>
57+
<div>
58+
<Tag color="#1677ff">filled</Tag>
59+
<Tag color="#1677ff" variant="soft">soft</Tag>
60+
<Tag color="#1677ff" variant="solid">solid</Tag>
61+
<Tag color="#1677ff" variant="outlined">outlined</Tag>
62+
</div>
63+
</>
64+
);
65+
}

packages/react/src/tag/index.md

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import DynamicDemo from './demo/Dynamic';
1010
import DynamicSource from './demo/Dynamic.tsx?raw';
1111
import StatusDemo from './demo/Status';
1212
import StatusSource from './demo/Status.tsx?raw';
13+
import VariantDemo from './demo/Variant';
14+
import VariantSource from './demo/Variant.tsx?raw';
1315

1416
# Tag
1517

@@ -59,17 +61,6 @@ Adding or removing a set of tags dynamically.
5961
6062
<DemoBlock component={CheckableDemo} source={CheckableSource} />
6163

62-
</Demo>
63-
</Column>
64-
<Column>
65-
<Demo>
66-
67-
### Colorful Tag
68-
69-
We preset a series of colorful tag styles for use in different situations. You can also set it to a hex color string for custom color.
70-
71-
<DemoBlock component={ColorDemo} source={ColorSource} />
72-
7364
</Demo>
7465
<Demo>
7566

@@ -88,6 +79,26 @@ By using the `visible` prop, you can control the close state of Tag.
8879

8980
<DemoBlock component={ControlledDemo} source={ControlledSource} />
9081

82+
</Demo>
83+
</Column>
84+
<Column>
85+
<Demo>
86+
87+
### Colorful Tag
88+
89+
We preset a series of colorful tag styles for use in different situations. You can also set it to a hex color string for custom color.
90+
91+
<DemoBlock component={ColorDemo} source={ColorSource} />
92+
93+
</Demo>
94+
<Demo>
95+
96+
### Variant
97+
98+
Tags support four variants: `filled` (default), `soft`, `solid`, and `outlined`.
99+
100+
<DemoBlock component={VariantDemo} source={VariantSource} />
101+
91102
</Demo>
92103
</Column>
93104
</Layout>
@@ -96,16 +107,17 @@ By using the `visible` prop, you can control the close state of Tag.
96107

97108
### Tag
98109

99-
| Property | Description | Type | Default |
100-
| -------------- | ---------------------------------------------- | ------------------------------ | ------- |
101-
| color | color of the tag (preset or custom hex) | string | - |
102-
| closable | whether the tag can be closed | boolean | false |
103-
| defaultVisible | initial visibility | boolean | true |
104-
| visible | controlled visibility | boolean | - |
105-
| onClose | callback when tag is closed | (e: MouseEvent) => void | - |
106-
| onClick | click callback | (e: MouseEvent) => void | - |
107-
| style | style object of container | CSSProperties | - |
108-
| className | className of container | string | - |
110+
| Property | Description | Type | Default |
111+
| -------------- | ---------------------------------------------- | --------------------------------------- | --------- |
112+
| color | color of the tag (preset or custom hex) | string | - |
113+
| variant | variant style of the tag | `'filled'` \| `'soft'` \| `'solid'` \| `'outlined'` | `'filled'` |
114+
| closable | whether the tag can be closed | boolean | false |
115+
| defaultVisible | initial visibility | boolean | true |
116+
| visible | controlled visibility | boolean | - |
117+
| onClose | callback when tag is closed | (e: MouseEvent) => void | - |
118+
| onClick | click callback | (e: MouseEvent) => void | - |
119+
| style | style object of container | CSSProperties | - |
120+
| className | className of container | string | - |
109121

110122
Preset colors: `magenta`, `red`, `volcano`, `orange`, `gold`, `lime`, `green`, `cyan`, `blue`, `geekblue`, `purple`.
111123

packages/react/src/tag/index.zh_CN.md

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import DynamicDemo from './demo/Dynamic';
1010
import DynamicSource from './demo/Dynamic.tsx?raw';
1111
import StatusDemo from './demo/Status';
1212
import StatusSource from './demo/Status.tsx?raw';
13+
import VariantDemo from './demo/Variant';
14+
import VariantSource from './demo/Variant.tsx?raw';
1315

1416
# Tag
1517

@@ -59,17 +61,6 @@ const { CheckableTag } = Tag;
5961
6062
<DemoBlock component={CheckableDemo} source={CheckableSource} />
6163

62-
</Demo>
63-
</Column>
64-
<Column>
65-
<Demo>
66-
67-
### 多彩标签
68-
69-
我们提供了一系列预设的彩色标签样式,适用于不同场景。你也可以自定义十六进制颜色值。
70-
71-
<DemoBlock component={ColorDemo} source={ColorSource} />
72-
7364
</Demo>
7465
<Demo>
7566

@@ -88,6 +79,26 @@ const { CheckableTag } = Tag;
8879

8980
<DemoBlock component={ControlledDemo} source={ControlledSource} />
9081

82+
</Demo>
83+
</Column>
84+
<Column>
85+
<Demo>
86+
87+
### 多彩标签
88+
89+
我们提供了一系列预设的彩色标签样式,适用于不同场景。你也可以自定义十六进制颜色值。
90+
91+
<DemoBlock component={ColorDemo} source={ColorSource} />
92+
93+
</Demo>
94+
<Demo>
95+
96+
### 变体
97+
98+
标签支持四种变体样式:`filled`(默认)、`soft``solid``outlined`
99+
100+
<DemoBlock component={VariantDemo} source={VariantSource} />
101+
91102
</Demo>
92103
</Column>
93104
</Layout>
@@ -96,16 +107,17 @@ const { CheckableTag } = Tag;
96107

97108
### Tag
98109

99-
| 属性 | 说明 | 类型 | 默认值 |
100-
| -------------- | ---------------------------------------------- | ------------------------------ | ------- |
101-
| color | 标签颜色(预设颜色或自定义十六进制值) | string | - |
102-
| closable | 标签是否可关闭 | boolean | false |
103-
| defaultVisible | 初始显示状态 | boolean | true |
104-
| visible | 受控的显示状态 | boolean | - |
105-
| onClose | 关闭标签时的回调 | (e: MouseEvent) => void | - |
106-
| onClick | 点击回调 | (e: MouseEvent) => void | - |
107-
| style | 容器样式对象 | CSSProperties | - |
108-
| className | 容器的 className | string | - |
110+
| 属性 | 说明 | 类型 | 默认值 |
111+
| -------------- | ---------------------------------------------- | ----------------------------------------------------- | ---------- |
112+
| color | 标签颜色(预设颜色或自定义十六进制值) | string | - |
113+
| variant | 标签的变体样式 | `'filled'` \| `'soft'` \| `'solid'` \| `'outlined'` | `'filled'` |
114+
| closable | 标签是否可关闭 | boolean | false |
115+
| defaultVisible | 初始显示状态 | boolean | true |
116+
| visible | 受控的显示状态 | boolean | - |
117+
| onClose | 关闭标签时的回调 | (e: MouseEvent) => void | - |
118+
| onClick | 点击回调 | (e: MouseEvent) => void | - |
119+
| style | 容器样式对象 | CSSProperties | - |
120+
| className | 容器的 className | string | - |
109121

110122
预设颜色:`magenta``red``volcano``orange``gold``lime``green``cyan``blue``geekblue``purple`
111123

0 commit comments

Comments
 (0)