feat(input-number): add suffix prop & change controls animation (#49674)

* feat: add suffix prop & change controls animation

* feat: add opacity

* refactor: calc

* refactor: change file

* test: change text

---------

Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
ice 2024-07-10 14:43:39 +08:00 committed by GitHub
parent 09e6ed7278
commit 10e46c107e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 230 additions and 23 deletions

View File

@ -3203,7 +3203,7 @@ exports[`renders components/input-number/demo/out-of-range.tsx extend context co
exports[`renders components/input-number/demo/out-of-range.tsx extend context correctly 2`] = `[]`;
exports[`renders components/input-number/demo/prefix.tsx extend context correctly 1`] = `
exports[`renders components/input-number/demo/presuffix.tsx extend context correctly 1`] = `
Array [
<div
class="ant-input-number-affix-wrapper ant-input-number-outlined"
@ -3490,10 +3490,95 @@ Array [
</div>
</div>
</div>,
<br />,
<br />,
<div
class="ant-input-number-affix-wrapper ant-input-number-outlined"
style="width: 100%;"
>
<div
class="ant-input-number"
>
<div
class="ant-input-number-handler-wrap"
>
<span
aria-disabled="false"
aria-label="Increase Value"
class="ant-input-number-handler ant-input-number-handler-up"
role="button"
unselectable="on"
>
<span
aria-label="up"
class="anticon anticon-up ant-input-number-handler-up-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="up"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"
/>
</svg>
</span>
</span>
<span
aria-disabled="false"
aria-label="Decrease Value"
class="ant-input-number-handler ant-input-number-handler-down"
role="button"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-input-number-handler-down-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-input-number-input-wrap"
>
<input
autocomplete="off"
class="ant-input-number-input"
role="spinbutton"
step="1"
value=""
/>
</div>
</div>
<span
class="ant-input-number-suffix"
>
RMB
</span>
</div>,
]
`;
exports[`renders components/input-number/demo/prefix.tsx extend context correctly 2`] = `[]`;
exports[`renders components/input-number/demo/presuffix.tsx extend context correctly 2`] = `[]`;
exports[`renders components/input-number/demo/render-panel.tsx extend context correctly 1`] = `
<div

View File

@ -2911,7 +2911,7 @@ exports[`renders components/input-number/demo/out-of-range.tsx correctly 1`] = `
</div>
`;
exports[`renders components/input-number/demo/prefix.tsx correctly 1`] = `
exports[`renders components/input-number/demo/presuffix.tsx correctly 1`] = `
Array [
<div
class="ant-input-number-affix-wrapper ant-input-number-outlined"
@ -3198,6 +3198,91 @@ Array [
</div>
</div>
</div>,
<br />,
<br />,
<div
class="ant-input-number-affix-wrapper ant-input-number-outlined"
style="width:100%"
>
<div
class="ant-input-number"
>
<div
class="ant-input-number-handler-wrap"
>
<span
aria-disabled="false"
aria-label="Increase Value"
class="ant-input-number-handler ant-input-number-handler-up"
role="button"
unselectable="on"
>
<span
aria-label="up"
class="anticon anticon-up ant-input-number-handler-up-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="up"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 00140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"
/>
</svg>
</span>
</span>
<span
aria-disabled="false"
aria-label="Decrease Value"
class="ant-input-number-handler ant-input-number-handler-down"
role="button"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-input-number-handler-down-inner"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-input-number-input-wrap"
>
<input
autocomplete="off"
class="ant-input-number-input"
role="spinbutton"
step="1"
value=""
/>
</div>
</div>
<span
class="ant-input-number-suffix"
>
RMB
</span>
</div>,
]
`;

View File

@ -0,0 +1,19 @@
import React from 'react';
import InputNumber from '..';
import { fireEvent, render } from '../../../tests/utils';
describe('suffix', () => {
it('should support suffix prop', () => {
const { container } = render(<InputNumber suffix={<i>hello</i>} />);
expect(container.querySelector('.ant-input-number-suffix')).toBeInTheDocument();
});
it('should trigger focus when suffix is clicked', () => {
const { container } = render(<InputNumber suffix={<i>antd</i>} />);
const mockFocus = jest.spyOn(container.querySelector('input')!, 'focus');
fireEvent.click(container.querySelector('i')!);
expect(mockFocus).toHaveBeenCalled();
});
});

View File

@ -1,7 +0,0 @@
## zh-CN
在输入框上添加前缀图标。
## en-US
Add a prefix inside input.

View File

@ -0,0 +1,7 @@
## zh-CN
在输入框上添加前缀或后缀图标。
## en-US
Add a prefix or suffix inside input.

View File

@ -11,6 +11,9 @@ const App: React.FC = () => (
<br />
<br />
<InputNumber prefix="¥" disabled style={{ width: '100%' }} />
<br />
<br />
<InputNumber suffix="RMB" style={{ width: '100%' }} />
</>
);

View File

@ -27,7 +27,7 @@ When a numeric value needs to be provided.
<code src="./demo/variant.tsx" version="5.13.0">Variants</code>
<code src="./demo/filled-debug.tsx" debug>Filled Debug</code>
<code src="./demo/out-of-range.tsx">Out of range</code>
<code src="./demo/prefix.tsx">Prefix</code>
<code src="./demo/presuffix.tsx">Prefix / Suffix</code>
<code src="./demo/status.tsx">Status</code>
<code src="./demo/controls.tsx" debug>Icon</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
@ -58,6 +58,7 @@ Common props ref[Common props](/docs/react/common-props)
| readOnly | If readonly the input | boolean | false | - |
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
| prefix | The prefix icon for the Input | ReactNode | - | 4.17.0 |
| suffix | The suffix icon for the Input | ReactNode | - | 5.20.0 |
| size | The height of input box | `large` \| `middle` \| `small` | - | - |
| step | The number to which the current value is increased or decreased. It can be an integer or decimal | number \| string | 1 | - |
| stringMode | Set value as string to support high precision decimals. Will return string value by `onChange` | boolean | false | 4.13.0 |

View File

@ -27,6 +27,7 @@ export interface InputNumberProps<T extends ValueType = ValueType>
addonBefore?: React.ReactNode;
addonAfter?: React.ReactNode;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
size?: SizeType;
disabled?: boolean;
/** @deprecated Use `variant` instead. */
@ -66,6 +67,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
addonBefore,
addonAfter,
prefix,
suffix,
bordered,
readOnly,
status: customStatus,
@ -141,7 +143,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
readOnly={readOnly}
controls={controlsTemp}
prefix={prefix}
suffix={suffixNode}
suffix={suffixNode || suffix}
addonBefore={
addonBefore && (
<ContextIsolator form space>

View File

@ -28,7 +28,7 @@ demo:
<code src="./demo/variant.tsx" version="5.13.0">形态变体</code>
<code src="./demo/filled-debug.tsx" debug>Filled Debug</code>
<code src="./demo/out-of-range.tsx">超出边界</code>
<code src="./demo/prefix.tsx">前缀</code>
<code src="./demo/presuffix.tsx">缀/后</code>
<code src="./demo/status.tsx">自定义状态</code>
<code src="./demo/controls.tsx" debug>图标按钮</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
@ -59,6 +59,7 @@ demo:
| readOnly | 只读 | boolean | false | - |
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
| prefix | 带有前缀图标的 input | ReactNode | - | 4.17.0 |
| suffix | 带有后缀图标的 input | ReactNode | - | 5.20.0 |
| size | 输入框大小 | `large` \| `middle` \| `small` | - | - |
| step | 每次改变步数,可以为小数 | number \| string | 1 | - |
| stringMode | 字符值模式,开启后支持高精度小数。同时 `onChange` 将返回 string 类型 | boolean | false | 4.13.0 |

View File

@ -61,6 +61,7 @@ const genInputNumberStyles: GenerateStyle<InputNumberToken> = (token: InputNumbe
colorTextDescription,
motionDurationMid,
handleHoverColor,
handleOpacity,
paddingInline,
paddingBlock,
handleBg,
@ -69,7 +70,6 @@ const genInputNumberStyles: GenerateStyle<InputNumberToken> = (token: InputNumbe
borderRadiusSM,
borderRadiusLG,
controlWidth,
handleOpacity,
handleBorderColor,
filledHandleBg,
lineHeightLG,
@ -236,31 +236,32 @@ const genInputNumberStyles: GenerateStyle<InputNumberToken> = (token: InputNumbe
},
},
},
[`&:hover ${componentCls}-handler-wrap, &-focused ${componentCls}-handler-wrap`]: {
width: token.handleWidth,
opacity: 1,
},
},
},
// Handler
{
[componentCls]: {
[`&:hover ${componentCls}-handler-wrap, &-focused ${componentCls}-handler-wrap`]: {
opacity: 1,
},
[`${componentCls}-handler-wrap`]: {
position: 'absolute',
insetBlockStart: 0,
insetInlineEnd: 0,
width: token.handleWidth,
width: 0,
opacity: handleOpacity,
height: '100%',
borderStartStartRadius: 0,
borderStartEndRadius: borderRadius,
borderEndEndRadius: borderRadius,
borderEndStartRadius: 0,
opacity: handleOpacity,
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch',
transition: `opacity ${motionDurationMid} linear ${motionDurationMid}`,
transition: `all ${motionDurationMid}`,
overflow: 'hidden',
// Fix input number inside Menu makes icon too large
// We arise the selector priority by nest selector here
@ -370,6 +371,7 @@ const genAffixWrapperStyles: GenerateStyle<InputNumberToken> = (token: InputNumb
paddingInlineSM,
paddingBlockLG,
paddingBlockSM,
motionDurationMid,
} = token;
return {
@ -382,6 +384,7 @@ const genAffixWrapperStyles: GenerateStyle<InputNumberToken> = (token: InputNumb
// or number handler will cover form status
position: 'relative',
display: 'inline-flex',
alignItems: 'center',
width: controlWidth,
padding: 0,
paddingInlineStart: paddingInline,
@ -438,6 +441,7 @@ const genAffixWrapperStyles: GenerateStyle<InputNumberToken> = (token: InputNumb
},
[componentCls]: {
position: 'static',
color: 'inherit',
'&-prefix, &-suffix': {
@ -452,15 +456,22 @@ const genAffixWrapperStyles: GenerateStyle<InputNumberToken> = (token: InputNumb
},
'&-suffix': {
position: 'absolute',
insetBlockStart: 0,
insetInlineEnd: 0,
zIndex: 1,
height: '100%',
marginInlineEnd: paddingInline,
marginInlineStart: inputAffixPadding,
transition: `margin ${motionDurationMid}`,
},
},
[`&:hover ${componentCls}-handler-wrap, &-focused ${componentCls}-handler-wrap`]: {
width: token.handleWidth,
opacity: 1,
},
[`&:hover ${componentCls}-suffix`]: {
marginInlineEnd: token.calc(token.handleWidth).add(paddingInline).equal(),
},
},
};
};