Skip to content

Commit fda11c6

Browse files
committed
feat(spinner): support spinner type
1 parent 195463e commit fda11c6

File tree

5 files changed

+170
-24
lines changed

5 files changed

+170
-24
lines changed

assets/index.less

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,29 @@
133133
.handler-disabled();
134134
}
135135
}
136+
137+
&-type-spinner {
138+
display: inline-flex;
139+
align-items: center;
140+
}
141+
142+
&-type-spinner &-handler-wrap {
143+
flex: 0 0 20px;
144+
border-left: 0;
145+
}
146+
147+
&-type-spinner &-handler {
148+
line-height: 26px;
149+
}
150+
151+
&-type-spinner &-handler-up {
152+
border-bottom: 0;
153+
border-left: 1px solid #d9d9d9;
154+
height: 100%;
155+
}
156+
&-type-spinner &-handler-down {
157+
border-top: 0;
158+
border-right: 1px solid #d9d9d9;
159+
height: 100%;
160+
}
136161
}

docs/demo/spinner.tsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* eslint no-console:0 */
2+
import InputNumber from '@rc-component/input-number';
3+
import React from 'react';
4+
import '../../assets/index.less';
5+
6+
export default () => {
7+
const [disabled, setDisabled] = React.useState(false);
8+
const [readOnly, setReadOnly] = React.useState(false);
9+
const [keyboard, setKeyboard] = React.useState(true);
10+
const [wheel, setWheel] = React.useState(true);
11+
const [stringMode, setStringMode] = React.useState(false);
12+
const [value, setValue] = React.useState<string | number>(93);
13+
14+
const onChange = (val: number) => {
15+
console.warn('onChange:', val, typeof val);
16+
setValue(val);
17+
};
18+
19+
return (
20+
<div style={{ margin: 10 }}>
21+
<h3>Controlled</h3>
22+
<InputNumber
23+
type="spinner"
24+
aria-label="Simple number input example"
25+
min={-8}
26+
max={10}
27+
style={{ width: 100 }}
28+
value={value}
29+
onChange={onChange}
30+
readOnly={readOnly}
31+
disabled={disabled}
32+
keyboard={keyboard}
33+
changeOnWheel={wheel}
34+
stringMode={stringMode}
35+
/>
36+
<p>
37+
<button type="button" onClick={() => setDisabled(!disabled)}>
38+
toggle Disabled ({String(disabled)})
39+
</button>
40+
<button type="button" onClick={() => setReadOnly(!readOnly)}>
41+
toggle readOnly ({String(readOnly)})
42+
</button>
43+
<button type="button" onClick={() => setKeyboard(!keyboard)}>
44+
toggle keyboard ({String(keyboard)})
45+
</button>
46+
<button type="button" onClick={() => setStringMode(!stringMode)}>
47+
toggle stringMode ({String(stringMode)})
48+
</button>
49+
<button type="button" onClick={() => setWheel(!wheel)}>
50+
toggle wheel ({String(wheel)})
51+
</button>
52+
</p>
53+
54+
<hr />
55+
<h3>Uncontrolled</h3>
56+
<InputNumber
57+
type="spinner"
58+
style={{ width: 100 }}
59+
onChange={onChange}
60+
min={-99}
61+
max={99}
62+
defaultValue={33}
63+
/>
64+
65+
<hr />
66+
<h3>!changeOnBlur</h3>
67+
<InputNumber
68+
type="spinner"
69+
style={{ width: 100 }}
70+
min={-9}
71+
max={9}
72+
defaultValue={10}
73+
onChange={onChange}
74+
changeOnBlur={false}
75+
/>
76+
</div>
77+
);
78+
};

docs/example.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,7 @@ nav:
5252
## focus
5353

5454
<code src="./demo/focus.tsx"></code>
55+
56+
## spinner
57+
58+
<code src="./demo/spinner.tsx"></code>

src/InputNumber.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ export interface InputNumberProps<T extends ValueType = ValueType>
6363
/** value will show as string */
6464
stringMode?: boolean;
6565

66+
type?: 'input' | 'spinner';
67+
6668
defaultValue?: T;
6769
value?: T | null;
6870

@@ -84,6 +86,8 @@ export interface InputNumberProps<T extends ValueType = ValueType>
8486
// Customize handler node
8587
upHandler?: React.ReactNode;
8688
downHandler?: React.ReactNode;
89+
spinnerUpHandler?: React.ReactNode;
90+
spinnerDownHandler?: React.ReactNode;
8791
keyboard?: boolean;
8892
changeOnWheel?: boolean;
8993

@@ -119,6 +123,7 @@ type InternalInputNumberProps = Omit<InputNumberProps, 'prefix' | 'suffix'> & {
119123
const InternalInputNumber = React.forwardRef(
120124
(props: InternalInputNumberProps, ref: React.Ref<HTMLInputElement>) => {
121125
const {
126+
type,
122127
prefixCls,
123128
className,
124129
style,
@@ -131,6 +136,8 @@ const InternalInputNumber = React.forwardRef(
131136
readOnly,
132137
upHandler,
133138
downHandler,
139+
spinnerUpHandler,
140+
spinnerDownHandler,
134141
keyboard,
135142
changeOnWheel = false,
136143
controls = true,
@@ -607,7 +614,7 @@ const InternalInputNumber = React.forwardRef(
607614
onCompositionEnd={onCompositionEnd}
608615
onBeforeInput={onBeforeInput}
609616
>
610-
{controls && (
617+
{type === 'input' && controls && (
611618
<StepHandler
612619
prefixCls={prefixCls}
613620
upNode={upHandler}
@@ -617,6 +624,17 @@ const InternalInputNumber = React.forwardRef(
617624
onStep={onInternalStep}
618625
/>
619626
)}
627+
628+
{type === 'spinner' && controls && (
629+
<StepHandler
630+
prefixCls={prefixCls}
631+
downNode={spinnerDownHandler || downHandler}
632+
downDisabled={downDisabled}
633+
upHidden
634+
onStep={onInternalStep}
635+
/>
636+
)}
637+
620638
<div className={`${inputClassName}-wrap`}>
621639
<input
622640
autoComplete="off"
@@ -634,13 +652,24 @@ const InternalInputNumber = React.forwardRef(
634652
readOnly={readOnly}
635653
/>
636654
</div>
655+
656+
{type === 'spinner' && controls && (
657+
<StepHandler
658+
prefixCls={prefixCls}
659+
upNode={spinnerUpHandler || upHandler}
660+
upDisabled={upDisabled}
661+
downHidden
662+
onStep={onInternalStep}
663+
/>
664+
)}
637665
</div>
638666
);
639667
},
640668
);
641669

642670
const InputNumber = React.forwardRef<InputNumberRef, InputNumberProps>((props, ref) => {
643671
const {
672+
type = 'input',
644673
disabled,
645674
style,
646675
prefixCls = 'rc-input-number',
@@ -675,7 +704,7 @@ const InputNumber = React.forwardRef<InputNumberRef, InputNumberProps>((props, r
675704
return (
676705
<SemanticContext.Provider value={memoizedValue}>
677706
<BaseInput
678-
className={className}
707+
className={clsx(`${prefixCls}-type-${type}`, className)}
679708
triggerFocus={focus}
680709
prefixCls={prefixCls}
681710
value={value}
@@ -696,6 +725,7 @@ const InputNumber = React.forwardRef<InputNumberRef, InputNumberProps>((props, r
696725
ref={holderRef}
697726
>
698727
<InternalInputNumber
728+
type={type}
699729
prefixCls={prefixCls}
700730
disabled={disabled}
701731
ref={inputFocusRef}

src/StepHandler.tsx

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ export interface StepHandlerProps {
1919
upNode?: React.ReactNode;
2020
downNode?: React.ReactNode;
2121
upDisabled?: boolean;
22+
upHidden?: boolean;
2223
downDisabled?: boolean;
24+
downHidden?: boolean;
2325
onStep: (up: boolean, emitter: 'handler' | 'keyboard' | 'wheel') => void;
2426
}
2527

@@ -29,6 +31,8 @@ export default function StepHandler({
2931
downNode,
3032
upDisabled,
3133
downDisabled,
34+
upHidden,
35+
downHidden,
3236
onStep,
3337
}: StepHandlerProps) {
3438
// ======================== Step ========================
@@ -98,28 +102,33 @@ export default function StepHandler({
98102

99103
return (
100104
<div className={clsx(`${handlerClassName}-wrap`, classNames?.actions)} style={styles?.actions}>
101-
<span
102-
{...sharedHandlerProps}
103-
onMouseDown={(e) => {
104-
onStepMouseDown(e, true);
105-
}}
106-
aria-label="Increase Value"
107-
aria-disabled={upDisabled}
108-
className={upClassName}
109-
>
110-
{upNode || <span unselectable="on" className={`${prefixCls}-handler-up-inner`} />}
111-
</span>
112-
<span
113-
{...sharedHandlerProps}
114-
onMouseDown={(e) => {
115-
onStepMouseDown(e, false);
116-
}}
117-
aria-label="Decrease Value"
118-
aria-disabled={downDisabled}
119-
className={downClassName}
120-
>
121-
{downNode || <span unselectable="on" className={`${prefixCls}-handler-down-inner`} />}
122-
</span>
105+
{!upHidden && (
106+
<span
107+
{...sharedHandlerProps}
108+
onMouseDown={(e) => {
109+
onStepMouseDown(e, true);
110+
}}
111+
aria-label="Increase Value"
112+
aria-disabled={upDisabled}
113+
className={upClassName}
114+
>
115+
{upNode || <span unselectable="on" className={`${prefixCls}-handler-up-inner`} />}
116+
</span>
117+
)}
118+
119+
{!downHidden && (
120+
<span
121+
{...sharedHandlerProps}
122+
onMouseDown={(e) => {
123+
onStepMouseDown(e, false);
124+
}}
125+
aria-label="Decrease Value"
126+
aria-disabled={downDisabled}
127+
className={downClassName}
128+
>
129+
{downNode || <span unselectable="on" className={`${prefixCls}-handler-down-inner`} />}
130+
</span>
131+
)}
123132
</div>
124133
);
125134
}

0 commit comments

Comments
 (0)