diff --git a/assets/index.less b/assets/index.less index a5e1abe5..e3e559e5 100644 --- a/assets/index.less +++ b/assets/index.less @@ -133,4 +133,24 @@ .handler-disabled(); } } + + &-type-spinner { + display: inline-flex; + align-items: center; + } + + &-type-spinner &-handler { + flex: 0 0 20px; + line-height: 26px; + height: 100%; + } + + &-type-spinner &-handler-up { + border-bottom: 0; + border-left: 1px solid #d9d9d9; + } + &-type-spinner &-handler-down { + border-top: 0; + border-right: 1px solid #d9d9d9; + } } diff --git a/docs/demo/spinner.tsx b/docs/demo/spinner.tsx new file mode 100644 index 00000000..085bc0b3 --- /dev/null +++ b/docs/demo/spinner.tsx @@ -0,0 +1,78 @@ +/* eslint no-console:0 */ +import InputNumber from '@rc-component/input-number'; +import React from 'react'; +import '../../assets/index.less'; + +export default () => { + const [disabled, setDisabled] = React.useState(false); + const [readOnly, setReadOnly] = React.useState(false); + const [keyboard, setKeyboard] = React.useState(true); + const [wheel, setWheel] = React.useState(true); + const [stringMode, setStringMode] = React.useState(false); + const [value, setValue] = React.useState(93); + + const onChange = (val: number) => { + console.warn('onChange:', val, typeof val); + setValue(val); + }; + + return ( +
+

Controlled

+ +

+ + + + + +

+ +
+

Uncontrolled

+ + +
+

!changeOnBlur

+ +
+ ); +}; diff --git a/docs/example.md b/docs/example.md index 7743a757..b88e7135 100644 --- a/docs/example.md +++ b/docs/example.md @@ -52,3 +52,7 @@ nav: ## focus + +## spinner + + diff --git a/src/InputNumber.tsx b/src/InputNumber.tsx index 8cb3d822..a39ad176 100644 --- a/src/InputNumber.tsx +++ b/src/InputNumber.tsx @@ -63,6 +63,8 @@ export interface InputNumberProps /** value will show as string */ stringMode?: boolean; + type?: 'input' | 'spinner'; + defaultValue?: T; value?: T | null; @@ -119,6 +121,7 @@ type InternalInputNumberProps = Omit & { const InternalInputNumber = React.forwardRef( (props: InternalInputNumberProps, ref: React.Ref) => { const { + type, prefixCls, className, style, @@ -154,6 +157,8 @@ const InternalInputNumber = React.forwardRef( ...inputProps } = props; + const { classNames, styles } = React.useContext(SemanticContext) || {}; + const inputClassName = `${prefixCls}-input`; const inputRef = React.useRef(null); @@ -586,6 +591,23 @@ const InternalInputNumber = React.forwardRef( }, [inputValue]); // ============================ Render ============================ + const upNode = ( + + {upHandler} + + ); + + const downNode = ( + + {downHandler} + + ); + return (
- {controls && ( - + {type === 'input' && controls && ( +
+ {upNode} + {downNode} +
)} + + {type === 'spinner' && controls && downNode} +
+ + {type === 'spinner' && controls && upNode}
); }, @@ -641,6 +667,7 @@ const InternalInputNumber = React.forwardRef( const InputNumber = React.forwardRef((props, ref) => { const { + type = 'input', disabled, style, prefixCls = 'rc-input-number', @@ -675,7 +702,7 @@ const InputNumber = React.forwardRef((props, r return ( ((props, r ref={holderRef} > void; } export default function StepHandler({ prefixCls, - upNode, - downNode, - upDisabled, - downDisabled, + action, + children, + disabled, onStep, }: StepHandlerProps) { // ======================== Step ======================== @@ -38,22 +35,20 @@ export default function StepHandler({ const onStepRef = React.useRef(); onStepRef.current = onStep; - const { classNames, styles } = React.useContext(SemanticContext) || {}; - const onStopStep = () => { clearTimeout(stepTimeoutRef.current); }; // We will interval update step when hold mouse down - const onStepMouseDown = (e: React.MouseEvent, up: boolean) => { + const onStepMouseDown = (e: React.MouseEvent) => { e.preventDefault(); onStopStep(); - onStepRef.current(up, 'handler'); + onStepRef.current(action === 'up', 'handler'); // Loop step for interval function loopStep() { - onStepRef.current(up, 'handler'); + onStepRef.current(action === 'up', 'handler'); stepTimeoutRef.current = setTimeout(loopStep, STEP_INTERVAL); } @@ -75,11 +70,8 @@ export default function StepHandler({ // ======================= Render ======================= const handlerClassName = `${prefixCls}-handler`; - const upClassName = clsx(handlerClassName, `${handlerClassName}-up`, { - [`${handlerClassName}-up-disabled`]: upDisabled, - }); - const downClassName = clsx(handlerClassName, `${handlerClassName}-down`, { - [`${handlerClassName}-down-disabled`]: downDisabled, + const className = clsx(handlerClassName, `${handlerClassName}-${action}`, { + [`${handlerClassName}-${action}-disabled`]: disabled, }); // fix: https://github.com/ant-design/ant-design/issues/43088 @@ -97,29 +89,16 @@ export default function StepHandler({ }; return ( -
- { - onStepMouseDown(e, true); - }} - aria-label="Increase Value" - aria-disabled={upDisabled} - className={upClassName} - > - {upNode || } - - { - onStepMouseDown(e, false); - }} - aria-label="Decrease Value" - aria-disabled={downDisabled} - className={downClassName} - > - {downNode || } - -
+ { + onStepMouseDown(e); + }} + aria-label={action === 'up' ? 'Increase Value' : 'Decrease Value'} + aria-disabled={disabled} + className={className} + > + {children || } + ); } diff --git a/tests/__snapshots__/baseInput.test.tsx.snap b/tests/__snapshots__/baseInput.test.tsx.snap index a8e10153..dfc613ff 100644 --- a/tests/__snapshots__/baseInput.test.tsx.snap +++ b/tests/__snapshots__/baseInput.test.tsx.snap @@ -4,7 +4,7 @@ exports[`baseInput addon should render properly 1`] = `

{ - it('max', () => { const onChange = jest.fn(); const { container } = render(); @@ -61,7 +60,6 @@ describe('InputNumber.Props', () => { expect(input).toHaveFocus(); done(); }, 500); - }); describe('step', () => { @@ -96,8 +94,8 @@ describe('InputNumber.Props', () => { , ); @@ -114,8 +112,8 @@ describe('InputNumber.Props', () => { , ); @@ -186,7 +184,7 @@ describe('InputNumber.Props', () => { return (