| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767 |
- import React, { useRef, useState } from 'react';
- // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
- import './inputNumber.scss';
- import InputNumber from '../index';
- import Button from '../../button/index';
- import { withField, Form } from '../../index';
- import { useFormApi } from '../../form';
- import { Space } from '../../index';
- export default {
- title: 'InputNumber',
- }
- function log(v, e) {
- const type = typeof v;
- console.log(type, v);
- }
- const createOnChange = changeFn => {
- return (...args) => {
- log(...args);
- if (typeof changeFn === 'function') {
- changeFn(...args);
- }
- };
- };
- export const _InputNumber = () => {
- const Demo = () => {
- const [controlledValue, setControlledValue] = useState(10.1);
- const controlledOnChange = createOnChange(setControlledValue);
- const [controlledValue2, setControlledValue2] = useState(9);
- const controlledOnChange2 = createOnChange(setControlledValue2);
- const [decimal, setDecimal] = useState(10.01);
- const decimalOnChange = createOnChange(setDecimal);
- const [formattedVal, setFormattedVal] = useState(10.02);
- const formattedValOnChange = createOnChange(setFormattedVal);
- const [formattedDecimal, setFormattedDecimal] = useState(10.03);
- const formattedDecimalOnChange = createOnChange(setFormattedDecimal);
- return (
- <div className="inputNumber">
- <label>简单数字输入框</label>
- <InputNumber onChange={log} />
- <br />
- <label>限定上下界与整数步长</label>
- <InputNumber max={10} min={0} step={1} />
- <br />
- <label>限定上下界与小数步长</label>
- <InputNumber max={10} min={0} step={0.1} defaultValue={0.2} precision={2} />
- <br />
- <label>格式化</label>
- <InputNumber
- defaultValue={1000}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <label>小数(没有初始化值)</label>
- <InputNumber precision={2} onChange={log} />
- <br />
- <label>小数</label>
- <InputNumber defaultValue={10.08} precision={2} onChange={log} />
- <br />
- <label>格式化+小数</label>
- <InputNumber
- defaultValue={1000}
- precision={2}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <label>受控</label>
- <InputNumber value={controlledValue} onChange={controlledOnChange} />
- <br />
- <label>受控+上下界</label>
- <InputNumber min={1} max={10} value={controlledValue2} onChange={controlledOnChange2} />
- <br />
- <label>小数+受控</label>
- <InputNumber value={decimal} precision={2} onChange={decimalOnChange} />
- <br />
- <label>格式化+受控</label>
- <InputNumber
- defaultValue={1000}
- precision={0}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- onChange={formattedValOnChange}
- value={formattedVal}
- />
- <br />
- <label>格式化+小数+受控</label>
- <InputNumber
- precision={2}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- onChange={formattedDecimalOnChange}
- value={formattedDecimal}
- />
- </div>
- );
- };
- return <Demo />;
- };
- _InputNumber.story = {
- name: 'Input number',
- };
- export const InputnumberUseRefCallFocus = () => {
- const Demo = () => {
- const ref = useRef();
- const focus = () => {
- ref.current && ref.current.focus();
- };
- const blur = () => ref.current && ref.current.blur();
- return (
- <>
- <InputNumber ref={ref} />
- <Button onClick={focus}>focus</Button>
- <Button onClick={blur}>blur</Button>
- </>
- );
- };
- return <Demo />;
- };
- InputnumberUseRefCallFocus.story = {
- name: 'inputnumber use ref call focus',
- };
- export const UncontrolledInputNumber = () => {
- const Demo = function Demo(props = {}) {
- return (
- <div style={{ width: 450, padding: 20 }}>
- <h5>defaultValue</h5>
- <InputNumber defaultValue={1020} onChange={log} />
- <br />
- <h5>defaultValue + formatter + parser</h5>
- <InputNumber
- defaultValue={1020}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>defaultValue + precision + formatter + parser</h5>
- <InputNumber
- defaultValue={1020}
- precision={2}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>defaultValue + precision + max + min + formatter + parser</h5>
- <InputNumber
- defaultValue={1020}
- precision={2}
- onChange={log}
- max={1000}
- min={500}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- </div>
- );
- };
- return <Demo />;
- };
- UncontrolledInputNumber.story = {
- name: 'uncontrolled InputNumber',
- };
- export const ControlledInputNumber = () => {
- const ControlledDemo = function ControlledDemo(props = {}) {
- const [value, setValue] = useState(0);
- const _setValue = createOnChange(setValue);
- const [value1, setValue1] = useState(0.234);
- const _setValue1 = createOnChange(setValue1);
- const [value2, setValue2] = useState(1000);
- const _setValue2 = createOnChange(setValue2);
- const [value3, setValue3] = useState(0.21);
- const _setValue3 = createOnChange(setValue3);
- const [value4, setValue4] = useState(3);
- const randomSetValue4 = createOnChange(v => {
- setValue4(Math.random() * 3 + 1);
- });
- const [value5, setValue5] = useState(5);
- const randomSetValue5 = createOnChange(v => {
- setValue5(Math.random() * 5 + 1);
- });
- const [value6, setValue6] = useState(6);
- const randomSetValue6 = createOnChange(v => {
- const num = Math.random() * 10 + 9;
- console.log('random set: ', num);
- setValue6(num);
- });
- const _setValue6 = createOnChange(setValue6);
- return (
- <div style={{ width: 450, padding: 20 }}>
- <h5>defaultValue</h5>
- <InputNumber defaultValue={1020} onChange={log} />
- <br />
- <h5>value</h5>
- <InputNumber value={1000} onChange={log} />
- <br />
- <h5>value + onChange</h5>
- <InputNumber value={value} onChange={_setValue} onBlur={() => console.log('blur')} />
- <br />
- <h5>value + precision + onChange</h5>
- <InputNumber value={value1} onChange={_setValue1} precision={2} />
- <br />
- <h5>value + step + precision + onChange</h5>
- <InputNumber step={0.2} value={value3} onChange={_setValue3} precision={2} />
- <br />
- <h5>value + precision + onChange + formatter + parser</h5>
- <Button onClick={() => setValue2(undefined)}>Empty</Button>
- <InputNumber
- value={value2}
- precision={2}
- onChange={_setValue2}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>random set value + precision</h5>
- <Button onClick={randomSetValue4}>Random Set Value</Button>
- <InputNumber value={value4} precision={2} onChange={log} />
- <br />
- <h5>random set value + precision + formatter + parser</h5>
- <Button onClick={randomSetValue5}>Random Set Value</Button>
- <Button onClick={() => setValue5(undefined)}>Empty</Button>
- <InputNumber
- value={value5}
- precision={2}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>random set value + max + min + precision + onChange</h5>
- <Button onClick={randomSetValue6}>Random Set Value</Button>
- <Button onClick={() => setValue6(undefined)}>Empty</Button>
- <InputNumber max={18} min={-8} value={value6} precision={2} onChange={_setValue6} />
- <br />
- </div>
- );
- };
- return <ControlledDemo />;
- };
- ControlledInputNumber.story = {
- name: 'controlled InputNumber',
- };
- export const InnnerButtons = () => {
- const Demo = () => {
- return (
- <div style={{ width: 450 }}>
- <label>innerButtons=false</label>
- <div>
- <InputNumber innerButtons={false} />
- </div>
- <br />
- <label>innerButtons=true</label>
- <div>
- <InputNumber innerButtons={true} suffix={'小时'} min={0} />
- </div>
- </div>
- );
- };
- return <Demo />;
- };
- InnnerButtons.story = {
- name: 'innnerButtons',
- };
- export const ShiftStep = () => {
- const Demo = () => {
- return (
- <div style={{ width: 450 }}>
- <label>shiftStep=100,可长按</label>
- <div>
- <InputNumber shiftStep={100} />
- </div>
- </div>
- );
- };
- return <Demo />;
- };
- ShiftStep.story = {
- name: 'shiftStep',
- };
- export const OnChangeLimit = () => {
- const Demo = () => {
- const [disabled, setDisabled] = useState(true);
- const [disabled2, setDisabled2] = useState(false);
- const [val, setVal] = useState(2);
- return (
- <>
- <h3>数值没有持续变化说明正常,v1.10.0修复</h3>
- <br />
- <br />
- <div>点击2后点击输入框,然后点击按钮会触发</div>
- {disabled ? (
- <div
- onClick={() => {
- setDisabled(false);
- }}
- >
- {val}
- </div>
- ) : (
- <InputNumber
- style={{ width: 120 }}
- val={val}
- innerButtons
- onChange={res => setVal(res)}
- />
- )}
- <br />
- <br />
- <div>点击按钮后切换 disabled 状态</div>
- <div>disablde: {String(disabled2)}</div>
- <div>
- <InputNumber
- defaultValue={12}
- innerButtons
- disabled={disabled2}
- onChange={() => setDisabled2(true)}
- />
- </div>
- </>
- );
- };
- return <Demo />;
- };
- OnChangeLimit.story = {
- name: 'onChange无限触发问题',
- };
- export const ClearIconPosition = () => {
- const Demo = () => {
- return <InputNumber autoFocus defaultValue={12} innerButtons showClear />;
- };
- return <Demo />;
- };
- ClearIconPosition.story = {
- name: 'clear icon 位置',
- };
- export const UncontrolledKeepFocus = () => {
- const Demo = () => {
- const [val, setVal] = useState(2);
- const [val2, setVal2] = useState(2);
- return (
- <div style={{ width: 450, padding: 20 }}>
- <h5>defaultValue</h5>
- <InputNumber defaultValue={1020} onChange={log} keepFocus={true} />
- <br />
- <h5>defaultValue + formatter + parser</h5>
- <InputNumber
- keepFocus={true}
- defaultValue={1020}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>defaultValue + precision + formatter + parser</h5>
- <InputNumber
- keepFocus={true}
- defaultValue={1020}
- precision={2}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>defaultValue + precision + max + min + formatter + parser</h5>
- <InputNumber
- keepFocus={true}
- defaultValue={1020}
- precision={2}
- onChange={log}
- max={1000}
- min={500}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- </div>
- );
- };
- return <Demo />;
- };
- UncontrolledKeepFocus.story = {
- name: 'uncontrolled keepFocus',
- };
- export const ControlledKeepFocus = () => {
- const Demo = () => {
- const [value, setValue] = useState(0);
- const _setValue = createOnChange(setValue);
- const [value1, setValue1] = useState(0.234);
- const _setValue1 = createOnChange(setValue1);
- const [value2, setValue2] = useState(1000);
- const _setValue2 = createOnChange(setValue2);
- const [value3, setValue3] = useState(0.21);
- const _setValue3 = createOnChange(setValue3);
- const [value4, setValue4] = useState(3);
- const randomSetValue4 = createOnChange(v => {
- setValue4(Math.random() * 3 + 1);
- });
- const [value5, setValue5] = useState(5);
- const randomSetValue5 = createOnChange(v => {
- setValue5(Math.random() * 5 + 1);
- });
- const [value6, setValue6] = useState(6);
- const randomSetValue6 = createOnChange(v => {
- const num = Math.random() * 10 + 9;
- console.log('random set: ', num);
- setValue6(num);
- });
- const _setValue6 = createOnChange(setValue6);
- return (
- <div style={{ width: 450, padding: 20 }}>
- <h5>defaultValue</h5>
- <InputNumber keepFocus={true} defaultValue={1020} onChange={log} />
- <br />
- <h5>value</h5>
- <InputNumber keepFocus={true} value={1000} onChange={log} />
- <br />
- <h5>value + onChange</h5>
- <InputNumber
- keepFocus={true}
- value={value}
- onChange={_setValue}
- onBlur={() => console.log('blur')}
- />
- <br />
- <h5>value + precision + onChange</h5>
- <InputNumber keepFocus={true} value={value1} onChange={_setValue1} precision={2} />
- <br />
- <h5>value + step + precision + onChange</h5>
- <InputNumber
- keepFocus={true}
- step={0.2}
- value={value3}
- onChange={_setValue3}
- precision={2}
- />
- <br />
- <h5>value + precision + onChange + formatter + parser</h5>
- <Button onClick={() => setValue2(undefined)}>Empty</Button>
- <InputNumber
- keepFocus={true}
- value={value2}
- precision={2}
- onChange={_setValue2}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>random set value + precision</h5>
- <Button onClick={randomSetValue4}>Random Set Value</Button>
- <InputNumber keepFocus={true} value={value4} precision={2} onChange={log} />
- <br />
- <h5>random set value + precision + formatter + parser</h5>
- <Button onClick={randomSetValue5}>Random Set Value</Button>
- <Button onClick={() => setValue5(undefined)}>Empty</Button>
- <InputNumber
- keepFocus={true}
- value={value5}
- precision={2}
- onChange={log}
- formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\$\s?|(,*)/g, '')}
- />
- <br />
- <h5>random set value + max + min + precision + onChange</h5>
- <Button onClick={randomSetValue6}>Random Set Value</Button>
- <Button onClick={() => setValue6(undefined)}>Empty</Button>
- <InputNumber
- keepFocus={true}
- max={18}
- min={-8}
- value={value6}
- precision={2}
- onChange={_setValue6}
- />
- <br />
- </div>
- );
- };
- return <Demo />;
- };
- ControlledKeepFocus.story = {
- name: 'controlled keepFocus',
- };
- export const DisabledStyle = () => {
- const Demo = () => {
- return (
- <>
- <label>prop disabled</label>
- <InputNumber disabled />
- <br />
- <br />
- <label>max limit</label>
- <InputNumber min={1} max={10} defaultValue={10} />
- <br />
- <br />
- <label>min limit</label>
- <InputNumber min={1} max={10} defaultValue={1} />
- <br />
- <br />
- </>
- );
- };
- return <Demo />;
- };
- DisabledStyle.story = {
- name: 'disabled style',
- };
- export const FormCustomInput = () => {
- const Demo = () => {
- const CustomInput = withField(InputNumber, { onKeyChangeFnName: 'onNumberChange' });
- return (
- <>
- <h4>not controlled + without formatter</h4>
- <InputNumber
- onChange={(...args) => console.log('inputNumber change', ...args)}
- onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
- />
- <h4>not controlled + formatter(onChange会包括英文字符,onNumberChange不包括)</h4>
- <InputNumber
- formatter={value => `${value}`.replace(/\D/g, '')}
- onChange={(...args) => console.log('inputNumber change', ...args)}
- onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
- />
- <Form onValueChange={v => console.log(v)}>
- <h4>
- Form + Form.InputNumber + formatter + onChange(onChange包括英文字符,显示没有英文字符)
- </h4>
- <Form.InputNumber
- field="formOriginalInputNumber"
- noLabel
- formatter={value => `${value}`.replace(/\D/g, '')}
- onChange={(...args) => console.log('form inputNumber change', ...args)}
- />
- <h4>
- Form + withField InputNumber + formatter +
- onNumberChange(onNumberChange不包括英文字符,显示也不包括英文字符)
- </h4>
- <CustomInput
- field="formCustomInputNumber"
- noLabel
- formatter={value => `${value}`.replace(/\D/g, '')}
- />
- </Form>
- <h4>
- type=number (TODO:需要关注内置的按钮+不同浏览器对type=number的支持情况,比如 safari
- 貌似就不支持)
- </h4>
- <InputNumber
- type="number"
- onChange={(...args) => console.log('inputNumber change', ...args)}
- onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
- />
- <h4>测试 formatter + parser 是否正常</h4>
- <InputNumber
- onChange={v => console.log(`Changed to: [${typeof v}] ${v}`)}
- defaultValue={1000}
- min={0}
- formatter={value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
- parser={value => value.replace(/\¥\s?|(,*)/g, '')}
- />
- </>
- );
- };
- return <Demo />;
- };
- FormCustomInput.story = {
- name: 'Form.CustomInput',
- };
- export const FixPrecision = () => {
- const [value, setValue] = useState(5.12);
- const [value2, setValue2] = useState(5.12);
- return (
- <div>
- <InputNumber onChange={v => setValue(v)} value={value} style={{ width: 190 }} precision={2} />
- <InputNumber keepFocus onBlur={() => console.log('blur')} onChange={v => setValue2(v)} value={value2} style={{ width: 190 }} precision={2} />
- </div>
- );
- }
- /**
- * 受控传超出 min value 的值,需要触发 onChange
- * 不然在 Form 中使用可能会导致 Form State 与 InputNumber 展示的值不同问题
- */
- export const FixMinValue = () => {
- const [value, setValue] = useState();
- const formRef = useFormApi();
- return (
- <div style={{ width: 280 }}>
- <Button onClick={() => setValue(0)}>min=1, setValue=0</Button>
- <InputNumber
- min={1}
- value={value}
- onChange={(v, e) => {
- console.log('inputNumber1 change', `'${v}'`, e);
- setValue(v);
- }}
- />
- <InputNumber
- min={1}
- value={0}
- onChange={(v, e) => {
- console.log('inputNumber2 change', v, e);
- }}
- />
- <Form initValues={{ minControlled: 0 }}>
- <Form.InputNumber
- field='minControlled'
- min={1}
- onChange={(v, e) => {
- console.log('form inputNumber change', v, e);
- }}
- />
- </Form>
- <Button onClick={() => formRef.current.setValue('minControlled', 0) }>set form value</Button>
- <Button onClick={() => { console.log('form value', JSON.stringify(formRef.current.getValues()))}}>get form values</Button>
- </div>
- );
- }
- FixMinValue.storyName = 'fix min value';
- /**
- * fix InputNumber precision 删除后,输入非法字符显示 0.00
- * https://github.com/DouyinFE/semi-design/issues/786
- */
- export const FixPrecision786 = () => {
- return (
- <div data-cy="fix-precision-786">
- <InputNumber defaultValue={10.00} precision={2} />
- </div>
- );
- }
- FixPrecision786.storyName = 'fix precision 删除后输入非法值会显示 0.00';
- export const FixFormValidate = () => {
- return (
- <div data-cy="fix-precision-786">
- <Form >
- <Form.InputNumber
- field="inputnumber"
- label='inputnumber'
- rules={[
- {
- required: true,
- },
- ]}
- />
- <Form.Input
- field="input"
- label='input'
- rules={[
- {
- required: true,
- },
- ]}
- />
- </Form>
- </div>
- );
- }
- FixFormValidate.storyName = 'fix form validate';
- export const InputNumberA11y = () => {
- return (
- <Space vertical align="start" data-cy="a11y">
- <label for="default">
- step=1, shiftStep=10
- </label>
- <InputNumber id="default" data-cy="default" />
- <label for="step">
- step=5, shiftStep=100
- </label>
- <InputNumber id="step" data-cy="step" step={5} shiftStep={100} />
- <label for="max">
- step=1, shiftStep=10, max=10
- </label>
- <InputNumber id="max" data-cy="max" max={10} />
- <Form>
- <Form.InputNumber field="test" label="item number" />
- </Form>
- </Space>
- );
- }
- InputNumberA11y.storyName = "inputNumber a11y";
|