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

fix: User typing should not block #328

Merged
merged 9 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions docs/examples/simple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default () => {
const [disabled, setDisabled] = React.useState(false);
const [readOnly, setReadOnly] = React.useState(false);
const [keyboard, setKeyboard] = React.useState(true);
const [stringMode, setStringMode] = React.useState(true);
const [value, setValue] = React.useState<string | number>(5);
const [stringMode, setStringMode] = React.useState(false);
const [value, setValue] = React.useState<string | number>(93);

const onChange = (val: number) => {
console.warn('onChange:', val, typeof val);
Expand All @@ -18,7 +18,7 @@ export default () => {
return (
<div style={{ margin: 10 }}>
<h3>Controlled</h3>
{/* <InputNumber
<InputNumber
aria-label="Simple number input example"
min={-8}
max={10}
Expand All @@ -29,7 +29,7 @@ export default () => {
disabled={disabled}
keyboard={keyboard}
stringMode={stringMode}
/> */}
/>
<p>
<button type="button" onClick={() => setDisabled(!disabled)}>
toggle Disabled ({String(disabled)})
Expand All @@ -47,7 +47,13 @@ export default () => {

<hr />
<h3>Uncontrolled</h3>
<InputNumber style={{ width: 100 }} onChange={onChange} min={1} max={99} defaultValue={33} />
<InputNumber
style={{ width: 100 }}
onChange={onChange}
min={-99}
max={99}
defaultValue={33}
/>
</div>
);
};
32 changes: 20 additions & 12 deletions src/InputNumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const InputNumber = React.forwardRef(
/**
* `precision` is used for formatter & onChange.
* It will auto generate by `value` & `step`.
* But it will not block user typing when auto generated.
* But it will not block user typing.
*
* Note: Auto generate `precision` is used for legacy logic.
* We should remove this since we already support high precision with BigInt.
Expand All @@ -136,14 +136,14 @@ const InputNumber = React.forwardRef(
*/
const getPrecision = React.useCallback(
(numStr: string, userTyping: boolean) => {
if (precision >= 0) {
return precision;
}

if (userTyping) {
return undefined;
}

if (precision >= 0) {
return precision;
}

return Math.max(getNumberPrecision(numStr), getNumberPrecision(step));
},
[precision, step],
Expand Down Expand Up @@ -215,7 +215,15 @@ const InputNumber = React.forwardRef(

// Should always be string
function setInputValue(newValue: DecimalClass, userTyping: boolean) {
setInternalInputValue(mergedFormatter(newValue.toString(false), userTyping));
setInternalInputValue(
mergedFormatter(
// Invalidate number is sometime passed by external control, we should let it go
// Otherwise is controlled by internal interactive logic which check by userTyping
// You can ref 'show limited value when input is not focused' test for more info.
newValue.isInvalidate() ? newValue.toString(false) : newValue.toString(!userTyping),
userTyping,
),
);
}

// >>> Max & Min limit
Expand Down Expand Up @@ -336,7 +344,7 @@ const InputNumber = React.forwardRef(
};

// >>> Input
const onInternalInput: React.ChangeEventHandler<HTMLInputElement> = e => {
const onInternalInput: React.ChangeEventHandler<HTMLInputElement> = (e) => {
let inputStr = e.target.value;

// optimize for chinese input experience
Expand Down Expand Up @@ -383,14 +391,14 @@ const InputNumber = React.forwardRef(
/**
* Flush current input content to trigger value change & re-formatter input if needed
*/
const flushInputValue = () => {
const flushInputValue = (userTyping: boolean) => {
const parsedValue = getMiniDecimal(mergedParser(inputValue));
let formatValue: DecimalClass = parsedValue;

if (!parsedValue.isNaN()) {
// Only validate value or empty value can be re-fill to inputValue
// Reassign the formatValue within ranged of trigger control
formatValue = triggerValueUpdate(parsedValue, true);
formatValue = triggerValueUpdate(parsedValue, userTyping);
} else {
formatValue = decimalValue;
}
Expand All @@ -404,15 +412,15 @@ const InputNumber = React.forwardRef(
}
};

const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = event => {
const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (event) => {
const { which } = event;
userTypingRef.current = true;

if (which === KeyCode.ENTER) {
if (!compositionRef.current) {
userTypingRef.current = false;
}
flushInputValue();
flushInputValue(true);
onPressEnter?.(event);
}

Expand All @@ -433,7 +441,7 @@ const InputNumber = React.forwardRef(

// >>> Focus & Blur
const onBlur = () => {
flushInputValue();
flushInputValue(false);

setFocus(false);

Expand Down
17 changes: 13 additions & 4 deletions src/utils/MiniDecimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,13 @@ export class NumberDecimal implements DecimalClass {
return this.number;
}

toString(safe = true) {
toString(safe: boolean = true) {
if (!safe) {
return this.origin;
}

if (this.isInvalidate()) {
return safe ? '' : this.origin;
return '';
}

return num2str(this.number);
Expand Down Expand Up @@ -238,10 +242,15 @@ export class BigIntDecimal implements DecimalClass {
return Number(this.toString());
}

toString(safe = true): string {
toString(safe: boolean = true) {
if (!safe) {
return this.origin;
}

if (this.isInvalidate()) {
return safe ? '' : this.origin;
return '';
}

return trimNumber(`${this.getMark()}${this.getIntegerStr()}.${this.getDecimalStr()}`).fullStr;
}
}
Expand Down
24 changes: 12 additions & 12 deletions tests/decimal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,15 @@ describe('InputNumber.Decimal', () => {
expect(wrapper.getInputValue()).toEqual('1.00');
});

it('zero precision should work',()=>{
it('zero precision should work', () => {
const onChange = jest.fn();
const wrapper = mount(<InputNumber onChange={onChange} precision={0} />);

wrapper.changeValue('1.44');
wrapper.blurInput();
expect(onChange).toHaveBeenCalledWith(1);
expect(wrapper.getInputValue()).toEqual('1');
})
});

it('should not trigger onChange when blur InputNumber with precision', () => {
const onChange = jest.fn();
Expand Down Expand Up @@ -159,7 +159,7 @@ describe('InputNumber.Decimal', () => {
expect(wrapper.getInputValue()).toEqual('');
});

it('should trigger onChange when removing value',()=>{
it('should trigger onChange when removing value', () => {
const onChange = jest.fn();
const wrapper = mount(<InputNumber onChange={onChange} />);

Expand All @@ -168,18 +168,18 @@ describe('InputNumber.Decimal', () => {
expect(wrapper.getInputValue()).toEqual('1');
expect(onChange).toHaveBeenCalledWith(1);

wrapper.changeValue('')
wrapper.changeValue('');
expect(wrapper.getInputValue()).toEqual('');
expect(onChange).toHaveBeenCalledWith(null);

wrapper.setProps({min:0,max:10})
wrapper.changeValue('2')
expect(wrapper.getInputValue()).toEqual('2')
expect(onChange).toHaveBeenCalledWith(2)
wrapper.setProps({ min: 0, max: 10 });
wrapper.changeValue('2');
expect(wrapper.getInputValue()).toEqual('2');
expect(onChange).toHaveBeenCalledWith(2);

wrapper.changeValue('')
expect(wrapper.getInputValue()).toEqual('')
expect(onChange).toHaveBeenCalledWith(null)
})
wrapper.changeValue('');
expect(wrapper.getInputValue()).toEqual('');
expect(onChange).toHaveBeenCalledWith(null);
});
});
});
9 changes: 9 additions & 0 deletions tests/github.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,13 @@ describe('InputNumber.Github', () => {

expect(wrapper.find('input').last().props().value).toEqual('1');
});

// https://github.com/ant-design/ant-design/issues/30478
it('-0 should input able', () => {
const wrapper = mount(<InputNumber />);
wrapper.changeValue('-');
wrapper.changeValue('-0');

expect(wrapper.getInputValue()).toEqual('-0');
});
});
6 changes: 6 additions & 0 deletions tests/util.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ describe('InputNumber.Util', () => {
// mini value
expect(getDecimal(0).add(-0.000000001).toString()).toEqual('-0.000000001');
});

it('toString !safe', () => {
const invalidate = getDecimal('Invalidate');
expect(invalidate.toString()).toEqual('');
expect(invalidate.toString(false)).toEqual('Invalidate');
});
});
});

Expand Down