Skip to content

feat(statustag): support bg statusTag #450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
20 changes: 14 additions & 6 deletions src/statusTag/__tests__/__snapshots__/index.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ exports[`test StatusTag suite should support StatusTag success render 1`] = `
"baseElement": <body>
<div>
<div
class="dtc-statusTag dtc-statusTag__border"
class="dtc-statusTag"
>
<div
class="dtc-statusTag__default dtc-statusTag__success"
/>
class="dtc-statusTag__icon"
>
<span
class="dtc-statusTag__icon--default dtc-statusTag__success--iconBg"
/>
</div>
<span
class="dtc-statusTag__text"
>
Expand All @@ -21,11 +25,15 @@ exports[`test StatusTag suite should support StatusTag success render 1`] = `
</body>,
"container": <div>
<div
class="dtc-statusTag dtc-statusTag__border"
class="dtc-statusTag"
>
<div
class="dtc-statusTag__default dtc-statusTag__success"
/>
class="dtc-statusTag__icon"
>
<span
class="dtc-statusTag__icon--default dtc-statusTag__success--iconBg"
/>
</div>
<span
class="dtc-statusTag__text"
>
Expand Down
40 changes: 30 additions & 10 deletions src/statusTag/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,38 @@ describe('test StatusTag suite', () => {
const wrapper = render(<StatusTag>完成</StatusTag>);
expect(wrapper).toMatchSnapshot();
});
test('should support StatusTag render the default className in StatusTag', () => {
const { container } = render(<StatusTag>完成</StatusTag>);
expect(container.firstChild).toHaveClass(...[`${prefixCls}`, `${prefixCls}__border`]);
test('should support StatusTag render correct', () => {
const { container, rerender } = render(<StatusTag>完成</StatusTag>);
expect(container.firstChild).toHaveClass(...[`${prefixCls}`]);
rerender(<StatusTag type="outline">完成</StatusTag>);
expect(container.firstChild).toHaveClass(...[`${prefixCls}`, `${prefixCls}--border`]);
rerender(<StatusTag type="fill">完成</StatusTag>);
expect(container.firstChild).toHaveClass(...[`${prefixCls}`, `${prefixCls}--fill`]);
});
test('should render StatusTag render correct type', () => {
const { container } = render(<StatusTag type="run">完成</StatusTag>);
expect(container.querySelector(`.${prefixCls}__run`)).toBeInTheDocument();
test('should render StatusTag render correct inner color', () => {
const { container, rerender } = render(<StatusTag color="run">完成</StatusTag>);
expect(container.querySelector(`.${prefixCls}__run--iconBg`)).toBeInTheDocument();
rerender(
<StatusTag color="stopped" type="fill">
完成
</StatusTag>
);
expect(container.querySelector(`.${prefixCls}__stopped--fill`)).toBeInTheDocument();
});
test('should render StatusTag render correct color', () => {
const { container } = render(<StatusTag color="#2177b8">完成</StatusTag>);
const textWapper = container.querySelector(`.${prefixCls}__default`);
expect(textWapper).toHaveStyle({ background: '#2177b8' });
test('should render StatusTag render correct custom color', () => {
const { container, rerender } = render(<StatusTag color="#2177b8">完成</StatusTag>);
let wrapper = container.querySelector(`.${prefixCls}__icon--default`);
expect(wrapper).toHaveStyle({ background: '#2177b8' });
rerender(
<StatusTag color="#2177b8" type="fill">
完成
</StatusTag>
);
wrapper = container.querySelector(`.${prefixCls}--fill`);
expect(wrapper).toHaveStyle({
color: 'rgb(33, 119, 184)',
background: 'rgba(33, 119, 184, 0.3)',
});
});
test('should render StatusTag render correct text', () => {
const { container } = render(<StatusTag>自定义文案</StatusTag>);
Expand Down
46 changes: 37 additions & 9 deletions src/statusTag/demos/basic.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
import React from 'react';
import { Space } from 'antd';
import React, { useState } from 'react';
import { Divider, Radio, Space } from 'antd';
import { StatusTag } from 'dt-react-component';
import { StatusTagType } from 'dt-react-component/statusTag';

export default () => {
const presets = ['warning', 'error', 'success', 'run', 'stopped', 'frozen'];

const [type, setType] = useState<StatusTagType>('default');

return (
<Space direction="vertical">
<StatusTag type="run">运行中</StatusTag>
<StatusTag type="success">成功</StatusTag>
<StatusTag type="stopped">取消</StatusTag>
<StatusTag type="error">运行失败</StatusTag>
<StatusTag type="warning">提交中</StatusTag>
</Space>
<>
<Radio.Group value={type} onChange={(e) => setType(e.target.value)}>
<Radio.Button value="default">无外边框</Radio.Button>
<Radio.Button value="outline">有外边框</Radio.Button>
<Radio.Button value="fill">有背景色</Radio.Button>
</Radio.Group>
<Divider orientation="left">Presets</Divider>
<Space direction="vertical">
{presets.map((preset) => (
<StatusTag key={preset} type={type} color={preset}>
{preset}
</StatusTag>
))}
</Space>
<Divider orientation="left">Custom</Divider>
<Space direction="vertical">
<StatusTag type={type} color="#f50">
#f50
</StatusTag>
<StatusTag type={type} color="rgb(45, 183, 245)">
rgb(45, 183, 245)
</StatusTag>
<StatusTag type={type} color="#a31980">
#a31980
</StatusTag>
<StatusTag type={type} color="#0fd5e8">
#0fd5e8
</StatusTag>
</Space>
</>
);
};
24 changes: 0 additions & 24 deletions src/statusTag/demos/border.tsx

This file was deleted.

29 changes: 0 additions & 29 deletions src/statusTag/demos/colorful.tsx

This file was deleted.

23 changes: 23 additions & 0 deletions src/statusTag/demos/icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import { SketchOutlined } from '@ant-design/icons';
import { Space } from 'antd';
import { StatusTag } from 'dt-react-component';

export default () => {
return (
<Space direction="vertical">
<StatusTag color="success" type="outline" icon={<SketchOutlined />}>
成功
</StatusTag>
<StatusTag color="run" icon={<SketchOutlined />}>
运行中
</StatusTag>
<StatusTag color="warning" type="fill" icon={<SketchOutlined />}>
运行中
</StatusTag>
<StatusTag color="#2f10fb" type="fill" icon={<SketchOutlined />}>
运行中
</StatusTag>
</Space>
);
};
4 changes: 2 additions & 2 deletions src/statusTag/demos/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { StatusTag } from 'dt-react-component';
export default () => {
return (
<Space direction="vertical">
<StatusTag type="success" showBorder={false} loading>
<StatusTag color="success" type="outline" loading>
成功
</StatusTag>
<StatusTag type="run" loading>
<StatusTag color="run" type="outline" loading>
运行中
</StatusTag>
</Space>
Expand Down
13 changes: 7 additions & 6 deletions src/statusTag/demos/status.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from 'react';
import { Space } from 'antd';
import { StatusTag } from 'dt-react-component';

export default () => {
return (
<>
<StatusTag type="run" showBorder={false} />
<StatusTag type="success" showBorder={false} />
<StatusTag type="stopped" showBorder={false} />
<StatusTag type="warning" showBorder={false} />
</>
<Space direction="vertical">
<StatusTag color="run" />
<StatusTag color="success" />
<StatusTag color="stopped" />
<StatusTag color="warning" />
</Space>
);
};
19 changes: 9 additions & 10 deletions src/statusTag/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@ StatusTag 组件作用于任务运行状态效果展示

## 示例

<code src="./demos/basic.tsx" description="内置五种不同的 `type` ">基础使用</code>
<code src="./demos/basic.tsx" description="内置6种不同的`color`,三种类型`default | outline | fill`,同时我们添加了多种预设色彩的状态样式,用作不同场景使用。如果预设值不能满足你的需求,可以设置为具体的色值">基础使用</code>
<code src="./demos/status.tsx" description="用于表示状态的小圆点">状态点</code>
<code src="./demos/border.tsx" description="通过设置 `showBorder={false}` 可以隐藏外边框,默认为存在外边框">外边框</code>
<code src="./demos/colorful.tsx" description="我们添加了多种预设色彩的状态样式,用作不同场景使用。如果预设值不能满足你的需求,可以设置为具体的色值">自定义状态</code>
<code src="./demos/loading.tsx" description="通过设置 `loading` 可以设置加载中的状态标签">加载中</code>
<code src="./demos/icon.tsx" description="可以通过`icon`自定义图标">加载中</code>

## API

### StatusTag

| 参数 | 说明 | 类型 | 默认值 |
| ---------- | -------------------------------------------------------- | --------------------------------------------------------- | ----------- |
| type | 设置状态类型 | `'warning' \| 'error' \| 'success' \| 'run' \| 'stopped'` | `'success'` |
| showBorder | 是否展示外面的 border | `boolean` | `true` |
| color | 自定义颜色(当 type 所支持的颜色不满足时可用,优先级更高) | `string` | - |
| onClick | 点击事件 | `() => void` | - |
| loading | 设置状态标签载入状态 | `boolean` | `false` |
| 参数 | 说明 | 类型 | 默认值 |
| ------- | ----------------------------------------------------------- | --------------------------------------------------------------------- | --------- | --- |
| color | 内置了六种颜色,不满足时可自定义(仅支持 RGB 和十六进制颜色) | `warning \| error \| success \| run \| stopped \| frozen` \| `string` | `success` | - |
| icon | 自定义图标 | `React.ReactNode` | - |
| loading | 设置状态标签载入状态 | `boolean` | `false` |
| type | 设置状态类型 | `default \| outline \| fill` | `default` |
| onClick | 点击事件 | `() => void` | - |
66 changes: 53 additions & 13 deletions src/statusTag/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,83 @@ import classNames from 'classnames';

import './style.scss';

export type StatusTagType = 'warning' | 'error' | 'success' | 'run' | 'stopped';
const calculateTransparentColor = (color: string) => {
if (color.startsWith('rgb')) return `${color.slice(0, -1)},0.3)`;
let hex = color;
if (hex.length === 4) {
hex = hex.replace(/^#(.)(.)(.)$/, '#$1$1$2$2$3$3');
}
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${0.3})`;
};

const PresetColorTypes = ['warning', 'error', 'success', 'run', 'stopped', 'frozen'] as const;
const StatusTagTypes = ['default', 'outline', 'fill'] as const;

export type PresetColorType = (typeof PresetColorTypes)[number] | string;

export type StatusTagType = (typeof StatusTagTypes)[number];

function isPresetStatus(color?: any): color is PresetColorType {
return PresetColorTypes.includes(color);
}
export interface IStatusTagProps extends HTMLAttributes<HTMLDivElement> {
type?: StatusTagType;
className?: string;
showBorder?: boolean;
color?: string;
color?: PresetColorType;
loading?: boolean;
icon?: ReactNode;
children?: ReactNode;
onClick?: () => void;
}

const StatusTag: React.FC<IStatusTagProps> = function StatusTag(props) {
const {
className,
type = 'success',
showBorder = true,
color,
type = 'default',
icon,
color = 'success',
loading = false,
...other
} = props;
const prefixCls = 'dtc-statusTag';

const classes = classNames(`${prefixCls}`, className, {
[`${prefixCls}__border`]: showBorder,
});
const statusClass = classNames(`${prefixCls}__default`, {
[`${prefixCls}__${type}`]: type,
[`${prefixCls}--border`]: type === 'outline',
[`${prefixCls}--fill`]: type === 'fill',
[`${prefixCls}__${color}--fill`]: type === 'fill' && isPresetStatus(color),
});
const style: CSSProperties = color ? { background: `${color}` } : {};

const tagStyle: CSSProperties =
!isPresetStatus(color) && type === 'fill'
? { color, background: `${calculateTransparentColor(color)}` }
: {};

const getIconStyleAndClass = () => {
if (isPresetStatus(color)) {
return {
className: icon
? `${prefixCls}__${color}--icon`
: `${prefixCls}__icon--default ${prefixCls}__${color}--iconBg`,
style: icon ? { color: `${color}` } : { background: `${color}` },
};
}
return {
className: icon ? '' : `${prefixCls}__icon--default`,
style: icon ? { color: `${color}` } : { background: `${color}` },
};
};

return (
<div {...other} className={classes}>
<div {...other} className={classes} style={tagStyle}>
{loading ? (
<Spin spinning indicator={<LoadingOutlined />} size="small" />
) : (
<div className={statusClass} style={style} />
<div className={`${prefixCls}__icon`}>
<span {...getIconStyleAndClass()}>{icon ?? <></>}</span>
</div>
)}
<span className={`${prefixCls}__text`}>{props.children}</span>
</div>
Expand Down
Loading