inputNumber.stories.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. import React, { useRef, useState } from 'react';
  2. // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
  3. import './inputNumber.scss';
  4. import InputNumber from '../index';
  5. import Button from '../../button/index';
  6. import { withField, Form } from '../../index';
  7. export default {
  8. title: 'InputNumber',
  9. }
  10. function log(v, e) {
  11. const type = typeof v;
  12. console.log(type, v);
  13. }
  14. const createOnChange = changeFn => {
  15. return (...args) => {
  16. log(...args);
  17. if (typeof changeFn === 'function') {
  18. changeFn(...args);
  19. }
  20. };
  21. };
  22. export const _InputNumber = () => {
  23. const Demo = () => {
  24. const [controlledValue, setControlledValue] = useState(10.1);
  25. const controlledOnChange = createOnChange(setControlledValue);
  26. const [controlledValue2, setControlledValue2] = useState(9);
  27. const controlledOnChange2 = createOnChange(setControlledValue2);
  28. const [decimal, setDecimal] = useState(10.01);
  29. const decimalOnChange = createOnChange(setDecimal);
  30. const [formattedVal, setFormattedVal] = useState(10.02);
  31. const formattedValOnChange = createOnChange(setFormattedVal);
  32. const [formattedDecimal, setFormattedDecimal] = useState(10.03);
  33. const formattedDecimalOnChange = createOnChange(setFormattedDecimal);
  34. return (
  35. <div className="inputNumber">
  36. <label>简单数字输入框</label>
  37. <InputNumber onChange={log} />
  38. <br />
  39. <label>限定上下界与整数步长</label>
  40. <InputNumber max={10} min={0} step={1} />
  41. <br />
  42. <label>限定上下界与小数步长</label>
  43. <InputNumber max={10} min={0} step={0.1} defaultValue={0.2} precision={2} />
  44. <br />
  45. <label>格式化</label>
  46. <InputNumber
  47. defaultValue={1000}
  48. onChange={log}
  49. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  50. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  51. />
  52. <br />
  53. <label>小数</label>
  54. <InputNumber defaultValue={10.08} precision={2} onChange={log} />
  55. <br />
  56. <label>格式化+小数</label>
  57. <InputNumber
  58. defaultValue={1000}
  59. precision={2}
  60. onChange={log}
  61. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  62. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  63. />
  64. <br />
  65. <label>受控</label>
  66. <InputNumber value={controlledValue} onChange={controlledOnChange} />
  67. <br />
  68. <label>受控+上下界</label>
  69. <InputNumber min={1} max={10} value={controlledValue2} onChange={controlledOnChange2} />
  70. <br />
  71. <label>小数+受控</label>
  72. <InputNumber value={decimal} precision={2} onChange={decimalOnChange} />
  73. <br />
  74. <label>格式化+受控</label>
  75. <InputNumber
  76. defaultValue={1000}
  77. precision={0}
  78. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  79. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  80. onChange={formattedValOnChange}
  81. value={formattedVal}
  82. />
  83. <br />
  84. <label>格式化+小数+受控</label>
  85. <InputNumber
  86. precision={2}
  87. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  88. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  89. onChange={formattedDecimalOnChange}
  90. value={formattedDecimal}
  91. />
  92. </div>
  93. );
  94. };
  95. return <Demo />;
  96. };
  97. _InputNumber.story = {
  98. name: 'Input number',
  99. };
  100. export const InputnumberUseRefCallFocus = () => {
  101. const Demo = () => {
  102. const ref = useRef();
  103. const focus = () => {
  104. ref.current && ref.current.focus();
  105. };
  106. const blur = () => ref.current && ref.current.blur();
  107. return (
  108. <>
  109. <InputNumber ref={ref} />
  110. <Button onClick={focus}>focus</Button>
  111. <Button onClick={blur}>blur</Button>
  112. </>
  113. );
  114. };
  115. return <Demo />;
  116. };
  117. InputnumberUseRefCallFocus.story = {
  118. name: 'inputnumber use ref call focus',
  119. };
  120. export const UncontrolledInputNumber = () => {
  121. const Demo = function Demo(props = {}) {
  122. return (
  123. <div style={{ width: 450, padding: 20 }}>
  124. <h5>defaultValue</h5>
  125. <InputNumber defaultValue={1020} onChange={log} />
  126. <br />
  127. <h5>defaultValue + formatter + parser</h5>
  128. <InputNumber
  129. defaultValue={1020}
  130. onChange={log}
  131. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  132. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  133. />
  134. <br />
  135. <h5>defaultValue + precision + formatter + parser</h5>
  136. <InputNumber
  137. defaultValue={1020}
  138. precision={2}
  139. onChange={log}
  140. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  141. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  142. />
  143. <br />
  144. <h5>defaultValue + precision + max + min + formatter + parser</h5>
  145. <InputNumber
  146. defaultValue={1020}
  147. precision={2}
  148. onChange={log}
  149. max={1000}
  150. min={500}
  151. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  152. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  153. />
  154. <br />
  155. </div>
  156. );
  157. };
  158. return <Demo />;
  159. };
  160. UncontrolledInputNumber.story = {
  161. name: 'uncontrolled InputNumber',
  162. };
  163. export const ControlledInputNumber = () => {
  164. const ControlledDemo = function ControlledDemo(props = {}) {
  165. const [value, setValue] = useState(0);
  166. const _setValue = createOnChange(setValue);
  167. const [value1, setValue1] = useState(0.234);
  168. const _setValue1 = createOnChange(setValue1);
  169. const [value2, setValue2] = useState(1000);
  170. const _setValue2 = createOnChange(setValue2);
  171. const [value3, setValue3] = useState(0.21);
  172. const _setValue3 = createOnChange(setValue3);
  173. const [value4, setValue4] = useState(3);
  174. const randomSetValue4 = createOnChange(v => {
  175. setValue4(Math.random() * 3 + 1);
  176. });
  177. const [value5, setValue5] = useState(5);
  178. const randomSetValue5 = createOnChange(v => {
  179. setValue5(Math.random() * 5 + 1);
  180. });
  181. const [value6, setValue6] = useState(6);
  182. const randomSetValue6 = createOnChange(v => {
  183. const num = Math.random() * 10 + 9;
  184. console.log('random set: ', num);
  185. setValue6(num);
  186. });
  187. const _setValue6 = createOnChange(setValue6);
  188. return (
  189. <div style={{ width: 450, padding: 20 }}>
  190. <h5>defaultValue</h5>
  191. <InputNumber defaultValue={1020} onChange={log} />
  192. <br />
  193. <h5>value</h5>
  194. <InputNumber value={1000} onChange={log} />
  195. <br />
  196. <h5>value + onChange</h5>
  197. <InputNumber value={value} onChange={_setValue} onBlur={() => console.log('blur')} />
  198. <br />
  199. <h5>value + precision + onChange</h5>
  200. <InputNumber value={value1} onChange={_setValue1} precision={2} />
  201. <br />
  202. <h5>value + step + precision + onChange</h5>
  203. <InputNumber step={0.2} value={value3} onChange={_setValue3} precision={2} />
  204. <br />
  205. <h5>value + precision + onChange + formatter + parser</h5>
  206. <Button onClick={() => setValue2(undefined)}>Empty</Button>
  207. <InputNumber
  208. value={value2}
  209. precision={2}
  210. onChange={_setValue2}
  211. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  212. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  213. />
  214. <br />
  215. <h5>random set value + precision</h5>
  216. <Button onClick={randomSetValue4}>Random Set Value</Button>
  217. <InputNumber value={value4} precision={2} onChange={log} />
  218. <br />
  219. <h5>random set value + precision + formatter + parser</h5>
  220. <Button onClick={randomSetValue5}>Random Set Value</Button>
  221. <Button onClick={() => setValue5(undefined)}>Empty</Button>
  222. <InputNumber
  223. value={value5}
  224. precision={2}
  225. onChange={log}
  226. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  227. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  228. />
  229. <br />
  230. <h5>random set value + max + min + precision + onChange</h5>
  231. <Button onClick={randomSetValue6}>Random Set Value</Button>
  232. <Button onClick={() => setValue6(undefined)}>Empty</Button>
  233. <InputNumber max={18} min={-8} value={value6} precision={2} onChange={_setValue6} />
  234. <br />
  235. </div>
  236. );
  237. };
  238. return <ControlledDemo />;
  239. };
  240. ControlledInputNumber.story = {
  241. name: 'controlled InputNumber',
  242. };
  243. export const InnnerButtons = () => {
  244. const Demo = () => {
  245. return (
  246. <div style={{ width: 450 }}>
  247. <label>innerButtons=false</label>
  248. <div>
  249. <InputNumber innerButtons={false} />
  250. </div>
  251. <br />
  252. <label>innerButtons=true</label>
  253. <div>
  254. <InputNumber innerButtons={true} suffix={'小时'} min={0} />
  255. </div>
  256. </div>
  257. );
  258. };
  259. return <Demo />;
  260. };
  261. InnnerButtons.story = {
  262. name: 'innnerButtons',
  263. };
  264. export const ShiftStep = () => {
  265. const Demo = () => {
  266. return (
  267. <div style={{ width: 450 }}>
  268. <label>shiftStep=100,可长按</label>
  269. <div>
  270. <InputNumber shiftStep={100} />
  271. </div>
  272. </div>
  273. );
  274. };
  275. return <Demo />;
  276. };
  277. ShiftStep.story = {
  278. name: 'shiftStep',
  279. };
  280. export const OnChangeLimit = () => {
  281. const Demo = () => {
  282. const [disabled, setDisabled] = useState(true);
  283. const [disabled2, setDisabled2] = useState(false);
  284. const [val, setVal] = useState(2);
  285. return (
  286. <>
  287. <h3>数值没有持续变化说明正常,v1.10.0修复</h3>
  288. <br />
  289. <br />
  290. <div>点击2后点击输入框,然后点击按钮会触发</div>
  291. {disabled ? (
  292. <div
  293. onClick={() => {
  294. setDisabled(false);
  295. }}
  296. >
  297. {val}
  298. </div>
  299. ) : (
  300. <InputNumber
  301. style={{ width: 120 }}
  302. val={val}
  303. innerButtons
  304. onChange={res => setVal(res)}
  305. />
  306. )}
  307. <br />
  308. <br />
  309. <div>点击按钮后切换 disabled 状态</div>
  310. <div>disablde: {String(disabled2)}</div>
  311. <div>
  312. <InputNumber
  313. defaultValue={12}
  314. innerButtons
  315. disabled={disabled2}
  316. onChange={() => setDisabled2(true)}
  317. />
  318. </div>
  319. </>
  320. );
  321. };
  322. return <Demo />;
  323. };
  324. OnChangeLimit.story = {
  325. name: 'onChange无限触发问题',
  326. };
  327. export const ClearIconPosition = () => {
  328. const Demo = () => {
  329. return <InputNumber autoFocus defaultValue={12} innerButtons showClear />;
  330. };
  331. return <Demo />;
  332. };
  333. ClearIconPosition.story = {
  334. name: 'clear icon 位置',
  335. };
  336. export const UncontrolledKeepFocus = () => {
  337. const Demo = () => {
  338. const [val, setVal] = useState(2);
  339. const [val2, setVal2] = useState(2);
  340. return (
  341. <div style={{ width: 450, padding: 20 }}>
  342. <h5>defaultValue</h5>
  343. <InputNumber defaultValue={1020} onChange={log} keepFocus={true} />
  344. <br />
  345. <h5>defaultValue + formatter + parser</h5>
  346. <InputNumber
  347. keepFocus={true}
  348. defaultValue={1020}
  349. onChange={log}
  350. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  351. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  352. />
  353. <br />
  354. <h5>defaultValue + precision + formatter + parser</h5>
  355. <InputNumber
  356. keepFocus={true}
  357. defaultValue={1020}
  358. precision={2}
  359. onChange={log}
  360. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  361. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  362. />
  363. <br />
  364. <h5>defaultValue + precision + max + min + formatter + parser</h5>
  365. <InputNumber
  366. keepFocus={true}
  367. defaultValue={1020}
  368. precision={2}
  369. onChange={log}
  370. max={1000}
  371. min={500}
  372. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  373. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  374. />
  375. <br />
  376. </div>
  377. );
  378. };
  379. return <Demo />;
  380. };
  381. UncontrolledKeepFocus.story = {
  382. name: 'uncontrolled keepFocus',
  383. };
  384. export const ControlledKeepFocus = () => {
  385. const Demo = () => {
  386. const [value, setValue] = useState(0);
  387. const _setValue = createOnChange(setValue);
  388. const [value1, setValue1] = useState(0.234);
  389. const _setValue1 = createOnChange(setValue1);
  390. const [value2, setValue2] = useState(1000);
  391. const _setValue2 = createOnChange(setValue2);
  392. const [value3, setValue3] = useState(0.21);
  393. const _setValue3 = createOnChange(setValue3);
  394. const [value4, setValue4] = useState(3);
  395. const randomSetValue4 = createOnChange(v => {
  396. setValue4(Math.random() * 3 + 1);
  397. });
  398. const [value5, setValue5] = useState(5);
  399. const randomSetValue5 = createOnChange(v => {
  400. setValue5(Math.random() * 5 + 1);
  401. });
  402. const [value6, setValue6] = useState(6);
  403. const randomSetValue6 = createOnChange(v => {
  404. const num = Math.random() * 10 + 9;
  405. console.log('random set: ', num);
  406. setValue6(num);
  407. });
  408. const _setValue6 = createOnChange(setValue6);
  409. return (
  410. <div style={{ width: 450, padding: 20 }}>
  411. <h5>defaultValue</h5>
  412. <InputNumber keepFocus={true} defaultValue={1020} onChange={log} />
  413. <br />
  414. <h5>value</h5>
  415. <InputNumber keepFocus={true} value={1000} onChange={log} />
  416. <br />
  417. <h5>value + onChange</h5>
  418. <InputNumber
  419. keepFocus={true}
  420. value={value}
  421. onChange={_setValue}
  422. onBlur={() => console.log('blur')}
  423. />
  424. <br />
  425. <h5>value + precision + onChange</h5>
  426. <InputNumber keepFocus={true} value={value1} onChange={_setValue1} precision={2} />
  427. <br />
  428. <h5>value + step + precision + onChange</h5>
  429. <InputNumber
  430. keepFocus={true}
  431. step={0.2}
  432. value={value3}
  433. onChange={_setValue3}
  434. precision={2}
  435. />
  436. <br />
  437. <h5>value + precision + onChange + formatter + parser</h5>
  438. <Button onClick={() => setValue2(undefined)}>Empty</Button>
  439. <InputNumber
  440. keepFocus={true}
  441. value={value2}
  442. precision={2}
  443. onChange={_setValue2}
  444. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  445. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  446. />
  447. <br />
  448. <h5>random set value + precision</h5>
  449. <Button onClick={randomSetValue4}>Random Set Value</Button>
  450. <InputNumber keepFocus={true} value={value4} precision={2} onChange={log} />
  451. <br />
  452. <h5>random set value + precision + formatter + parser</h5>
  453. <Button onClick={randomSetValue5}>Random Set Value</Button>
  454. <Button onClick={() => setValue5(undefined)}>Empty</Button>
  455. <InputNumber
  456. keepFocus={true}
  457. value={value5}
  458. precision={2}
  459. onChange={log}
  460. formatter={value => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  461. parser={value => value.replace(/\$\s?|(,*)/g, '')}
  462. />
  463. <br />
  464. <h5>random set value + max + min + precision + onChange</h5>
  465. <Button onClick={randomSetValue6}>Random Set Value</Button>
  466. <Button onClick={() => setValue6(undefined)}>Empty</Button>
  467. <InputNumber
  468. keepFocus={true}
  469. max={18}
  470. min={-8}
  471. value={value6}
  472. precision={2}
  473. onChange={_setValue6}
  474. />
  475. <br />
  476. </div>
  477. );
  478. };
  479. return <Demo />;
  480. };
  481. ControlledKeepFocus.story = {
  482. name: 'controlled keepFocus',
  483. };
  484. export const DisabledStyle = () => {
  485. const Demo = () => {
  486. return (
  487. <>
  488. <label>prop disabled</label>
  489. <InputNumber disabled />
  490. <br />
  491. <br />
  492. <label>max limit</label>
  493. <InputNumber min={1} max={10} defaultValue={10} />
  494. <br />
  495. <br />
  496. <label>min limit</label>
  497. <InputNumber min={1} max={10} defaultValue={1} />
  498. <br />
  499. <br />
  500. </>
  501. );
  502. };
  503. return <Demo />;
  504. };
  505. DisabledStyle.story = {
  506. name: 'disabled style',
  507. };
  508. export const FormCustomInput = () => {
  509. const Demo = () => {
  510. const CustomInput = withField(InputNumber, { onKeyChangeFnName: 'onNumberChange' });
  511. return (
  512. <>
  513. <h4>not controlled + without formatter</h4>
  514. <InputNumber
  515. onChange={(...args) => console.log('inputNumber change', ...args)}
  516. onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
  517. />
  518. <h4>not controlled + formatter(onChange会包括英文字符,onNumberChange不包括)</h4>
  519. <InputNumber
  520. formatter={value => `${value}`.replace(/\D/g, '')}
  521. onChange={(...args) => console.log('inputNumber change', ...args)}
  522. onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
  523. />
  524. <Form onValueChange={v => console.log(v)}>
  525. <h4>
  526. Form + Form.InputNumber + formatter + onChange(onChange包括英文字符,显示没有英文字符)
  527. </h4>
  528. <Form.InputNumber
  529. field="formOriginalInputNumber"
  530. noLabel
  531. formatter={value => `${value}`.replace(/\D/g, '')}
  532. onChange={(...args) => console.log('form inputNumber change', ...args)}
  533. />
  534. <h4>
  535. Form + withField InputNumber + formatter +
  536. onNumberChange(onNumberChange不包括英文字符,显示也不包括英文字符)
  537. </h4>
  538. <CustomInput
  539. field="formCustomInputNumber"
  540. noLabel
  541. formatter={value => `${value}`.replace(/\D/g, '')}
  542. />
  543. </Form>
  544. <h4>
  545. type=number (TODO:需要关注内置的按钮+不同浏览器对type=number的支持情况,比如 safari
  546. 貌似就不支持)
  547. </h4>
  548. <InputNumber
  549. type="number"
  550. onChange={(...args) => console.log('inputNumber change', ...args)}
  551. onNumberChange={(...args) => console.log('inputNumber number change', ...args)}
  552. />
  553. <h4>测试 formatter + parser 是否正常</h4>
  554. <InputNumber
  555. onChange={v => console.log(`Changed to: [${typeof v}] ${v}`)}
  556. defaultValue={1000}
  557. min={0}
  558. formatter={value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
  559. parser={value => value.replace(/\¥\s?|(,*)/g, '')}
  560. />
  561. </>
  562. );
  563. };
  564. return <Demo />;
  565. };
  566. FormCustomInput.story = {
  567. name: 'Form.CustomInput',
  568. };