diff --git a/src/statusTag/__tests__/__snapshots__/index.test.tsx.snap b/src/statusTag/__tests__/__snapshots__/index.test.tsx.snap index 58e9e880f..173626f97 100644 --- a/src/statusTag/__tests__/__snapshots__/index.test.tsx.snap +++ b/src/statusTag/__tests__/__snapshots__/index.test.tsx.snap @@ -6,11 +6,15 @@ exports[`test StatusTag suite should support StatusTag success render 1`] = ` "baseElement":
+ class="dtc-statusTag__icon" + > + +
@@ -21,11 +25,15 @@ exports[`test StatusTag suite should support StatusTag success render 1`] = ` , "container":
+ class="dtc-statusTag__icon" + > + +
diff --git a/src/statusTag/__tests__/index.test.tsx b/src/statusTag/__tests__/index.test.tsx index 0628a2c5c..365e11b16 100644 --- a/src/statusTag/__tests__/index.test.tsx +++ b/src/statusTag/__tests__/index.test.tsx @@ -10,27 +10,49 @@ describe('test StatusTag suite', () => { const wrapper = render(完成); expect(wrapper).toMatchSnapshot(); }); - test('should support StatusTag render the default className in StatusTag', () => { - const { container } = render(完成); - expect(container.firstChild).toHaveClass(...[`${prefixCls}`, `${prefixCls}__border`]); + test('should support StatusTag render correct', () => { + const { container, rerender } = render(完成); + expect(container.firstChild).toHaveClass(...[`${prefixCls}`]); + rerender(完成); + expect(container.firstChild).toHaveClass(...[`${prefixCls}`, `${prefixCls}--border`]); + rerender(完成); + expect(container.firstChild).toHaveClass(...[`${prefixCls}`, `${prefixCls}--fill`]); }); - test('should render StatusTag render correct type', () => { - const { container } = render(完成); - expect(container.querySelector(`.${prefixCls}__run`)).toBeInTheDocument(); + test('should render StatusTag render correct inner color', () => { + const { container, rerender } = render(完成); + expect(container.querySelector(`.${prefixCls}__green--iconBg`)).toBeInTheDocument(); + rerender( + + 完成 + + ); + expect(container.querySelector(`.${prefixCls}__purple--fill`)).toBeInTheDocument(); }); - test('should render StatusTag render correct color', () => { - const { container } = render(完成); - const textWapper = container.querySelector(`.${prefixCls}__default`); - expect(textWapper).toHaveStyle({ background: '#2177b8' }); + test('should render StatusTag render correct custom color', () => { + const { container, rerender } = render(完成); + let wrapper = container.querySelector(`.${prefixCls}__icon--default`); + expect(wrapper).toHaveStyle({ + background: 'rgb(33, 119, 184)', + }); + rerender( + + 完成 + + ); + wrapper = container.querySelector(`.${prefixCls}--fill`); + expect(wrapper).toHaveStyle({ + color: 'rgb(33, 119, 184)', + background: 'rgba(33, 119, 184, 0.15)', + }); }); test('should render StatusTag render correct text', () => { const { container } = render(自定义文案); - const textWapper = container.querySelector(`.${prefixCls}__text`)!; - expect(textWapper.innerHTML).toEqual('自定义文案'); + const textWarper = container.querySelector(`.${prefixCls}__text`)!; + expect(textWarper.innerHTML).toEqual('自定义文案'); }); test('should render StatusTag loading', () => { const { container } = render(自定义文案); - const loadingWapper = container.querySelector(`.ant-spin-spinning`)!; - expect(loadingWapper).toBeInTheDocument(); + const loadingWarper = container.querySelector(`.ant-spin-spinning`)!; + expect(loadingWarper).toBeInTheDocument(); }); }); diff --git a/src/statusTag/demos/basic.tsx b/src/statusTag/demos/basic.tsx index 98b9df205..5b7453760 100644 --- a/src/statusTag/demos/basic.tsx +++ b/src/statusTag/demos/basic.tsx @@ -1,15 +1,46 @@ -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 = ['blue', 'yellow', 'green', 'gray', 'red', 'purple', 'cyan', 'pink']; + + const [type, setType] = useState('default'); + return ( - - 运行中 - 成功 - 取消 - 运行失败 - 提交中 - + <> + setType(e.target.value)}> + 无外边框 + 有外边框 + 有背景色 + + Presets + + {presets.map((preset) => ( + + {preset} + + ))} + + Custom + + + #f50 + + + rgb(45, 183, 245) + + + #a31980 + + + #0fd5e8 + + + #3D446E + + + ); }; diff --git a/src/statusTag/demos/border.tsx b/src/statusTag/demos/border.tsx deleted file mode 100644 index 3762d31f6..000000000 --- a/src/statusTag/demos/border.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React, { useState } from 'react'; -import { Radio, Space } from 'antd'; -import { StatusTag } from 'dt-react-component'; - -export default () => { - const [showBorder, setShowBorder] = useState(true); - return ( - <> - - setShowBorder(e.target.value)}> - Default - 无外边框 - -
- - 运行中 - - - rgb(45, 183, 245) - -
- - ); -}; diff --git a/src/statusTag/demos/colorful.tsx b/src/statusTag/demos/colorful.tsx deleted file mode 100644 index 0398626ec..000000000 --- a/src/statusTag/demos/colorful.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { Divider, Space } from 'antd'; -import { StatusTag } from 'dt-react-component'; - -import { StatusTagType } from '../index'; - -export default () => { - const types = ['warning', 'error', 'success', 'run', 'stopped'] as StatusTagType[]; - - return ( - <> - Presets - - {types.map((type) => ( - - {type} - - ))} - - Custom - - #f50 - rgb(45, 183, 245) - hsl(102, 53%, 61%) - hwb(205 6% 9%) - - - ); -}; diff --git a/src/statusTag/demos/icon.tsx b/src/statusTag/demos/icon.tsx new file mode 100644 index 000000000..588743b62 --- /dev/null +++ b/src/statusTag/demos/icon.tsx @@ -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 ( + + }> + 成功 + + }> + 运行中 + + }> + 运行中 + + }> + 运行中 + + + ); +}; diff --git a/src/statusTag/demos/loading.tsx b/src/statusTag/demos/loading.tsx index 9c5a169ee..02fdf339f 100644 --- a/src/statusTag/demos/loading.tsx +++ b/src/statusTag/demos/loading.tsx @@ -5,10 +5,10 @@ import { StatusTag } from 'dt-react-component'; export default () => { return ( - + 成功 - + 运行中 diff --git a/src/statusTag/demos/status.tsx b/src/statusTag/demos/status.tsx index 0478b0fc6..818077d92 100644 --- a/src/statusTag/demos/status.tsx +++ b/src/statusTag/demos/status.tsx @@ -1,13 +1,14 @@ import React from 'react'; +import { Space } from 'antd'; import { StatusTag } from 'dt-react-component'; export default () => { return ( - <> - - - - - + + + + + + ); }; diff --git a/src/statusTag/index.md b/src/statusTag/index.md index dbf9774d9..92d34e71e 100644 --- a/src/statusTag/index.md +++ b/src/statusTag/index.md @@ -16,20 +16,19 @@ StatusTag 组件作用于任务运行状态效果展示 ## 示例 -基础使用 +基础使用 状态点 -外边框 -自定义状态 加载中 +加载中 ## API ### StatusTag -| 参数 | 说明 | 类型 | 默认值 | -| ---------- | -------------------------------------------------------- | --------------------------------------------------------- | ----------- | -| type | 设置状态类型 | `'warning' \| 'error' \| 'success' \| 'run' \| 'stopped'` | `'success'` | -| showBorder | 是否展示外面的 border | `boolean` | `true` | -| color | 自定义颜色(当 type 所支持的颜色不满足时可用,优先级更高) | `string` | - | -| onClick | 点击事件 | `() => void` | - | -| loading | 设置状态标签载入状态 | `boolean` | `false` | +| 参数 | 说明 | 类型 | 默认值 | +| ---------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------ | --------- | --- | +| color | 状态色,内置了六种颜色,不满足时可自定义(仅支持 RGB 和十六进制颜色) | `blue \| yellow \| green \| gray \| red \| purple \| cyan \| pink` \| `string` | `success` | - | +| icon | 自定义图标 | `React.ReactNode` | - | +| loading | 状态标签载入状态 | `boolean` | `false` | +| type | 状态类型 | `default \| outline \| fill` | `default` | +| background | 背景颜色,仅在自定义颜色且为 fill 的情况下生效 | `string` | `--` | diff --git a/src/statusTag/index.tsx b/src/statusTag/index.tsx index d44ea032b..2f5c431c5 100644 --- a/src/statusTag/index.tsx +++ b/src/statusTag/index.tsx @@ -5,43 +5,108 @@ 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.15)`; + 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.15})`; +}; + +const PresetColorTypes = [ + 'blue', + 'yellow', + 'green', + 'gray', + 'red', + 'purple', + 'cyan', + 'pink', +] 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 { + /** + * @description 状态类型 + */ type?: StatusTagType; - className?: string; - showBorder?: boolean; - color?: string; + /** + * @description 状态颜色色 + */ + color?: PresetColorType; + /** + * @description 状态是否加载中 + */ loading?: boolean; + /** + * @description 设置图标 + */ + icon?: ReactNode; + /** + * @description 背景颜色,仅仅在 fill 的情况下生效 + * @description 使用自定义颜色的时候,可以自定义背景颜色,如果不设置默认取字体颜色的0.15透明度 + */ + background?: string; + className?: string; children?: ReactNode; - onClick?: () => void; } const StatusTag: React.FC = function StatusTag(props) { const { className, - type = 'success', - showBorder = true, - color, + type = 'default', + icon, + color = 'green', loading = false, + background, ...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: background || `${calculateTransparentColor(color)}` } + : {}; + + const getIconStyleAndClass = () => { + if (isPresetStatus(color)) { + return { + className: icon + ? `${prefixCls}__${color}--icon` + : `${prefixCls}__icon--default ${prefixCls}__${color}--iconBg`, + }; + } + return { + className: icon ? '' : `${prefixCls}__icon--default`, + style: icon ? { color: `${color}` } : { background: `${color}` }, + }; + }; return ( -
+
{loading ? ( } size="small" /> ) : ( -
+
+ {icon ?? <>} +
)} {props.children}
diff --git a/src/statusTag/style.scss b/src/statusTag/style.scss index d61a7e085..ef01a9a12 100644 --- a/src/statusTag/style.scss +++ b/src/statusTag/style.scss @@ -1,46 +1,83 @@ $card_prefix: "dtc-statusTag"; -$warning_color: #FBB310; -$run_color: #1D78FF; -$success_color: #11D782; -$frozen_color: #EBECF0; -$error_color: #F96C5B; -$stopped_color: #AC9DFF; +$colors: ( + "yellow": ( + color: #FBB310, + bg: #FFF4D9, + ), + "blue": ( + color: #1D78FF, + bg: #E8F1FF, + ), + "green": ( + color: #11D782, + bg: #E7FBF7, + ), + "gray": ( + color: #B1B4C5, + bg: #F5F5F8, + ), + "red": ( + color: #F96C5B, + bg: #FDE9E7, + ), + "purple": ( + color: #AC9DFF, + bg: #EAE6FF, + ), + "cyan": ( + color: #2CCCDF, + bg: #E7F8FA, + ), + "pink": ( + color: #FF82AE, + bg: #FFE6EF, + ), +); .#{$card_prefix} { display: flex; align-items: center; width: fit-content; height: 24px; + font-size: 12px; color: #3D446E; - &__border { + &--border { padding: 2px 12px; - border: 1px solid #EBECF0; + border: 1px solid #D8DAE2; border-radius: 14px; } + &--fill { + padding: 2px 12px; + border-radius: 14px; + } + &__icon { + display: flex; + align-items: center; + &--default { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + } + } &__text { margin-left: 8px; line-height: 22px; white-space: nowrap; } - &__default { - display: inline-block; - width: 6px; - height: 6px; - border-radius: 50%; - } - &__warning { - background: $warning_color; - } - &__error { - background: $error_color; - } - &__success { - background: $success_color; - } - &__run { - background: $run_color; - } - &__stopped { - background: $stopped_color; + + @each $type, $values in $colors { + &__#{$type} { + &--icon { + color: map-get($values, color); + } + &--fill { + color: map-get($values, color); + background-color: map-get($values, bg); + } + &--iconBg { + background: map-get($values, color); + } + } } }