feat: CP support Badge className / classNames and style / styles (#43197)

* feat: CP support Badge className and style

* fix

* Update basic.tsx

* fix

* fix

* fix

* Update components/config-provider/context.ts

Co-authored-by: MadCcc <1075746765@qq.com>

* Update components/badge/index.tsx

Co-authored-by: MadCcc <1075746765@qq.com>

* Update components/badge/index.tsx

Co-authored-by: MadCcc <1075746765@qq.com>

* fix

* fix

* fix

* fix

---------

Co-authored-by: MadCcc <1075746765@qq.com>
This commit is contained in:
lijianan 2023-06-29 16:43:11 +08:00 committed by GitHub
parent 6bb18b361d
commit 316b7b8c5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 18 deletions

View File

@ -72,7 +72,7 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
showZero = false, showZero = false,
...restProps ...restProps
} = props; } = props;
const { getPrefixCls, direction } = React.useContext(ConfigContext); const { getPrefixCls, direction, badge } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('badge', customizePrefixCls); const prefixCls = getPrefixCls('badge', customizePrefixCls);
// Style // Style
@ -123,7 +123,7 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
// =============================== Styles =============================== // =============================== Styles ===============================
const mergedStyle = useMemo<React.CSSProperties>(() => { const mergedStyle = useMemo<React.CSSProperties>(() => {
if (!offset) { if (!offset) {
return { ...style }; return { ...badge?.style, ...style };
} }
const offsetStyle: React.CSSProperties = { marginTop: offset[1] }; const offsetStyle: React.CSSProperties = { marginTop: offset[1] };
@ -133,11 +133,8 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
offsetStyle.right = -parseInt(offset[0] as string, 10); offsetStyle.right = -parseInt(offset[0] as string, 10);
} }
return { return { ...offsetStyle, ...badge?.style, ...style };
...offsetStyle, }, [direction, offset, style, badge?.style]);
...style,
};
}, [direction, offset, style]);
// =============================== Render =============================== // =============================== Render ===============================
// >>> Title // >>> Title
@ -154,17 +151,14 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
!livingCount || typeof livingCount !== 'object' !livingCount || typeof livingCount !== 'object'
? undefined ? undefined
: cloneElement(livingCount, (oriProps) => ({ : cloneElement(livingCount, (oriProps) => ({
style: { style: { ...mergedStyle, ...oriProps.style },
...mergedStyle,
...oriProps.style,
},
})); }));
// InternalColor // InternalColor
const isInternalColor = isPresetColor(color, false); const isInternalColor = isPresetColor(color, false);
// Shared styles // Shared styles
const statusCls = classnames(classNames?.indicator, { const statusCls = classnames(classNames?.indicator, badge?.classNames?.indicator, {
[`${prefixCls}-status-dot`]: hasStatus, [`${prefixCls}-status-dot`]: hasStatus,
[`${prefixCls}-status-${status}`]: !!status, [`${prefixCls}-status-${status}`]: !!status,
[`${prefixCls}-color-${color}`]: isInternalColor, [`${prefixCls}-color-${color}`]: isInternalColor,
@ -185,6 +179,8 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
}, },
className, className,
rootClassName, rootClassName,
badge?.className,
badge?.classNames?.root,
classNames?.root, classNames?.root,
hashId, hashId,
); );
@ -193,8 +189,15 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
if (!children && hasStatus) { if (!children && hasStatus) {
const statusTextColor = mergedStyle.color; const statusTextColor = mergedStyle.color;
return wrapSSR( return wrapSSR(
<span {...restProps} className={badgeClassName} style={{ ...styles?.root, ...mergedStyle }}> <span
<span className={statusCls} style={{ ...styles?.indicator, ...statusStyle }} /> {...restProps}
className={badgeClassName}
style={{ ...styles?.root, ...badge?.styles?.root, ...mergedStyle }}
>
<span
className={statusCls}
style={{ ...styles?.indicator, ...badge?.styles?.indicator, ...statusStyle }}
/>
{text && ( {text && (
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}> <span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
{text} {text}
@ -205,7 +208,12 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
} }
return wrapSSR( return wrapSSR(
<span ref={ref} {...restProps} className={badgeClassName} style={styles?.root}> <span
ref={ref}
{...restProps}
className={badgeClassName}
style={{ ...badge?.styles?.root, ...styles?.root }}
>
{children} {children}
<CSSMotion <CSSMotion
visible={!isHidden} visible={!isHidden}
@ -221,7 +229,7 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
const isDot = isDotRef.current; const isDot = isDotRef.current;
const scrollNumberCls = classnames(classNames?.indicator, { const scrollNumberCls = classnames(classNames?.indicator, badge?.classNames?.indicator, {
[`${prefixCls}-dot`]: isDot, [`${prefixCls}-dot`]: isDot,
[`${prefixCls}-count`]: !isDot, [`${prefixCls}-count`]: !isDot,
[`${prefixCls}-count-sm`]: size === 'small', [`${prefixCls}-count-sm`]: size === 'small',
@ -231,7 +239,12 @@ const InternalBadge: React.ForwardRefRenderFunction<HTMLSpanElement, BadgeProps>
[`${prefixCls}-color-${color}`]: isInternalColor, [`${prefixCls}-color-${color}`]: isInternalColor,
}); });
let scrollNumberStyle: React.CSSProperties = { ...styles?.indicator, ...mergedStyle }; let scrollNumberStyle: React.CSSProperties = {
...styles?.indicator,
...badge?.styles?.indicator,
...mergedStyle,
};
if (color && !isInternalColor) { if (color && !isInternalColor) {
scrollNumberStyle = scrollNumberStyle || {}; scrollNumberStyle = scrollNumberStyle || {};
scrollNumberStyle.background = color; scrollNumberStyle.background = color;

View File

@ -2,6 +2,7 @@ import React from 'react';
import ConfigProvider from '..'; import ConfigProvider from '..';
import { render } from '../../../tests/utils'; import { render } from '../../../tests/utils';
import Anchor from '../../anchor'; import Anchor from '../../anchor';
import Badge from '../../badge';
import Breadcrumb from '../../breadcrumb'; import Breadcrumb from '../../breadcrumb';
import Cascader from '../../cascader'; import Cascader from '../../cascader';
import Checkbox from '../../checkbox'; import Checkbox from '../../checkbox';
@ -544,4 +545,40 @@ describe('ConfigProvider support style and className props', () => {
expect(container.querySelector('.ant-empty')).toHaveClass('cp-className'); expect(container.querySelector('.ant-empty')).toHaveClass('cp-className');
expect(container.querySelector('.ant-empty')).toHaveStyle({ background: 'red' }); expect(container.querySelector('.ant-empty')).toHaveStyle({ background: 'red' });
}); });
it('Should Badge className & style & classNames works', () => {
const { container } = render(
<ConfigProvider
badge={{
className: 'cp-badge',
style: {
backgroundColor: 'blue',
},
classNames: {
root: 'cp-badge-root',
indicator: 'cp-badge-indicator',
},
styles: {
root: { color: 'yellow' },
indicator: { color: 'green' },
},
}}
>
<Badge count={10}>test</Badge>
</ConfigProvider>,
);
const element = container.querySelector<HTMLSpanElement>('.ant-badge');
// test className
expect(element).toHaveClass('cp-badge');
expect(element).toHaveClass('cp-badge-root');
expect(element?.querySelector<HTMLElement>('sup')).toHaveClass('cp-badge-indicator');
// test style
expect(element).toHaveStyle({ color: 'yellow' });
expect(element?.querySelector<HTMLElement>('sup')).toHaveStyle({
color: 'green',
backgroundColor: 'blue',
});
});
}); });

View File

@ -1,6 +1,7 @@
import type { DerivativeFunc } from '@ant-design/cssinjs'; import type { DerivativeFunc } from '@ant-design/cssinjs';
import * as React from 'react'; import * as React from 'react';
import type { Options } from 'scroll-into-view-if-needed'; import type { Options } from 'scroll-into-view-if-needed';
import type { BadgeProps } from '../badge';
import type { ButtonProps } from '../button'; import type { ButtonProps } from '../button';
import type { RequiredMark } from '../form/Form'; import type { RequiredMark } from '../form/Form';
import type { InputProps } from '../input'; import type { InputProps } from '../input';
@ -42,6 +43,11 @@ export interface ComponentStyleConfig {
style?: React.CSSProperties; style?: React.CSSProperties;
} }
export interface BadgeConfig extends ComponentStyleConfig {
classNames?: BadgeProps['classNames'];
styles?: BadgeProps['styles'];
}
export interface ButtonConfig extends ComponentStyleConfig { export interface ButtonConfig extends ComponentStyleConfig {
classNames?: ButtonProps['classNames']; classNames?: ButtonProps['classNames'];
styles?: ButtonProps['styles']; styles?: ButtonProps['styles'];
@ -106,6 +112,7 @@ export interface ConfigConsumerProps {
checkbox?: ComponentStyleConfig; checkbox?: ComponentStyleConfig;
descriptions?: ComponentStyleConfig; descriptions?: ComponentStyleConfig;
empty?: ComponentStyleConfig; empty?: ComponentStyleConfig;
badge?: BadgeConfig;
radio?: ComponentStyleConfig; radio?: ComponentStyleConfig;
} }

View File

@ -102,6 +102,7 @@ const {
| Property | Description | Type | Default | Version | | Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| anchor | Set Anchor common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | anchor | Set Anchor common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| badge | Set Badge common props | { className?: string, style?: React.CSSProperties, classNames?: { count?: string, indicator?: string }, styles?: { count?: React.CSSProperties, indicator?: React.CSSProperties } } | - | 5.7.0 |
| breadcrumb | Set Breadcrumb common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | breadcrumb | Set Breadcrumb common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 | | button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| cascader | Set Cascader common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | cascader | Set Cascader common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |

View File

@ -19,6 +19,7 @@ import type { SpaceProps } from '../space';
import { DesignTokenContext } from '../theme/internal'; import { DesignTokenContext } from '../theme/internal';
import defaultSeedToken from '../theme/themes/seed'; import defaultSeedToken from '../theme/themes/seed';
import type { import type {
BadgeConfig,
ButtonConfig, ButtonConfig,
ComponentStyleConfig, ComponentStyleConfig,
ConfigConsumerProps, ConfigConsumerProps,
@ -155,6 +156,7 @@ export interface ConfigProviderProps {
checkbox?: ComponentStyleConfig; checkbox?: ComponentStyleConfig;
descriptions?: ComponentStyleConfig; descriptions?: ComponentStyleConfig;
empty?: ComponentStyleConfig; empty?: ComponentStyleConfig;
badge?: BadgeConfig;
radio?: ComponentStyleConfig; radio?: ComponentStyleConfig;
} }
@ -208,7 +210,9 @@ const setGlobalConfig = ({
export const globalConfig = () => ({ export const globalConfig = () => ({
getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => { getPrefixCls: (suffixCls?: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls; if (customizePrefixCls) {
return customizePrefixCls;
}
return suffixCls ? `${getGlobalPrefixCls()}-${suffixCls}` : getGlobalPrefixCls(); return suffixCls ? `${getGlobalPrefixCls()}-${suffixCls}` : getGlobalPrefixCls();
}, },
getIconPrefixCls: getGlobalIconPrefixCls, getIconPrefixCls: getGlobalIconPrefixCls,
@ -262,6 +266,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
pagination, pagination,
input, input,
empty, empty,
badge,
radio, radio,
} = props; } = props;
@ -333,6 +338,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
breadcrumb, breadcrumb,
pagination, pagination,
empty, empty,
badge,
radio, radio,
}; };

View File

@ -104,6 +104,7 @@ const {
| 参数 | 说明 | 类型 | 默认值 | 版本 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| anchor | 设置 Anchor 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | anchor | 设置 Anchor 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| badge | 设置 Badge 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { count?: string, indicator?: string }, styles?: { count?: React.CSSProperties, indicator?: React.CSSProperties } } | - | 5.7.0 |
| breadcrumb | 设置 Breadcrumb 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | breadcrumb | 设置 Breadcrumb 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 | | button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| cascader | 设置 Cascader 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | cascader | 设置 Cascader 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |