feat: input number support prefix (#32600)

This commit is contained in:
Austaras 2021-10-30 22:25:12 +08:00 committed by GitHub
parent 184402a9bc
commit d1f87ccc80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 884 additions and 7 deletions

View File

@ -108,3 +108,30 @@ exports[`Alert rtl render component should be rendered correctly in RTL directio
/>
</div>
`;
exports[`Alert support closeIcon 1`] = `
<div
class="ant-alert ant-alert-warning ant-alert-no-icon"
data-show="true"
role="alert"
>
<div
class="ant-alert-content"
>
<div
class="ant-alert-message"
>
Warning Text Warning Text Warning TextW arning Text Warning Text Warning TextWarning Text
</div>
</div>
<button
class="ant-alert-close-icon"
tabindex="0"
type="button"
>
<span>
close
</span>
</button>
</div>
`;

View File

@ -354,6 +354,222 @@ exports[`renders ./components/dropdown/demo/item.md correctly 1`] = `
</a>
`;
exports[`renders ./components/dropdown/demo/loading.md correctly 1`] = `
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-btn-group ant-dropdown-button"
>
<button
class="ant-btn ant-btn-primary ant-btn-loading"
type="button"
>
<span
class="ant-btn-loading-icon"
>
<span
aria-label="loading"
class="anticon anticon-loading anticon-spin"
role="img"
>
<svg
aria-hidden="true"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</span>
</span>
<span>
Submit
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only ant-dropdown-trigger"
type="button"
>
<span
aria-label="ellipsis"
class="anticon anticon-ellipsis"
role="img"
>
<svg
aria-hidden="true"
data-icon="ellipsis"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
</button>
</div>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-btn-group ant-btn-group-sm ant-dropdown-button"
>
<button
class="ant-btn ant-btn-primary ant-btn-loading"
type="button"
>
<span
class="ant-btn-loading-icon"
>
<span
aria-label="loading"
class="anticon anticon-loading anticon-spin"
role="img"
>
<svg
aria-hidden="true"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</span>
</span>
<span>
Submit
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only ant-dropdown-trigger"
type="button"
>
<span
aria-label="ellipsis"
class="anticon anticon-ellipsis"
role="img"
>
<svg
aria-hidden="true"
data-icon="ellipsis"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
</button>
</div>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-btn-group ant-dropdown-button"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Submit
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-icon-only ant-dropdown-trigger"
type="button"
>
<span
aria-label="ellipsis"
class="anticon anticon-ellipsis"
role="img"
>
<svg
aria-hidden="true"
data-icon="ellipsis"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
</button>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-btn-group ant-dropdown-button"
>
<button
class="ant-btn"
type="button"
>
<span>
Submit
</span>
</button>
<button
class="ant-btn ant-btn-icon-only ant-dropdown-trigger"
type="button"
>
<span
aria-label="down"
class="anticon anticon-down"
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>
</button>
</div>
</div>
</div>
`;
exports[`renders ./components/dropdown/demo/menu-full.md correctly 1`] = `
<a
class="ant-dropdown-trigger ant-dropdown-link"

View File

@ -12,7 +12,8 @@
}
// 输入框的不同校验状态
:not(.@{ant-prefix}-input-disabled):not(.@{ant-prefix}-input-borderless).@{ant-prefix}-input,
:not(.@{ant-prefix}-input-affix-wrapper-disabled):not(.@{ant-prefix}-input-affix-wrapper-borderless).@{ant-prefix}-input-affix-wrapper {
:not(.@{ant-prefix}-input-affix-wrapper-disabled):not(.@{ant-prefix}-input-affix-wrapper-borderless).@{ant-prefix}-input-affix-wrapper,
:not(.@{ant-prefix}-input-number-affix-wrapper-disabled):not(.@{ant-prefix}-input-number-affix-wrapper-borderless).@{ant-prefix}-input-number-affix-wrapper {
&,
&:hover {
background-color: @background-color;
@ -29,7 +30,8 @@
.active(@border-color, @hoverBorderColor, @outlineColor);
}
.@{ant-prefix}-input-prefix {
.@{ant-prefix}-input-prefix,
.@{ant-prefix}-input-number-prefix {
color: @text-color;
}

View File

@ -80,6 +80,14 @@
}
}
.@{ant-prefix}-input-number-affix-wrapper {
.@{ant-prefix}-input-number {
.@{form-prefix-cls}-rtl & {
padding: 0;
}
}
}
.@{ant-prefix}-input-search:not(.@{ant-prefix}-input-search-enter-button) {
.@{ant-prefix}-input-suffix {
.@{form-prefix-cls}-rtl & {

View File

@ -1287,6 +1287,454 @@ exports[`renders ./components/input-number/demo/out-of-range.md correctly 1`] =
</div>
`;
exports[`renders ./components/input-number/demo/prefix.md correctly 1`] = `
Array [
<div
class="ant-input-number-affix-wrapper"
style="width:100%"
>
<span
class="ant-input-number-prefix"
>
</span>
<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>
</div>,
<br />,
<br />,
<div
class="ant-input-number-group-wrapper"
style="width:100%"
>
<div
class="ant-input-number-wrapper ant-input-number-group"
>
<div
class="ant-input-number-group-addon"
>
<span
aria-label="user"
class="anticon anticon-user"
role="img"
>
<svg
aria-hidden="true"
data-icon="user"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M858.5 763.6a374 374 0 00-80.6-119.5 375.63 375.63 0 00-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 00-80.6 119.5A371.7 371.7 0 00136 901.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 008-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
/>
</svg>
</span>
</div>
<div
class="ant-input-number-affix-wrapper"
>
<span
class="ant-input-number-prefix"
>
</span>
<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>
</div>
</div>
</div>,
<br />,
<br />,
<div
class="ant-input-number-affix-wrapper ant-input-number-affix-wrapper-disabled"
style="width:100%"
>
<span
class="ant-input-number-prefix"
>
</span>
<div
class="ant-input-number ant-input-number-disabled"
>
<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"
disabled=""
role="spinbutton"
step="1"
value=""
/>
</div>
</div>
</div>,
<br />,
<br />,
<form
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-has-feedback ant-form-item-has-warning"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Warning"
>
Warning
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-input-number-affix-wrapper"
style="width:100%"
>
<span
class="ant-input-number-prefix"
>
<span
aria-label="smile"
class="anticon anticon-smile"
role="img"
>
<svg
aria-hidden="true"
data-icon="smile"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M288 421a48 48 0 1096 0 48 48 0 10-96 0zm352 0a48 48 0 1096 0 48 48 0 10-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 01248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 01249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 01775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 01775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 00-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 00-8-8.4z"
/>
</svg>
</span>
</span>
<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"
id="warning"
placeholder="Warning"
role="spinbutton"
step="1"
value=""
/>
</div>
</div>
</div>
</div>
<span
class="ant-form-item-children-icon"
>
<span
aria-label="exclamation-circle"
class="anticon anticon-exclamation-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="exclamation-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
</form>,
]
`;
exports[`renders ./components/input-number/demo/size.md correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center"

View File

@ -0,0 +1,24 @@
import React from 'react';
import { mount } from 'enzyme';
import InputNumber from '..';
import focusTest from '../../../tests/shared/focusTest';
describe('prefix', () => {
focusTest(
React.forwardRef((props, ref) => <InputNumber {...props} prefix="A" ref={ref} />),
{ refFocus: true },
);
it('should support className when has prefix', () => {
const wrapper = mount(<InputNumber prefix="suffix" className="my-class-name" />);
expect(wrapper.getDOMNode().className.includes('my-class-name')).toBe(true);
expect(wrapper.find('input').getDOMNode().className.includes('my-class-name')).toBe(false);
});
it('should trigger focus when prefix is clicked', () => {
const wrapper = mount(<InputNumber prefix={<i>123</i>} />);
const mockFocus = jest.spyOn(wrapper.find('input').getDOMNode(), 'focus');
wrapper.find('i').simulate('mouseUp');
expect(mockFocus).toBeCalled();
});
});

View File

@ -0,0 +1,44 @@
---
order: 7
title:
zh-CN: 前缀
en-US: Prefix
---
## zh-CN
在输入框上添加前缀图标。
## en-US
Add a prefix inside input.
```jsx
import { Form, InputNumber, Tooltip } from 'antd';
import { InfoCircleOutlined, SmileOutlined, UserOutlined } from '@ant-design/icons';
ReactDOM.render(
<>
<InputNumber prefix="¥" style={{ width: '100%' }} />
<br />
<br />
<InputNumber addonBefore={<UserOutlined />} prefix="¥" style={{ width: '100%' }} />
<br />
<br />
<InputNumber prefix="¥" disabled style={{ width: '100%' }} />
<br />
<br />
<Form>
<Form.Item label="Warning" hasFeedback validateStatus="warning">
<InputNumber
style={{ width: '100%' }}
placeholder="Warning"
id="warning"
prefix={<SmileOutlined />}
/>
</Form.Item>
</Form>
</>,
mountNode,
);
```

View File

@ -30,6 +30,7 @@ When a numeric value needs to be provided.
| parser | Specifies the value extracted from formatter | function(string): number | - | - |
| precision | The precision of input value. Will use `formatter` when config of `formatter` | number | - | - |
| readOnly | If readonly the input | boolean | false | - |
| prefix | The prefix icon for the Input | ReactNode | - | 4.17.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

@ -11,10 +11,11 @@ import { cloneElement } from '../_util/reactNode';
type ValueType = string | number;
export interface InputNumberProps<T extends ValueType = ValueType>
extends Omit<RcInputNumberProps<T>, 'size'> {
extends Omit<RcInputNumberProps<T>, 'prefix' | 'size'> {
prefixCls?: string;
addonBefore?: React.ReactNode;
addonAfter?: React.ReactNode;
prefix?: React.ReactNode;
size?: SizeType;
bordered?: boolean;
}
@ -22,6 +23,10 @@ export interface InputNumberProps<T extends ValueType = ValueType>
const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props, ref) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const size = React.useContext(SizeContext);
const [focused, setFocus] = React.useState(false);
const inputRef = React.useRef<HTMLInputElement>(null);
React.useImperativeHandle(ref, () => inputRef.current!);
const {
className,
@ -29,6 +34,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
prefixCls: customizePrefixCls,
addonBefore,
addonAfter,
prefix,
bordered = true,
readOnly,
...others
@ -50,9 +56,9 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
className,
);
const element = (
let element = (
<RcInputNumber
ref={ref}
ref={inputRef}
className={inputNumberClass}
upHandler={upIcon}
downHandler={downIcon}
@ -62,6 +68,41 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
/>
);
if (prefix != null) {
const affixWrapperCls = classNames(`${prefixCls}-affix-wrapper`, {
[`${prefixCls}-affix-wrapper-focused`]: focused,
[`${prefixCls}-affix-wrapper-disabled`]: props.disabled,
[`${prefixCls}-affix-wrapper-sm`]: size === 'small',
[`${prefixCls}-affix-wrapper-lg`]: size === 'large',
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-affix-wrapper-readonly`]: readOnly,
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
// className will go to addon wrapper
[`${className}`]: !(addonBefore || addonAfter) && className,
});
element = (
<div
className={affixWrapperCls}
style={props.style}
onMouseUp={() => inputRef.current!.focus()}
>
<span className={`${prefixCls}-prefix`}>{prefix}</span>
{cloneElement(element, {
style: null,
value: props.value,
onFocus: (event: React.FocusEvent<HTMLInputElement>) => {
setFocus(true);
props.onFocus?.(event);
},
onBlur: (event: React.FocusEvent<HTMLInputElement>) => {
setFocus(false);
props.onBlur?.(event);
},
})}
</div>
);
}
if (addonBefore != null || addonAfter != null) {
const wrapperClassName = `${prefixCls}-group`;
const addonClassName = `${wrapperClassName}-addon`;
@ -83,7 +124,7 @@ const InputNumber = React.forwardRef<HTMLInputElement, InputNumberProps>((props,
},
className,
);
return (
element = (
<div className={mergedGroupClassName} style={props.style}>
<div className={mergedWrapperClassName}>
{addonBeforeNode}

View File

@ -33,6 +33,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/XOS8qZ0kU/InputNumber.svg
| parser | 指定从 `formatter` 里转换回数字的方式,和 `formatter` 搭配使用 | function(string): number | - | - |
| precision | 数值精度,配置 `formatter` 时会以 `formatter` 为准 | number | - | - |
| readOnly | 只读 | boolean | false | - |
| prefix | 带有前缀图标的 input | ReactNode | - | 4.17.0 |
| size | 输入框大小 | `large` \| `middle` \| `small` | - | - |
| step | 每次改变步数,可以为小数 | number \| string | 1 | - |
| stringMode | 字符值模式,开启后支持高精度小数。同时 `onChange` 将返回 string 类型 | boolean | false | 4.13.0 |

View File

@ -0,0 +1,64 @@
@import '../../input/style/mixin';
@import (reference) '../../style/themes/index';
@input-prefix-cls: ~'@{ant-prefix}-input';
@input-affix-margin: 4px;
.@{ant-prefix}-input-number {
&-affix-wrapper {
.input();
// or number handler will cover form status
position: static;
display: inline-flex;
width: 90px;
padding: 0;
padding-inline-start: @input-padding-horizontal-base;
&:not(&-disabled):hover {
.hover();
z-index: 1;
}
&-focused,
&:focus {
z-index: 1;
}
&-disabled {
.@{ant-prefix}-input-number[disabled] {
background: transparent;
}
}
> div.@{ant-prefix}-input-number {
width: 100%;
border: none;
outline: none;
&.@{ant-prefix}-input-number-focused {
box-shadow: none !important;
}
}
input.@{ant-prefix}-input-number-input {
padding: 0;
}
&::before {
width: 0;
visibility: hidden;
content: '\a0';
}
}
&-prefix {
display: flex;
flex: none;
align-items: center;
margin-inline-end: @input-affix-margin;
}
}
.@{ant-prefix}-input-number-group-wrapper .@{ant-prefix}-input-number-affix-wrapper {
width: 100%;
}

View File

@ -1,6 +1,7 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@import './affix';
@input-number-prefix-cls: ~'@{ant-prefix}-input-number';
@form-item-prefix-cls: ~'@{ant-prefix}-form-item';

View File

@ -105,13 +105,13 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
readOnly,
bordered,
} = this.props;
const suffixNode = this.renderSuffix(prefixCls);
if (!hasPrefixSuffix(this.props)) {
return cloneElement(element, {
value,
});
}
const suffixNode = this.renderSuffix(prefixCls);
const prefixNode = prefix ? <span className={`${prefixCls}-prefix`}>{prefix}</span> : null;
const affixWrapperCls = classNames(`${prefixCls}-affix-wrapper`, {