cascader.stories.jsx 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585
  1. import React, { useState, useCallback, useEffect } from 'react';
  2. import CustomTrigger from './CustomTrigger';
  3. import { Button, Typography, Toast, Cascader } from '../../index';
  4. const { Text } = Typography;
  5. export default {
  6. title: 'Cascader',
  7. parameters: {
  8. chromatic: { disableSnapshot: true },
  9. },
  10. }
  11. export {
  12. CustomTrigger
  13. };
  14. const treeData1 = [
  15. {
  16. label: 'Node1',
  17. value: '0-0',
  18. children: [
  19. {
  20. label: 'Child Node1',
  21. value: '0-0-1',
  22. disabled: true,
  23. },
  24. {
  25. label: 'Child Node2',
  26. value: '0-0-2',
  27. },
  28. ],
  29. },
  30. {
  31. label: 'Node2',
  32. value: '0-1',
  33. },
  34. ];
  35. const treeData2 = [
  36. {
  37. label: '亚洲',
  38. value: 'yazhou',
  39. children: [
  40. {
  41. label: '中国',
  42. value: 'zhongguo',
  43. children: [
  44. {
  45. label: '北京',
  46. value: 'beijing',
  47. },
  48. {
  49. label: '上海',
  50. value: 'shanghai',
  51. },
  52. ],
  53. },
  54. {
  55. label: '日本',
  56. value: 'riben',
  57. disabled: true,
  58. children: [
  59. {
  60. label: '大阪',
  61. value: 'daban',
  62. },
  63. ],
  64. },
  65. ],
  66. },
  67. {
  68. label: '北美洲',
  69. value: 'beimeizhou',
  70. children: [
  71. {
  72. label: '美国',
  73. value: 'meiguo',
  74. },
  75. {
  76. label: '加拿大',
  77. value: 'jianada',
  78. },
  79. ],
  80. },
  81. ];
  82. const treeData3 = [
  83. {
  84. label: '亚洲',
  85. value: 'yazhou',
  86. children: [
  87. {
  88. label: '中国',
  89. value: 'zhongguo',
  90. children: [
  91. {
  92. label: '北京',
  93. value: 'beijing',
  94. },
  95. {
  96. label: '上海',
  97. value: 'shanghai',
  98. },
  99. ],
  100. },
  101. {
  102. label: '日本',
  103. value: 'riben',
  104. children: [
  105. {
  106. label: '大阪',
  107. value: 'daban',
  108. },
  109. ],
  110. },
  111. ],
  112. },
  113. ];
  114. const treeData4 = [
  115. {
  116. label: '浙江省',
  117. value: 'zhejiang',
  118. children: [
  119. {
  120. label: '杭州市',
  121. value: 'hangzhou',
  122. children: [
  123. {
  124. label: '西湖区',
  125. value: 'xihu',
  126. },
  127. {
  128. label: '萧山区',
  129. value: 'xiaoshan',
  130. },
  131. {
  132. label: '临安区',
  133. value: 'linan',
  134. },
  135. ],
  136. },
  137. {
  138. label: '宁波市',
  139. value: 'ningbo',
  140. children: [
  141. {
  142. label: '海曙区',
  143. value: 'haishu',
  144. },
  145. {
  146. label: '江北区',
  147. value: 'jiangbei',
  148. },
  149. ],
  150. },
  151. ],
  152. },
  153. ];
  154. const treeOrder = [
  155. {
  156. label: '-1',
  157. value: '0-0',
  158. key: '-1',
  159. children: [
  160. {
  161. label: 'Child Node1',
  162. value: '0-0-1',
  163. key: '0-0-1',
  164. },
  165. {
  166. label: 'Child Node2',
  167. value: '0-0-2',
  168. key: '0-0-2',
  169. },
  170. ],
  171. },
  172. {
  173. label: '1',
  174. value: '0-1',
  175. key: '1',
  176. },
  177. ];
  178. const longTreeData = [
  179. {
  180. label: 'udghajsasndanm,',
  181. value: 'A',
  182. children: [
  183. {
  184. label: 'Bsasfads',
  185. value: 'B',
  186. children: [
  187. {
  188. label: 'C',
  189. value: 'C',
  190. children: [
  191. {
  192. label: 'D',
  193. value: 'D',
  194. children: [
  195. {
  196. label: 'E',
  197. value: 'E',
  198. children: [
  199. {
  200. label: 'F',
  201. value: 'F',
  202. }
  203. ]
  204. }
  205. ]
  206. }
  207. ]
  208. }
  209. ],
  210. }
  211. ]
  212. }
  213. ];
  214. const treedataWithNodeLabel = [
  215. {
  216. label: '浙江省',
  217. value: 'zhejiang',
  218. children: [
  219. {
  220. label: '杭州市',
  221. value: 'hangzhou',
  222. children: [
  223. {
  224. label: '西湖市区',
  225. value: 'xihu',
  226. },
  227. {
  228. label: '萧山区',
  229. value: 'xiaoshan',
  230. },
  231. {
  232. label: '临安区',
  233. value: 'linan',
  234. },
  235. ],
  236. },
  237. {
  238. label: <strong>宁波市</strong>,
  239. value: 'ningbo',
  240. children: [
  241. {
  242. label: '海曙区',
  243. value: 'haishu',
  244. },
  245. {
  246. label: '江北区',
  247. value: 'jiangbei',
  248. }
  249. ]
  250. },
  251. ],
  252. }
  253. ];
  254. export const issue703 = () => {
  255. const initialData = [
  256. {
  257. label: 'Node1',
  258. value: '0-0',
  259. },
  260. {
  261. label: 'Node2',
  262. value: '0-1',
  263. },
  264. {
  265. label: 'Node3',
  266. value: '0-2',
  267. isLeaf: true
  268. },
  269. ];
  270. const [data, setData] = useState(initialData);
  271. const updateTreeData = (list, value, children) => {
  272. return list.map(node => {
  273. if (node.value === value) {
  274. return { ...node, children };
  275. }
  276. if (node.children) {
  277. return { ...node, children: updateTreeData(node.children, value, children) };
  278. }
  279. return node;
  280. });
  281. };
  282. const onLoadData = selectedOpt => {
  283. const targetOpt = selectedOpt[selectedOpt.length - 1];
  284. const { label, value } = targetOpt;
  285. return new Promise(resolve => {
  286. if (targetOpt.children) {
  287. resolve();
  288. return;
  289. }
  290. setTimeout(() => {
  291. setData(origin =>
  292. updateTreeData(origin, value, [
  293. {
  294. label: `${label}-1`,
  295. value: `${label}-1`,
  296. isLeaf: selectedOpt.length > 1
  297. },
  298. {
  299. label: `${label}-2`,
  300. value: `${label}-2`,
  301. isLeaf: selectedOpt.length > 1
  302. },
  303. ]),
  304. );
  305. resolve();
  306. }, 1000);
  307. });
  308. };
  309. const [v,setV]=useState([['0-0'], ['0-1', 'Node2-2']]);
  310. useEffect(()=>{
  311. console.log('data change');
  312. setTimeout(()=>setV([['0-0'], ['0-1', 'Node2-2', 'Node2-2-2']]),0);
  313. },[data])
  314. return (
  315. <>
  316. <div>treeData和value动态更新,value中的值在treeData中存在则能够正确显示</div>
  317. <Cascader
  318. multiple
  319. onChange={(a)=>console.log(a)}
  320. value={v}
  321. style={{ width: 300 }}
  322. treeData={data}
  323. loadData={onLoadData}
  324. placeholder="Please select"
  325. />
  326. <div>非受控,动态更新treeData</div>
  327. <Cascader
  328. multiple
  329. onChange={(a)=>console.log(a)}
  330. style={{ width: 300 }}
  331. treeData={data}
  332. loadData={onLoadData}
  333. placeholder="Please select"
  334. />
  335. </>
  336. );
  337. };
  338. export const _Cascader = () => {
  339. return (
  340. <div>
  341. <Cascader
  342. style={{ width: 300 }}
  343. treeData={treeData1}
  344. placeholder="Please select"
  345. motion={false}
  346. />
  347. <br />
  348. <br />
  349. <Cascader
  350. style={{ width: 300 }}
  351. treeData={treeData1}
  352. placeholder="Multiple select"
  353. multiple
  354. motion={false}
  355. />
  356. <br />
  357. <br />
  358. <Cascader
  359. style={{ width: 300 }}
  360. treeData={treeData1}
  361. placeholder="Multiple select enableLeafClick"
  362. multiple
  363. enableLeafClick
  364. motion={false}
  365. />
  366. <br />
  367. <br />
  368. <Cascader
  369. style={{ width: 300 }}
  370. treeData={[]}
  371. motion={false}
  372. placeholder="Please select"
  373. // defaultOpen={true}
  374. />
  375. </div>
  376. );
  377. };
  378. export const ChangeOnSelect = () => {
  379. return (
  380. <div>
  381. <Cascader
  382. style={{ width: 300 }}
  383. treeData={treeData2}
  384. placeholder="Please select"
  385. changeOnSelect={true}
  386. />
  387. </div>
  388. );
  389. };
  390. export const Searchable = () => {
  391. return (
  392. <div>
  393. <Cascader
  394. style={{ width: 300 }}
  395. treeData={treeData2}
  396. placeholder="Please select"
  397. filterTreeNode
  398. motion={false}
  399. />
  400. <br />
  401. <br />
  402. <Cascader
  403. style={{ width: 300 }}
  404. treeData={treeData2}
  405. placeholder="Please select"
  406. filterTreeNode
  407. changeOnSelect
  408. allowHalfPath
  409. />
  410. <br />
  411. <br />
  412. <Cascader
  413. style={{ width: 300 }}
  414. treeData={treeData2}
  415. placeholder="Please select"
  416. filterTreeNode
  417. filterLeafOnly={false}
  418. onChange={e => console.log(e)}
  419. />
  420. <br />
  421. <br />
  422. <div>fix-1449,当 label 为 ReactNode 时,搜索显示结果[object object]</div>
  423. <Cascader
  424. style={{ width: 300 }}
  425. treeData={treedataWithNodeLabel}
  426. placeholder="宁波为 ReactNode"
  427. filterTreeNode
  428. />
  429. <br />
  430. <br />
  431. <div>
  432. filterTreeNode=false,且 label 为 ReactNode
  433. 时,配合displayRender使用,使得回显到input的内容符合预期
  434. </div>
  435. <Cascader
  436. style={{ width: 300 }}
  437. treeData={treedataWithNodeLabel}
  438. placeholder="自定义回填时显示数据的格式"
  439. displayRender={list =>
  440. list.map((v, i) => {
  441. return list.length - 1 === i ? (
  442. <React.Fragment key={i}>{v}</React.Fragment>
  443. ) : (
  444. <React.Fragment key={i}>{v} / </React.Fragment>
  445. );
  446. })
  447. }
  448. defaultValue={['zhejiang', 'ningbo', 'jiangbei']}
  449. />
  450. <br />
  451. <br />
  452. <div>
  453. v2.5 起,filterTreeNode=false,且 label 为 ReactNode
  454. 时,无配合displayRender 使用,回显到input的内容也是符合预期
  455. </div>
  456. <Cascader
  457. style={{ width: 300 }}
  458. treeData={treedataWithNodeLabel}
  459. placeholder="宁波为 ReactNode"
  460. defaultValue={['zhejiang', 'ningbo', 'jiangbei']}
  461. />
  462. </div>
  463. );
  464. };
  465. Searchable.parameters = {
  466. chromatic: { disableSnapshot: false },
  467. }
  468. export const filterTreeNodeAndDisplayRender = () => {
  469. return (
  470. <>
  471. <div>
  472. filterTreeNode=true,配合displayRender 使用,回显到input的内容也是符合预期
  473. </div>
  474. <Cascader
  475. filterTreeNode
  476. style={{ width: 300 }}
  477. treeData={treeData4}
  478. placeholder="自定义回填时显示数据的格式"
  479. defaultValue={['zhejiang', 'ningbo', 'jiangbei']}
  480. displayRender={(item) => {
  481. console.log('item', item);
  482. return <div>
  483. {'已选择:' + item.join(' -> ')}
  484. </div>;}}
  485. />
  486. </>
  487. );
  488. };
  489. export const Disabled = () => {
  490. return (
  491. <div>
  492. <Cascader
  493. style={{ width: 300 }}
  494. treeData={treeData2}
  495. placeholder="Please select"
  496. filterTreeNode
  497. disabled
  498. />
  499. <br /><br />
  500. <Cascader
  501. defaultValue={['yazhou', 'zhongguo']}
  502. style={{ width: 300 }}
  503. treeData={treeData2}
  504. multiple
  505. filterTreeNode
  506. disabled
  507. />
  508. <br /><br />
  509. <Cascader
  510. defaultValue={['yazhou', 'zhongguo']}
  511. style={{ width: 300 }}
  512. treeData={treeData2}
  513. multiple
  514. disabled
  515. />
  516. </div>
  517. );
  518. };
  519. Disabled.parameters = {
  520. chromatic: { disableSnapshot: false },
  521. }
  522. export const DisabledOption = () => {
  523. return (
  524. <div>
  525. <div>common disabled option</div>
  526. <Cascader style={{ width: 300 }} treeData={treeData2} placeholder="Japan node is disabled" />
  527. <br />
  528. <br />
  529. <div>single selection + defaultValue is disabled option + changeOnSelect</div>
  530. <Cascader
  531. style={{ width: 300 }}
  532. treeData={treeData2}
  533. changeOnSelect
  534. defaultValue={['yazhou', 'riben']}
  535. placeholder="Japan node is disabled"
  536. />
  537. <br />
  538. <br />
  539. <div>
  540. single selection + defaultValue is disabled option + changeOnSelect + filterTreeNode
  541. </div>
  542. <Cascader
  543. style={{ width: 300 }}
  544. treeData={treeData2}
  545. changeOnSelect
  546. filterTreeNode
  547. defaultValue={['yazhou', 'riben']}
  548. placeholder="Japan node is disabled"
  549. />
  550. <br />
  551. <br />
  552. <div>multiple selection + defaultValue is disabled option</div>
  553. <Cascader
  554. multiple
  555. filterTreeNode
  556. style={{ width: 300 }}
  557. treeData={treeData2}
  558. defaultValue={['yazhou', 'riben']}
  559. placeholder="Japan node is disabled"
  560. />
  561. <br />
  562. <br />
  563. <div>multiple selection + filterTreeNode + defaultValue is disabled option</div>
  564. <Cascader
  565. filterTreeNode
  566. multiple
  567. style={{ width: 300 }}
  568. treeData={treeData2}
  569. defaultValue={[
  570. ['yazhou', 'riben'],
  571. ['beimeizhou', 'jianada']
  572. ]}
  573. placeholder="Japan node is disabled"
  574. />
  575. </div>
  576. );
  577. };
  578. export const CustomSearch = () => {
  579. return (
  580. <div>
  581. <Cascader
  582. style={{ width: 300 }}
  583. treeData={treeData2}
  584. placeholder="Please select"
  585. filterTreeNode
  586. treeNodeFilterProp="value"
  587. />
  588. </div>
  589. );
  590. };
  591. export const CustomDisplayProp = () => {
  592. return (
  593. <div>
  594. <Cascader
  595. style={{ width: 300 }}
  596. treeData={treeData2}
  597. placeholder="Please select"
  598. changeOnSelect={true}
  599. displayProp="value"
  600. filterTreeNode
  601. />
  602. </div>
  603. );
  604. };
  605. export const DefaultValue = () => {
  606. return (
  607. <div>
  608. <Cascader
  609. style={{ width: 300 }}
  610. treeData={treeData3}
  611. placeholder="Please select"
  612. defaultValue={['yazhou', 'zhongguo', 'shanghai']}
  613. />
  614. <br />
  615. <br />
  616. <Cascader
  617. style={{ width: 300 }}
  618. treeData={treeData3}
  619. placeholder="Please select"
  620. changeOnSelect
  621. defaultValue={['yazhou']}
  622. />
  623. <br />
  624. <br />
  625. <Cascader
  626. style={{ width: 300 }}
  627. treeData={treeData3}
  628. placeholder="Please select"
  629. changeOnSelect
  630. defaultValue={['yazhou', 'zhongguo']}
  631. filterTreeNode
  632. />
  633. <br />
  634. <br />
  635. <Cascader
  636. style={{ width: 300 }}
  637. treeData={treeData3}
  638. placeholder="Please select"
  639. changeOnSelect
  640. defaultValue={'yazhou'}
  641. filterTreeNode
  642. />
  643. <br />
  644. <br />
  645. <Cascader
  646. style={{ width: 300 }}
  647. treeData={treeData3}
  648. placeholder="Please select"
  649. defaultValue={['yazhou', 'zhongguo']}
  650. filterTreeNode
  651. />
  652. </div>
  653. );
  654. };
  655. export const DefaultValueNotExist = () => {
  656. return (
  657. <>
  658. <Cascader
  659. style={{ width: 300 }}
  660. treeData={treeData3}
  661. placeholder="Please select"
  662. changeOnSelect
  663. defaultValue={'yazhou not exist'}
  664. filterTreeNode
  665. />
  666. <br />
  667. <br />
  668. <Cascader
  669. style={{ width: 300 }}
  670. treeData={treeData3}
  671. placeholder="Please select"
  672. defaultValue={'tokyo not exist'}
  673. />
  674. </>
  675. );
  676. };
  677. class ControlledDemo extends React.Component {
  678. constructor() {
  679. super();
  680. this.state = {
  681. value: [],
  682. };
  683. }
  684. onChange(value) {
  685. this.setState({ value });
  686. }
  687. render() {
  688. const treeData = [
  689. {
  690. label: '浙江省',
  691. value: 'zhejiang',
  692. children: [
  693. {
  694. label: '杭州市',
  695. value: 'hangzhou',
  696. children: [
  697. {
  698. label: '西湖区',
  699. value: 'xihu',
  700. },
  701. {
  702. label: '萧山区',
  703. value: 'xiaoshan',
  704. },
  705. {
  706. label: '临安区',
  707. value: 'linan',
  708. },
  709. ],
  710. },
  711. {
  712. label: '宁波市',
  713. value: 'ningbo',
  714. children: [
  715. {
  716. label: '海曙区',
  717. value: 'haishu',
  718. },
  719. {
  720. label: '江北区',
  721. value: 'jiangbei',
  722. },
  723. ],
  724. },
  725. ],
  726. },
  727. ];
  728. return (
  729. <Cascader
  730. multiple
  731. style={{ width: 300 }}
  732. treeData={treeData}
  733. placeholder="请选择所在地区"
  734. value={this.state.value}
  735. changeOnSelect
  736. filterTreeNode
  737. onChangeWithObject
  738. onChange={e => this.onChange(e)}
  739. />
  740. );
  741. }
  742. }
  743. export const ControlledComponent = () => <ControlledDemo />;
  744. export const CascaderOrderTest = () => {
  745. return (
  746. <div>
  747. <Cascader style={{ width: 300 }} treeData={treeOrder} placeholder="Please select" />
  748. </div>
  749. );
  750. };
  751. export const OnFocusAndOnBlur = () => {
  752. return (
  753. <div>
  754. <Cascader
  755. style={{ width: 300 }}
  756. treeData={treeData1}
  757. placeholder="Please select"
  758. onFocus={(val, e) => console.log('focus', e, val)}
  759. onBlur={(val, e) => console.log('blur', e, val)}
  760. />
  761. </div>
  762. );
  763. };
  764. export const ShowClear = () => {
  765. return (
  766. <div>
  767. <Cascader
  768. style={{ marginLeft: 700, width: 300 }}
  769. treeData={treeData1}
  770. placeholder="Please select"
  771. showClear
  772. filterTreeNode
  773. />
  774. <br />
  775. <br />
  776. <Cascader
  777. style={{ marginLeft: 700, width: 300 }}
  778. treeData={treeData1}
  779. placeholder="Please select when multiple"
  780. multiple
  781. showClear
  782. />
  783. <br />
  784. <br />
  785. <div style={{ marginLeft: 700 }}>
  786. <p>有用户反馈,超长列表点击 showClear 后,dropdown错位。1.30.0-beta.1 fixed</p>
  787. <Cascader
  788. style={{ width: 300 }}
  789. treeData={longTreeData}
  790. placeholder="Please select"
  791. showClear
  792. />
  793. </div>
  794. </div>
  795. );
  796. };
  797. const LoadDataDemo = () => {
  798. const initialData = [
  799. {
  800. label: 'Node1',
  801. value: '0-0',
  802. },
  803. {
  804. label: 'Node2',
  805. value: '0-1',
  806. },
  807. {
  808. label: 'Node3',
  809. value: '0-2',
  810. isLeaf: true,
  811. },
  812. ];
  813. const [data, setData] = useState(initialData);
  814. const updateTreeData = (list, value, children) => {
  815. return list.map(node => {
  816. if (node.value === value) {
  817. return { ...node, children };
  818. }
  819. if (node.children) {
  820. return { ...node, children: updateTreeData(node.children, value, children) };
  821. }
  822. return node;
  823. });
  824. };
  825. const onLoadData = selectedOpt => {
  826. const targetOpt = selectedOpt[selectedOpt.length - 1];
  827. const { label, value } = targetOpt;
  828. return new Promise(resolve => {
  829. if (targetOpt.children) {
  830. resolve();
  831. return;
  832. }
  833. setTimeout(() => {
  834. setData(origin =>
  835. updateTreeData(origin, value, [
  836. {
  837. label: `${label} - 1`,
  838. value: `${label}-1`,
  839. isLeaf: selectedOpt.length > 1,
  840. },
  841. {
  842. label: `${label} - 2`,
  843. value: `${label}-2`,
  844. isLeaf: selectedOpt.length > 1,
  845. },
  846. ])
  847. );
  848. resolve();
  849. }, 1000);
  850. });
  851. };
  852. return (
  853. <Cascader
  854. style={{ width: 300 }}
  855. treeData={data}
  856. loadData={onLoadData}
  857. onChangeWithSelect
  858. placeholder="Please select"
  859. />
  860. );
  861. };
  862. const LoadDataWithReset = () => {
  863. const initialData = [
  864. {
  865. label: 'Node1',
  866. value: '0-0',
  867. },
  868. {
  869. label: 'Node2',
  870. value: '0-1',
  871. },
  872. {
  873. label: 'Node3',
  874. value: '0-2',
  875. isLeaf: true,
  876. },
  877. ];
  878. const [data, setData] = useState(initialData);
  879. const [value, setValue] = useState([]);
  880. const updateTreeData = (list, value, children) => {
  881. return list.map(node => {
  882. if (node.value === value) {
  883. return { ...node, children };
  884. }
  885. if (node.children) {
  886. return { ...node, children: updateTreeData(node.children, value, children) };
  887. }
  888. return node;
  889. });
  890. };
  891. const onLoadData = selectedOpt => {
  892. const targetOpt = selectedOpt[selectedOpt.length - 1];
  893. const { label, value } = targetOpt;
  894. return new Promise(resolve => {
  895. if (targetOpt.children) {
  896. resolve();
  897. return;
  898. }
  899. setTimeout(() => {
  900. setData(origin =>
  901. updateTreeData(origin, value, [
  902. {
  903. label: `${label} - 1`,
  904. value: `${label}-1`,
  905. isLeaf: selectedOpt.length > 1,
  906. },
  907. {
  908. label: `${label} - 2`,
  909. value: `${label}-2`,
  910. isLeaf: selectedOpt.length > 1,
  911. },
  912. ])
  913. );
  914. resolve();
  915. }, 1000);
  916. });
  917. };
  918. return (
  919. <>
  920. <Cascader
  921. style={{ width: 300 }}
  922. treeData={data}
  923. loadData={onLoadData}
  924. value={value}
  925. onChangeWithObject
  926. changeOnSelect
  927. onChange={setValue}
  928. placeholder="Please select"
  929. />
  930. <Button onClick={() => setValue([])}>重置</Button>
  931. </>
  932. );
  933. };
  934. export const LoadData = () => (
  935. <>
  936. <LoadDataDemo />
  937. <br />
  938. <br />
  939. <div>fix:1448,重置失效</div>
  940. <LoadDataWithReset />
  941. </>
  942. );
  943. export const DynamicPlaceholder = () => {
  944. const [isSelect, setSelect] = useState(false);
  945. return (
  946. <>
  947. <Button onClick={() => setSelect(!isSelect)}>Toggle</Button>
  948. <Cascader
  949. style={{ width: 300 }}
  950. treeData={treeData2}
  951. placeholder="Please select"
  952. searchPlaceholder="Search something"
  953. filterTreeNode={isSelect}
  954. showClear
  955. />
  956. </>
  957. );
  958. };
  959. export const FixDedupOnSelect = () => {
  960. return (
  961. <div>
  962. <Cascader
  963. style={{ width: 300 }}
  964. treeData={treeData2}
  965. placeholder="Please select"
  966. onSelect={v => console.log(v)}
  967. />
  968. <Cascader
  969. style={{ width: 300 }}
  970. treeData={treeData2}
  971. placeholder="Please select"
  972. onSelect={v => console.log(v)}
  973. dedupOnSelect={false}
  974. />
  975. </div>
  976. );
  977. };
  978. const slotStyle = {
  979. height: '36px',
  980. display: 'flex',
  981. padding: '0 32px',
  982. alignItems: 'center',
  983. cursor: 'pointer',
  984. borderRadius: '0 0 6px 6px',
  985. };
  986. export const CascaderWithSlot = () => {
  987. return (
  988. <div>
  989. <Cascader
  990. style={{ width: 300 }}
  991. treeData={treeData2}
  992. placeholder="请选择所在地区"
  993. topSlot={<Text style={slotStyle}>选择地区</Text>}
  994. bottomSlot={
  995. <div style={slotStyle}>
  996. <Text>找不大相关选项?</Text>
  997. <Text link>去新建</Text>
  998. </div>
  999. }
  1000. />
  1001. </div>
  1002. );
  1003. };
  1004. export const CascaderWithMaxTagCountShowRestTagsPopoverRestTagsPopoverProps = () => {
  1005. return (
  1006. <div>
  1007. <Cascader
  1008. style={{ width: 300 }}
  1009. treeData={treeData4}
  1010. placeholder="请选择所在地区"
  1011. multiple
  1012. maxTagCount={1}
  1013. showRestTagsPopover
  1014. restTagsPopoverProps={{ position: 'bottom' }}
  1015. defaultValue={[
  1016. ['zhejiang', 'ningbo', 'haishu'],
  1017. ['zhejiang', 'hangzhou', 'xihu'],
  1018. ]}
  1019. />
  1020. </div>
  1021. );
  1022. };
  1023. CascaderWithMaxTagCountShowRestTagsPopoverRestTagsPopoverProps.story = {
  1024. name: 'Cascader with maxTagCount/showRestTagsPopover/restTagsPopoverProps',
  1025. };
  1026. CascaderWithMaxTagCountShowRestTagsPopoverRestTagsPopoverProps.parameters = {
  1027. chromatic: { disableSnapshot: false },
  1028. }
  1029. export const CascaderWithShowNext = () => {
  1030. return (
  1031. <div>
  1032. <Cascader
  1033. style={{ width: 300 }}
  1034. treeData={treeData4}
  1035. placeholder="请选择所在地区"
  1036. showNext="hover"
  1037. />
  1038. </div>
  1039. );
  1040. };
  1041. export const CascaderWithMaxOnExceed = () => {
  1042. return (
  1043. <div>
  1044. <div>普通情况</div>
  1045. <Cascader
  1046. style={{ width: 300 }}
  1047. treeData={treeData4}
  1048. placeholder="请选择所在地区"
  1049. multiple
  1050. max={1}
  1051. onExceed={v => {
  1052. Toast.warning('exceed max');
  1053. console.log(v);
  1054. }}
  1055. defaultValue={['zhejiang', 'ningbo', 'haishu']}
  1056. />
  1057. <br />
  1058. <br />
  1059. <div>defaultValue的数量超过max,则只允许减少到合法,不允许再增加</div>
  1060. <Cascader
  1061. style={{ width: 300 }}
  1062. treeData={treeData4}
  1063. placeholder="请选择所在地区"
  1064. multiple
  1065. max={1}
  1066. onExceed={v => {
  1067. Toast.warning('exceed max');
  1068. console.log(v);
  1069. }}
  1070. defaultValue={[
  1071. ['zhejiang', 'ningbo', 'haishu'],
  1072. ['zhejiang', 'hangzhou', 'xihu'],
  1073. ]}
  1074. />
  1075. <br />
  1076. <br />
  1077. <div>autoMergeValue=false时的情况</div>
  1078. <Cascader
  1079. style={{ width: 300 }}
  1080. treeData={treeData4}
  1081. placeholder="请选择所在地区"
  1082. multiple
  1083. max={2}
  1084. autoMergeValue={false}
  1085. onExceed={v => {
  1086. Toast.warning('exceed max');
  1087. console.log(v);
  1088. }}
  1089. defaultValue={[
  1090. ['zhejiang', 'ningbo', 'haishu'],
  1091. ['zhejiang', 'hangzhou', 'xihu'],
  1092. ]}
  1093. />
  1094. </div>
  1095. );
  1096. };
  1097. CascaderWithMaxOnExceed.story = {
  1098. name: 'Cascader with max/onExceed',
  1099. };
  1100. CascaderWithMaxOnExceed.parameters = {
  1101. chromatic: { disableSnapshot: false },
  1102. }
  1103. const ControlledLoadDataWithDefaultValue = () => {
  1104. const [v, setV] = useState('受控 Value');
  1105. const initialData = [
  1106. {
  1107. label: 'Node1',
  1108. value: '0-0',
  1109. },
  1110. {
  1111. label: 'Node2',
  1112. value: '0-1',
  1113. },
  1114. {
  1115. label: 'Node3',
  1116. value: '0-2',
  1117. isLeaf: true,
  1118. },
  1119. ];
  1120. const [data, setData] = useState(initialData);
  1121. const updateTreeData = (list, value, children) => {
  1122. return list.map(node => {
  1123. if (node.value === value) {
  1124. return { ...node, children };
  1125. }
  1126. if (node.children) {
  1127. return { ...node, children: updateTreeData(node.children, value, children) };
  1128. }
  1129. return node;
  1130. });
  1131. };
  1132. const onLoadData = selectedOpt => {
  1133. const targetOpt = selectedOpt[selectedOpt.length - 1];
  1134. const { label, value } = targetOpt;
  1135. return new Promise(resolve => {
  1136. if (targetOpt.children) {
  1137. resolve();
  1138. return;
  1139. }
  1140. setTimeout(() => {
  1141. setData(origin =>
  1142. updateTreeData(origin, value, [
  1143. {
  1144. label: `${label} - 1`,
  1145. value: `${label}-1`,
  1146. isLeaf: selectedOpt.length > 1,
  1147. },
  1148. {
  1149. label: `${label} - 2`,
  1150. value: `${label}-2`,
  1151. isLeaf: selectedOpt.length > 1,
  1152. },
  1153. ])
  1154. );
  1155. resolve();
  1156. }, 1000);
  1157. });
  1158. };
  1159. return (
  1160. <Cascader
  1161. defaultValue="123"
  1162. value={v}
  1163. onChange={v => setV(v)}
  1164. style={{ width: 300 }}
  1165. treeData={data}
  1166. loadData={onLoadData}
  1167. placeholder="Please select"
  1168. />
  1169. );
  1170. };
  1171. const LoadDataWithDefaultValue = () => {
  1172. const initialData = [
  1173. {
  1174. label: 'Node1',
  1175. value: '0-0',
  1176. },
  1177. {
  1178. label: 'Node2',
  1179. value: '0-1',
  1180. },
  1181. {
  1182. label: 'Node3',
  1183. value: '0-2',
  1184. isLeaf: true,
  1185. },
  1186. ];
  1187. const [data, setData] = useState(initialData);
  1188. const updateTreeData = (list, value, children) => {
  1189. return list.map(node => {
  1190. if (node.value === value) {
  1191. return { ...node, children };
  1192. }
  1193. if (node.children) {
  1194. return { ...node, children: updateTreeData(node.children, value, children) };
  1195. }
  1196. return node;
  1197. });
  1198. };
  1199. const onLoadData = selectedOpt => {
  1200. const targetOpt = selectedOpt[selectedOpt.length - 1];
  1201. const { label, value } = targetOpt;
  1202. return new Promise(resolve => {
  1203. if (targetOpt.children) {
  1204. resolve();
  1205. return;
  1206. }
  1207. setTimeout(() => {
  1208. setData(origin =>
  1209. updateTreeData(origin, value, [
  1210. {
  1211. label: `${label} - 1`,
  1212. value: `${label}-1`,
  1213. isLeaf: selectedOpt.length > 1,
  1214. },
  1215. {
  1216. label: `${label} - 2`,
  1217. value: `${label}-2`,
  1218. isLeaf: selectedOpt.length > 1,
  1219. },
  1220. ])
  1221. );
  1222. resolve();
  1223. }, 1000);
  1224. });
  1225. };
  1226. return (
  1227. <Cascader
  1228. defaultValue="defaultValue"
  1229. style={{ width: 300 }}
  1230. treeData={data}
  1231. loadData={onLoadData}
  1232. showClear
  1233. placeholder="Please select"
  1234. />
  1235. );
  1236. };
  1237. export const LoadDataWithDefaultValueDemo = () => {
  1238. return (
  1239. <div>
  1240. <div>fix-1429,检查defaultValue在异步时是否有异常</div>
  1241. <ControlledLoadDataWithDefaultValue />
  1242. <br />
  1243. <br />
  1244. <LoadDataWithDefaultValue />
  1245. </div>
  1246. );
  1247. };
  1248. LoadDataWithDefaultValueDemo.parameters = {
  1249. chromatic: { disableSnapshot: false },
  1250. }
  1251. export const OnChangeWithObject = () => (
  1252. <>
  1253. <div>单选 + onChangeWithObject + defaultValue 为 string []</div>
  1254. <Cascader
  1255. onChangeWithObject
  1256. style={{ width: 300 }}
  1257. treeData={treeData4}
  1258. placeholder="请选择所在地区"
  1259. defaultValue={['zhejiang', 'hangzhou', 'xihu']}
  1260. />
  1261. <br />
  1262. <br />
  1263. <div>多选 + onChangeWithObject + defaultValue 为 string []</div>
  1264. <Cascader
  1265. multiple
  1266. changeOnSelect
  1267. onChangeWithObject
  1268. style={{ width: 300 }}
  1269. treeData={treeData4}
  1270. placeholder="请选择所在地区"
  1271. defaultValue={'zhejiang'}
  1272. />
  1273. <br />
  1274. <br />
  1275. <div>单选 + onChangeWithObject + defaultValue 为 object []</div>
  1276. <Cascader
  1277. onChangeWithObject
  1278. changeOnSelect
  1279. style={{ width: 300 }}
  1280. treeData={treeData2}
  1281. placeholder="请选择所在地区"
  1282. defaultValue={{
  1283. label: '北美洲',
  1284. value: 'beimeizhou',
  1285. children: [
  1286. {
  1287. label: '美国',
  1288. value: 'meiguo',
  1289. },
  1290. {
  1291. label: '加拿大',
  1292. value: 'jianada',
  1293. },
  1294. ],
  1295. }}
  1296. />
  1297. <br />
  1298. <br />
  1299. <div>多选 + onChangeWithObject + defaultValue 为 object []</div>
  1300. <Cascader
  1301. multiple
  1302. onChangeWithObject
  1303. style={{ width: 300 }}
  1304. treeData={treeData2}
  1305. placeholder="请选择所在地区"
  1306. defaultValue={{
  1307. label: '北美洲',
  1308. value: 'beimeizhou',
  1309. children: [
  1310. {
  1311. label: '美国',
  1312. value: 'meiguo',
  1313. },
  1314. {
  1315. label: '加拿大',
  1316. value: 'jianada',
  1317. },
  1318. ],
  1319. }}
  1320. />
  1321. </>
  1322. );
  1323. export const undefinedValueWhileMutipleAndOnChangeWithObject = () => {
  1324. const [value, setValue] = useState(undefined);
  1325. return (
  1326. <>
  1327. <div>多选 + onChangeWithObject + value 为 undefined</div>
  1328. <Cascader
  1329. multiple
  1330. onChangeWithObject
  1331. style={{ width: 300 }}
  1332. treeData={treeData2}
  1333. placeholder="请选择所在地区"
  1334. value={value}
  1335. onChange={(v)=>{
  1336. setValue(v);
  1337. }}
  1338. />
  1339. </>
  1340. )
  1341. }
  1342. export const LeafOnly = () => {
  1343. const [value, setValue] = useState([])
  1344. return (
  1345. <div>
  1346. <div>autoMergeValue=false,leafOnly=false</div>
  1347. <Cascader
  1348. style={{ width: 300 }}
  1349. treeData={treeData4}
  1350. placeholder="请选择所在地区"
  1351. multiple
  1352. autoMergeValue={false}
  1353. leafOnly={false}
  1354. defaultValue={['zhejiang']}
  1355. />
  1356. <br />
  1357. <br />
  1358. <div>autoMergeValue=false,leafOnly=true, leafOnly生效</div>
  1359. <Cascader
  1360. style={{ width: 300 }}
  1361. treeData={treeData4}
  1362. placeholder="请选择所在地区"
  1363. multiple
  1364. autoMergeValue={false}
  1365. leafOnly={true}
  1366. defaultValue={['zhejiang']}
  1367. />
  1368. <br />
  1369. <br />
  1370. <div>受控,autoMergeValue=false,leafOnly=true, leafOnly生效</div>
  1371. <Cascader
  1372. style={{ width: 300 }}
  1373. treeData={treeData4}
  1374. placeholder="请选择所在地区"
  1375. multiple
  1376. onChange={v=>{
  1377. console.log(v);
  1378. setValue(v)
  1379. }}
  1380. autoMergeValue={false}
  1381. leafOnly={true}
  1382. value={value}
  1383. />
  1384. <br />
  1385. <br />
  1386. <div>受控 onChangeWithObject, autoMergeValue=false,leafOnly=true, leafOnly生效</div>
  1387. <Cascader
  1388. style={{ width: 300 }}
  1389. treeData={treeData4}
  1390. placeholder="请选择所在地区"
  1391. multiple
  1392. onChange={v=>{
  1393. console.log(v);
  1394. setValue(v)
  1395. }}
  1396. onChangeWithObject
  1397. autoMergeValue={false}
  1398. leafOnly={true}
  1399. value={value}
  1400. />
  1401. <br />
  1402. <br />
  1403. <div>autoMergeValue=true,leafOnly=false</div>
  1404. <Cascader
  1405. style={{ width: 300 }}
  1406. treeData={treeData4}
  1407. placeholder="请选择所在地区"
  1408. multiple
  1409. autoMergeValue={true}
  1410. leafOnly={false}
  1411. defaultValue={['zhejiang']}
  1412. />
  1413. <br />
  1414. <br />
  1415. <br />
  1416. <div>autoMergeValue=true,leafOnly=true</div>
  1417. <Cascader
  1418. style={{ width: 300 }}
  1419. treeData={treeData4}
  1420. placeholder="请选择所在地区"
  1421. multiple
  1422. autoMergeValue={true}
  1423. leafOnly={true}
  1424. defaultValue={['zhejiang']}
  1425. />
  1426. </div>
  1427. );
  1428. }
  1429. export const DynamicTreeData = () => {
  1430. const [treeDataDemo1,setTreeData1]=useState(treeData2);
  1431. const [treeDataDemo2,setTreeData2]=useState(treeData2);
  1432. const [treeDataDemo3,setTreeData3]=useState(treeData2);
  1433. const [treeDataDemo4,setTreeData4]=useState(treeData2);
  1434. const [treeDataDemo5,setTreeData5]=useState(treeData2);
  1435. const [value3,setValue3]=useState();
  1436. const [value4,setValue4]=useState();
  1437. return (
  1438. <div>
  1439. <div>多选 + 动态更新 tree</div>
  1440. <Cascader
  1441. style={{ width: 300 }}
  1442. treeData={treeDataDemo1}
  1443. multiple
  1444. placeholder="请选择所在地区"
  1445. />
  1446. <Button onClick={()=>{setTreeData1(treeData3)}}>改变treeData</Button>
  1447. <br />
  1448. <br />
  1449. <div>单选 + 动态更新 tree</div>
  1450. <Cascader
  1451. style={{ width: 300 }}
  1452. treeData={treeDataDemo2}
  1453. placeholder="请选择所在地区"
  1454. />
  1455. <Button onClick={()=>{setTreeData2(treeData3)}}>改变treeData</Button>
  1456. <br />
  1457. <br />
  1458. <div>多选 + 动态更新 tree + 受控</div>
  1459. <Cascader
  1460. style={{ width: 300 }}
  1461. treeData={treeDataDemo3}
  1462. multiple
  1463. value={value3}
  1464. onChange={v=>{
  1465. console.log(v);
  1466. setValue3(v);
  1467. }}
  1468. placeholder="请选择所在地区"
  1469. />
  1470. <Button onClick={()=>{setTreeData3(treeData3)}}>改变treeData</Button>
  1471. <br />
  1472. <br />
  1473. <div>单选 + 动态更新 tree + 受控</div>
  1474. <Cascader
  1475. style={{ width: 300 }}
  1476. treeData={treeDataDemo4}
  1477. value={value4}
  1478. onChange={v=>{
  1479. console.log(v);
  1480. setValue4(v);
  1481. }}
  1482. placeholder="请选择所在地区"
  1483. />
  1484. <Button onClick={()=>{setTreeData4(treeData3)}}>改变treeData</Button>
  1485. <br />
  1486. <br />
  1487. <div>多选 + 动态更新 tree + defaultValue 为亚洲</div>
  1488. <Cascader
  1489. style={{ width: 300 }}
  1490. treeData={treeDataDemo5}
  1491. multiple
  1492. defaultValue='yazhou'
  1493. placeholder="请选择所在地区"
  1494. />
  1495. <Button onClick={()=>{setTreeData5(treeData3)}}>改变treeData</Button>
  1496. <br />
  1497. <br />
  1498. </div>
  1499. );
  1500. }
  1501. export const SuperLongList = () => {
  1502. let treeData = new Array(100).fill().map(() => ({ label: '浙江省', value: 'zhejiang' }));
  1503. treeData.push({ label: '到底啦', value: 'bottom' })
  1504. return (
  1505. <Cascader
  1506. style={{ width: 300 }}
  1507. treeData={treeData}
  1508. placeholder="请选择所在地区"
  1509. onListScroll={()=>{console.log(123)}}
  1510. />
  1511. );
  1512. };