chore: auto merge branches (#54590)

chore: master merge feature
This commit is contained in:
github-actions[bot] 2025-08-04 13:30:54 +00:00 committed by GitHub
commit 3f94d76ba9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 1640 additions and 301 deletions

View file

@ -11,9 +11,13 @@ const App: React.FC = () => (
containerSizeLG: 30, containerSizeLG: 30,
containerSizeSM: 16, containerSizeSM: 16,
textFontSize: 18, textFontSize: 14,
textFontSizeLG: 28, textFontSizeLG: 14,
textFontSizeSM: 12, textFontSizeSM: 14,
iconFontSize: 18,
iconFontSizeLG: 28,
iconFontSizeSM: 12,
borderRadius: 10, borderRadius: 10,
groupOverlapping: -10, groupOverlapping: -10,

View file

@ -36,6 +36,21 @@ export interface ComponentToken {
* @descEN Font size of small Avatar * @descEN Font size of small Avatar
*/ */
textFontSizeSM: number; textFontSizeSM: number;
/**
* @desc
* @descEN Font size of Avatar icon
*/
iconFontSize: number;
/**
* @desc
* @descEN Font size of large Avatar icon
*/
iconFontSizeLG: number;
/**
* @desc
* @descEN Font size of small Avatar icon
*/
iconFontSizeSM: number;
/** /**
* @desc * @desc
* @descEN Spacing between avatars in a group * @descEN Spacing between avatars in a group
@ -76,6 +91,9 @@ const genBaseStyle: GenerateStyle<AvatarToken> = (token) => {
textFontSize, textFontSize,
textFontSizeLG, textFontSizeLG,
textFontSizeSM, textFontSizeSM,
iconFontSize,
iconFontSizeLG,
iconFontSizeSM,
borderRadius, borderRadius,
borderRadiusLG, borderRadiusLG,
borderRadiusSM, borderRadiusSM,
@ -84,17 +102,23 @@ const genBaseStyle: GenerateStyle<AvatarToken> = (token) => {
} = token; } = token;
// Avatar size style // Avatar size style
const avatarSizeStyle = (size: number, fontSize: number, radius: number): CSSObject => ({ const avatarSizeStyle = (
size: number,
fontSize: number,
iconFontSize: number,
radius: number,
): CSSObject => ({
width: size, width: size,
height: size, height: size,
borderRadius: '50%', borderRadius: '50%',
fontSize,
[`&${componentCls}-square`]: { [`&${componentCls}-square`]: {
borderRadius: radius, borderRadius: radius,
}, },
[`&${componentCls}-icon`]: { [`&${componentCls}-icon`]: {
fontSize, fontSize: iconFontSize,
[`> ${iconCls}`]: { [`> ${iconCls}`]: {
margin: 0, margin: 0,
}, },
@ -124,14 +148,14 @@ const genBaseStyle: GenerateStyle<AvatarToken> = (token) => {
display: 'block', display: 'block',
}, },
...avatarSizeStyle(containerSize, textFontSize, borderRadius), ...avatarSizeStyle(containerSize, textFontSize, iconFontSize, borderRadius),
'&-lg': { '&-lg': {
...avatarSizeStyle(containerSizeLG, textFontSizeLG, borderRadiusLG), ...avatarSizeStyle(containerSizeLG, textFontSizeLG, iconFontSizeLG, borderRadiusLG),
}, },
'&-sm': { '&-sm': {
...avatarSizeStyle(containerSizeSM, textFontSizeSM, borderRadiusSM), ...avatarSizeStyle(containerSizeSM, textFontSizeSM, iconFontSizeSM, borderRadiusSM),
}, },
'> img': { '> img': {
@ -180,13 +204,17 @@ export const prepareComponentToken: GetDefaultToken<'Avatar'> = (token) => {
marginXXS, marginXXS,
colorBorderBg, colorBorderBg,
} = token; } = token;
return { return {
containerSize: controlHeight, containerSize: controlHeight,
containerSizeLG: controlHeightLG, containerSizeLG: controlHeightLG,
containerSizeSM: controlHeightSM, containerSizeSM: controlHeightSM,
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2), textFontSize: fontSize,
textFontSizeLG: fontSizeHeading3, textFontSizeLG: fontSize,
textFontSizeSM: fontSize, textFontSizeSM: fontSize,
iconFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
iconFontSizeLG: fontSizeHeading3,
iconFontSizeSM: fontSize,
groupSpace: marginXXS, groupSpace: marginXXS,
groupOverlapping: -marginXS, groupOverlapping: -marginXS,
groupBorderColor: colorBorderBg, groupBorderColor: colorBorderBg,

View file

@ -525,6 +525,15 @@ describe('Button', () => {
expect(container.firstChild).toHaveClass('ant-btn-color-blue'); expect(container.firstChild).toHaveClass('ant-btn-color-blue');
}); });
it('ConfigProvider support button shape', () => {
const { container } = render(
<ConfigProvider button={{ shape: 'round' }}>
<Button>Button</Button>
</ConfigProvider>,
);
expect(container.firstChild).toHaveClass('ant-btn-round');
});
it('should show the component internal properties', () => { it('should show the component internal properties', () => {
const { container } = render( const { container } = render(
<ConfigProvider button={{ variant: 'dashed', color: 'blue' }}> <ConfigProvider button={{ variant: 'dashed', color: 'blue' }}>

View file

@ -105,7 +105,7 @@ const InternalCompoundedButton = React.forwardRef<
variant, variant,
type, type,
danger = false, danger = false,
shape = 'default', shape: customizeShape,
size: customizeSize, size: customizeSize,
styles, styles,
disabled: customDisabled, disabled: customDisabled,
@ -130,6 +130,8 @@ const InternalCompoundedButton = React.forwardRef<
const mergedType = type || 'default'; const mergedType = type || 'default';
const { button } = React.useContext(ConfigContext); const { button } = React.useContext(ConfigContext);
const shape = customizeShape || button?.shape || 'default';
const [mergedColor, mergedVariant] = useMemo<ColorVariantPairType>(() => { const [mergedColor, mergedVariant] = useMemo<ColorVariantPairType>(() => {
// >>>>> Local // >>>>> Local
// Color & Variant // Color & Variant

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`ConfigProvider components Alert configProvider 1`] = ` exports[`ConfigProvider components Alert configProvider 1`] = `
<div <div
@ -29766,7 +29766,9 @@ exports[`ConfigProvider components Tags configProvider 1`] = `
<span <span
class="config-tag config-tag-checkable" class="config-tag config-tag-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;
@ -29781,7 +29783,9 @@ exports[`ConfigProvider components Tags configProvider componentDisabled 1`] = `
<span <span
class="config-tag config-tag-checkable" class="config-tag config-tag-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;
@ -29796,7 +29800,9 @@ exports[`ConfigProvider components Tags configProvider componentSize large 1`] =
<span <span
class="config-tag config-tag-checkable" class="config-tag config-tag-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;
@ -29811,7 +29817,9 @@ exports[`ConfigProvider components Tags configProvider componentSize middle 1`]
<span <span
class="config-tag config-tag-checkable" class="config-tag config-tag-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;
@ -29826,7 +29834,9 @@ exports[`ConfigProvider components Tags configProvider componentSize small 1`] =
<span <span
class="config-tag config-tag-checkable" class="config-tag config-tag-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;
@ -29841,7 +29851,9 @@ exports[`ConfigProvider components Tags normal 1`] = `
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;
@ -29856,7 +29868,9 @@ exports[`ConfigProvider components Tags prefixCls 1`] = `
<span <span
class="prefix-Tags prefix-Tags-checkable" class="prefix-Tags prefix-Tags-checkable"
> >
Light <span>
Light
</span>
</span> </span>
</div> </div>
`; `;

View file

@ -40,6 +40,7 @@ import type { TourProps } from '../tour/interface';
import type { TransferProps } from '../transfer'; import type { TransferProps } from '../transfer';
import type { TreeSelectProps } from '../tree-select'; import type { TreeSelectProps } from '../tree-select';
import type { RenderEmptyHandler } from './defaultRenderEmpty'; import type { RenderEmptyHandler } from './defaultRenderEmpty';
import type { UploadProps } from '../upload';
export const defaultPrefixCls = 'ant'; export const defaultPrefixCls = 'ant';
export const defaultIconPrefixCls = 'anticon'; export const defaultIconPrefixCls = 'anticon';
@ -161,7 +162,7 @@ export type TextAreaConfig = ComponentStyleConfig &
Pick<TextAreaProps, 'autoComplete' | 'classNames' | 'styles' | 'allowClear' | 'variant'>; Pick<TextAreaProps, 'autoComplete' | 'classNames' | 'styles' | 'allowClear' | 'variant'>;
export type ButtonConfig = ComponentStyleConfig & export type ButtonConfig = ComponentStyleConfig &
Pick<ButtonProps, 'classNames' | 'styles' | 'autoInsertSpace' | 'variant' | 'color'>; Pick<ButtonProps, 'classNames' | 'styles' | 'autoInsertSpace' | 'variant' | 'color' | 'shape'>;
export type NotificationConfig = ComponentStyleConfig & Pick<ArgsProps, 'closeIcon'>; export type NotificationConfig = ComponentStyleConfig & Pick<ArgsProps, 'closeIcon'>;
@ -226,6 +227,8 @@ export interface ListConfig extends ComponentStyleConfig {
item?: Pick<ListItemProps, 'classNames' | 'styles'>; item?: Pick<ListItemProps, 'classNames' | 'styles'>;
} }
export type UploadConfig = ComponentStyleConfig & Pick<UploadProps, 'customRequest'>;
export const Variants = ['outlined', 'borderless', 'filled', 'underlined'] as const; export const Variants = ['outlined', 'borderless', 'filled', 'underlined'] as const;
export type Variant = (typeof Variants)[number]; export type Variant = (typeof Variants)[number];
@ -300,7 +303,7 @@ export interface ConfigComponentProps {
tooltip?: TooltipConfig; tooltip?: TooltipConfig;
popover?: PopoverConfig; popover?: PopoverConfig;
popconfirm?: PopconfirmConfig; popconfirm?: PopconfirmConfig;
upload?: ComponentStyleConfig; upload?: UploadConfig;
notification?: NotificationConfig; notification?: NotificationConfig;
tree?: ComponentStyleConfig; tree?: ComponentStyleConfig;
colorPicker?: ComponentStyleConfig; colorPicker?: ComponentStyleConfig;

View file

@ -113,7 +113,7 @@ const {
| avatar | Set Avatar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | avatar | Set Avatar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| badge | Set Badge common props | { className?: string, style?: React.CSSProperties, classNames?: [BadgeProps\["classNames"\]](/components/badge#api), styles?: [BadgeProps\["styles"\]](/components/badge#api) } | - | 5.7.0 | | badge | Set Badge common props | { className?: string, style?: React.CSSProperties, classNames?: [BadgeProps\["classNames"\]](/components/badge#api), styles?: [BadgeProps\["styles"\]](/components/badge#api) } | - | 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?: [ButtonProps\["classNames"\]](/components/button#api), styles?: [ButtonProps\["styles"\]](/components/button#api), autoInsertSpace?: boolean, variant?: ButtonVariantType, color?: ButtonColorType } | - | 5.6.0, `autoInsertSpace`: 5.17.0, `variant` and `color`: 5.25.0 | | button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: [ButtonProps\["classNames"\]](/components/button#api), styles?: [ButtonProps\["styles"\]](/components/button#api), autoInsertSpace?: boolean, variant?: ButtonVariantType, color?: ButtonColorType, shape?: [ButtonProps\["shape"\]](/components/button#api) } | - | 5.6.0, `autoInsertSpace`: 5.17.0, `variant` and `color`: 5.25.0, `shape`: 5.27.0 |
| card | Set Card common props | { className?: string, style?: React.CSSProperties, classNames?: [CardProps\["classNames"\]](/components/card#api), styles?: [CardProps\["styles"\]](/components/card#api) } | - | 5.7.0, `classNames` and `styles`: 5.14.0 | | card | Set Card common props | { className?: string, style?: React.CSSProperties, classNames?: [CardProps\["classNames"\]](/components/card#api), styles?: [CardProps\["styles"\]](/components/card#api) } | - | 5.7.0, `classNames` and `styles`: 5.14.0 |
| calendar | Set Calendar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | calendar | Set Calendar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| carousel | Set Carousel common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | carousel | Set Carousel common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
@ -169,7 +169,7 @@ const {
| tree | Set Tree common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | tree | Set Tree common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api) } | - | 5.25.0 | | treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api) } | - | 5.25.0 |
| typography | Set Typography common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | typography | Set Typography common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| upload | Set Upload common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | upload | Set Upload common props | { className?: string, style?: React.CSSProperties, customRequest?: [Upload\["customRequest"\]](/components/upload#api) } | - | 5.7.0, `customRequest`: 5.27.0 |
| wave | Config wave effect | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 | | wave | Config wave effect | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |
## FAQ ## FAQ

View file

@ -58,6 +58,7 @@ import type {
TourConfig, TourConfig,
TransferConfig, TransferConfig,
TreeSelectConfig, TreeSelectConfig,
UploadConfig,
Variant, Variant,
WaveConfig, WaveConfig,
} from './context'; } from './context';
@ -226,7 +227,7 @@ export interface ConfigProviderProps {
tabs?: TabsConfig; tabs?: TabsConfig;
timeline?: ComponentStyleConfig; timeline?: ComponentStyleConfig;
timePicker?: TimePickerConfig; timePicker?: TimePickerConfig;
upload?: ComponentStyleConfig; upload?: UploadConfig;
notification?: NotificationConfig; notification?: NotificationConfig;
tree?: ComponentStyleConfig; tree?: ComponentStyleConfig;
colorPicker?: ComponentStyleConfig; colorPicker?: ComponentStyleConfig;

View file

@ -115,7 +115,7 @@ const {
| avatar | 设置 Avatar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | avatar | 设置 Avatar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| badge | 设置 Badge 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [BadgeProps\["classNames"\]](/components/badge-cn#api), styles?: [BadgeProps\["styles"\]](/components/badge-cn#api) } | - | 5.7.0 | | badge | 设置 Badge 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [BadgeProps\["classNames"\]](/components/badge-cn#api), styles?: [BadgeProps\["styles"\]](/components/badge-cn#api) } | - | 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?: [ButtonProps\["classNames"\]](/components/button-cn#api), styles?: [ButtonProps\["styles"\]](/components/button-cn#api), autoInsertSpace?: boolean, variant?: ButtonVariantType, color?: ButtonColorType } | - | 5.6.0, `autoInsertSpace`: 5.17.0, `variant``color`: 5.25.0 | | button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [ButtonProps\["classNames"\]](/components/button-cn#api), styles?: [ButtonProps\["styles"\]](/components/button-cn#api), autoInsertSpace?: boolean, variant?: ButtonVariantType, color?: ButtonColorType, shape?: [ButtonProps\["shape"\]](/components/button-cn#api) } | - | 5.6.0, `autoInsertSpace`: 5.17.0, `variant``color`: 5.25.0, `shape`: 5.27.0 |
| calendar | 设置 Calendar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | calendar | 设置 Calendar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| card | 设置 Card 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [CardProps\["classNames"\]](/components/card-cn#api), styles?: [CardProps\["styles"\]](/components/card-cn#api) } | - | 5.7.0, `classNames``styles`: 5.14.0 | | card | 设置 Card 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [CardProps\["classNames"\]](/components/card-cn#api), styles?: [CardProps\["styles"\]](/components/card-cn#api) } | - | 5.7.0, `classNames``styles`: 5.14.0 |
| carousel | 设置 Carousel 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | carousel | 设置 Carousel 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
@ -171,7 +171,7 @@ const {
| tree | 设置 Tree 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | tree | 设置 Tree 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api) } | - | 5.25.0 | | treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api) } | - | 5.25.0 |
| typography | 设置 Typography 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | typography | 设置 Typography 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| upload | 设置 Upload 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | upload | 设置 Upload 组件的通用属性 | { className?: string, style?: React.CSSProperties, customRequest?: [Upload\["customRequest"\]](/components/upload-cn#api) } | - | 5.7.0, `customRequest`: 5.27.0 |
| wave | 设置水波纹特效 | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 | | wave | 设置水波纹特效 | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |
## FAQ ## FAQ

View file

@ -25,6 +25,10 @@ export interface PasswordProps extends InputProps {
readonly inputPrefixCls?: string; readonly inputPrefixCls?: string;
readonly action?: 'click' | 'hover'; readonly action?: 'click' | 'hover';
visibilityToggle?: boolean | VisibilityToggle; visibilityToggle?: boolean | VisibilityToggle;
/**
* @since 5.27.0
*/
suffix?: React.ReactNode;
iconRender?: (visible: boolean) => React.ReactNode; iconRender?: (visible: boolean) => React.ReactNode;
} }
@ -41,6 +45,7 @@ const Password = React.forwardRef<InputRef, PasswordProps>((props, ref) => {
action = 'click', action = 'click',
visibilityToggle = true, visibilityToggle = true,
iconRender = defaultIconRender, iconRender = defaultIconRender,
suffix,
} = props; } = props;
// ===================== Disabled ===================== // ===================== Disabled =====================
@ -126,7 +131,12 @@ const Password = React.forwardRef<InputRef, PasswordProps>((props, ref) => {
type: visible ? 'text' : 'password', type: visible ? 'text' : 'password',
className: inputClassName, className: inputClassName,
prefixCls: inputPrefixCls, prefixCls: inputPrefixCls,
suffix: suffixIcon, suffix: (
<>
{suffixIcon}
{suffix}
</>
),
}; };
if (size) { if (size) {

View file

@ -7,6 +7,7 @@ import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest'; import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils'; import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import Password from '../Password'; import Password from '../Password';
import { LockOutlined } from '@ant-design/icons';
describe('Input.Password', () => { describe('Input.Password', () => {
focusTest(Input.Password, { refFocus: true }); focusTest(Input.Password, { refFocus: true });
@ -153,4 +154,16 @@ describe('Input.Password', () => {
fireEvent.click(container.querySelector('.ant-input-password-icon')!); fireEvent.click(container.querySelector('.ant-input-password-icon')!);
expect(handlePasswordVisibleChange).toHaveBeenCalledTimes(2); expect(handlePasswordVisibleChange).toHaveBeenCalledTimes(2);
}); });
it('should support suffix', () => {
const { container } = render(<Input.Password suffix={<LockOutlined />} />);
expect(container.querySelector('.anticon')).toBeTruthy();
});
it('should support custom icon by suffix', () => {
const { container } = render(
<Input.Password suffix={<div className="custom-icon">custom icon</div>} />,
);
expect(container.querySelector('.custom-icon')).toBeTruthy();
});
}); });

View file

@ -11300,6 +11300,64 @@ Array [
RMB RMB
</span> </span>
</span>, </span>,
<br />,
<br />,
<span
class="ant-input-affix-wrapper ant-input-outlined ant-input-password"
>
<input
class="ant-input"
placeholder="input password support suffix"
type="password"
value=""
/>
<span
class="ant-input-suffix"
>
<span
aria-label="eye-invisible"
class="anticon anticon-eye-invisible ant-input-password-icon"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="eye-invisible"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
/>
<path
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
/>
</svg>
</span>
<span
aria-label="lock"
class="anticon anticon-lock"
role="img"
>
<svg
aria-hidden="true"
data-icon="lock"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 10-56 0z"
/>
</svg>
</span>
</span>
</span>,
] ]
`; `;

View file

@ -4622,6 +4622,64 @@ Array [
RMB RMB
</span> </span>
</span>, </span>,
<br />,
<br />,
<span
class="ant-input-affix-wrapper ant-input-outlined ant-input-password"
>
<input
class="ant-input"
placeholder="input password support suffix"
type="password"
value=""
/>
<span
class="ant-input-suffix"
>
<span
aria-label="eye-invisible"
class="anticon anticon-eye-invisible ant-input-password-icon"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="eye-invisible"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
/>
<path
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
/>
</svg>
</span>
<span
aria-label="lock"
class="anticon anticon-lock"
role="img"
>
<svg
aria-hidden="true"
data-icon="lock"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 10-56 0z"
/>
</svg>
</span>
</span>
</span>,
] ]
`; `;

View file

@ -1,7 +1,7 @@
## zh-CN ## zh-CN
在输入框上添加前缀或后缀图标。 在输入框上添加前缀或后缀图标。注意Input.Password 的 `suffix` 属性在 `>=5.27.0` 版本支持。
## en-US ## en-US
Add a prefix or suffix icons inside input. Add a prefix or suffix icons inside input. Note: The `suffix` prop for Input.Password is supported starting from version `5.27.0`.

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { InfoCircleOutlined, UserOutlined } from '@ant-design/icons'; import { InfoCircleOutlined, UserOutlined, LockOutlined } from '@ant-design/icons';
import { Input, Tooltip } from 'antd'; import { Input, Tooltip } from 'antd';
const App: React.FC = () => ( const App: React.FC = () => (
@ -19,6 +19,12 @@ const App: React.FC = () => (
<br /> <br />
<br /> <br />
<Input prefix="¥" suffix="RMB" disabled /> <Input prefix="¥" suffix="RMB" disabled />
<br />
<br />
<Input.Password
suffix={<LockOutlined />} // `suffix` available since `5.27.0`
placeholder="input password support suffix"
/>
</> </>
); );

View file

@ -7,6 +7,8 @@ import classNames from 'classnames';
import useEvent from 'rc-util/lib/hooks/useEvent'; import useEvent from 'rc-util/lib/hooks/useEvent';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect'; import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
export type ShowCollapsibleIconMode = boolean | 'auto';
export interface SplitBarProps { export interface SplitBarProps {
index: number; index: number;
active: boolean; active: boolean;
@ -14,6 +16,8 @@ export interface SplitBarProps {
resizable: boolean; resizable: boolean;
startCollapsible: boolean; startCollapsible: boolean;
endCollapsible: boolean; endCollapsible: boolean;
showStartCollapsibleIcon: ShowCollapsibleIconMode;
showEndCollapsibleIcon: ShowCollapsibleIconMode;
onOffsetStart: (index: number) => void; onOffsetStart: (index: number) => void;
onOffsetUpdate: (index: number, offsetX: number, offsetY: number, lazyEnd?: boolean) => void; onOffsetUpdate: (index: number, offsetX: number, offsetY: number, lazyEnd?: boolean) => void;
onOffsetEnd: (lazyEnd?: boolean) => void; onOffsetEnd: (lazyEnd?: boolean) => void;
@ -48,6 +52,8 @@ const SplitBar: React.FC<SplitBarProps> = (props) => {
onCollapse, onCollapse,
lazy, lazy,
containerSize, containerSize,
showStartCollapsibleIcon,
showEndCollapsibleIcon,
} = props; } = props;
const splitBarPrefixCls = `${prefixCls}-bar`; const splitBarPrefixCls = `${prefixCls}-bar`;
@ -99,6 +105,17 @@ const SplitBar: React.FC<SplitBarProps> = (props) => {
onOffsetEnd(true); onOffsetEnd(true);
}); });
const getVisibilityClass = (mode: ShowCollapsibleIconMode): string => {
switch (mode) {
case true:
return `${splitBarPrefixCls}-collapse-bar-always-visible`;
case false:
return `${splitBarPrefixCls}-collapse-bar-always-hidden`;
case 'auto':
return `${splitBarPrefixCls}-collapse-bar-hover-only`;
}
};
useLayoutEffect(() => { useLayoutEffect(() => {
if (!startPos) { if (!startPos) {
return; return;
@ -205,6 +222,7 @@ const SplitBar: React.FC<SplitBarProps> = (props) => {
className={classNames( className={classNames(
`${splitBarPrefixCls}-collapse-bar`, `${splitBarPrefixCls}-collapse-bar`,
`${splitBarPrefixCls}-collapse-bar-start`, `${splitBarPrefixCls}-collapse-bar-start`,
getVisibilityClass(showStartCollapsibleIcon),
)} )}
onClick={() => onCollapse(index, 'start')} onClick={() => onCollapse(index, 'start')}
> >
@ -223,6 +241,7 @@ const SplitBar: React.FC<SplitBarProps> = (props) => {
className={classNames( className={classNames(
`${splitBarPrefixCls}-collapse-bar`, `${splitBarPrefixCls}-collapse-bar`,
`${splitBarPrefixCls}-collapse-bar-end`, `${splitBarPrefixCls}-collapse-bar-end`,
getVisibilityClass(showEndCollapsibleIcon),
)} )}
onClick={() => onCollapse(index, 'end')} onClick={() => onCollapse(index, 'end')}
> >

View file

@ -196,6 +196,8 @@ const Splitter: React.FC<React.PropsWithChildren<SplitterProps>> = (props) => {
ariaMax={Math.min(ariaMaxStart, ariaMaxEnd) * 100} ariaMax={Math.min(ariaMaxStart, ariaMaxEnd) * 100}
startCollapsible={resizableInfo.startCollapsible} startCollapsible={resizableInfo.startCollapsible}
endCollapsible={resizableInfo.endCollapsible} endCollapsible={resizableInfo.endCollapsible}
showStartCollapsibleIcon={resizableInfo.showStartCollapsibleIcon}
showEndCollapsibleIcon={resizableInfo.showEndCollapsibleIcon}
onOffsetStart={onInternalResizeStart} onOffsetStart={onInternalResizeStart}
onOffsetUpdate={(index, offsetX, offsetY, lazyEnd) => { onOffsetUpdate={(index, offsetX, offsetY, lazyEnd) => {
let offset = isVertical ? offsetY : offsetX; let offset = isVertical ? offsetY : offsetX;

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`renders components/splitter/demo/collapsible.tsx extend context correctly 1`] = ` exports[`renders components/splitter/demo/collapsible.tsx extend context correctly 1`] = `
<div <div
@ -105,6 +105,170 @@ exports[`renders components/splitter/demo/collapsible.tsx extend context correct
exports[`renders components/splitter/demo/collapsible.tsx extend context correctly 2`] = `[]`; exports[`renders components/splitter/demo/collapsible.tsx extend context correctly 2`] = `[]`;
exports[`renders components/splitter/demo/collapsibleIcon.tsx extend context correctly 1`] = `
<div
class="ant-flex ant-flex-align-stretch ant-flex-vertical"
style="gap: 20px;"
>
<div
class="ant-flex"
style="gap: 5px;"
>
<p>
ShowCollapsibleIcon:
</p>
<div
class="ant-radio-group ant-radio-group-outline"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="auto"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Auto
</span>
</label>
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
>
<span
class="ant-radio ant-wave-target ant-radio-checked"
>
<input
checked=""
class="ant-radio-input"
name="test-id"
type="radio"
value="true"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
True
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="false"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
False
</span>
</label>
</div>
</div>
<div
class="ant-splitter ant-splitter-horizontal"
style="height: 200px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"
>
<div
class="ant-splitter-panel"
style="flex-basis: auto; flex-grow: 1;"
>
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center"
style="height: 100%;"
>
<h5
class="ant-typography ant-typography-secondary"
style="white-space: nowrap;"
>
First
</h5>
</div>
</div>
<div
aria-valuemax="0"
aria-valuemin="0"
aria-valuenow="33"
class="ant-splitter-bar"
role="separator"
>
<div
class="ant-splitter-bar-dragger ant-splitter-bar-dragger-disabled"
/>
</div>
<div
class="ant-splitter-panel"
style="flex-basis: auto; flex-grow: 1;"
>
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center"
style="height: 100%;"
>
<h5
class="ant-typography ant-typography-secondary"
style="white-space: nowrap;"
>
Second
</h5>
</div>
</div>
<div
aria-valuemax="0"
aria-valuemin="0"
aria-valuenow="67"
class="ant-splitter-bar"
role="separator"
>
<div
class="ant-splitter-bar-dragger"
/>
</div>
<div
class="ant-splitter-panel"
style="flex-basis: auto; flex-grow: 1;"
>
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center"
style="height: 100%;"
>
<h5
class="ant-typography ant-typography-secondary"
style="white-space: nowrap;"
>
Third
</h5>
</div>
</div>
</div>
</div>
`;
exports[`renders components/splitter/demo/collapsibleIcon.tsx extend context correctly 2`] = `[]`;
exports[`renders components/splitter/demo/control.tsx extend context correctly 1`] = ` exports[`renders components/splitter/demo/control.tsx extend context correctly 1`] = `
<div <div
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical" class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`renders components/splitter/demo/collapsible.tsx correctly 1`] = ` exports[`renders components/splitter/demo/collapsible.tsx correctly 1`] = `
<div <div
@ -103,6 +103,168 @@ exports[`renders components/splitter/demo/collapsible.tsx correctly 1`] = `
</div> </div>
`; `;
exports[`renders components/splitter/demo/collapsibleIcon.tsx correctly 1`] = `
<div
class="ant-flex ant-flex-align-stretch ant-flex-vertical"
style="gap:20px"
>
<div
class="ant-flex"
style="gap:5px"
>
<p>
ShowCollapsibleIcon:
</p>
<div
class="ant-radio-group ant-radio-group-outline"
>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="auto"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
Auto
</span>
</label>
<label
class="ant-radio-wrapper ant-radio-wrapper-checked"
>
<span
class="ant-radio ant-wave-target ant-radio-checked"
>
<input
checked=""
class="ant-radio-input"
name="test-id"
type="radio"
value="true"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
True
</span>
</label>
<label
class="ant-radio-wrapper"
>
<span
class="ant-radio ant-wave-target"
>
<input
class="ant-radio-input"
name="test-id"
type="radio"
value="false"
/>
<span
class="ant-radio-inner"
/>
</span>
<span
class="ant-radio-label"
>
False
</span>
</label>
</div>
</div>
<div
class="ant-splitter ant-splitter-horizontal"
style="height:200px;box-shadow:0 0 10px rgba(0, 0, 0, 0.1)"
>
<div
class="ant-splitter-panel"
style="flex-basis:auto;flex-grow:1"
>
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center"
style="height:100%"
>
<h5
class="ant-typography ant-typography-secondary"
style="white-space:nowrap"
>
First
</h5>
</div>
</div>
<div
aria-valuemax="0"
aria-valuemin="0"
aria-valuenow="33"
class="ant-splitter-bar"
role="separator"
>
<div
class="ant-splitter-bar-dragger ant-splitter-bar-dragger-disabled"
/>
</div>
<div
class="ant-splitter-panel"
style="flex-basis:auto;flex-grow:1"
>
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center"
style="height:100%"
>
<h5
class="ant-typography ant-typography-secondary"
style="white-space:nowrap"
>
Second
</h5>
</div>
</div>
<div
aria-valuemax="0"
aria-valuemin="0"
aria-valuenow="67"
class="ant-splitter-bar"
role="separator"
>
<div
class="ant-splitter-bar-dragger"
/>
</div>
<div
class="ant-splitter-panel"
style="flex-basis:auto;flex-grow:1"
>
<div
class="ant-flex ant-flex-align-center ant-flex-justify-center"
style="height:100%"
>
<h5
class="ant-typography ant-typography-secondary"
style="white-space:nowrap"
>
Third
</h5>
</div>
</div>
</div>
</div>
`;
exports[`renders components/splitter/demo/control.tsx correctly 1`] = ` exports[`renders components/splitter/demo/control.tsx correctly 1`] = `
<div <div
class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical" class="ant-flex ant-flex-align-stretch ant-flex-gap-middle ant-flex-vertical"

View file

@ -450,6 +450,218 @@ describe('Splitter', () => {
expect(onResizeEnd).toHaveBeenCalledWith([40, 0, 60]); expect(onResizeEnd).toHaveBeenCalledWith([40, 0, 60]);
}); });
it('collapsible - showCollapsibleIcon:true', async () => {
const { container, rerender } = render(
<SplitterDemo
items={[
{},
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: true,
},
},
{},
]}
/>,
);
await resizeSplitter();
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-visible'),
).toHaveLength(2);
rerender(
<SplitterDemo
items={[
{},
{
collapsible: {
start: true,
end: false,
showCollapsibleIcon: true,
},
},
{},
]}
/>,
);
await resizeSplitter();
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-visible'),
).toHaveLength(1);
rerender(
<SplitterDemo
items={[
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: true,
},
},
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: true,
},
},
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: true,
},
},
]}
/>,
);
await resizeSplitter();
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-visible'),
).toHaveLength(4);
fireEvent.click(container.querySelectorAll('.ant-splitter-bar-collapse-start')[0]);
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-visible'),
).toHaveLength(3);
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-end')).toHaveLength(2);
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-start')).toHaveLength(1);
fireEvent.click(container.querySelectorAll('.ant-splitter-bar-collapse-end')[0]);
fireEvent.click(container.querySelectorAll('.ant-splitter-bar-collapse-end')[0]);
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-visible'),
).toHaveLength(2);
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-start')).toHaveLength(1);
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-end')).toHaveLength(1);
fireEvent.click(container.querySelectorAll('.ant-splitter-bar-collapse-end')[0]);
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-visible'),
).toHaveLength(4);
});
it('collapsible - showCollapsibleIcon:false', async () => {
const { container, rerender } = render(
<SplitterDemo
items={[
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: false,
},
},
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: false,
},
},
]}
/>,
);
await resizeSplitter();
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-hidden'),
).toHaveLength(2);
rerender(
<SplitterDemo
items={[
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: false,
},
},
{
size: 0,
collapsible: {
start: true,
end: true,
showCollapsibleIcon: false,
},
},
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: false,
},
},
]}
/>,
);
await resizeSplitter();
expect(
container.querySelectorAll('.ant-splitter-bar-collapse-bar-always-hidden'),
).toHaveLength(2);
});
it('collapsible - showCollapsibleIcon:auto', async () => {
// Default: auto
const { container, rerender } = render(
<SplitterDemo
items={[
{},
{
collapsible: true,
},
{},
]}
/>,
);
await resizeSplitter();
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-hover-only')).toHaveLength(
2,
);
rerender(
<SplitterDemo
items={[
{},
{
collapsible: {
start: true,
},
},
{},
]}
/>,
);
await resizeSplitter();
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-hover-only')).toHaveLength(
1,
);
rerender(
<SplitterDemo
items={[
{},
{
collapsible: {
start: true,
end: true,
showCollapsibleIcon: 'auto',
},
},
{},
]}
/>,
);
await resizeSplitter();
expect(container.querySelectorAll('.ant-splitter-bar-collapse-bar-hover-only')).toHaveLength(
2,
);
});
it('both collapsible', async () => { it('both collapsible', async () => {
const onResize = jest.fn(); const onResize = jest.fn();
const onResizeEnd = jest.fn(); const onResizeEnd = jest.fn();

View file

@ -0,0 +1,7 @@
## zh-CN
配置 `collapsible.showCollapsibleIcon` 控制可折叠图标的显示方式。
## en-US
Set `collapsible.showCollapsibleIcon` to control the display mode of collapsible icons.

View file

@ -0,0 +1,51 @@
import React, { useState } from 'react';
import { Flex, Radio, Splitter, Typography } from 'antd';
import type { RadioChangeEvent } from 'antd';
import type { CheckboxGroupProps } from 'antd/es/checkbox';
const Desc: React.FC<Readonly<{ text?: string | number }>> = (props) => (
<Flex justify="center" align="center" style={{ height: '100%' }}>
<Typography.Title type="secondary" level={5} style={{ whiteSpace: 'nowrap' }}>
{props.text}
</Typography.Title>
</Flex>
);
const options: CheckboxGroupProps<'auto' | boolean>['options'] = [
{ label: 'Auto', value: 'auto' },
{ label: 'True', value: true },
{ label: 'False', value: false },
];
const App: React.FC = () => {
const [showIconMode, setShowIconMode] = useState<'auto' | boolean>(true);
const onChange = (e: RadioChangeEvent) => {
setShowIconMode(e.target.value);
};
return (
<Flex vertical gap={20}>
<Flex gap={5}>
<p>ShowCollapsibleIcon: </p>
<Radio.Group options={options} value={showIconMode} onChange={onChange} />
</Flex>
<Splitter style={{ height: 200, boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
<Splitter.Panel
collapsible={{ start: true, end: true, showCollapsibleIcon: showIconMode }}
min="20%"
>
<Desc text="First" />
</Splitter.Panel>
<Splitter.Panel collapsible={{ start: true, end: true, showCollapsibleIcon: showIconMode }}>
<Desc text="Second" />
</Splitter.Panel>
<Splitter.Panel collapsible={{ start: true, end: true, showCollapsibleIcon: showIconMode }}>
<Desc text="Third" />
</Splitter.Panel>
</Splitter>
</Flex>
);
};
export default App;

View file

@ -3,25 +3,31 @@ import toArray from 'rc-util/lib/Children/toArray';
import type { PanelProps } from '../interface'; import type { PanelProps } from '../interface';
function getCollapsible(collapsible?: PanelProps['collapsible']) { export type ItemType = Omit<PanelProps, 'collapsible'> & {
collapsible: {
start?: boolean;
end?: boolean;
showCollapsibleIcon: 'auto' | boolean;
};
};
function getCollapsible(collapsible?: PanelProps['collapsible']): ItemType['collapsible'] {
if (collapsible && typeof collapsible === 'object') { if (collapsible && typeof collapsible === 'object') {
return collapsible; return {
...collapsible,
showCollapsibleIcon:
collapsible.showCollapsibleIcon === undefined ? 'auto' : collapsible.showCollapsibleIcon,
};
} }
const mergedCollapsible = !!collapsible; const mergedCollapsible = !!collapsible;
return { return {
start: mergedCollapsible, start: mergedCollapsible,
end: mergedCollapsible, end: mergedCollapsible,
showCollapsibleIcon: 'auto',
}; };
} }
export type ItemType = Omit<PanelProps, 'collapsible'> & {
collapsible: {
start?: boolean;
end?: boolean;
};
};
/** /**
* Convert `children` into `items`. * Convert `children` into `items`.
*/ */

View file

@ -1,13 +1,37 @@
import * as React from 'react'; import * as React from 'react';
import type { ShowCollapsibleIconMode } from '../SplitBar';
import type { ItemType } from './useItems'; import type { ItemType } from './useItems';
export type ResizableInfo = { export type ResizableInfo = {
resizable: boolean; resizable: boolean;
startCollapsible: boolean; startCollapsible: boolean;
endCollapsible: boolean; endCollapsible: boolean;
showStartCollapsibleIcon: ShowCollapsibleIconMode;
showEndCollapsibleIcon: ShowCollapsibleIconMode;
}; };
type Option = { collapsible: boolean; showCollapsibleIcon: ShowCollapsibleIconMode };
function getShowCollapsibleIcon(prev: Option, next: Option) {
if (prev.collapsible && next.collapsible) {
if (prev.showCollapsibleIcon === true || next.showCollapsibleIcon === true) {
return true;
}
if (prev.showCollapsibleIcon === 'auto' || next.showCollapsibleIcon === 'auto') {
return 'auto';
}
return false;
}
if (prev.collapsible) {
return prev.showCollapsibleIcon;
}
if (next.collapsible) {
return next.showCollapsibleIcon;
}
return false;
}
export default function useResizable(items: ItemType[], pxSizes: number[], isRTL: boolean) { export default function useResizable(items: ItemType[], pxSizes: number[], isRTL: boolean) {
return React.useMemo(() => { return React.useMemo(() => {
const resizeInfos: ResizableInfo[] = []; const resizeInfos: ResizableInfo[] = [];
@ -38,22 +62,42 @@ export default function useResizable(items: ItemType[], pxSizes: number[], isRTL
// Next is not collapsed and limit min size // Next is not collapsed and limit min size
(nextSize !== 0 || !nextMin); (nextSize !== 0 || !nextMin);
const startCollapsible = const prevEndCollapsible = !!prevCollapsible.end && prevSize > 0;
// Self is collapsible const nextStartExpandable = !!nextCollapsible.start && nextSize === 0 && prevSize > 0;
(prevCollapsible.end && prevSize > 0) || const startCollapsible = prevEndCollapsible || nextStartExpandable;
// Collapsed and can be collapsed
(nextCollapsible.start && nextSize === 0 && prevSize > 0);
const endCollapsible = const nextStartCollapsible = !!nextCollapsible.start && nextSize > 0;
// Self is collapsible const prevEndExpandable = !!prevCollapsible.end && prevSize === 0 && nextSize > 0;
(nextCollapsible.start && nextSize > 0) || const endCollapsible = nextStartCollapsible || prevEndExpandable;
// Collapsed and can be collapsed
(prevCollapsible.end && prevSize === 0 && nextSize > 0); const showStartCollapsibleIcon = getShowCollapsibleIcon(
{
collapsible: prevEndCollapsible,
showCollapsibleIcon: prevCollapsible.showCollapsibleIcon,
},
{
collapsible: nextStartExpandable,
showCollapsibleIcon: nextCollapsible.showCollapsibleIcon,
},
);
const showEndCollapsibleIcon = getShowCollapsibleIcon(
{
collapsible: nextStartCollapsible,
showCollapsibleIcon: nextCollapsible.showCollapsibleIcon,
},
{
collapsible: prevEndExpandable,
showCollapsibleIcon: prevCollapsible.showCollapsibleIcon,
},
);
resizeInfos[i] = { resizeInfos[i] = {
resizable: mergedResizable, resizable: mergedResizable,
startCollapsible: !!(isRTL ? endCollapsible : startCollapsible), startCollapsible: !!(isRTL ? endCollapsible : startCollapsible),
endCollapsible: !!(isRTL ? startCollapsible : endCollapsible), endCollapsible: !!(isRTL ? startCollapsible : endCollapsible),
showStartCollapsibleIcon: isRTL ? showEndCollapsibleIcon : showStartCollapsibleIcon,
showEndCollapsibleIcon: isRTL ? showStartCollapsibleIcon : showEndCollapsibleIcon,
}; };
} }

View file

@ -21,6 +21,9 @@ Can be used to separate areas horizontally or vertically. When you need to freel
<code src="./demo/control.tsx">Control mode</code> <code src="./demo/control.tsx">Control mode</code>
<code src="./demo/vertical.tsx">Vertical</code> <code src="./demo/vertical.tsx">Vertical</code>
<code src="./demo/collapsible.tsx">Collapsible</code> <code src="./demo/collapsible.tsx">Collapsible</code>
<code src="./demo/collapsibleIcon.tsx" version="5.27.0">
Control collapsible icons
</code>
<code src="./demo/multiple.tsx">Multiple panels</code> <code src="./demo/multiple.tsx">Multiple panels</code>
<code src="./demo/group.tsx">Complex combination</code> <code src="./demo/group.tsx">Complex combination</code>
<code src="./demo/nested-in-tabs.tsx" debug>Nested in tabs</code> <code src="./demo/nested-in-tabs.tsx" debug>Nested in tabs</code>
@ -51,7 +54,7 @@ Common props ref[Common props](/docs/react/common-props)
| min | Minimum threshold support number for px or 'percent%' usage | `number \| string` | - | - | | min | Minimum threshold support number for px or 'percent%' usage | `number \| string` | - | - |
| max | Maximum threshold support number for px or 'percent%' usage | `number \| string` | - | - | | max | Maximum threshold support number for px or 'percent%' usage | `number \| string` | - | - |
| size | Controlled panel size support number for px or 'percent%' usage | `number \| string` | - | - | | size | Controlled panel size support number for px or 'percent%' usage | `number \| string` | - | - |
| collapsible | Quick folding | `boolean \| { start?: boolean; end?: boolean }` | `false` | - | | collapsible | Quick folding | `boolean \| { start?: boolean; end?: boolean; showCollapsibleIcon?: boolean \| 'auto' }` | `false` | showCollapsibleIcon: 5.27.0 |
| resizable | Whether to enable drag and drop | `boolean` | `true` | - | | resizable | Whether to enable drag and drop | `boolean` | `true` | - |
## Design Token ## Design Token

View file

@ -24,6 +24,7 @@ tag: 5.21.0
<code src="./demo/control.tsx">受控模式</code> <code src="./demo/control.tsx">受控模式</code>
<code src="./demo/vertical.tsx">垂直方向</code> <code src="./demo/vertical.tsx">垂直方向</code>
<code src="./demo/collapsible.tsx">可折叠</code> <code src="./demo/collapsible.tsx">可折叠</code>
<code src="./demo/collapsibleIcon.tsx" version="5.27.0">可折叠图标显示</code>
<code src="./demo/multiple.tsx">多面板</code> <code src="./demo/multiple.tsx">多面板</code>
<code src="./demo/group.tsx">复杂组合</code> <code src="./demo/group.tsx">复杂组合</code>
<code src="./demo/nested-in-tabs.tsx" debug>标签页中嵌套</code> <code src="./demo/nested-in-tabs.tsx" debug>标签页中嵌套</code>
@ -54,7 +55,7 @@ tag: 5.21.0
| min | 最小阈值,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - | | min | 最小阈值,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - |
| max | 最大阈值,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - | | max | 最大阈值,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - |
| size | 受控面板大小,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - | | size | 受控面板大小,支持数字 px 或者文字 '百分比%' 类型 | `number \| string` | - | - |
| collapsible | 快速折叠 | `boolean \| { start?: boolean; end?: boolean }` | `false` | - | | collapsible | 快速折叠 | `boolean \| { start?: boolean; end?: boolean; showCollapsibleIcon?: boolean \| 'auto' }` | `false` | showCollapsibleIcon: 5.27.0 |
| resizable | 是否开启拖拽伸缩 | `boolean` | `true` | - | | resizable | 是否开启拖拽伸缩 | `boolean` | `true` | - |
## 主题变量Design Token ## 主题变量Design Token

View file

@ -1,3 +1,5 @@
import type { ShowCollapsibleIconMode } from './SplitBar';
// ================ outside ================ // ================ outside ================
export interface SplitterProps { export interface SplitterProps {
prefixCls?: string; prefixCls?: string;
@ -17,7 +19,9 @@ export interface PanelProps {
min?: number | string; min?: number | string;
max?: number | string; max?: number | string;
size?: number | string; size?: number | string;
collapsible?: boolean | { start?: boolean; end?: boolean }; collapsible?:
| boolean
| { start?: boolean; end?: boolean; showCollapsibleIcon?: ShowCollapsibleIconMode };
resizable?: boolean; resizable?: boolean;
defaultSize?: number | string; defaultSize?: number | string;
} }

View file

@ -185,10 +185,6 @@ const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): C
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
'@media(hover:none)': {
opacity: 1,
},
// Hover // Hover
'&:hover': { '&:hover': {
background: controlItemBgActive, background: controlItemBgActive,
@ -200,13 +196,25 @@ const genSplitterStyle: GenerateStyle<SplitterToken> = (token: SplitterToken): C
}, },
}, },
// ======================== Status ========================
// Hover
'&:hover, &:active': { '&:hover, &:active': {
[`${splitBarCls}-collapse-bar`]: { [`${splitBarCls}-collapse-bar-hover-only`]: {
opacity: 1, opacity: 1,
}, },
}, },
[`${splitBarCls}-collapse-bar-hover-only`]: {
'@media(hover:none)': {
opacity: 1,
},
},
[`${splitBarCls}-collapse-bar-always-hidden`]: {
display: 'none',
},
[`${splitBarCls}-collapse-bar-always-visible`]: {
opacity: 1,
},
}, },
// =========================== Mask ========================= // =========================== Mask =========================

View file

@ -15,6 +15,10 @@ export interface CheckableTagProps {
*/ */
checked: boolean; checked: boolean;
children?: React.ReactNode; children?: React.ReactNode;
/**
* @since 5.27.0
*/
icon?: React.ReactNode;
onChange?: (checked: boolean) => void; onChange?: (checked: boolean) => void;
onClick?: (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => void; onClick?: (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => void;
} }
@ -25,6 +29,8 @@ const CheckableTag = React.forwardRef<HTMLSpanElement, CheckableTagProps>((props
style, style,
className, className,
checked, checked,
children,
icon,
onChange, onChange,
onClick, onClick,
...restProps ...restProps
@ -59,7 +65,10 @@ const CheckableTag = React.forwardRef<HTMLSpanElement, CheckableTagProps>((props
style={{ ...style, ...tag?.style }} style={{ ...style, ...tag?.style }}
className={cls} className={cls}
onClick={handleClick} onClick={handleClick}
/>, >
{icon}
<span>{children}</span>
</span>,
); );
}); });

View file

@ -540,22 +540,30 @@ exports[`renders components/tag/demo/checkable.tsx extend context correctly 1`]
<span <span
class="ant-tag ant-tag-checkable ant-tag-checkable-checked" class="ant-tag ant-tag-checkable ant-tag-checkable-checked"
> >
Movies <span>
Movies
</span>
</span> </span>
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Books <span>
Books
</span>
</span> </span>
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Music <span>
Music
</span>
</span> </span>
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Sports <span>
Sports
</span>
</span> </span>
</div> </div>
`; `;
@ -942,119 +950,250 @@ Array [
exports[`renders components/tag/demo/draggable.tsx extend context correctly 2`] = `[]`; exports[`renders components/tag/demo/draggable.tsx extend context correctly 2`] = `[]`;
exports[`renders components/tag/demo/icon.tsx extend context correctly 1`] = ` exports[`renders components/tag/demo/icon.tsx extend context correctly 1`] = `
<div Array [
class="ant-flex ant-flex-wrap-wrap" <div
style="gap: 4px 0;" class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-start"
> role="separator"
<span
class="ant-tag ant-tag-has-color"
style="background-color: rgb(85, 172, 238);"
> >
<span <span
aria-label="twitter" class="ant-divider-inner-text"
class="anticon anticon-twitter"
role="img"
> >
<svg Tag with icon
aria-hidden="true"
data-icon="twitter"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M928 254.3c-30.6 13.2-63.9 22.7-98.2 26.4a170.1 170.1 0 0075-94 336.64 336.64 0 01-108.2 41.2A170.1 170.1 0 00672 174c-94.5 0-170.5 76.6-170.5 170.6 0 13.2 1.6 26.4 4.2 39.1-141.5-7.4-267.7-75-351.6-178.5a169.32 169.32 0 00-23.2 86.1c0 59.2 30.1 111.4 76 142.1a172 172 0 01-77.1-21.7v2.1c0 82.9 58.6 151.6 136.7 167.4a180.6 180.6 0 01-44.9 5.8c-11.1 0-21.6-1.1-32.2-2.6C211 652 273.9 701.1 348.8 702.7c-58.6 45.9-132 72.9-211.7 72.9-14.3 0-27.5-.5-41.2-2.1C171.5 822 261.2 850 357.8 850 671.4 850 843 590.2 843 364.7c0-7.4 0-14.8-.5-22.2 33.2-24.3 62.3-54.4 85.5-88.2z"
/>
</svg>
</span> </span>
<span> </div>,
Twitter <div
</span> class="ant-flex ant-flex-wrap-wrap ant-flex-align-center"
</span> style="gap: 4px 0;"
<span
class="ant-tag ant-tag-has-color"
style="background-color: rgb(205, 32, 31);"
> >
<span <span
aria-label="youtube" class="ant-tag ant-tag-has-color"
class="anticon anticon-youtube" style="background-color: rgb(85, 172, 238);"
role="img"
> >
<svg <span
aria-hidden="true" aria-label="twitter"
data-icon="youtube" class="anticon anticon-twitter"
fill="currentColor" role="img"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
> >
<path <svg
d="M960 509.2c0-2.2 0-4.7-.1-7.6-.1-8.1-.3-17.2-.5-26.9-.8-27.9-2.2-55.7-4.4-81.9-3-36.1-7.4-66.2-13.4-88.8a139.52 139.52 0 00-98.3-98.5c-28.3-7.6-83.7-12.3-161.7-15.2-37.1-1.4-76.8-2.3-116.5-2.8-13.9-.2-26.8-.3-38.4-.4h-29.4c-11.6.1-24.5.2-38.4.4-39.7.5-79.4 1.4-116.5 2.8-78 3-133.5 7.7-161.7 15.2A139.35 139.35 0 0082.4 304C76.3 326.6 72 356.7 69 392.8c-2.2 26.2-3.6 54-4.4 81.9-.3 9.7-.4 18.8-.5 26.9 0 2.9-.1 5.4-.1 7.6v5.6c0 2.2 0 4.7.1 7.6.1 8.1.3 17.2.5 26.9.8 27.9 2.2 55.7 4.4 81.9 3 36.1 7.4 66.2 13.4 88.8 12.8 47.9 50.4 85.7 98.3 98.5 28.2 7.6 83.7 12.3 161.7 15.2 37.1 1.4 76.8 2.3 116.5 2.8 13.9.2 26.8.3 38.4.4h29.4c11.6-.1 24.5-.2 38.4-.4 39.7-.5 79.4-1.4 116.5-2.8 78-3 133.5-7.7 161.7-15.2 47.9-12.8 85.5-50.5 98.3-98.5 6.1-22.6 10.4-52.7 13.4-88.8 2.2-26.2 3.6-54 4.4-81.9.3-9.7.4-18.8.5-26.9 0-2.9.1-5.4.1-7.6v-5.6zm-72 5.2c0 2.1 0 4.4-.1 7.1-.1 7.8-.3 16.4-.5 25.7-.7 26.6-2.1 53.2-4.2 77.9-2.7 32.2-6.5 58.6-11.2 76.3-6.2 23.1-24.4 41.4-47.4 47.5-21 5.6-73.9 10.1-145.8 12.8-36.4 1.4-75.6 2.3-114.7 2.8-13.7.2-26.4.3-37.8.3h-28.6l-37.8-.3c-39.1-.5-78.2-1.4-114.7-2.8-71.9-2.8-124.9-7.2-145.8-12.8-23-6.2-41.2-24.4-47.4-47.5-4.7-17.7-8.5-44.1-11.2-76.3-2.1-24.7-3.4-51.3-4.2-77.9-.3-9.3-.4-18-.5-25.7 0-2.7-.1-5.1-.1-7.1v-4.8c0-2.1 0-4.4.1-7.1.1-7.8.3-16.4.5-25.7.7-26.6 2.1-53.2 4.2-77.9 2.7-32.2 6.5-58.6 11.2-76.3 6.2-23.1 24.4-41.4 47.4-47.5 21-5.6 73.9-10.1 145.8-12.8 36.4-1.4 75.6-2.3 114.7-2.8 13.7-.2 26.4-.3 37.8-.3h28.6l37.8.3c39.1.5 78.2 1.4 114.7 2.8 71.9 2.8 124.9 7.2 145.8 12.8 23 6.2 41.2 24.4 47.4 47.5 4.7 17.7 8.5 44.1 11.2 76.3 2.1 24.7 3.4 51.3 4.2 77.9.3 9.3.4 18 .5 25.7 0 2.7.1 5.1.1 7.1v4.8zM423 646l232-135-232-133z" aria-hidden="true"
/> data-icon="twitter"
</svg> fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M928 254.3c-30.6 13.2-63.9 22.7-98.2 26.4a170.1 170.1 0 0075-94 336.64 336.64 0 01-108.2 41.2A170.1 170.1 0 00672 174c-94.5 0-170.5 76.6-170.5 170.6 0 13.2 1.6 26.4 4.2 39.1-141.5-7.4-267.7-75-351.6-178.5a169.32 169.32 0 00-23.2 86.1c0 59.2 30.1 111.4 76 142.1a172 172 0 01-77.1-21.7v2.1c0 82.9 58.6 151.6 136.7 167.4a180.6 180.6 0 01-44.9 5.8c-11.1 0-21.6-1.1-32.2-2.6C211 652 273.9 701.1 348.8 702.7c-58.6 45.9-132 72.9-211.7 72.9-14.3 0-27.5-.5-41.2-2.1C171.5 822 261.2 850 357.8 850 671.4 850 843 590.2 843 364.7c0-7.4 0-14.8-.5-22.2 33.2-24.3 62.3-54.4 85.5-88.2z"
/>
</svg>
</span>
<span>
Twitter
</span>
</span> </span>
<span> <span
Youtube class="ant-tag ant-tag-has-color"
style="background-color: rgb(205, 32, 31);"
>
<span
aria-label="youtube"
class="anticon anticon-youtube"
role="img"
>
<svg
aria-hidden="true"
data-icon="youtube"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M960 509.2c0-2.2 0-4.7-.1-7.6-.1-8.1-.3-17.2-.5-26.9-.8-27.9-2.2-55.7-4.4-81.9-3-36.1-7.4-66.2-13.4-88.8a139.52 139.52 0 00-98.3-98.5c-28.3-7.6-83.7-12.3-161.7-15.2-37.1-1.4-76.8-2.3-116.5-2.8-13.9-.2-26.8-.3-38.4-.4h-29.4c-11.6.1-24.5.2-38.4.4-39.7.5-79.4 1.4-116.5 2.8-78 3-133.5 7.7-161.7 15.2A139.35 139.35 0 0082.4 304C76.3 326.6 72 356.7 69 392.8c-2.2 26.2-3.6 54-4.4 81.9-.3 9.7-.4 18.8-.5 26.9 0 2.9-.1 5.4-.1 7.6v5.6c0 2.2 0 4.7.1 7.6.1 8.1.3 17.2.5 26.9.8 27.9 2.2 55.7 4.4 81.9 3 36.1 7.4 66.2 13.4 88.8 12.8 47.9 50.4 85.7 98.3 98.5 28.2 7.6 83.7 12.3 161.7 15.2 37.1 1.4 76.8 2.3 116.5 2.8 13.9.2 26.8.3 38.4.4h29.4c11.6-.1 24.5-.2 38.4-.4 39.7-.5 79.4-1.4 116.5-2.8 78-3 133.5-7.7 161.7-15.2 47.9-12.8 85.5-50.5 98.3-98.5 6.1-22.6 10.4-52.7 13.4-88.8 2.2-26.2 3.6-54 4.4-81.9.3-9.7.4-18.8.5-26.9 0-2.9.1-5.4.1-7.6v-5.6zm-72 5.2c0 2.1 0 4.4-.1 7.1-.1 7.8-.3 16.4-.5 25.7-.7 26.6-2.1 53.2-4.2 77.9-2.7 32.2-6.5 58.6-11.2 76.3-6.2 23.1-24.4 41.4-47.4 47.5-21 5.6-73.9 10.1-145.8 12.8-36.4 1.4-75.6 2.3-114.7 2.8-13.7.2-26.4.3-37.8.3h-28.6l-37.8-.3c-39.1-.5-78.2-1.4-114.7-2.8-71.9-2.8-124.9-7.2-145.8-12.8-23-6.2-41.2-24.4-47.4-47.5-4.7-17.7-8.5-44.1-11.2-76.3-2.1-24.7-3.4-51.3-4.2-77.9-.3-9.3-.4-18-.5-25.7 0-2.7-.1-5.1-.1-7.1v-4.8c0-2.1 0-4.4.1-7.1.1-7.8.3-16.4.5-25.7.7-26.6 2.1-53.2 4.2-77.9 2.7-32.2 6.5-58.6 11.2-76.3 6.2-23.1 24.4-41.4 47.4-47.5 21-5.6 73.9-10.1 145.8-12.8 36.4-1.4 75.6-2.3 114.7-2.8 13.7-.2 26.4-.3 37.8-.3h28.6l37.8.3c39.1.5 78.2 1.4 114.7 2.8 71.9 2.8 124.9 7.2 145.8 12.8 23 6.2 41.2 24.4 47.4 47.5 4.7 17.7 8.5 44.1 11.2 76.3 2.1 24.7 3.4 51.3 4.2 77.9.3 9.3.4 18 .5 25.7 0 2.7.1 5.1.1 7.1v4.8zM423 646l232-135-232-133z"
/>
</svg>
</span>
<span>
Youtube
</span>
</span> </span>
</span> <span
<span class="ant-tag ant-tag-has-color"
class="ant-tag ant-tag-has-color" style="background-color: rgb(59, 89, 153);"
style="background-color: rgb(59, 89, 153);" >
<span
aria-label="facebook"
class="anticon anticon-facebook"
role="img"
>
<svg
aria-hidden="true"
data-icon="facebook"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-32 736H663.9V602.2h104l15.6-120.7H663.9v-77.1c0-35 9.7-58.8 59.8-58.8h63.9v-108c-11.1-1.5-49-4.8-93.2-4.8-92.2 0-155.3 56.3-155.3 159.6v89H434.9v120.7h104.3V848H176V176h672v672z"
/>
</svg>
</span>
<span>
Facebook
</span>
</span>
<span
class="ant-tag ant-tag-has-color"
style="background-color: rgb(85, 172, 238);"
>
<span
aria-label="linkedin"
class="anticon anticon-linkedin"
role="img"
>
<svg
aria-hidden="true"
data-icon="linkedin"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M847.7 112H176.3c-35.5 0-64.3 28.8-64.3 64.3v671.4c0 35.5 28.8 64.3 64.3 64.3h671.4c35.5 0 64.3-28.8 64.3-64.3V176.3c0-35.5-28.8-64.3-64.3-64.3zm0 736c-447.8-.1-671.7-.2-671.7-.3.1-447.8.2-671.7.3-671.7 447.8.1 671.7.2 671.7.3-.1 447.8-.2 671.7-.3 671.7zM230.6 411.9h118.7v381.8H230.6zm59.4-52.2c37.9 0 68.8-30.8 68.8-68.8a68.8 68.8 0 10-137.6 0c-.1 38 30.7 68.8 68.8 68.8zm252.3 245.1c0-49.8 9.5-98 71.2-98 60.8 0 61.7 56.9 61.7 101.2v185.7h118.6V584.3c0-102.8-22.2-181.9-142.3-181.9-57.7 0-96.4 31.7-112.3 61.7h-1.6v-52.2H423.7v381.8h118.6V604.8z"
/>
</svg>
</span>
<span>
LinkedIn
</span>
</span>
</div>,
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-start"
role="separator"
> >
<span <span
aria-label="facebook" class="ant-divider-inner-text"
class="anticon anticon-facebook"
role="img"
> >
<svg CheckableTag with icon
aria-hidden="true"
data-icon="facebook"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-32 736H663.9V602.2h104l15.6-120.7H663.9v-77.1c0-35 9.7-58.8 59.8-58.8h63.9v-108c-11.1-1.5-49-4.8-93.2-4.8-92.2 0-155.3 56.3-155.3 159.6v89H434.9v120.7h104.3V848H176V176h672v672z"
/>
</svg>
</span> </span>
<span> </div>,
Facebook <div
</span> class="ant-flex ant-flex-wrap-wrap ant-flex-align-center"
</span> style="gap: 4px 0;"
<span
class="ant-tag ant-tag-has-color"
style="background-color: rgb(85, 172, 238);"
> >
<span <span
aria-label="linkedin" class="ant-tag ant-tag-checkable ant-tag-checkable-checked"
class="anticon anticon-linkedin"
role="img"
> >
<svg <span
aria-hidden="true" aria-label="twitter"
data-icon="linkedin" class="anticon anticon-twitter"
fill="currentColor" role="img"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
> >
<path <svg
d="M847.7 112H176.3c-35.5 0-64.3 28.8-64.3 64.3v671.4c0 35.5 28.8 64.3 64.3 64.3h671.4c35.5 0 64.3-28.8 64.3-64.3V176.3c0-35.5-28.8-64.3-64.3-64.3zm0 736c-447.8-.1-671.7-.2-671.7-.3.1-447.8.2-671.7.3-671.7 447.8.1 671.7.2 671.7.3-.1 447.8-.2 671.7-.3 671.7zM230.6 411.9h118.7v381.8H230.6zm59.4-52.2c37.9 0 68.8-30.8 68.8-68.8a68.8 68.8 0 10-137.6 0c-.1 38 30.7 68.8 68.8 68.8zm252.3 245.1c0-49.8 9.5-98 71.2-98 60.8 0 61.7 56.9 61.7 101.2v185.7h118.6V584.3c0-102.8-22.2-181.9-142.3-181.9-57.7 0-96.4 31.7-112.3 61.7h-1.6v-52.2H423.7v381.8h118.6V604.8z" aria-hidden="true"
/> data-icon="twitter"
</svg> fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M928 254.3c-30.6 13.2-63.9 22.7-98.2 26.4a170.1 170.1 0 0075-94 336.64 336.64 0 01-108.2 41.2A170.1 170.1 0 00672 174c-94.5 0-170.5 76.6-170.5 170.6 0 13.2 1.6 26.4 4.2 39.1-141.5-7.4-267.7-75-351.6-178.5a169.32 169.32 0 00-23.2 86.1c0 59.2 30.1 111.4 76 142.1a172 172 0 01-77.1-21.7v2.1c0 82.9 58.6 151.6 136.7 167.4a180.6 180.6 0 01-44.9 5.8c-11.1 0-21.6-1.1-32.2-2.6C211 652 273.9 701.1 348.8 702.7c-58.6 45.9-132 72.9-211.7 72.9-14.3 0-27.5-.5-41.2-2.1C171.5 822 261.2 850 357.8 850 671.4 850 843 590.2 843 364.7c0-7.4 0-14.8-.5-22.2 33.2-24.3 62.3-54.4 85.5-88.2z"
/>
</svg>
</span>
<span>
Twitter
</span>
</span> </span>
<span> <span
LinkedIn class="ant-tag ant-tag-checkable"
>
<span
aria-label="youtube"
class="anticon anticon-youtube"
role="img"
>
<svg
aria-hidden="true"
data-icon="youtube"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M960 509.2c0-2.2 0-4.7-.1-7.6-.1-8.1-.3-17.2-.5-26.9-.8-27.9-2.2-55.7-4.4-81.9-3-36.1-7.4-66.2-13.4-88.8a139.52 139.52 0 00-98.3-98.5c-28.3-7.6-83.7-12.3-161.7-15.2-37.1-1.4-76.8-2.3-116.5-2.8-13.9-.2-26.8-.3-38.4-.4h-29.4c-11.6.1-24.5.2-38.4.4-39.7.5-79.4 1.4-116.5 2.8-78 3-133.5 7.7-161.7 15.2A139.35 139.35 0 0082.4 304C76.3 326.6 72 356.7 69 392.8c-2.2 26.2-3.6 54-4.4 81.9-.3 9.7-.4 18.8-.5 26.9 0 2.9-.1 5.4-.1 7.6v5.6c0 2.2 0 4.7.1 7.6.1 8.1.3 17.2.5 26.9.8 27.9 2.2 55.7 4.4 81.9 3 36.1 7.4 66.2 13.4 88.8 12.8 47.9 50.4 85.7 98.3 98.5 28.2 7.6 83.7 12.3 161.7 15.2 37.1 1.4 76.8 2.3 116.5 2.8 13.9.2 26.8.3 38.4.4h29.4c11.6-.1 24.5-.2 38.4-.4 39.7-.5 79.4-1.4 116.5-2.8 78-3 133.5-7.7 161.7-15.2 47.9-12.8 85.5-50.5 98.3-98.5 6.1-22.6 10.4-52.7 13.4-88.8 2.2-26.2 3.6-54 4.4-81.9.3-9.7.4-18.8.5-26.9 0-2.9.1-5.4.1-7.6v-5.6zm-72 5.2c0 2.1 0 4.4-.1 7.1-.1 7.8-.3 16.4-.5 25.7-.7 26.6-2.1 53.2-4.2 77.9-2.7 32.2-6.5 58.6-11.2 76.3-6.2 23.1-24.4 41.4-47.4 47.5-21 5.6-73.9 10.1-145.8 12.8-36.4 1.4-75.6 2.3-114.7 2.8-13.7.2-26.4.3-37.8.3h-28.6l-37.8-.3c-39.1-.5-78.2-1.4-114.7-2.8-71.9-2.8-124.9-7.2-145.8-12.8-23-6.2-41.2-24.4-47.4-47.5-4.7-17.7-8.5-44.1-11.2-76.3-2.1-24.7-3.4-51.3-4.2-77.9-.3-9.3-.4-18-.5-25.7 0-2.7-.1-5.1-.1-7.1v-4.8c0-2.1 0-4.4.1-7.1.1-7.8.3-16.4.5-25.7.7-26.6 2.1-53.2 4.2-77.9 2.7-32.2 6.5-58.6 11.2-76.3 6.2-23.1 24.4-41.4 47.4-47.5 21-5.6 73.9-10.1 145.8-12.8 36.4-1.4 75.6-2.3 114.7-2.8 13.7-.2 26.4-.3 37.8-.3h28.6l37.8.3c39.1.5 78.2 1.4 114.7 2.8 71.9 2.8 124.9 7.2 145.8 12.8 23 6.2 41.2 24.4 47.4 47.5 4.7 17.7 8.5 44.1 11.2 76.3 2.1 24.7 3.4 51.3 4.2 77.9.3 9.3.4 18 .5 25.7 0 2.7.1 5.1.1 7.1v4.8zM423 646l232-135-232-133z"
/>
</svg>
</span>
<span>
Youtube
</span>
</span> </span>
</span> <span
</div> class="ant-tag ant-tag-checkable"
>
<span
aria-label="facebook"
class="anticon anticon-facebook"
role="img"
>
<svg
aria-hidden="true"
data-icon="facebook"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-32 736H663.9V602.2h104l15.6-120.7H663.9v-77.1c0-35 9.7-58.8 59.8-58.8h63.9v-108c-11.1-1.5-49-4.8-93.2-4.8-92.2 0-155.3 56.3-155.3 159.6v89H434.9v120.7h104.3V848H176V176h672v672z"
/>
</svg>
</span>
<span>
Facebook
</span>
</span>
<span
class="ant-tag ant-tag-checkable"
>
<span
aria-label="linkedin"
class="anticon anticon-linkedin"
role="img"
>
<svg
aria-hidden="true"
data-icon="linkedin"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M847.7 112H176.3c-35.5 0-64.3 28.8-64.3 64.3v671.4c0 35.5 28.8 64.3 64.3 64.3h671.4c35.5 0 64.3-28.8 64.3-64.3V176.3c0-35.5-28.8-64.3-64.3-64.3zm0 736c-447.8-.1-671.7-.2-671.7-.3.1-447.8.2-671.7.3-671.7 447.8.1 671.7.2 671.7.3-.1 447.8-.2 671.7-.3 671.7zM230.6 411.9h118.7v381.8H230.6zm59.4-52.2c37.9 0 68.8-30.8 68.8-68.8a68.8 68.8 0 10-137.6 0c-.1 38 30.7 68.8 68.8 68.8zm252.3 245.1c0-49.8 9.5-98 71.2-98 60.8 0 61.7 56.9 61.7 101.2v185.7h118.6V584.3c0-102.8-22.2-181.9-142.3-181.9-57.7 0-96.4 31.7-112.3 61.7h-1.6v-52.2H423.7v381.8h118.6V604.8z"
/>
</svg>
</span>
<span>
LinkedIn
</span>
</span>
</div>,
]
`; `;
exports[`renders components/tag/demo/icon.tsx extend context correctly 2`] = `[]`; exports[`renders components/tag/demo/icon.tsx extend context correctly 2`] = `[]`;

View file

@ -532,22 +532,30 @@ exports[`renders components/tag/demo/checkable.tsx correctly 1`] = `
<span <span
class="ant-tag ant-tag-checkable ant-tag-checkable-checked" class="ant-tag ant-tag-checkable ant-tag-checkable-checked"
> >
Movies <span>
Movies
</span>
</span> </span>
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Books <span>
Books
</span>
</span> </span>
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Music <span>
Music
</span>
</span> </span>
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
> >
Sports <span>
Sports
</span>
</span> </span>
</div> </div>
`; `;
@ -905,119 +913,250 @@ exports[`renders components/tag/demo/draggable.tsx correctly 1`] = `
`; `;
exports[`renders components/tag/demo/icon.tsx correctly 1`] = ` exports[`renders components/tag/demo/icon.tsx correctly 1`] = `
<div Array [
class="ant-flex ant-flex-wrap-wrap" <div
style="gap:4px 0" class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-start"
> role="separator"
<span
class="ant-tag ant-tag-has-color"
style="background-color:#55acee"
> >
<span <span
aria-label="twitter" class="ant-divider-inner-text"
class="anticon anticon-twitter"
role="img"
> >
<svg Tag with icon
aria-hidden="true"
data-icon="twitter"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M928 254.3c-30.6 13.2-63.9 22.7-98.2 26.4a170.1 170.1 0 0075-94 336.64 336.64 0 01-108.2 41.2A170.1 170.1 0 00672 174c-94.5 0-170.5 76.6-170.5 170.6 0 13.2 1.6 26.4 4.2 39.1-141.5-7.4-267.7-75-351.6-178.5a169.32 169.32 0 00-23.2 86.1c0 59.2 30.1 111.4 76 142.1a172 172 0 01-77.1-21.7v2.1c0 82.9 58.6 151.6 136.7 167.4a180.6 180.6 0 01-44.9 5.8c-11.1 0-21.6-1.1-32.2-2.6C211 652 273.9 701.1 348.8 702.7c-58.6 45.9-132 72.9-211.7 72.9-14.3 0-27.5-.5-41.2-2.1C171.5 822 261.2 850 357.8 850 671.4 850 843 590.2 843 364.7c0-7.4 0-14.8-.5-22.2 33.2-24.3 62.3-54.4 85.5-88.2z"
/>
</svg>
</span> </span>
<span> </div>,
Twitter <div
</span> class="ant-flex ant-flex-wrap-wrap ant-flex-align-center"
</span> style="gap:4px 0"
<span
class="ant-tag ant-tag-has-color"
style="background-color:#cd201f"
> >
<span <span
aria-label="youtube" class="ant-tag ant-tag-has-color"
class="anticon anticon-youtube" style="background-color:#55acee"
role="img"
> >
<svg <span
aria-hidden="true" aria-label="twitter"
data-icon="youtube" class="anticon anticon-twitter"
fill="currentColor" role="img"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
> >
<path <svg
d="M960 509.2c0-2.2 0-4.7-.1-7.6-.1-8.1-.3-17.2-.5-26.9-.8-27.9-2.2-55.7-4.4-81.9-3-36.1-7.4-66.2-13.4-88.8a139.52 139.52 0 00-98.3-98.5c-28.3-7.6-83.7-12.3-161.7-15.2-37.1-1.4-76.8-2.3-116.5-2.8-13.9-.2-26.8-.3-38.4-.4h-29.4c-11.6.1-24.5.2-38.4.4-39.7.5-79.4 1.4-116.5 2.8-78 3-133.5 7.7-161.7 15.2A139.35 139.35 0 0082.4 304C76.3 326.6 72 356.7 69 392.8c-2.2 26.2-3.6 54-4.4 81.9-.3 9.7-.4 18.8-.5 26.9 0 2.9-.1 5.4-.1 7.6v5.6c0 2.2 0 4.7.1 7.6.1 8.1.3 17.2.5 26.9.8 27.9 2.2 55.7 4.4 81.9 3 36.1 7.4 66.2 13.4 88.8 12.8 47.9 50.4 85.7 98.3 98.5 28.2 7.6 83.7 12.3 161.7 15.2 37.1 1.4 76.8 2.3 116.5 2.8 13.9.2 26.8.3 38.4.4h29.4c11.6-.1 24.5-.2 38.4-.4 39.7-.5 79.4-1.4 116.5-2.8 78-3 133.5-7.7 161.7-15.2 47.9-12.8 85.5-50.5 98.3-98.5 6.1-22.6 10.4-52.7 13.4-88.8 2.2-26.2 3.6-54 4.4-81.9.3-9.7.4-18.8.5-26.9 0-2.9.1-5.4.1-7.6v-5.6zm-72 5.2c0 2.1 0 4.4-.1 7.1-.1 7.8-.3 16.4-.5 25.7-.7 26.6-2.1 53.2-4.2 77.9-2.7 32.2-6.5 58.6-11.2 76.3-6.2 23.1-24.4 41.4-47.4 47.5-21 5.6-73.9 10.1-145.8 12.8-36.4 1.4-75.6 2.3-114.7 2.8-13.7.2-26.4.3-37.8.3h-28.6l-37.8-.3c-39.1-.5-78.2-1.4-114.7-2.8-71.9-2.8-124.9-7.2-145.8-12.8-23-6.2-41.2-24.4-47.4-47.5-4.7-17.7-8.5-44.1-11.2-76.3-2.1-24.7-3.4-51.3-4.2-77.9-.3-9.3-.4-18-.5-25.7 0-2.7-.1-5.1-.1-7.1v-4.8c0-2.1 0-4.4.1-7.1.1-7.8.3-16.4.5-25.7.7-26.6 2.1-53.2 4.2-77.9 2.7-32.2 6.5-58.6 11.2-76.3 6.2-23.1 24.4-41.4 47.4-47.5 21-5.6 73.9-10.1 145.8-12.8 36.4-1.4 75.6-2.3 114.7-2.8 13.7-.2 26.4-.3 37.8-.3h28.6l37.8.3c39.1.5 78.2 1.4 114.7 2.8 71.9 2.8 124.9 7.2 145.8 12.8 23 6.2 41.2 24.4 47.4 47.5 4.7 17.7 8.5 44.1 11.2 76.3 2.1 24.7 3.4 51.3 4.2 77.9.3 9.3.4 18 .5 25.7 0 2.7.1 5.1.1 7.1v4.8zM423 646l232-135-232-133z" aria-hidden="true"
/> data-icon="twitter"
</svg> fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M928 254.3c-30.6 13.2-63.9 22.7-98.2 26.4a170.1 170.1 0 0075-94 336.64 336.64 0 01-108.2 41.2A170.1 170.1 0 00672 174c-94.5 0-170.5 76.6-170.5 170.6 0 13.2 1.6 26.4 4.2 39.1-141.5-7.4-267.7-75-351.6-178.5a169.32 169.32 0 00-23.2 86.1c0 59.2 30.1 111.4 76 142.1a172 172 0 01-77.1-21.7v2.1c0 82.9 58.6 151.6 136.7 167.4a180.6 180.6 0 01-44.9 5.8c-11.1 0-21.6-1.1-32.2-2.6C211 652 273.9 701.1 348.8 702.7c-58.6 45.9-132 72.9-211.7 72.9-14.3 0-27.5-.5-41.2-2.1C171.5 822 261.2 850 357.8 850 671.4 850 843 590.2 843 364.7c0-7.4 0-14.8-.5-22.2 33.2-24.3 62.3-54.4 85.5-88.2z"
/>
</svg>
</span>
<span>
Twitter
</span>
</span> </span>
<span> <span
Youtube class="ant-tag ant-tag-has-color"
style="background-color:#cd201f"
>
<span
aria-label="youtube"
class="anticon anticon-youtube"
role="img"
>
<svg
aria-hidden="true"
data-icon="youtube"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M960 509.2c0-2.2 0-4.7-.1-7.6-.1-8.1-.3-17.2-.5-26.9-.8-27.9-2.2-55.7-4.4-81.9-3-36.1-7.4-66.2-13.4-88.8a139.52 139.52 0 00-98.3-98.5c-28.3-7.6-83.7-12.3-161.7-15.2-37.1-1.4-76.8-2.3-116.5-2.8-13.9-.2-26.8-.3-38.4-.4h-29.4c-11.6.1-24.5.2-38.4.4-39.7.5-79.4 1.4-116.5 2.8-78 3-133.5 7.7-161.7 15.2A139.35 139.35 0 0082.4 304C76.3 326.6 72 356.7 69 392.8c-2.2 26.2-3.6 54-4.4 81.9-.3 9.7-.4 18.8-.5 26.9 0 2.9-.1 5.4-.1 7.6v5.6c0 2.2 0 4.7.1 7.6.1 8.1.3 17.2.5 26.9.8 27.9 2.2 55.7 4.4 81.9 3 36.1 7.4 66.2 13.4 88.8 12.8 47.9 50.4 85.7 98.3 98.5 28.2 7.6 83.7 12.3 161.7 15.2 37.1 1.4 76.8 2.3 116.5 2.8 13.9.2 26.8.3 38.4.4h29.4c11.6-.1 24.5-.2 38.4-.4 39.7-.5 79.4-1.4 116.5-2.8 78-3 133.5-7.7 161.7-15.2 47.9-12.8 85.5-50.5 98.3-98.5 6.1-22.6 10.4-52.7 13.4-88.8 2.2-26.2 3.6-54 4.4-81.9.3-9.7.4-18.8.5-26.9 0-2.9.1-5.4.1-7.6v-5.6zm-72 5.2c0 2.1 0 4.4-.1 7.1-.1 7.8-.3 16.4-.5 25.7-.7 26.6-2.1 53.2-4.2 77.9-2.7 32.2-6.5 58.6-11.2 76.3-6.2 23.1-24.4 41.4-47.4 47.5-21 5.6-73.9 10.1-145.8 12.8-36.4 1.4-75.6 2.3-114.7 2.8-13.7.2-26.4.3-37.8.3h-28.6l-37.8-.3c-39.1-.5-78.2-1.4-114.7-2.8-71.9-2.8-124.9-7.2-145.8-12.8-23-6.2-41.2-24.4-47.4-47.5-4.7-17.7-8.5-44.1-11.2-76.3-2.1-24.7-3.4-51.3-4.2-77.9-.3-9.3-.4-18-.5-25.7 0-2.7-.1-5.1-.1-7.1v-4.8c0-2.1 0-4.4.1-7.1.1-7.8.3-16.4.5-25.7.7-26.6 2.1-53.2 4.2-77.9 2.7-32.2 6.5-58.6 11.2-76.3 6.2-23.1 24.4-41.4 47.4-47.5 21-5.6 73.9-10.1 145.8-12.8 36.4-1.4 75.6-2.3 114.7-2.8 13.7-.2 26.4-.3 37.8-.3h28.6l37.8.3c39.1.5 78.2 1.4 114.7 2.8 71.9 2.8 124.9 7.2 145.8 12.8 23 6.2 41.2 24.4 47.4 47.5 4.7 17.7 8.5 44.1 11.2 76.3 2.1 24.7 3.4 51.3 4.2 77.9.3 9.3.4 18 .5 25.7 0 2.7.1 5.1.1 7.1v4.8zM423 646l232-135-232-133z"
/>
</svg>
</span>
<span>
Youtube
</span>
</span> </span>
</span> <span
<span class="ant-tag ant-tag-has-color"
class="ant-tag ant-tag-has-color" style="background-color:#3b5999"
style="background-color:#3b5999" >
<span
aria-label="facebook"
class="anticon anticon-facebook"
role="img"
>
<svg
aria-hidden="true"
data-icon="facebook"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-32 736H663.9V602.2h104l15.6-120.7H663.9v-77.1c0-35 9.7-58.8 59.8-58.8h63.9v-108c-11.1-1.5-49-4.8-93.2-4.8-92.2 0-155.3 56.3-155.3 159.6v89H434.9v120.7h104.3V848H176V176h672v672z"
/>
</svg>
</span>
<span>
Facebook
</span>
</span>
<span
class="ant-tag ant-tag-has-color"
style="background-color:#55acee"
>
<span
aria-label="linkedin"
class="anticon anticon-linkedin"
role="img"
>
<svg
aria-hidden="true"
data-icon="linkedin"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M847.7 112H176.3c-35.5 0-64.3 28.8-64.3 64.3v671.4c0 35.5 28.8 64.3 64.3 64.3h671.4c35.5 0 64.3-28.8 64.3-64.3V176.3c0-35.5-28.8-64.3-64.3-64.3zm0 736c-447.8-.1-671.7-.2-671.7-.3.1-447.8.2-671.7.3-671.7 447.8.1 671.7.2 671.7.3-.1 447.8-.2 671.7-.3 671.7zM230.6 411.9h118.7v381.8H230.6zm59.4-52.2c37.9 0 68.8-30.8 68.8-68.8a68.8 68.8 0 10-137.6 0c-.1 38 30.7 68.8 68.8 68.8zm252.3 245.1c0-49.8 9.5-98 71.2-98 60.8 0 61.7 56.9 61.7 101.2v185.7h118.6V584.3c0-102.8-22.2-181.9-142.3-181.9-57.7 0-96.4 31.7-112.3 61.7h-1.6v-52.2H423.7v381.8h118.6V604.8z"
/>
</svg>
</span>
<span>
LinkedIn
</span>
</span>
</div>,
<div
class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-start"
role="separator"
> >
<span <span
aria-label="facebook" class="ant-divider-inner-text"
class="anticon anticon-facebook"
role="img"
> >
<svg CheckableTag with icon
aria-hidden="true"
data-icon="facebook"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-32 736H663.9V602.2h104l15.6-120.7H663.9v-77.1c0-35 9.7-58.8 59.8-58.8h63.9v-108c-11.1-1.5-49-4.8-93.2-4.8-92.2 0-155.3 56.3-155.3 159.6v89H434.9v120.7h104.3V848H176V176h672v672z"
/>
</svg>
</span> </span>
<span> </div>,
Facebook <div
</span> class="ant-flex ant-flex-wrap-wrap ant-flex-align-center"
</span> style="gap:4px 0"
<span
class="ant-tag ant-tag-has-color"
style="background-color:#55acee"
> >
<span <span
aria-label="linkedin" class="ant-tag ant-tag-checkable ant-tag-checkable-checked"
class="anticon anticon-linkedin"
role="img"
> >
<svg <span
aria-hidden="true" aria-label="twitter"
data-icon="linkedin" class="anticon anticon-twitter"
fill="currentColor" role="img"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
> >
<path <svg
d="M847.7 112H176.3c-35.5 0-64.3 28.8-64.3 64.3v671.4c0 35.5 28.8 64.3 64.3 64.3h671.4c35.5 0 64.3-28.8 64.3-64.3V176.3c0-35.5-28.8-64.3-64.3-64.3zm0 736c-447.8-.1-671.7-.2-671.7-.3.1-447.8.2-671.7.3-671.7 447.8.1 671.7.2 671.7.3-.1 447.8-.2 671.7-.3 671.7zM230.6 411.9h118.7v381.8H230.6zm59.4-52.2c37.9 0 68.8-30.8 68.8-68.8a68.8 68.8 0 10-137.6 0c-.1 38 30.7 68.8 68.8 68.8zm252.3 245.1c0-49.8 9.5-98 71.2-98 60.8 0 61.7 56.9 61.7 101.2v185.7h118.6V584.3c0-102.8-22.2-181.9-142.3-181.9-57.7 0-96.4 31.7-112.3 61.7h-1.6v-52.2H423.7v381.8h118.6V604.8z" aria-hidden="true"
/> data-icon="twitter"
</svg> fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M928 254.3c-30.6 13.2-63.9 22.7-98.2 26.4a170.1 170.1 0 0075-94 336.64 336.64 0 01-108.2 41.2A170.1 170.1 0 00672 174c-94.5 0-170.5 76.6-170.5 170.6 0 13.2 1.6 26.4 4.2 39.1-141.5-7.4-267.7-75-351.6-178.5a169.32 169.32 0 00-23.2 86.1c0 59.2 30.1 111.4 76 142.1a172 172 0 01-77.1-21.7v2.1c0 82.9 58.6 151.6 136.7 167.4a180.6 180.6 0 01-44.9 5.8c-11.1 0-21.6-1.1-32.2-2.6C211 652 273.9 701.1 348.8 702.7c-58.6 45.9-132 72.9-211.7 72.9-14.3 0-27.5-.5-41.2-2.1C171.5 822 261.2 850 357.8 850 671.4 850 843 590.2 843 364.7c0-7.4 0-14.8-.5-22.2 33.2-24.3 62.3-54.4 85.5-88.2z"
/>
</svg>
</span>
<span>
Twitter
</span>
</span> </span>
<span> <span
LinkedIn class="ant-tag ant-tag-checkable"
>
<span
aria-label="youtube"
class="anticon anticon-youtube"
role="img"
>
<svg
aria-hidden="true"
data-icon="youtube"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M960 509.2c0-2.2 0-4.7-.1-7.6-.1-8.1-.3-17.2-.5-26.9-.8-27.9-2.2-55.7-4.4-81.9-3-36.1-7.4-66.2-13.4-88.8a139.52 139.52 0 00-98.3-98.5c-28.3-7.6-83.7-12.3-161.7-15.2-37.1-1.4-76.8-2.3-116.5-2.8-13.9-.2-26.8-.3-38.4-.4h-29.4c-11.6.1-24.5.2-38.4.4-39.7.5-79.4 1.4-116.5 2.8-78 3-133.5 7.7-161.7 15.2A139.35 139.35 0 0082.4 304C76.3 326.6 72 356.7 69 392.8c-2.2 26.2-3.6 54-4.4 81.9-.3 9.7-.4 18.8-.5 26.9 0 2.9-.1 5.4-.1 7.6v5.6c0 2.2 0 4.7.1 7.6.1 8.1.3 17.2.5 26.9.8 27.9 2.2 55.7 4.4 81.9 3 36.1 7.4 66.2 13.4 88.8 12.8 47.9 50.4 85.7 98.3 98.5 28.2 7.6 83.7 12.3 161.7 15.2 37.1 1.4 76.8 2.3 116.5 2.8 13.9.2 26.8.3 38.4.4h29.4c11.6-.1 24.5-.2 38.4-.4 39.7-.5 79.4-1.4 116.5-2.8 78-3 133.5-7.7 161.7-15.2 47.9-12.8 85.5-50.5 98.3-98.5 6.1-22.6 10.4-52.7 13.4-88.8 2.2-26.2 3.6-54 4.4-81.9.3-9.7.4-18.8.5-26.9 0-2.9.1-5.4.1-7.6v-5.6zm-72 5.2c0 2.1 0 4.4-.1 7.1-.1 7.8-.3 16.4-.5 25.7-.7 26.6-2.1 53.2-4.2 77.9-2.7 32.2-6.5 58.6-11.2 76.3-6.2 23.1-24.4 41.4-47.4 47.5-21 5.6-73.9 10.1-145.8 12.8-36.4 1.4-75.6 2.3-114.7 2.8-13.7.2-26.4.3-37.8.3h-28.6l-37.8-.3c-39.1-.5-78.2-1.4-114.7-2.8-71.9-2.8-124.9-7.2-145.8-12.8-23-6.2-41.2-24.4-47.4-47.5-4.7-17.7-8.5-44.1-11.2-76.3-2.1-24.7-3.4-51.3-4.2-77.9-.3-9.3-.4-18-.5-25.7 0-2.7-.1-5.1-.1-7.1v-4.8c0-2.1 0-4.4.1-7.1.1-7.8.3-16.4.5-25.7.7-26.6 2.1-53.2 4.2-77.9 2.7-32.2 6.5-58.6 11.2-76.3 6.2-23.1 24.4-41.4 47.4-47.5 21-5.6 73.9-10.1 145.8-12.8 36.4-1.4 75.6-2.3 114.7-2.8 13.7-.2 26.4-.3 37.8-.3h28.6l37.8.3c39.1.5 78.2 1.4 114.7 2.8 71.9 2.8 124.9 7.2 145.8 12.8 23 6.2 41.2 24.4 47.4 47.5 4.7 17.7 8.5 44.1 11.2 76.3 2.1 24.7 3.4 51.3 4.2 77.9.3 9.3.4 18 .5 25.7 0 2.7.1 5.1.1 7.1v4.8zM423 646l232-135-232-133z"
/>
</svg>
</span>
<span>
Youtube
</span>
</span> </span>
</span> <span
</div> class="ant-tag ant-tag-checkable"
>
<span
aria-label="facebook"
class="anticon anticon-facebook"
role="img"
>
<svg
aria-hidden="true"
data-icon="facebook"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-32 736H663.9V602.2h104l15.6-120.7H663.9v-77.1c0-35 9.7-58.8 59.8-58.8h63.9v-108c-11.1-1.5-49-4.8-93.2-4.8-92.2 0-155.3 56.3-155.3 159.6v89H434.9v120.7h104.3V848H176V176h672v672z"
/>
</svg>
</span>
<span>
Facebook
</span>
</span>
<span
class="ant-tag ant-tag-checkable"
>
<span
aria-label="linkedin"
class="anticon anticon-linkedin"
role="img"
>
<svg
aria-hidden="true"
data-icon="linkedin"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M847.7 112H176.3c-35.5 0-64.3 28.8-64.3 64.3v671.4c0 35.5 28.8 64.3 64.3 64.3h671.4c35.5 0 64.3-28.8 64.3-64.3V176.3c0-35.5-28.8-64.3-64.3-64.3zm0 736c-447.8-.1-671.7-.2-671.7-.3.1-447.8.2-671.7.3-671.7 447.8.1 671.7.2 671.7.3-.1 447.8-.2 671.7-.3 671.7zM230.6 411.9h118.7v381.8H230.6zm59.4-52.2c37.9 0 68.8-30.8 68.8-68.8a68.8 68.8 0 10-137.6 0c-.1 38 30.7 68.8 68.8 68.8zm252.3 245.1c0-49.8 9.5-98 71.2-98 60.8 0 61.7 56.9 61.7 101.2v185.7h118.6V584.3c0-102.8-22.2-181.9-142.3-181.9-57.7 0-96.4 31.7-112.3 61.7h-1.6v-52.2H423.7v381.8h118.6V604.8z"
/>
</svg>
</span>
<span>
LinkedIn
</span>
</span>
</div>,
]
`; `;
exports[`renders components/tag/demo/status.tsx correctly 1`] = ` exports[`renders components/tag/demo/status.tsx correctly 1`] = `

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Tag rtl render component should be rendered correctly in RTL direction 1`] = ` exports[`Tag rtl render component should be rendered correctly in RTL direction 1`] = `
<span <span
@ -9,5 +9,7 @@ exports[`Tag rtl render component should be rendered correctly in RTL direction
exports[`Tag rtl render component should be rendered correctly in RTL direction 2`] = ` exports[`Tag rtl render component should be rendered correctly in RTL direction 2`] = `
<span <span
class="ant-tag ant-tag-checkable" class="ant-tag ant-tag-checkable"
/> >
<span />
</span>
`; `;

View file

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { CheckCircleOutlined } from '@ant-design/icons'; import { CheckCircleOutlined, LinkedinOutlined } from '@ant-design/icons';
import Tag from '..'; import Tag from '..';
import { resetWarned } from '../../_util/warning'; import { resetWarned } from '../../_util/warning';
@ -190,6 +190,21 @@ describe('Tag', () => {
expect(queryTarget?.textContent).toBe('Tag Text'); expect(queryTarget?.textContent).toBe('Tag Text');
expect(refElement).toBe(queryTarget); expect(refElement).toBe(queryTarget);
}); });
it('should render icon', () => {
const { container } = render(<Tag.CheckableTag icon={<LinkedinOutlined />} checked />);
expect(container.querySelector('.anticon')).toBeInTheDocument();
});
it('should render custom icon', () => {
const { container } = render(
<Tag.CheckableTag icon={<div className="custom-icon">custom icon</div>} checked />,
);
expect(container.querySelector('.custom-icon')).toBeInTheDocument();
});
it('not render icon', () => {
const { container } = render(<Tag.CheckableTag checked />);
expect(container.querySelector('.anticon')).not.toBeInTheDocument();
});
}); });
it('should onClick is undefined', async () => { it('should onClick is undefined', async () => {
const { container } = render(<Tag onClick={undefined} />); const { container } = render(<Tag onClick={undefined} />);

View file

@ -1,11 +1,11 @@
## zh-CN ## zh-CN
当需要在 `Tag` 内嵌入 `Icon` 时,可以设置 `icon` 属性,或者直接在 `Tag` 内使用 `Icon` 组件 你可以通过 `icon` 属性为标签添加自定义图标。注意CheckableTag 的 `icon` 属性在 `>=5.27.0` 版本支持
如果想控制 `Icon` 具体的位置,只能直接使用 `Icon` 组件,而非 `icon` 属性 若需要控制图标的位置,请在 `children` 中直接使用 `<XXXIcon />` 组件,而非通过 `icon` 属性实现
## en-US ## en-US
`Tag` components can contain an `Icon`. This is done by setting the `icon` property or placing an `Icon` component within the `Tag`. You can add a custom icon to the tag via the `icon` prop. Note that the `icon` prop for CheckableTag is only supported in version `>=5.27.0`.
If you want specific control over the positioning and placement of the `Icon`, then that should be done by placing the `Icon` component within the `Tag` rather than using the `icon` property. If you need to control the icon position, please use the `<XXXIcon />` component directly in `children` instead of the `icon` prop.

View file

@ -5,23 +5,67 @@ import {
TwitterOutlined, TwitterOutlined,
YoutubeOutlined, YoutubeOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { Flex, Tag } from 'antd'; import { Divider, Flex, Tag } from 'antd';
const App: React.FC = () => ( const App: React.FC = () => {
<Flex gap="4px 0" wrap> const [checked, setChecked] = React.useState<Array<boolean>>([true, false, false, false]);
<Tag icon={<TwitterOutlined />} color="#55acee">
Twitter const handleChange = (index: number, value: boolean) => {
</Tag> const newChecked = [...checked];
<Tag icon={<YoutubeOutlined />} color="#cd201f"> newChecked[index] = value;
Youtube setChecked(newChecked);
</Tag> };
<Tag icon={<FacebookOutlined />} color="#3b5999">
Facebook return (
</Tag> <>
<Tag icon={<LinkedinOutlined />} color="#55acee"> <Divider orientation="left">Tag with icon</Divider>
LinkedIn <Flex gap="4px 0" wrap align="center">
</Tag> <Tag icon={<TwitterOutlined />} color="#55acee">
</Flex> Twitter
); </Tag>
<Tag icon={<YoutubeOutlined />} color="#cd201f">
Youtube
</Tag>
<Tag icon={<FacebookOutlined />} color="#3b5999">
Facebook
</Tag>
<Tag icon={<LinkedinOutlined />} color="#55acee">
LinkedIn
</Tag>
</Flex>
<Divider orientation="left">CheckableTag with icon</Divider>
<Flex gap="4px 0" wrap align="center">
<Tag.CheckableTag
icon={<TwitterOutlined />} // `icon` available since `5.27.0`
checked={checked[0]}
onChange={(checked) => handleChange(0, checked)}
>
Twitter
</Tag.CheckableTag>
<Tag.CheckableTag
icon={<YoutubeOutlined />}
checked={checked[1]}
onChange={(checked) => handleChange(1, checked)}
>
Youtube
</Tag.CheckableTag>
<Tag.CheckableTag
icon={<FacebookOutlined />}
checked={checked[2]}
onChange={(checked) => handleChange(2, checked)}
>
Facebook
</Tag.CheckableTag>
<Tag.CheckableTag
icon={<LinkedinOutlined />}
checked={checked[3]}
onChange={(checked) => handleChange(3, checked)}
>
LinkedIn
</Tag.CheckableTag>
</Flex>
</>
);
};
export default App; export default App;

View file

@ -48,10 +48,11 @@ Common props ref[Common props](/docs/react/common-props)
### Tag.CheckableTag ### Tag.CheckableTag
| Property | Description | Type | Default | | Property | Description | Type | Default | Version |
| -------- | ----------------------------------------------- | ----------------- | ------- | | --- | --- | --- | --- | --- |
| checked | Checked status of Tag | boolean | false | | checked | Checked status of Tag | boolean | false | |
| onChange | Callback executed when Tag is checked/unchecked | (checked) => void | - | | icon | Set the icon of tag | ReactNode | - | 5.27.0 |
| onChange | Callback executed when Tag is checked/unchecked | (checked) => void | - | |
## Design Token ## Design Token

View file

@ -147,7 +147,6 @@ const InternalTag = React.forwardRef<HTMLSpanElement, TagProps>((tagProps, ref)
{isStatus && <StatusCmp key="status" prefixCls={prefixCls} />} {isStatus && <StatusCmp key="status" prefixCls={prefixCls} />}
</span> </span>
); );
return wrapCSSVar(isNeedWave ? <Wave component="Tag">{tagNode}</Wave> : tagNode); return wrapCSSVar(isNeedWave ? <Wave component="Tag">{tagNode}</Wave> : tagNode);
}); });

View file

@ -48,10 +48,11 @@ demo:
### Tag.CheckableTag ### Tag.CheckableTag
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| -------- | -------------------- | ----------------- | ------ | | -------- | -------------------- | ----------------- | ------ | ------ |
| checked | 设置标签的选中状态 | boolean | false | | checked | 设置标签的选中状态 | boolean | false | |
| onChange | 点击标签时触发的回调 | (checked) => void | - | | icon | 设置图标 | ReactNode | - | 5.27.0 |
| onChange | 点击标签时触发的回调 | (checked) => void | - | |
## 主题变量Design Token ## 主题变量Design Token

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`renders components/tooltip/demo/arrow.tsx extend context correctly 1`] = ` exports[`renders components/tooltip/demo/arrow.tsx extend context correctly 1`] = `
Array [ Array [
@ -1224,7 +1224,7 @@ Array [
class="ant-tooltip-inner" class="ant-tooltip-inner"
id="test-id" id="test-id"
role="tooltip" role="tooltip"
style="background: rgb(255, 85, 0);" style="background: rgb(255, 85, 0); --ant-tooltip-color: #FFF;"
> >
prompt text prompt text
</div> </div>
@ -1258,7 +1258,7 @@ Array [
class="ant-tooltip-inner" class="ant-tooltip-inner"
id="test-id" id="test-id"
role="tooltip" role="tooltip"
style="background: rgb(45, 183, 245);" style="background: rgb(45, 183, 245); --ant-tooltip-color: #000;"
> >
prompt text prompt text
</div> </div>
@ -1292,7 +1292,7 @@ Array [
class="ant-tooltip-inner" class="ant-tooltip-inner"
id="test-id" id="test-id"
role="tooltip" role="tooltip"
style="background: rgb(135, 208, 104);" style="background: rgb(135, 208, 104); --ant-tooltip-color: #000;"
> >
prompt text prompt text
</div> </div>
@ -1326,7 +1326,7 @@ Array [
class="ant-tooltip-inner" class="ant-tooltip-inner"
id="test-id" id="test-id"
role="tooltip" role="tooltip"
style="background: rgb(16, 142, 233);" style="background: rgb(16, 142, 233); --ant-tooltip-color: #FFF;"
> >
prompt text prompt text
</div> </div>
@ -2217,7 +2217,7 @@ Array [
<div <div
class="ant-tooltip-inner" class="ant-tooltip-inner"
role="tooltip" role="tooltip"
style="background: rgb(255, 85, 0);" style="background: rgb(255, 85, 0); --ant-tooltip-color: #FFF;"
> >
Hello, Customize Color Pure Panel! Hello, Customize Color Pure Panel!
</div> </div>

View file

@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`renders components/tooltip/demo/arrow.tsx correctly 1`] = ` exports[`renders components/tooltip/demo/arrow.tsx correctly 1`] = `
Array [ Array [
@ -981,7 +981,7 @@ Array [
<div <div
class="ant-tooltip-inner" class="ant-tooltip-inner"
role="tooltip" role="tooltip"
style="background:#f50" style="background:#f50;--ant-tooltip-color:#FFF"
> >
Hello, Customize Color Pure Panel! Hello, Customize Color Pure Panel!
</div> </div>

View file

@ -14,6 +14,7 @@ import Input from '../../input';
import Group from '../../input/Group'; import Group from '../../input/Group';
import Radio from '../../radio'; import Radio from '../../radio';
import Switch from '../../switch'; import Switch from '../../switch';
import { parseColor } from '../util';
import { isTooltipOpen } from './util'; import { isTooltipOpen } from './util';
describe('Tooltip', () => { describe('Tooltip', () => {
@ -639,4 +640,44 @@ describe('Tooltip', () => {
expect(tooltipElement.style.backgroundColor).toBe('blue'); expect(tooltipElement.style.backgroundColor).toBe('blue');
expect(tooltipBodyElement.style.color).toBe('red'); expect(tooltipBodyElement.style.color).toBe('red');
}); });
describe('parseColor', () => {
const prefixCls = 'ant-tooltip';
it('should set white text for dark backgrounds', () => {
const darkColor = '#003366'; // 深色
const { overlayStyle } = parseColor(prefixCls, darkColor);
expect(overlayStyle.background).toBe(darkColor);
expect(overlayStyle['--ant-tooltip-color']).toBe('#FFF');
});
it('should set black text for light backgrounds', () => {
const lightColor = '#f8f8f8';
const { overlayStyle } = parseColor(prefixCls, lightColor);
expect(overlayStyle.background).toBe(lightColor);
expect(overlayStyle['--ant-tooltip-color']).toBe('#000');
});
it('actual tooltip color rendering(defult)', () => {
const { container } = render(
<Tooltip title="Test" color="#003366" open>
<span>Hover me</span>
</Tooltip>,
);
const tooltipInner = container.querySelector('.ant-tooltip-inner');
expect(tooltipInner).toHaveStyle('--ant-tooltip-color: #FFF');
});
it('actual tooltip color rendering (styles)', () => {
const { container } = render(
<Tooltip title="Test" open color="#003366" styles={{ body: { color: 'rgb(0, 255, 255)' } }}>
<span>Hover me</span>
</Tooltip>,
);
const tooltipInner = container.querySelector('.ant-tooltip-inner');
expect(getComputedStyle(tooltipInner!).color).toBe('rgb(0, 255, 255)');
});
});
}); });

View file

@ -80,7 +80,7 @@ const genTooltipStyle: GenerateStyle<TooltipToken> = (token) => {
minWidth: centerAlignMinWidth, minWidth: centerAlignMinWidth,
minHeight: controlHeight, minHeight: controlHeight,
padding: `${unit(token.calc(paddingSM).div(2).equal())} ${unit(paddingXS)}`, padding: `${unit(token.calc(paddingSM).div(2).equal())} ${unit(paddingXS)}`,
color: tooltipColor, color: `var(--ant-tooltip-color,${tooltipColor})`,
textAlign: 'start', textAlign: 'start',
textDecoration: 'none', textDecoration: 'none',
wordWrap: 'break-word', wordWrap: 'break-word',

View file

@ -2,6 +2,8 @@ import type * as React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { isPresetColor } from '../_util/colors'; import { isPresetColor } from '../_util/colors';
import { ColorGenInput } from '../color-picker/interface';
import { generateColor } from '../color-picker/util';
export function parseColor(prefixCls: string, color?: string) { export function parseColor(prefixCls: string, color?: string) {
const isInternalColor = isPresetColor(color); const isInternalColor = isPresetColor(color);
@ -12,9 +14,12 @@ export function parseColor(prefixCls: string, color?: string) {
const overlayStyle: React.CSSProperties = {}; const overlayStyle: React.CSSProperties = {};
const arrowStyle: React.CSSProperties = {}; const arrowStyle: React.CSSProperties = {};
const rgb = generateColor(color as ColorGenInput).toRgb();
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
const textColor = luminance < 0.5 ? '#FFF' : '#000';
if (color && !isInternalColor) { if (color && !isInternalColor) {
overlayStyle.background = color; overlayStyle.background = color;
overlayStyle['--ant-tooltip-color'] = textColor;
// @ts-ignore // @ts-ignore
arrowStyle['--antd-arrow-background-color'] = color; arrowStyle['--antd-arrow-background-color'] = color;
} }

View file

@ -20,6 +20,7 @@ import type {
import useStyle from './style'; import useStyle from './style';
import UploadList from './UploadList'; import UploadList from './UploadList';
import { file2Obj, getFileItem, removeFileItem, updateFileList } from './utils'; import { file2Obj, getFileItem, removeFileItem, updateFileList } from './utils';
import { useComponentConfig } from '../config-provider/context';
export const LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`; export const LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`;
@ -40,6 +41,7 @@ export interface UploadRef<T = any> {
} }
const InternalUpload: React.ForwardRefRenderFunction<UploadRef, UploadProps> = (props, ref) => { const InternalUpload: React.ForwardRefRenderFunction<UploadRef, UploadProps> = (props, ref) => {
const config = useComponentConfig('upload');
const { const {
fileList, fileList,
defaultFileList, defaultFileList,
@ -76,6 +78,8 @@ const InternalUpload: React.ForwardRefRenderFunction<UploadRef, UploadProps> = (
const disabled = React.useContext(DisabledContext); const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled; const mergedDisabled = customDisabled ?? disabled;
const customRequest = props.customRequest || config.customRequest;
const [mergedFileList, setMergedFileList] = useMergedState(defaultFileList || [], { const [mergedFileList, setMergedFileList] = useMergedState(defaultFileList || [], {
value: fileList, value: fileList,
postState: (list) => list ?? [], postState: (list) => list ?? [],
@ -352,6 +356,7 @@ const InternalUpload: React.ForwardRefRenderFunction<UploadRef, UploadProps> = (
onProgress, onProgress,
onSuccess, onSuccess,
...props, ...props,
customRequest,
data, data,
multiple, multiple,
action, action,

View file

@ -9,6 +9,7 @@ import { resetWarned } from '../../_util/warning';
import mountTest from '../../../tests/shared/mountTest'; import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest'; import rtlTest from '../../../tests/shared/rtlTest';
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils'; import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import ConfigProvider from '../../config-provider';
import Form from '../../form'; import Form from '../../form';
import { getFileItem, isImageUrl, removeFileItem } from '../utils'; import { getFileItem, isImageUrl, removeFileItem } from '../utils';
import { setup, teardown } from './mock'; import { setup, teardown } from './mock';
@ -1151,4 +1152,53 @@ describe('Upload', () => {
expect(draggerEl).toBeTruthy(); expect(draggerEl).toBeTruthy();
expect(getComputedStyle(draggerEl!).background).toContain('yellow'); expect(getComputedStyle(draggerEl!).background).toContain('yellow');
}); });
it('supports ConfigProvider customRequest', async () => {
const mockFile1 = new File(['bamboo'], 'bamboo.png', { type: 'image/png' });
const mockFile2 = new File(['light'], 'light.png', { type: 'image/png' });
const customRequest = jest.fn(async (options) => {
// stop here to make sure new fileList has been set and passed to Upload
await new Promise((resolve) => setTimeout(resolve, 0));
options.onProgress({ percent: 0 });
const url = Promise.resolve<string>('https://ant.design');
options.onProgress({ percent: 100 });
options.onSuccess({}, { ...options.file, url });
});
let fileListOut: UploadProps['fileList'] = [];
const Demo: React.FC = () => {
const [fileList, setFileList] = React.useState<UploadFile[]>([]);
const onChange: UploadProps['onChange'] = async (e) => {
const newFileList = Array.isArray(e) ? e : e.fileList;
setFileList(newFileList);
fileListOut = newFileList;
};
return (
<ConfigProvider upload={{ customRequest }}>
<Upload onChange={onChange} fileList={fileList}>
<button type="button">Upload</button>
</Upload>
</ConfigProvider>
);
};
const { container } = render(<Demo />);
fireEvent.change(container.querySelector<HTMLInputElement>('input')!, {
target: { files: [mockFile1, mockFile2] },
});
// React 18 is async now
await waitFakeTimer();
fileListOut.forEach((file) => {
expect(file.status).toBe('done');
});
});
}); });

View file

@ -149,7 +149,7 @@
"rc-steps": "~6.0.1", "rc-steps": "~6.0.1",
"rc-switch": "~4.1.0", "rc-switch": "~4.1.0",
"rc-table": "~7.51.1", "rc-table": "~7.51.1",
"rc-tabs": "~15.6.1", "rc-tabs": "~15.7.0",
"rc-textarea": "~1.10.2", "rc-textarea": "~1.10.2",
"rc-tooltip": "~6.4.0", "rc-tooltip": "~6.4.0",
"rc-tree": "~5.13.1", "rc-tree": "~5.13.1",
@ -331,7 +331,7 @@
"typescript": "~5.9.2", "typescript": "~5.9.2",
"vanilla-jsoneditor": "^3.0.0", "vanilla-jsoneditor": "^3.0.0",
"vanilla-tilt": "^1.8.1", "vanilla-tilt": "^1.8.1",
"webpack": "^5.97.1", "webpack": "^5.100.0",
"webpack-bundle-analyzer": "^4.10.2", "webpack-bundle-analyzer": "^4.10.2",
"xhr-mock": "^2.5.1" "xhr-mock": "^2.5.1"
}, },