Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat: Button support autoInsertSpace prop #48348

Merged
merged 17 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions components/button/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,10 @@ describe('Button', () => {
const { container } = render(<Button type={'' as any} />);
expect(container.querySelector('.ant-btn-default')).toBeTruthy();
});

it('should support autoInsertSpace', () => {
const text = '确定';
const { container } = render(<Button autoInsertSpace={false}>{text}</Button>);
expect(container.querySelector<HTMLButtonElement>('button')?.textContent).toBe(text);
});
});
22 changes: 15 additions & 7 deletions components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type MergedHTMLAttributes = Omit<
export interface ButtonProps extends BaseButtonProps, MergedHTMLAttributes {
href?: string;
htmlType?: ButtonHTMLType;
autoInsertSpace?: boolean;
}

type CompoundedComponent = React.ForwardRefExoticComponent<
Expand Down Expand Up @@ -114,14 +115,19 @@ const InternalButton: React.ForwardRefRenderFunction<
htmlType = 'button',
classNames: customClassNames,
style: customStyle = {},
autoInsertSpace,
...rest
} = props;

// https://github.com/ant-design/ant-design/issues/47605
// Compatible with original `type` behavior
const mergedType = type || 'default';

const { getPrefixCls, autoInsertSpaceInButton, direction, button } = useContext(ConfigContext);
const { getPrefixCls, button, autoInsertSpaceInButton, direction } = useContext(ConfigContext);
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved

const mergedAutoInsertSpace =
autoInsertSpace ?? button?.autoInsertSpace ?? autoInsertSpaceInButton;
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved

const prefixCls = getPrefixCls('btn', customizePrefixCls);

const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
Expand All @@ -139,7 +145,7 @@ const InternalButton: React.ForwardRefRenderFunction<

const internalRef = createRef<HTMLButtonElement | HTMLAnchorElement>();

const buttonRef = composeRef(ref, internalRef);
const buttonRef = composeRef<HTMLButtonElement | HTMLAnchorElement>(ref, internalRef);
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved

const needInserted =
Children.count(children) === 1 && !icon && !isUnBorderedButtonType(mergedType);
Expand Down Expand Up @@ -167,7 +173,7 @@ const InternalButton: React.ForwardRefRenderFunction<

useEffect(() => {
// FIXME: for HOC usage like <FormatMessage />
if (!buttonRef || !(buttonRef as any).current || autoInsertSpaceInButton === false) {
if (!buttonRef || !(buttonRef as any).current || mergedAutoInsertSpace === false) {
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
return;
}
const buttonText = (buttonRef as any).current.textContent;
Expand Down Expand Up @@ -206,7 +212,8 @@ const InternalButton: React.ForwardRefRenderFunction<
);
}

const autoInsertSpace = autoInsertSpaceInButton !== false;
const finalAutoInsertSpace = mergedAutoInsertSpace !== false;
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved

const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction);

const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined };
Expand All @@ -230,7 +237,7 @@ const InternalButton: React.ForwardRefRenderFunction<
[`${prefixCls}-icon-only`]: !children && children !== 0 && !!iconType,
[`${prefixCls}-background-ghost`]: ghost && !isUnBorderedButtonType(mergedType),
[`${prefixCls}-loading`]: innerLoading,
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace && !innerLoading,
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && finalAutoInsertSpace && !innerLoading,
[`${prefixCls}-block`]: block,
[`${prefixCls}-dangerous`]: !!danger,
[`${prefixCls}-rtl`]: direction === 'rtl',
Expand Down Expand Up @@ -268,12 +275,13 @@ const InternalButton: React.ForwardRefRenderFunction<
);

const kids =
children || children === 0 ? spaceChildren(children, needInserted && autoInsertSpace) : null;
children || children === 0
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
? spaceChildren(children, needInserted && finalAutoInsertSpace)
: null;

const genButtonContent = (iconComponent: React.ReactNode, kidsComponent: React.ReactNode) => {
const isRTL = direction === 'rtl';
const iconFirst = (iconPosition === 'start' && !isRTL) || (iconPosition === 'end' && isRTL);

return (
<>
{iconFirst ? iconComponent : kidsComponent}
Expand Down
17 changes: 16 additions & 1 deletion components/button/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Different button styles can be generated by setting Button properties. The recom

| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| autoInsertSpace | Set `false` to remove space between 2 chinese characters on Button | boolean | `true` | 5.17.0 |
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
| block | Option to fit button width to its parent width | boolean | false | |
| classNames | Semantic DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.4.0 |
| danger | Set the danger status of button | boolean | false | |
Expand All @@ -73,7 +74,7 @@ Different button styles can be generated by setting Button properties. The recom
| styles | Semantic DOM style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.4.0 |
| target | Same as target attribute of a, works when href is specified | string | - | |
| type | Set button type | `primary` \| `dashed` \| `link` \| `text` \| `default` | `default` | |
| onClick | Set the handler to handle `click` event | (event: MouseEvent) => void | - | |
| onClick | Set the handler to handle `click` event | (event: React.MouseEvent<HTMLElement, MouseEvent>) => void | - | |

It accepts all props which native buttons support.

Expand Down Expand Up @@ -107,6 +108,20 @@ Following the Ant Design specification, we will add one space between if Button
</ConfigProvider>
```

The above prop is available before the `5.17.0`, since `5.17.0`, the `autoInsertSpaceInButton` prop is deprecated, Button component itself supports the `autoInsertSpace` prop:

```jsx
<Button autoInsertSpace={false}>按钮</Button>
```

or:

```jsx
<ConfigProvider button={{ autoInsertSpace: false }}>
<Button>按钮</Button>
</ConfigProvider>
```
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved

<img src="https://gw.alipayobjects.com/zos/antfincdn/MY%26THAPZrW/38f06cb9-293a-4b42-b183-9f443e79ffea.png" width="100px" height="64px" style="box-shadow: none; margin: 0;" alt="Button with two Chinese characters" />

<style>
Expand Down
17 changes: 16 additions & 1 deletion components/button/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ group:

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| autoInsertSpace | 设置为 `false` 时,移除按钮中 2 个汉字之间的空格 | boolean | `true` | 5.17.0 |
| block | 将按钮宽度调整为其父宽度的选项 | boolean | false | |
| classNames | 语义化结构 class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.4.0 |
| danger | 设置危险按钮 | boolean | false | |
Expand All @@ -78,7 +79,7 @@ group:
| styles | 语义化结构 style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.4.0 |
| target | 相当于 a 链接的 target 属性,href 存在时生效 | string | - | |
| type | 设置按钮类型 | `primary` \| `dashed` \| `link` \| `text` \| `default` | `default` | |
| onClick | 点击按钮时的回调 | (event: MouseEvent) => void | - | |
| onClick | 点击按钮时的回调 | (event: React.MouseEvent<HTMLElement, MouseEvent>) => void | - | |

支持原生 button 的其他所有属性。

Expand Down Expand Up @@ -112,6 +113,20 @@ group:
</ConfigProvider>
```

以上属性在 `5.17.0` 版本之前可用,自 `5.17.0` 版本起,`autoInsertSpaceInButton` 属性废弃,Button 组件本身支持了 `autoInsertSpace` 属性:

```jsx
<Button autoInsertSpace={false}>按钮</Button>
```

或者:

```jsx
<ConfigProvider button={{ autoInsertSpace: false }}>
<Button>按钮</Button>
</ConfigProvider>
```
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved

<img src="https://gw.alipayobjects.com/zos/antfincdn/MY%26THAPZrW/38f06cb9-293a-4b42-b183-9f443e79ffea.png" style="box-shadow: none; margin: 0" width="100px" height="64px" alt="移除两个汉字之间的空格" />

<style>
Expand Down
12 changes: 11 additions & 1 deletion components/config-provider/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ describe('ConfigProvider', () => {
<Button>{text}</Button>
</ConfigProvider>,
);
expect(container.querySelector('span')?.innerHTML).toBe(text);
expect(container.querySelector<HTMLSpanElement>('span')?.innerHTML).toBe(text);
});

it('button.autoInsertSpace', () => {
const text = '确定';
const { container } = render(
<ConfigProvider button={{ autoInsertSpace: false }}>
<Button>{text}</Button>
</ConfigProvider>,
);
expect(container.querySelector<HTMLSpanElement>('span')?.innerHTML).toBe(text);
});

it('renderEmpty', () => {
Expand Down
17 changes: 16 additions & 1 deletion components/config-provider/__tests__/useConfig.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Button } from 'antd';

import ConfigProvider from '..';
import { resetWarned } from '../../_util/warning';
Expand Down Expand Up @@ -57,7 +58,21 @@ describe('ConfigProvider.useConfig', () => {
render(<App />);

expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: ConfigProvider] ConfigProvider.SizeContext is deprecated. Please use `ConfigProvider.useConfig().componentSize` instead.',
'Warning: [antd: ConfigProvider] `ConfigProvider.SizeContext` is deprecated. Please use `ConfigProvider.useConfig().componentSize` instead.',
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
);
errSpy.mockRestore();
});

it('deprecated autoInsertSpaceInButton', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(
<ConfigProvider autoInsertSpaceInButton={false}>
<Button>测试</Button>
</ConfigProvider>,
);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: ConfigProvider] `autoInsertSpaceInButton` is deprecated. Please use `{ button: { autoInsertSpace: boolean }}` instead.',
);
errSpy.mockRestore();
});
Expand Down
4 changes: 3 additions & 1 deletion components/config-provider/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ export type InputConfig = ComponentStyleConfig &
export type TextAreaConfig = ComponentStyleConfig &
Pick<TextAreaProps, 'autoComplete' | 'classNames' | 'styles' | 'allowClear'>;

export type ButtonConfig = ComponentStyleConfig & Pick<ButtonProps, 'classNames' | 'styles'>;
export type ButtonConfig = ComponentStyleConfig &
Pick<ButtonProps, 'classNames' | 'styles' | 'autoInsertSpace'>;

export type NotificationConfig = ComponentStyleConfig & Pick<ArgsProps, 'closeIcon'>;

Expand Down Expand Up @@ -194,6 +195,7 @@ export interface ConfigConsumerProps {
* @descEN Set the [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config.
*/
csp?: CSPConfig;
/** @deprecated Please use `{ button: { autoInsertSpace: boolean }}` instead */
autoInsertSpaceInButton?: boolean;
input?: InputConfig;
textArea?: TextAreaConfig;
Expand Down
4 changes: 2 additions & 2 deletions components/config-provider/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p

| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| autoInsertSpaceInButton | Set false to remove space between 2 chinese characters on Button | boolean | true | |
| autoInsertSpaceInButton | Set `false` to remove space between 2 chinese characters on Button | boolean | true | |
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
| componentDisabled | Config antd component `disabled` | boolean | - | 4.21.0 |
| componentSize | Config antd component size | `small` \| `middle` \| `large` | - | |
| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | |
Expand Down Expand Up @@ -105,7 +105,7 @@ const {
| avatar | Set Avatar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| badge | Set Badge common props | { className?: string, style?: React.CSSProperties, classNames?: { count?: string, indicator?: string }, styles?: { count?: React.CSSProperties, indicator?: React.CSSProperties } } | - | 5.7.0 |
| breadcrumb | Set Breadcrumb common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties }, autoInsertSpace?: boolean } | - | 5.6.0, autoInsertSpace: 5.17.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 |
| carousel | Set Carousel common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
Expand Down
25 changes: 19 additions & 6 deletions components/config-provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import IconContext from '@ant-design/icons/lib/components/Context';
import useMemo from 'rc-util/lib/hooks/useMemo';
import { merge } from 'rc-util/lib/utils/set';

import warning, { WarningContext } from '../_util/warning';
import warning, { devUseWarning, WarningContext } from '../_util/warning';
import type { WarningContextProps } from '../_util/warning';
import ValidateMessagesContext from '../form/validateMessagesContext';
import type { Locale } from '../locale';
Expand Down Expand Up @@ -122,6 +122,7 @@ export interface ConfigProviderProps {
children?: React.ReactNode;
renderEmpty?: RenderEmptyHandler;
csp?: CSPConfig;
/** @deprecated Please use `{ button: { autoInsertSpace: boolean }}` instead */
autoInsertSpaceInButton?: boolean;
form?: FormConfig;
input?: InputConfig;
Expand Down Expand Up @@ -463,6 +464,15 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
floatButtonGroup,
};

if (process.env.NODE_ENV !== 'production') {
const warningFn = devUseWarning('ConfigProvider');
warningFn(
!('autoInsertSpaceInButton' in props),
'deprecated',
'`autoInsertSpaceInButton` is deprecated. Please use `{ button: { autoInsertSpace: boolean }}` instead.',
);
}

const config: ConfigConsumerProps = {
...parentContext,
};
Expand Down Expand Up @@ -637,11 +647,14 @@ ConfigProvider.useConfig = useConfig;

Object.defineProperty(ConfigProvider, 'SizeContext', {
get: () => {
warning(
false,
'ConfigProvider',
'ConfigProvider.SizeContext is deprecated. Please use `ConfigProvider.useConfig().componentSize` instead.',
);
if (process.env.NODE_ENV !== 'production') {
const warningFn = devUseWarning('ConfigProvider');
warningFn(
false,
'deprecated',
'`ConfigProvider.SizeContext` is deprecated. Please use `ConfigProvider.useConfig().componentSize` instead.',
);
}
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
return SizeContext;
},
});
Expand Down
2 changes: 1 addition & 1 deletion components/config-provider/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const {
| avatar | 设置 Avatar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| badge | 设置 Badge 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { count?: string, indicator?: string }, styles?: { count?: React.CSSProperties, indicator?: React.CSSProperties } } | - | 5.7.0 |
| breadcrumb | 设置 Breadcrumb 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties }, autoInsertSpace?: boolean } | - | 5.6.0, autoInsertSpace: 5.17.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 |
| carousel | 设置 Carousel 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
Expand Down
2 changes: 1 addition & 1 deletion components/modal/__tests__/hook.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ describe('Modal.hook', () => {
});

it('not block origin ConfigProvider config', () => {
const Demo = () => {
const Demo: React.FC = () => {
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
const [modal, contextHolder] = Modal.useModal();

React.useEffect(() => {
Expand Down