datePicker.stories.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. import React, { useState, useRef } from 'react';
  2. import {
  3. addDays,
  4. addWeeks,
  5. addMonths,
  6. isBefore,
  7. startOfMonth,
  8. endOfMonth,
  9. parseISO,
  10. startOfWeek,
  11. endOfWeek,
  12. } from 'date-fns';
  13. import { Space, ConfigProvider, InputGroup, InputNumber, Form, withField } from '../../index';
  14. // stores
  15. import NeedConfirmDemo from './NeedConfirm';
  16. import RenderDate from './RenderDate';
  17. import RenderFullDate from './RenderFullDate';
  18. import DateOffset from './DateOffset';
  19. import AllTypesDemo from './AllTypes';
  20. import Callbacks from './Callbacks';
  21. import DatePicker from '../index';
  22. import ExceptionDemo from './ExceptionDemo';
  23. import ControlledDemo from './ControlledDemo';
  24. import DisabledDate from './DisabledDate';
  25. import CustomTrigger from './CustomTrigger';
  26. import OverPopover from './OverPopover';
  27. import OnChangeWithDateFirst from './OnChangeWithDateFirst';
  28. import Multiple from './Multiple';
  29. import Autofocus from './Autofocus';
  30. import CycledDatePicker from './Cycled';
  31. import AutoSwitchDate from './AutoSwitchDate';
  32. import TimepikcerOpts from './TimePickerOpts';
  33. import Density from './Density';
  34. import DatePickerSlot from './DatePickerSlot';
  35. import DatePickerTimeZone from './DatePickerTimeZone';
  36. import BetterRangePicker from './BetterRangePicker';
  37. import SyncSwitchMonth from './SyncSwitchMonth';
  38. import { YearButton } from './v2';
  39. export default {
  40. title: 'DatePicker',
  41. parameters: {
  42. chromatic: { disableSnapshot: true },
  43. },
  44. }
  45. export {
  46. ControlledDemo,
  47. NeedConfirmDemo,
  48. ExceptionDemo,
  49. AllTypesDemo,
  50. Callbacks,
  51. DisabledDate,
  52. CustomTrigger,
  53. OverPopover,
  54. OnChangeWithDateFirst,
  55. RenderDate,
  56. RenderFullDate,
  57. Autofocus,
  58. DateOffset,
  59. CycledDatePicker,
  60. AutoSwitchDate,
  61. TimepikcerOpts,
  62. Density,
  63. DatePickerSlot,
  64. DatePickerTimeZone,
  65. BetterRangePicker,
  66. SyncSwitchMonth,
  67. YearButton
  68. }
  69. const demoDiv = {
  70. marginTop: '20px',
  71. marginLeft: '20px',
  72. };
  73. export const DatePickerDefault = () => (
  74. <div style={demoDiv}>
  75. <span>datePicker施工现场</span>
  76. <DatePicker
  77. insetLabel={<span>日期</span>}
  78. onChange={(str, date) => console.log(str)}
  79. onOpenChange={status => console.log(status)}
  80. placeholder="请选择日期"
  81. />
  82. <br />
  83. <span>datePicker默认显示</span>
  84. <DatePicker defaultOpen />
  85. <br />
  86. <span>defaultValue: new Date('2019-07-07')</span>
  87. <DatePicker
  88. defaultValue={new Date('2019-07-07')}
  89. onOpenChange={isOpen => console.log(isOpen)}
  90. />
  91. <br />
  92. <span>defaultValue: 2019-07-09</span>
  93. <DatePicker defaultValue="2019-07-09" />
  94. <br />
  95. <span>defaultValue: 1569888000000</span>
  96. <DatePicker
  97. defaultValue={1569888000000}
  98. onChange={(input, value) => console.log({ input, value })}
  99. />
  100. </div>
  101. );
  102. export const DatePickerCallbacks = () => {
  103. const printArgs = (...args) => console.log(...args);
  104. return (
  105. <div style={demoDiv}>
  106. <span>datePicker施工现场</span>
  107. <DatePicker onOpenChange={printArgs} />
  108. <br />
  109. <span>defaultValue: new Date('2019-07-07')</span>
  110. <DatePicker defaultValue={new Date('2019-07-07')} />
  111. <br />
  112. <span>defaultValue: 2019-07-09</span>
  113. <DatePicker defaultValue="2019-07-09" />
  114. <br />
  115. <span>defaultValue: 1569888000000</span>
  116. <DatePicker
  117. defaultValue={1569888000000}
  118. onChange={(input, value) => console.log(input, value)}
  119. />
  120. </div>
  121. );
  122. };
  123. export const DatePickerMultiple = () => <Multiple />;
  124. export const DateRangePicker = () => (
  125. <div style={demoDiv}>
  126. <div>dateRangePicker</div>
  127. <DatePicker type="dateRange" insetLabel="结束日期" prefix="test" validateStatus="error" />
  128. <br />
  129. <div>small dateRangePicker</div>
  130. <DatePicker type="dateRange" size="small" disabled prefix="test" />
  131. <br />
  132. <div>large dateRangePicker</div>
  133. <DatePicker type="dateRange" size="large" />
  134. <br />
  135. <div>compact dateRangePicker</div>
  136. <DatePicker type="dateRange" density="compact" validateStatus="warning" />
  137. <br />
  138. <div>dateRangePicker with offset</div>
  139. <DatePicker
  140. type="dateRange"
  141. startDateOffset={date => startOfWeek(date, { weekStartsOn: 1 })}
  142. endDateOffset={date => endOfWeek(date, { weekStartsOn: 1 })}
  143. />
  144. <br />
  145. <div>defaultValue:07/01-08/02</div>
  146. <DatePicker type="dateRange" defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]} />
  147. </div>
  148. );
  149. DateRangePicker.parameters = {
  150. chromatic: { disableSnapshot: false },
  151. };
  152. const presets = [
  153. {
  154. text: 'Today',
  155. start: new Date(),
  156. end: new Date(),
  157. },
  158. {
  159. text: 'Tomorrow',
  160. start: addDays(new Date(), 1),
  161. end: addDays(new Date(), 1),
  162. },
  163. {
  164. text: 'Next Week',
  165. start: addWeeks(new Date(), 1),
  166. end: addWeeks(new Date(), 2),
  167. },
  168. {
  169. text: 'Next Month',
  170. start: startOfMonth(addMonths(new Date(), 1)),
  171. end: endOfMonth(addMonths(new Date(), 1)),
  172. },
  173. {
  174. text: 'Today',
  175. start: new Date(),
  176. end: new Date(),
  177. },
  178. {
  179. text: 'Tomorrow',
  180. start: addDays(new Date(), 1),
  181. end: addDays(new Date(), 1),
  182. },
  183. {
  184. text: 'Next Week',
  185. start: addWeeks(new Date(), 1),
  186. end: addWeeks(new Date(), 2),
  187. },
  188. {
  189. text: 'Next Month',
  190. start: startOfMonth(addMonths(new Date(), 1)),
  191. end: endOfMonth(addMonths(new Date(), 1)),
  192. },
  193. ];
  194. export const DatePickerWithPresets = () => {
  195. const onPresetClick = (item, e) => {
  196. console.log('preset click', item, e);
  197. };
  198. return (
  199. <div style={demoDiv}>
  200. <span>带快捷选择的DatePicker</span>
  201. <DatePicker
  202. type="dateRange"
  203. presets={presets}
  204. onPresetClick={onPresetClick}
  205. onChange={(...args) => console.log(...args)}
  206. />
  207. <DatePicker
  208. type="dateTime"
  209. presets={presets.map(preset => ({
  210. text: preset.text,
  211. start: preset.start,
  212. }))}
  213. onPresetClick={onPresetClick}
  214. onChange={(...args) => console.log(...args)}
  215. />
  216. <DatePicker
  217. type="dateTime"
  218. needConfirm
  219. presets={presets.map(preset => ({
  220. text: preset.text,
  221. start: preset.start,
  222. }))}
  223. onPresetClick={onPresetClick}
  224. onChange={(...args) => console.log(...args)}
  225. />
  226. <DatePicker
  227. type="month"
  228. presets={presets.map(preset => ({
  229. text: preset.text,
  230. start: preset.start,
  231. }))}
  232. onPresetClick={onPresetClick}
  233. onChange={(...args) => console.log(...args)}
  234. />
  235. </div>
  236. );
  237. };
  238. function isDisabled(dayStr) {
  239. return isBefore(new Date(dayStr), new Date());
  240. }
  241. export const DatePickerDisabledDate = () => (
  242. <div style={demoDiv}>
  243. <span>不可选日期</span>
  244. <DatePicker type="dateRange" presets={presets} disabledDate={isDisabled} />
  245. </div>
  246. );
  247. export const DateTimePicker = () => (
  248. <div style={demoDiv}>
  249. <span>dateTimePicker</span>
  250. <DatePicker
  251. defaultPickerValue={parseISO('2020-02-20 20:00:00')}
  252. type="dateTime"
  253. onChange={(...args) => console.log('onChange: ', ...args)}
  254. />
  255. </div>
  256. );
  257. export const DateTimeRangePicker = () => (
  258. <div style={demoDiv}>
  259. <span>dateTimeRangePicker</span>
  260. <DatePicker type="dateTimeRange" defaultPickerValue={parseISO('2020-02-20 20:00:00')} />
  261. <br />
  262. <span>dateTimeRangePicker</span>
  263. <DatePicker type="dateTimeRange" presets={presets} />
  264. <br />
  265. <span>dateTimeRangePicker - multiple</span>
  266. <DatePicker type="dateTimeRange" multiple />
  267. <br />
  268. </div>
  269. );
  270. export const YearPicker = () => (
  271. <>
  272. <div>
  273. <span>Year Picker</span>
  274. <DatePicker type="dateTimeRange" />
  275. </div>
  276. <div>
  277. <span>Year Picker</span>
  278. <DatePicker type="dateTimeRange" presets={presets} />
  279. </div>
  280. </>
  281. );
  282. export const MonthPicker = () => {
  283. const Demo = () => {
  284. const [controlledValue, setControlledValue] = useState('2019-09');
  285. const _setControlledValue = value => setControlledValue(value);
  286. return (
  287. <>
  288. <div>
  289. <span>MonthPicker</span>
  290. <DatePicker type="month" />
  291. </div>
  292. <div>
  293. <span>MonthPicker with presets</span>
  294. <DatePicker type="month" presets={presets} />
  295. </div>
  296. <div>
  297. <span>MonthPicker with disabledDate</span>
  298. <DatePicker
  299. type="month"
  300. disabledDate={str => {
  301. const date = new Date(str);
  302. if (str.length <= 4) {
  303. return date.getFullYear() < 2015;
  304. }
  305. return date.getMonth() + 1 < 10;
  306. }}
  307. />
  308. </div>
  309. <div>
  310. <span>MonthPicker with presets</span>
  311. <DatePicker type="month" presets={presets} />
  312. </div>
  313. <div>
  314. <span>MonthPicker with controlledValue</span>
  315. <DatePicker type="month" value={controlledValue} onChange={_setControlledValue} />
  316. </div>
  317. </>
  318. );
  319. };
  320. return <Demo />;
  321. };
  322. export const PropTypesAndDefaultProps = () => (
  323. <div>
  324. <article>
  325. <p>{JSON.stringify(Object.keys(DatePicker.propTypes))}</p>
  326. <p>{JSON.stringify(DatePicker.defaultProps)}</p>
  327. </article>
  328. </div>
  329. );
  330. export const InputReadOnly = () => <DatePicker inputReadOnly={true} />;
  331. export const DropdownClassNameDropdownStyle = () => (
  332. <div>
  333. <h4>fontSize: 16,dropdownClassName: 'my-datePicker'</h4>
  334. <DatePicker
  335. dropdownStyle={{ fontSize: 16 }}
  336. dropdownClassName="my-datePicker"
  337. onChange={(date, dateString) => console.log(dateString)}
  338. />
  339. </div>
  340. );
  341. export const CustomPlaceholder = () => (
  342. <Space wrap>
  343. <DatePicker placeholder="请选择日期" insetLabel="默认" />
  344. <DatePicker placeholder={undefined} insetLabel="undefined" />
  345. <DatePicker placeholder="" insetLabel="空字符串" />
  346. <DatePicker placeholder={false} insetLabel="false" />
  347. <DatePicker placeholder={null} insetLabel="null" />
  348. <DatePicker placeholder="" type="dateRange" insetLabel="空字符串" />
  349. </Space>
  350. );
  351. CustomPlaceholder.parameters = {
  352. chromatic: { disableSnapshot: false },
  353. };
  354. export const FixNotifyChange = () => {
  355. function Demo() {
  356. const [tz, setTz] = useState(0);
  357. const [value, setVal] = useState();
  358. const [value2, setVal2] = useState();
  359. const [value3, setVal3] = useState();
  360. const [value4, setVal4] = useState();
  361. const withLog = fn => {
  362. return val => {
  363. console.log('notifyChange', val);
  364. fn(val);
  365. };
  366. };
  367. return (
  368. <ConfigProvider timeZone={tz}>
  369. <InputGroup>
  370. <InputNumber defaultValue={0} onChange={setTz} hideButtons />
  371. <DatePicker type="dateTimeRange" value={value} onChange={withLog(setVal)} />
  372. <DatePicker
  373. type="dateTimeRange"
  374. needConfirm
  375. value={value2}
  376. onConfirm={withLog(setVal2)}
  377. />
  378. <DatePicker type="date" value={value3} onChange={withLog(setVal3)} />
  379. <DatePicker type="dateRange" value={value4} onChange={withLog(setVal4)} />
  380. </InputGroup>
  381. </ConfigProvider>
  382. );
  383. }
  384. return <Demo />;
  385. };
  386. export const SelectNotDisabledDateV126 = () => {
  387. const defaultValue = ['2021-08-06', '2021-08-15'];
  388. const disabledMonth = dateStr => {
  389. const date = new Date(dateStr);
  390. const month = date.getMonth();
  391. if (month === 7) {
  392. return true;
  393. }
  394. return false;
  395. };
  396. const disabledDate = dateStr => {
  397. const date = new Date(dateStr);
  398. const day = date.getDate();
  399. if (day > 20 && day < 25) {
  400. return true;
  401. }
  402. return false;
  403. };
  404. let props = {
  405. type: 'dateRange',
  406. motion: false,
  407. defaultValue,
  408. onChange: (...args) => console.log('changed', ...args),
  409. style: { width: 300 },
  410. };
  411. return (
  412. <>
  413. <h4>dateRange type + disabled rangeStart and select rangeEnd</h4>
  414. <DatePicker {...props} disabledDate={disabledMonth} />
  415. <h4>date type + multiple select + given disabled defaultValue</h4>
  416. <DatePicker {...props} type="date" multiple disabledDate={disabledDate} />
  417. </>
  418. );
  419. };
  420. SelectNotDisabledDateV126.story = {
  421. name: 'select not disabled date(v1.26+)',
  422. };
  423. const CustomDatePicker = props => {
  424. const { fieldRef, ...rest } = props;
  425. return <DatePicker {...rest} ref={fieldRef} />;
  426. };
  427. const CustomFieldDatePicker = withField(CustomDatePicker);
  428. export const FixOnFocus = () => {
  429. function FocusDemo() {
  430. const [open1, setOpen1] = useState(false);
  431. const [open2, setOpen2] = useState(false);
  432. const [open3, setOpen3] = useState(false);
  433. const ref = useRef();
  434. const ref2 = useRef();
  435. const presets = [
  436. {
  437. text: 'Today',
  438. start: new Date(),
  439. end: new Date(),
  440. },
  441. {
  442. text: 'Tomorrow',
  443. start: new Date(new Date().valueOf() + 1000 * 3600 * 24),
  444. end: new Date(new Date().valueOf() + 1000 * 3600 * 24),
  445. },
  446. ];
  447. return (
  448. <>
  449. <DatePicker
  450. type="date"
  451. presets={presets}
  452. open={open1}
  453. onPresetClick={() => {
  454. setOpen1(false);
  455. }}
  456. onFocus={() => {
  457. console.log('focus');
  458. setOpen1(true);
  459. }}
  460. onBlur={() => {
  461. console.log('blur');
  462. }}
  463. style={{ width: 300 }}
  464. />
  465. <br />
  466. <br />
  467. <DatePicker
  468. type="dateTimeRange"
  469. presets={presets}
  470. open={open2}
  471. onPresetClick={() => {
  472. console.log('click presets', ref);
  473. setOpen2(false);
  474. setTimeout(() => {
  475. ref.current.foundation.closePanel();
  476. console.log(ref);
  477. }, 0);
  478. }}
  479. onFocus={() => {
  480. console.log('focus');
  481. setOpen2(true);
  482. }}
  483. onBlur={() => {
  484. console.log('blur');
  485. }}
  486. style={{ width: 500 }}
  487. ref={ref}
  488. />
  489. <Form>
  490. <CustomFieldDatePicker
  491. type="dateTimeRange"
  492. field="a"
  493. label="Form.DatePicker"
  494. presets={presets}
  495. open={open3}
  496. onPresetClick={() => {
  497. console.log('click presets', ref2);
  498. setOpen3(false);
  499. setTimeout(() => {
  500. ref2.current && ref2.current.foundation.closePanel();
  501. }, 0);
  502. }}
  503. onFocus={() => {
  504. console.log('focus');
  505. setOpen3(true);
  506. }}
  507. onBlur={() => {
  508. console.log('blur');
  509. }}
  510. style={{ width: 500 }}
  511. fieldRef={ref2}
  512. />
  513. </Form>
  514. </>
  515. );
  516. }
  517. return <FocusDemo />;
  518. };
  519. FixOnFocus.story = {
  520. name: 'fix onFocus',
  521. };
  522. export const FixDisabledTimeCallback1418 = () => {
  523. function Demo() {
  524. const disabledTime2 = (date, panelType) => {
  525. console.log('disabledTime callback parameter: ', date, panelType);
  526. if (panelType === 'left') {
  527. return { disabledHours: () => [17, 18] };
  528. } else {
  529. return { disabledHours: () => [12, 13, 14, 15, 16, 17, 18] };
  530. }
  531. };
  532. return (
  533. <>
  534. <strong>fix disabledTime callback parameter bug</strong>
  535. <DatePicker
  536. type="dateTimeRange"
  537. hideDisabledOptions={false}
  538. disabledTime={disabledTime2}
  539. defaultValue={['2021-09-08', '2021-10-03']}
  540. style={{ width: 400 }}
  541. />
  542. <DatePicker
  543. type="dateTime"
  544. hideDisabledOptions={false}
  545. defaultValue={'2021-09-08'}
  546. disabledTime={disabledTime2}
  547. style={{ width: 400 }}
  548. />
  549. </>
  550. );
  551. }
  552. return <Demo />;
  553. };
  554. FixDisabledTimeCallback1418.story = {
  555. name: 'fix disabledTime callback #1418',
  556. };
  557. export const RangeSeparator = () => (
  558. <Space wrap>
  559. <div>
  560. <div>custom rangeSeparator</div>
  561. <DatePicker
  562. type="dateRange"
  563. rangeSeparator="-"
  564. defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
  565. />
  566. <DatePicker
  567. type="dateTimeRange"
  568. rangeSeparator="-"
  569. defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
  570. />
  571. </div>
  572. <div>
  573. <div>default rangeSeparator</div>
  574. <DatePicker
  575. type="dateRange"
  576. defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
  577. />
  578. <DatePicker
  579. type="dateTimeRange"
  580. defaultValue={[new Date('2019-07-01'), new Date('2019-08-02')]}
  581. />
  582. </div>
  583. </Space>
  584. );