tree.stories.js 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010
  1. import React, { useState, useRef, useEffect } from 'react';
  2. import { storiesOf } from '@storybook/react';
  3. // import { withKnobs, text, boolean } from '@storybook/addon-knobs';
  4. import withPropsCombinations from 'react-storybook-addon-props-combinations';
  5. import Tree from '../index';
  6. import AutoSizer from '../autoSizer';
  7. import { Icon, Toast, ButtonGroup, Button, Popover, Input } from '../../index';
  8. import BigTree from './BigData';
  9. import testData from './data';
  10. import {
  11. isEmpty,
  12. isPlainObject,
  13. cloneDeep,
  14. isObject,
  15. cloneDeepWith,
  16. isArray,
  17. isEqual,
  18. debounce,
  19. omit,
  20. update,
  21. difference,
  22. } from 'lodash-es';
  23. import {IconMapPin, IconMore, IconEdit } from '@douyinfe/semi-icons';
  24. const TreeNode = Tree.TreeNode;
  25. const stories = storiesOf('Tree', module);
  26. const treeChildren = [
  27. {
  28. label: '北京',
  29. value: 'beijing',
  30. key: 'beijing',
  31. },
  32. {
  33. label: '上海',
  34. value: 'shanghai',
  35. key: 'shanghai',
  36. },
  37. ];
  38. const treeData1 = [
  39. {
  40. label: '亚洲',
  41. value: 'yazhou',
  42. key: 'yazhou',
  43. children: [
  44. {
  45. label: '中国',
  46. value: 'zhongguo',
  47. key: 'zhongguo',
  48. disabled: true,
  49. children: treeChildren,
  50. },
  51. {
  52. label: '日本',
  53. value: 'riben',
  54. key: 'riben',
  55. children: [
  56. {
  57. label: '东京',
  58. value: 'dongjing',
  59. key: 'dongjing',
  60. },
  61. {
  62. label: '大阪',
  63. value: 'daban',
  64. key: 'daban',
  65. },
  66. ],
  67. },
  68. ],
  69. },
  70. {
  71. label: '北美洲',
  72. value: 'beimeizhou',
  73. key: 'beimeizhou',
  74. children: [
  75. {
  76. label: '美国',
  77. value: 'meiguo',
  78. key: 'meiguo',
  79. },
  80. {
  81. label: '加拿大',
  82. value: 'jianada',
  83. key: 'jianada',
  84. },
  85. ],
  86. },
  87. ];
  88. const treeDataWithoutValue = [
  89. {
  90. label: '亚洲',
  91. key: 'yazhou',
  92. children: [
  93. {
  94. label: '中国',
  95. key: 'zhongguo',
  96. disabled: true,
  97. children: treeChildren,
  98. },
  99. {
  100. label: '日本',
  101. key: 'riben',
  102. children: [
  103. {
  104. label: '东京',
  105. key: 'dongjing',
  106. },
  107. {
  108. label: '大阪',
  109. key: 'daban',
  110. },
  111. ],
  112. },
  113. ],
  114. },
  115. {
  116. label: '北美洲',
  117. key: 'beimeizhou',
  118. children: [
  119. {
  120. label: '美国',
  121. key: 'meiguo',
  122. },
  123. {
  124. label: '加拿大',
  125. key: 'jianada',
  126. },
  127. ],
  128. },
  129. ];
  130. const treeDataWithIcon = [
  131. {
  132. label: 'Asia',
  133. value: 'Asia',
  134. key: '0',
  135. icon: <IconMapPin style={{ color: 'var(--semi-color-text-2)' }} />,
  136. children: [
  137. {
  138. label: 'China',
  139. value: 'China',
  140. key: '0-0',
  141. icon: <IconMapPin style={{ color: 'var(--semi-color-text-2)' }} />,
  142. },
  143. {
  144. label: 'Japan',
  145. value: 'Japan',
  146. key: '0-1',
  147. icon: <IconMapPin style={{ color: 'var(--semi-color-text-2)' }} />,
  148. },
  149. ],
  150. },
  151. ];
  152. let opts = {
  153. content: 'Hi, Bytedance dance dance',
  154. duration: 3,
  155. };
  156. const treeDataWithNode = [
  157. {
  158. label: (
  159. <span>
  160. <span style={{ marginRight: 30 }}>亚洲</span>
  161. <Button
  162. style={{ zIndex: 2 }}
  163. onClick={e => {
  164. Toast.info(opts);
  165. e.stopPropagation();
  166. }}
  167. >
  168. Display Toast
  169. </Button>
  170. </span>
  171. ),
  172. value: 'yazhou',
  173. key: 'yazhou',
  174. children: [
  175. {
  176. label: '中国',
  177. value: 'zhongguo',
  178. key: 'zhongguo',
  179. children: [
  180. {
  181. label: '北京',
  182. value: 'beijing',
  183. key: 'beijing',
  184. },
  185. {
  186. label: '上海',
  187. value: 'shanghai',
  188. key: 'shanghai',
  189. },
  190. ],
  191. },
  192. {
  193. label: '日本',
  194. value: 'riben',
  195. key: 'riben',
  196. },
  197. ],
  198. },
  199. {
  200. label: '北美洲',
  201. value: 'beimeizhou',
  202. key: 'beimeizhou',
  203. children: [
  204. {
  205. label: '美国',
  206. value: 'meiguo',
  207. key: 'meiguo',
  208. },
  209. {
  210. label: '加拿大',
  211. value: 'jianada',
  212. key: 'jianada',
  213. },
  214. ],
  215. },
  216. ];
  217. const treeJson = {
  218. Node1: {
  219. Child1: '0-0-1',
  220. Child2: '0-0-2',
  221. },
  222. Node2: '0-1',
  223. };
  224. const benchmarkSet = size => {
  225. console.time('benchmarkSet');
  226. var set = new Set();
  227. for (var i = 0; i < size; i++) set.add(i);
  228. for (var i = 0; i < size; i++) set.has(i);
  229. console.timeEnd('benchmarkSet');
  230. };
  231. const benchmarkArr = size => {
  232. console.time('benchmarkArr');
  233. var arr = [];
  234. for (var i = 0; i < size; i++) arr.push(i);
  235. for (var i = 0; i < size; i++) arr.indexOf(i);
  236. console.timeEnd('benchmarkArr');
  237. };
  238. stories.add('bench mark', () => {
  239. const size = 100000;
  240. benchmarkSet(size);
  241. benchmarkArr(size);
  242. return <div>check console please</div>;
  243. });
  244. stories.add('simple tree', () => (
  245. <Tree
  246. treeData={treeData1}
  247. // onExpand={(e, { expanded, node }) => console.log('expand', e, expanded, node)}
  248. // onSelect={(e, bool, node) => console.log('select', e, bool, node)}
  249. // onChange={e => console.log('change', e)}
  250. onRightClick={(e, node) => console.log(e.currentTarget, node)}
  251. onDoubleClick={(e, node) => console.log(e, node)}
  252. motion={true}
  253. />
  254. ));
  255. stories.add('multiple tree', () => (
  256. <Tree
  257. treeData={treeData1}
  258. multiple
  259. labelInValue
  260. // onExpand={(e, { expanded, node }) => console.log('expand', e, expanded, node)}
  261. // onSelect={(e, bool) => console.log('select', e, bool)}
  262. onRightClick={(e, node) => console.log(e, node)}
  263. onDoubleClick={(e, node) => console.log(e, node)}
  264. onChange={e => console.log('change', e)}
  265. />
  266. ));
  267. stories.add('searchable tree', () => (
  268. <Tree treeData={treeData1} filterTreeNode treeNodeFilterProp="value" multiple searchStyle={{ width: '300px' }} />
  269. ));
  270. stories.add('disabled tree', () => (
  271. <Tree treeData={treeData1} defaultValue={['dongjing', 'daban']} multiple disabled />
  272. ));
  273. stories.add('default tree', () => (
  274. <div>
  275. <Tree treeData={treeData1} defaultValue={['zhongguo']} />
  276. <br />
  277. <Tree
  278. treeData={treeData1}
  279. multiple
  280. defaultValue={['shanghai', 'dongjing', 'beijing', 'daban']}
  281. onChange={e => console.log(e)}
  282. onSelect={e => console.log(e)}
  283. />
  284. </div>
  285. ));
  286. stories.add('expandAction', () => (
  287. <div>
  288. <Tree treeData={treeData1} defaultValue={['zhongguo']} />
  289. <br />
  290. <Tree
  291. treeData={treeData1}
  292. //multiple
  293. defaultValue={['shanghai', 'dongjing', 'beijing', 'daban']}
  294. expandAction="click"
  295. onDoubleClick={e => console.log(e.detail)}
  296. />
  297. <br />
  298. <Tree
  299. treeData={treeData1}
  300. multiple
  301. defaultValue={['shanghai', 'dongjing', 'beijing', 'daban']}
  302. expandAction="doubleClick"
  303. />
  304. </div>
  305. ));
  306. class Demo extends React.Component {
  307. constructor() {
  308. super();
  309. this.state = {
  310. value: 'shanghai',
  311. };
  312. }
  313. onChange(value) {
  314. this.setState({ value });
  315. }
  316. render() {
  317. return (
  318. <Tree
  319. style={{ width: 300 }}
  320. dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
  321. treeData={treeData1}
  322. value={this.state.value}
  323. placeholder="Please select"
  324. onChange={e => this.onChange(e)}
  325. />
  326. );
  327. }
  328. }
  329. stories.add('controlled Component single', () => <Demo />);
  330. class Demo2 extends React.Component {
  331. constructor() {
  332. super();
  333. this.state = {
  334. value: ['shanghai', 'beijing', 'zhongguo'],
  335. };
  336. }
  337. onChange(value) {
  338. console.log(value);
  339. this.setState({ value });
  340. }
  341. render() {
  342. console.log(this.state.value);
  343. return (
  344. <Tree
  345. style={{ width: 300 }}
  346. multiple
  347. dropdownStyle={{ maxHeight: 200, overflow: 'auto' }}
  348. treeData={treeData1}
  349. value={this.state.value}
  350. placeholder="Please select"
  351. onChange={e => this.onChange(e)}
  352. />
  353. );
  354. }
  355. }
  356. stories.add('controlled Component multiple', () => <Demo2 />);
  357. stories.add('json tree', () => (
  358. <div>
  359. <Tree
  360. treeDataSimpleJson={treeJson}
  361. onChange={e => console.log('change', e)}
  362. onSelect={e => console.log('select', e)}
  363. />
  364. <br />
  365. <Tree treeDataSimpleJson={treeJson} multiple onChange={e => console.log(e)} onSelect={e => console.log(e)} />
  366. </div>
  367. ));
  368. stories.add('icon tree', () => (
  369. <div>
  370. <Tree treeData={treeDataWithIcon} />
  371. <br />
  372. <Tree treeData={treeDataWithIcon} multiple blockNode />
  373. </div>
  374. ));
  375. stories.add('directory tree', () => <Tree treeData={treeData1} directory multiple blockNode />);
  376. const button = (
  377. <ButtonGroup size="small" theme="borderless">
  378. <Button
  379. onClick={e => {
  380. Toast.info(opts);
  381. e.stopPropagation();
  382. }}
  383. >
  384. 提示
  385. </Button>
  386. <Button>点击</Button>
  387. </ButtonGroup>
  388. );
  389. const style = {
  390. display: 'flex',
  391. justifyContent: 'space-between',
  392. alignItems: 'center',
  393. };
  394. const treeDataWithNode2 = [
  395. {
  396. label: (
  397. <div style={style}>
  398. <span>亚洲</span>
  399. <ButtonGroup size="small" theme="borderless">
  400. {button}
  401. </ButtonGroup>
  402. </div>
  403. ),
  404. value: 'yazhou',
  405. key: 'yazhou',
  406. children: [
  407. {
  408. label: (
  409. <div style={style}>
  410. <span>中国</span>
  411. {button}
  412. </div>
  413. ),
  414. value: 'zhongguo',
  415. key: 'zhongguo',
  416. children: [
  417. {
  418. label: (
  419. <div style={style}>
  420. <span>test</span>
  421. {button}
  422. </div>
  423. ),
  424. value: 'test',
  425. key: 'test',
  426. },
  427. ],
  428. },
  429. {
  430. label: (
  431. <div style={style}>
  432. <span>日本</span>
  433. {button}
  434. </div>
  435. ),
  436. value: 'riben',
  437. key: 'riben',
  438. },
  439. ],
  440. },
  441. ];
  442. stories.add('tree label using node', () => (
  443. <div>
  444. <Tree treeData={treeDataWithNode2} blockNode defaultExpandAll />
  445. </div>
  446. ));
  447. const treeDataTest = [
  448. {
  449. value: '一级标签1',
  450. label: '一级标签1',
  451. id: 1,
  452. key: '1',
  453. },
  454. ];
  455. class TagSideSheet2 extends React.Component {
  456. constructor() {
  457. super();
  458. this.state = {
  459. tagList: [],
  460. visibles: false,
  461. };
  462. this.onVisible = this.onVisible.bind(this);
  463. this.renderLabel = this.renderLabel.bind(this);
  464. this.transLabel = this.transLabel.bind(this);
  465. }
  466. componentDidMount() {
  467. let tagList = [...treeDataTest];
  468. this.setState({
  469. tagList,
  470. });
  471. }
  472. onVisible(visibles) {
  473. this.setState({
  474. visibles,
  475. });
  476. }
  477. renderLabel(item) {
  478. const { visibles } = this.state;
  479. console.log('rendering label', visibles);
  480. return (
  481. <Popover trigger="custom" position="bottomLeft" visible={visibles} content={'测试popover'}>
  482. <Button
  483. icon={<IconEdit />}
  484. onClick={e => {
  485. e.stopPropagation();
  486. this.onVisible(!visibles);
  487. }}
  488. >
  489. {item.label}
  490. </Button>
  491. </Popover>
  492. );
  493. }
  494. transLabel(list) {
  495. // list = cloneDeep(list);
  496. list.forEach(item => {
  497. item.label = this.renderLabel(item);
  498. // item.key += Math.random().toString().slice(0, 5);
  499. });
  500. return list;
  501. }
  502. render() {
  503. const { tagList = [] } = this.state;
  504. const transformedTags = this.transLabel(cloneDeep(tagList));
  505. console.log('transformedTags', transformedTags, treeDataTest);
  506. return <Tree treeData={transformedTags} />;
  507. }
  508. }
  509. stories.add('tree label using popover', () => <TagSideSheet2 />);
  510. stories.add('defaultExpandKeys tree', () => (
  511. <>
  512. <Tree treeData={treeData1} defaultExpandedKeys={['zhongguo', 'beimeizhou']} blockNode />
  513. <Tree treeData={treeData1} defaultExpandAll blockNode />
  514. <Tree treeData={treeData1} defaultExpandAll multiple blockNode />
  515. </>
  516. ));
  517. stories.add('labelInValue tree', () => (
  518. <>
  519. <Tree treeData={treeData1} labelInValue onChange={e => console.log(e)} />
  520. <Tree treeData={treeData1} labelInValue onChange={e => console.log(e)} multiple />
  521. <Tree treeData={treeDataWithIcon} labelInValue onChange={e => console.log(e)} multiple />
  522. </>
  523. ));
  524. class Test extends React.Component {
  525. constructor() {
  526. super();
  527. this.state = {
  528. loading: false,
  529. };
  530. }
  531. componentDidMount() {
  532. setTimeout(() => {
  533. console.log('set loading');
  534. this.setState({ loading: true });
  535. }, 5000);
  536. }
  537. render() {
  538. const treeDataWithNode2 = [
  539. {
  540. label: (
  541. <div style={style}>
  542. <span>亚洲</span>
  543. <ButtonGroup size="small" theme="borderless">
  544. {button}
  545. </ButtonGroup>
  546. </div>
  547. ),
  548. value: 'yazhou',
  549. key: 'yazhou',
  550. children: [
  551. {
  552. label: (
  553. <div style={style}>
  554. <span>中国</span>
  555. {button}
  556. </div>
  557. ),
  558. value: 'zhongguo',
  559. key: 'zhongguo',
  560. children: [
  561. {
  562. label: (
  563. <div style={style}>
  564. <span>test</span>
  565. {button}
  566. </div>
  567. ),
  568. value: 'test',
  569. key: 'test',
  570. },
  571. ],
  572. },
  573. {
  574. label: (
  575. <div style={style}>
  576. <span>日本</span>
  577. {button}
  578. </div>
  579. ),
  580. value: 'riben',
  581. key: 'riben',
  582. },
  583. ],
  584. },
  585. ];
  586. return <Tree treeData={treeDataWithNode2} />;
  587. }
  588. }
  589. stories.add('setState after 5s', () => <Test />);
  590. class DemoExpandedKeys extends React.Component {
  591. constructor() {
  592. super();
  593. this.state = {
  594. expand: ['zhongguo', 'beimeizhou'],
  595. };
  596. }
  597. onExpand(expand) {
  598. console.log(expand);
  599. this.setState({ expand });
  600. }
  601. render() {
  602. return (
  603. <Tree
  604. style={{ width: 300 }}
  605. dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
  606. treeData={treeData1}
  607. expandedKeys={this.state.expand}
  608. placeholder="Please select"
  609. onExpand={(e, rest) => this.onExpand(e, rest)}
  610. />
  611. );
  612. }
  613. }
  614. class DemoExpandeKeysMulti extends React.Component {
  615. constructor() {
  616. super();
  617. this.state = {
  618. expand: ['zhongguo'],
  619. };
  620. }
  621. onExpand(expand) {
  622. console.log(expand);
  623. this.setState({ expand });
  624. }
  625. render() {
  626. return (
  627. <Tree
  628. style={{ width: 300 }}
  629. multiple
  630. dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
  631. treeData={treeData1}
  632. expandedKeys={this.state.expand}
  633. placeholder="Please select"
  634. onExpand={e => this.onExpand(e)}
  635. />
  636. );
  637. }
  638. }
  639. stories.add('expandedKeys', () => (
  640. <>
  641. <DemoExpandedKeys />
  642. <br />
  643. <DemoExpandeKeysMulti />
  644. </>
  645. ));
  646. class DmExpandedKeys extends React.Component {
  647. constructor() {
  648. super();
  649. this.state = {
  650. treeData: [
  651. {
  652. key: '0',
  653. label: 'item-0',
  654. value: '0',
  655. },
  656. ],
  657. };
  658. this.add = this.add.bind(this);
  659. }
  660. add() {
  661. let itemLength = Math.floor(Math.random() * 5) + 1;
  662. let treeData = new Array(itemLength).fill(0).map((v, i) => {
  663. let length = Math.floor(Math.random() * 3);
  664. let children = new Array(length).fill(0).map((cv, ci) => {
  665. let child = {
  666. key: `${i}-${ci}`,
  667. label: `Leaf-${i}-${ci}`,
  668. value: `${i}-${ci}`,
  669. };
  670. return child;
  671. });
  672. let item = {
  673. key: `${i}`,
  674. label: `Item-${i}`,
  675. value: `${i}`,
  676. children,
  677. };
  678. return item;
  679. });
  680. this.setState({ treeData });
  681. }
  682. render() {
  683. const { treeData } = this.state;
  684. return (
  685. <>
  686. <Tree treeData={this.state.treeData} expandedKeys={['0', '1']} />
  687. <br />
  688. <Button onClick={this.add}>动态改变数据</Button>
  689. </>
  690. );
  691. }
  692. }
  693. stories.add('dynamic expandKeys', () => (
  694. <>
  695. <DmExpandedKeys />
  696. </>
  697. ));
  698. class DmSelectedKeys extends React.Component {
  699. constructor() {
  700. super();
  701. this.state = {
  702. treeData: [
  703. {
  704. key: '0',
  705. label: 'item-0',
  706. value: '0',
  707. },
  708. ],
  709. };
  710. this.add = this.add.bind(this);
  711. }
  712. add() {
  713. let itemLength = Math.floor(Math.random() * 5) + 1;
  714. let treeData = new Array(itemLength).fill(0).map((v, i) => {
  715. let length = Math.floor(Math.random() * 3);
  716. let children = new Array(length).fill(0).map((cv, ci) => {
  717. let child = {
  718. key: `${i}-${ci}`,
  719. label: `Leaf-${i}-${ci}`,
  720. value: `${i}-${ci}`,
  721. };
  722. return child;
  723. });
  724. let item = {
  725. key: `${i}`,
  726. label: `Item-${i}`,
  727. value: `${i}`,
  728. children,
  729. };
  730. return item;
  731. });
  732. this.setState({ treeData });
  733. }
  734. render() {
  735. const { treeData } = this.state;
  736. return (
  737. <>
  738. <Tree treeData={treeData} value={['0-0']} onChange={e => console.log(e)} />
  739. <br />
  740. <Button onClick={this.add}>动态改变数据</Button>
  741. </>
  742. );
  743. }
  744. }
  745. // the demo will not work anymore as value does not exist when the tree mounts
  746. stories.add('dynamic selectedKey', () => (
  747. <>
  748. <DmSelectedKeys />
  749. </>
  750. ));
  751. stories.add('large amount of data', () => (
  752. <>
  753. <BigTree />
  754. </>
  755. ));
  756. stories.add('autosizer', () => (
  757. <div style={{
  758. boxSizing: 'border-box',
  759. height: 400,
  760. width: 200,
  761. }}>
  762. <div
  763. style={{
  764. boxSizing: 'border-box',
  765. height: '50%',
  766. width: 200,
  767. }}
  768. >
  769. <AutoSizer
  770. // defaultHeight={defaultHeight}
  771. // defaultWidth={defaultWidth}
  772. >
  773. {({ height, width }) => (
  774. <div
  775. style={{
  776. width: width,
  777. height: height,
  778. }}
  779. >
  780. {`width:${width}, height:${height}`}
  781. </div>
  782. )}
  783. </AutoSizer>
  784. </div>
  785. </div>
  786. ));
  787. const MotionCustomLabelDemo = () => {
  788. const treeData = [
  789. {
  790. label: '亚洲',
  791. value: 'Asia',
  792. key: '0',
  793. children: [
  794. {
  795. label: '中国',
  796. value: 'China',
  797. key: '0-0',
  798. children: [
  799. {
  800. label: '北京',
  801. value: 'Beijing',
  802. key: '0-0-0',
  803. },
  804. {
  805. label: '上海',
  806. value: 'Shanghai',
  807. key: '0-0-1',
  808. },
  809. ],
  810. },
  811. ],
  812. },
  813. {
  814. label: '北美洲',
  815. value: 'North America',
  816. key: '1',
  817. },
  818. ];
  819. const [hoverKey, setHoverKey] = useState();
  820. const cusLabel = (list = []) => {
  821. const recusive = (list = []) => {
  822. if (!list.length) {
  823. return;
  824. }
  825. list.forEach(item => {
  826. const { type, label, key } = item;
  827. item.label = (
  828. <div onMouseEnter={() => setHoverKey(key)}>
  829. {label}
  830. {hoverKey === key ? <IconMore /> : null}
  831. </div>
  832. );
  833. recusive(item.children);
  834. });
  835. };
  836. recusive(list);
  837. return list;
  838. };
  839. return <Tree treeData={cusLabel(treeData)} defaultExpandAll />;
  840. };
  841. stories.add('motion custom label', () => <MotionCustomLabelDemo />);
  842. const AutoParentDemo = () => {
  843. const [expandedKeys, setExpandedKeys] = useState(['beimeizhou']);
  844. const [selectedKeys, setSelectedKeys] = useState(['beimeizhou']);
  845. const [autoExpandParent, setAutoExpandParent] = useState(true);
  846. const onExpand = expandedKeys => {
  847. console.log('onExpand', expandedKeys);
  848. // if not set autoExpandParent to false, if children expanded, parent can not collapse.
  849. // or, you can remove all expanded children keys.
  850. setExpandedKeys(expandedKeys);
  851. setAutoExpandParent(false);
  852. };
  853. const onSelect = (selectedKeys, info) => {
  854. console.log('onSelect:', info);
  855. setSelectedKeys(selectedKeys);
  856. };
  857. return (
  858. <div>
  859. <Button
  860. onClick={() => {
  861. setSelectedKeys(['riben']);
  862. setExpandedKeys(['riben']);
  863. setAutoExpandParent(true);
  864. }}
  865. >
  866. Update
  867. </Button>
  868. <Tree
  869. onExpand={onExpand}
  870. expandedKeys={expandedKeys}
  871. autoExpandParent={autoExpandParent}
  872. onChange={onSelect}
  873. value={selectedKeys}
  874. treeData={treeData1}
  875. multiple
  876. />
  877. </div>
  878. );
  879. };
  880. stories.add('autoExpandParent', () => (
  881. <>
  882. <AutoParentDemo />
  883. </>
  884. ));
  885. const findDescendantKeys = node => {
  886. let res = [node.key];
  887. const findChild = item => {
  888. if (!item) return;
  889. const { children } = item;
  890. if (children && children.length) {
  891. children.forEach(child => {
  892. res.push(child.key);
  893. findChild(child);
  894. });
  895. }
  896. };
  897. findChild(node);
  898. return res;
  899. };
  900. class DyTreeWithExpandControlled extends React.Component {
  901. constructor() {
  902. super();
  903. this.state = {
  904. treeData: [
  905. {
  906. key: '0',
  907. label: 'item-0',
  908. value: '0',
  909. },
  910. ],
  911. expandedKeys: [],
  912. autoExpandParent: false,
  913. inputValue: '',
  914. collapsedKeys: new Set([]),
  915. };
  916. }
  917. componentDidUpdate(prevProps, prevState) {
  918. if (
  919. !isEqual(prevState.treeData, this.state.treeData) ||
  920. !isEqual(prevState.inputValue, this.state.inputValue)
  921. ) {
  922. const { treeData, inputValue, collapsedKeys } = this.state;
  923. let filteredKeys = [];
  924. const findFilteredKey = arr => {
  925. arr.forEach(item => {
  926. if (item.label.indexOf(inputValue) > -1) {
  927. filteredKeys.push(item.key);
  928. }
  929. if (item.children) {
  930. findFilteredKey(item.children);
  931. }
  932. });
  933. };
  934. findFilteredKey(treeData);
  935. const expanded = difference(filteredKeys, [...collapsedKeys]);
  936. this.setState({
  937. expandedKeys: expanded,
  938. autoExpandParent: true,
  939. });
  940. }
  941. }
  942. add = () => {
  943. let itemLength = Math.floor(Math.random() * 5) + 1;
  944. let treeData = new Array(itemLength).fill(0).map((v, i) => {
  945. let length = Math.floor(Math.random() * 3) + 1;
  946. let children = new Array(length).fill(0).map((cv, ci) => {
  947. let child = {
  948. key: `${i}-${ci}`,
  949. label: `Leaf-${i}-${ci}`,
  950. value: `${i}-${ci}`,
  951. };
  952. return child;
  953. });
  954. let item = {
  955. key: `${i}`,
  956. label: `Item-${i}`,
  957. value: `${i}`,
  958. children,
  959. };
  960. return item;
  961. });
  962. this.setState({ treeData });
  963. };
  964. search = val => {
  965. this.setState({ inputValue: val });
  966. };
  967. onExpand = (keys, { expanded, node }) => {
  968. let collapsed = this.state.collapsedKeys;
  969. let desKeys = findDescendantKeys(node);
  970. if (!expanded) {
  971. desKeys.forEach(key => collapsed.add(key));
  972. } else {
  973. desKeys.forEach(key => collapsed.has(key) && collapsed.delete(key));
  974. }
  975. this.setState({
  976. expandedKeys: keys,
  977. autoExpandParent: false,
  978. collapsedKeys: collapsed,
  979. });
  980. };
  981. render() {
  982. const { treeData, expandedKeys, autoExpandParent } = this.state;
  983. return (
  984. <div>
  985. <Tree
  986. treeData={treeData}
  987. filterTreeNode
  988. autoExpandParent={autoExpandParent}
  989. expandedKeys={expandedKeys}
  990. onSearch={this.search}
  991. onExpand={this.onExpand}
  992. />
  993. <br />
  994. <Button onClick={this.add} style={{ margin: 20 }}>
  995. 动态改变数据
  996. </Button>
  997. </div>
  998. );
  999. }
  1000. }
  1001. stories.add('dynamic treeData with searchValue and controlled expand', () => <DyTreeWithExpandControlled />);
  1002. const CusSearchRender = () => {
  1003. const [inputValue, setInputValue] = useState('');
  1004. const ref = useRef();
  1005. const setValue = value => {
  1006. setInputValue(value);
  1007. ref.current.search(value);
  1008. };
  1009. return (
  1010. <Tree
  1011. ref={ref}
  1012. treeData={treeData1}
  1013. filterTreeNode
  1014. showFilteredOnly
  1015. searchRender={({ prefix, placeholder }) => (
  1016. <Input
  1017. prefix={prefix}
  1018. placeholder={placeholder}
  1019. value={inputValue}
  1020. onChange={value => setValue(value)}
  1021. />
  1022. )}
  1023. />
  1024. );
  1025. };
  1026. stories.add('CusSearchRender', () => (
  1027. <>
  1028. <CusSearchRender />
  1029. </>
  1030. ));
  1031. const RefSearch = () => {
  1032. const ref = useRef();
  1033. const treeData = [
  1034. {
  1035. label: 'Asia',
  1036. value: 'Asia',
  1037. key: '0',
  1038. children: [
  1039. {
  1040. label: 'China',
  1041. value: 'China',
  1042. key: '0-0',
  1043. children: [
  1044. {
  1045. label: 'Beijing',
  1046. value: 'Beijing',
  1047. key: '0-0-0',
  1048. },
  1049. {
  1050. label: 'Shanghai',
  1051. value: 'Shanghai',
  1052. key: '0-0-1',
  1053. },
  1054. ],
  1055. },
  1056. {
  1057. label: 'Japan',
  1058. value: 'Japan',
  1059. key: '0-1',
  1060. children: [
  1061. {
  1062. label: 'Osaka',
  1063. value: 'Osaka',
  1064. key: '0-1-0',
  1065. },
  1066. ],
  1067. },
  1068. ],
  1069. },
  1070. {
  1071. label: 'North America',
  1072. value: 'North America',
  1073. key: '1',
  1074. children: [
  1075. {
  1076. label: 'United States',
  1077. value: 'United States',
  1078. key: '1-0',
  1079. },
  1080. {
  1081. label: 'Canada',
  1082. value: 'Canada',
  1083. key: '1-1',
  1084. },
  1085. ],
  1086. },
  1087. ];
  1088. return (
  1089. <div>
  1090. <Input onChange={v => ref.current.search(v)} />
  1091. <Tree
  1092. treeData={treeData}
  1093. defaultValue="Shanghai"
  1094. blockNode={false}
  1095. ref={ref}
  1096. filterTreeNode
  1097. searchRender={() => null}
  1098. />
  1099. </div>
  1100. );
  1101. };
  1102. stories.add('RefSearch', () => (
  1103. <>
  1104. <RefSearch />
  1105. </>
  1106. ));
  1107. const initTreeDate = [
  1108. {
  1109. label: 'Expand to load',
  1110. key: '0',
  1111. },
  1112. {
  1113. label: 'Expand to load',
  1114. key: '1',
  1115. },
  1116. {
  1117. label: 'Tree Node',
  1118. key: '2',
  1119. isLeaf: true,
  1120. },
  1121. ];
  1122. function updateTreeData(list, key, children) {
  1123. return list.map(node => {
  1124. if (node.key === key) {
  1125. return { ...node, children };
  1126. }
  1127. if (node.children) {
  1128. return { ...node, children: updateTreeData(node.children, key, children) };
  1129. }
  1130. return node;
  1131. });
  1132. }
  1133. const LoadingTreeDemo = () => {
  1134. const [treeData, setTreeData] = useState(initTreeDate);
  1135. function onLoadData({ key, children }) {
  1136. return new Promise(resolve => {
  1137. if (children) {
  1138. resolve();
  1139. return;
  1140. }
  1141. setTimeout(() => {
  1142. setTreeData(origin =>
  1143. updateTreeData(origin, key, [
  1144. {
  1145. label: 'Child Node',
  1146. key: `${key}-0`,
  1147. },
  1148. {
  1149. label: 'Child Node',
  1150. key: `${key}-1`,
  1151. },
  1152. ])
  1153. );
  1154. resolve();
  1155. }, 1000);
  1156. });
  1157. }
  1158. return <Tree loadData={onLoadData} treeData={cloneDeep(treeData)} />;
  1159. };
  1160. stories.add('loading', () => (
  1161. <>
  1162. <LoadingTreeDemo />
  1163. </>
  1164. ));
  1165. const LoadingWithSearch = () => {
  1166. const [treeData, setTreeData] = useState(initTreeDate);
  1167. function onLoadData({ key, children }) {
  1168. return new Promise(resolve => {
  1169. if (children) {
  1170. resolve();
  1171. return;
  1172. }
  1173. setTimeout(() => {
  1174. setTreeData(origin =>
  1175. updateTreeData(origin, key, [
  1176. {
  1177. label: 'Child Node',
  1178. key: `${key}-0`,
  1179. },
  1180. {
  1181. label: 'Child Node',
  1182. key: `${key}-1`,
  1183. },
  1184. ])
  1185. );
  1186. resolve();
  1187. }, 1000);
  1188. });
  1189. }
  1190. return <Tree loadData={onLoadData} treeData={cloneDeep(treeData)} filterTreeNode />;
  1191. };
  1192. stories.add('Loading with search', () => (
  1193. <>
  1194. <LoadingWithSearch />
  1195. </>
  1196. ));
  1197. const DisabledStrictly = () => {
  1198. return (
  1199. <>
  1200. <span> disable shanghai(checked), China </span>
  1201. <Tree
  1202. treeData={[
  1203. {
  1204. label: 'Asia',
  1205. value: 'Asia',
  1206. key: '0',
  1207. children: [
  1208. {
  1209. label: 'China',
  1210. value: 'China',
  1211. key: '0-0',
  1212. disabled: true,
  1213. children: [
  1214. {
  1215. label: 'Beijing',
  1216. value: 'Beijing',
  1217. key: '0-0-0',
  1218. },
  1219. {
  1220. label: 'Shanghai',
  1221. value: 'Shanghai',
  1222. key: '0-0-1',
  1223. disabled: true,
  1224. },
  1225. ],
  1226. },
  1227. {
  1228. label: 'Japan',
  1229. value: 'Japan',
  1230. key: '0-1',
  1231. children: [
  1232. {
  1233. label: 'Osaka',
  1234. value: 'Osaka',
  1235. key: '0-1-0'
  1236. }
  1237. ]
  1238. },
  1239. ],
  1240. }
  1241. ]}
  1242. defaultValue='Shanghai'
  1243. multiple
  1244. defaultExpandAll
  1245. disableStrictly
  1246. />
  1247. <br />
  1248. <span> disable shanghai(checked), beijing(checked) </span>
  1249. <Tree
  1250. treeData={[
  1251. {
  1252. label: 'Asia',
  1253. value: 'Asia',
  1254. key: '0',
  1255. children: [
  1256. {
  1257. label: 'China',
  1258. value: 'China',
  1259. key: '0-0',
  1260. children: [
  1261. {
  1262. label: 'Beijing',
  1263. value: 'Beijing',
  1264. key: '0-0-0',
  1265. disabled: true,
  1266. },
  1267. {
  1268. label: 'Shanghai',
  1269. value: 'Shanghai',
  1270. key: '0-0-1',
  1271. disabled: true,
  1272. },
  1273. ],
  1274. },
  1275. {
  1276. label: 'Japan',
  1277. value: 'Japan',
  1278. key: '0-1',
  1279. children: [
  1280. {
  1281. label: 'Osaka',
  1282. value: 'Osaka',
  1283. key: '0-1-0'
  1284. }
  1285. ]
  1286. },
  1287. ],
  1288. }
  1289. ]}
  1290. defaultValue={['Shanghai', 'Beijing']}
  1291. multiple
  1292. defaultExpandAll
  1293. disableStrictly
  1294. />
  1295. <span> disable shanghai(checked) </span>
  1296. <Tree
  1297. treeData={[
  1298. {
  1299. label: 'Asia',
  1300. value: 'Asia',
  1301. key: '0',
  1302. children: [
  1303. {
  1304. label: 'China',
  1305. value: 'China',
  1306. key: '0-0',
  1307. children: [
  1308. {
  1309. label: 'Beijing',
  1310. value: 'Beijing',
  1311. key: '0-0-0',
  1312. },
  1313. {
  1314. label: 'Shanghai',
  1315. value: 'Shanghai',
  1316. key: '0-0-1',
  1317. disabled: true,
  1318. },
  1319. ],
  1320. },
  1321. {
  1322. label: 'Japan',
  1323. value: 'Japan',
  1324. key: '0-1',
  1325. children: [
  1326. {
  1327. label: 'Osaka',
  1328. value: 'Osaka',
  1329. key: '0-1-0'
  1330. }
  1331. ]
  1332. },
  1333. ],
  1334. }
  1335. ]}
  1336. defaultValue={['Shanghai']}
  1337. multiple
  1338. defaultExpandAll
  1339. disableStrictly
  1340. />
  1341. <br />
  1342. <span> disable shanghai </span>
  1343. <Tree
  1344. treeData={[
  1345. {
  1346. label: 'Asia',
  1347. value: 'Asia',
  1348. key: '0',
  1349. children: [
  1350. {
  1351. label: 'China',
  1352. value: 'China',
  1353. key: '0-0',
  1354. children: [
  1355. {
  1356. label: 'Beijing',
  1357. value: 'Beijing',
  1358. key: '0-0-0',
  1359. },
  1360. {
  1361. label: 'Chengdu',
  1362. value: 'Chengdu',
  1363. key: '0-0-2',
  1364. },
  1365. {
  1366. label: 'Shanghai',
  1367. value: 'Shanghai',
  1368. key: '0-0-1',
  1369. disabled: true,
  1370. },
  1371. ],
  1372. },
  1373. {
  1374. label: 'Japan',
  1375. value: 'Japan',
  1376. key: '0-1',
  1377. children: [
  1378. {
  1379. label: 'Osaka',
  1380. value: 'Osaka',
  1381. key: '0-1-0'
  1382. }
  1383. ]
  1384. },
  1385. ],
  1386. }
  1387. ]}
  1388. multiple
  1389. defaultExpandAll
  1390. disableStrictly
  1391. />
  1392. <span> disable China(checked) - Shanghai </span>
  1393. <Tree
  1394. treeData={[
  1395. {
  1396. label: 'Asia',
  1397. value: 'Asia',
  1398. key: '0',
  1399. children: [
  1400. {
  1401. label: 'China',
  1402. value: 'China',
  1403. key: '0-0',
  1404. disabled: true,
  1405. children: [
  1406. {
  1407. label: 'Beijing',
  1408. value: 'Beijing',
  1409. key: '0-0-0',
  1410. },
  1411. {
  1412. label: 'Shanghai',
  1413. value: 'Shanghai',
  1414. key: '0-0-1',
  1415. disabled: true,
  1416. },
  1417. ],
  1418. },
  1419. {
  1420. label: 'Japan',
  1421. value: 'Japan',
  1422. key: '0-1',
  1423. children: [
  1424. {
  1425. label: 'Osaka',
  1426. value: 'Osaka',
  1427. key: '0-1-0'
  1428. }
  1429. ]
  1430. },
  1431. ],
  1432. }
  1433. ]}
  1434. defaultValue='China'
  1435. multiple
  1436. defaultExpandAll
  1437. disableStrictly
  1438. />
  1439. <span> disable China </span>
  1440. <Tree
  1441. treeData={[
  1442. {
  1443. label: 'Asia',
  1444. value: 'Asia',
  1445. key: '0',
  1446. children: [
  1447. {
  1448. label: 'China',
  1449. value: 'China',
  1450. key: '0-0',
  1451. disabled: true,
  1452. children: [
  1453. {
  1454. label: 'Beijing',
  1455. value: 'Beijing',
  1456. key: '0-0-0',
  1457. },
  1458. {
  1459. label: 'Shanghai',
  1460. value: 'Shanghai',
  1461. key: '0-0-1',
  1462. },
  1463. ],
  1464. },
  1465. {
  1466. label: 'Japan',
  1467. value: 'Japan',
  1468. key: '0-1',
  1469. children: [
  1470. {
  1471. label: 'Osaka',
  1472. value: 'Osaka',
  1473. key: '0-1-0'
  1474. }
  1475. ]
  1476. },
  1477. ],
  1478. }
  1479. ]}
  1480. multiple
  1481. defaultExpandAll
  1482. disableStrictly
  1483. />
  1484. </>
  1485. )
  1486. }
  1487. stories.add('disableStrictly', () => <DisabledStrictly />);
  1488. const ActionTree = () => {
  1489. let initData = [{
  1490. label: 'Asia',
  1491. value: 'Asia',
  1492. key: 'asia',
  1493. children: [{
  1494. label: 0,
  1495. value: `${0}`,
  1496. key: `${0}`,
  1497. }, {
  1498. label: 1,
  1499. value: `${1}`,
  1500. key: `${1}`,
  1501. }, {
  1502. label: 2,
  1503. value: `${2}`,
  1504. key: `${2}`,
  1505. }, {
  1506. label: 3,
  1507. value: `${3}`,
  1508. key: `${3}`,
  1509. }, {
  1510. label: 4,
  1511. value: `${4}`,
  1512. key: `${4}`,
  1513. }]
  1514. }];
  1515. const [data, setData] = useState(initData);
  1516. const remove = key => {
  1517. let ind = data[0].children.findIndex(item => item.key === key);
  1518. if (ind >= 0) {
  1519. let items = cloneDeep(data);
  1520. items[0].children.splice(ind, 1);
  1521. setData(items);
  1522. }
  1523. }
  1524. return (
  1525. <Tree
  1526. treeData={cloneDeep(data)}
  1527. renderLabel={(label, data) => (<div>{label}<Button onClick={() => remove(data.key)}>remove</Button></div>)}
  1528. />
  1529. );
  1530. };
  1531. stories.add('Delete or Add Child Node', () => <ActionTree />);
  1532. const MutipleHLTree = () => {
  1533. const [selected, setSelected] = useState(new Set());
  1534. const [selectedThroughParent, setSelectedThroughParent] = useState(new Set());
  1535. const findDescendantKeys = (node) => {
  1536. let res = [node.key];
  1537. const findChild = item => {
  1538. if (!item) return;
  1539. const { children } = item;
  1540. if (children && children.length) {
  1541. children.forEach(child => {
  1542. res.push(child.key);
  1543. findChild(child);
  1544. });
  1545. }
  1546. };
  1547. findChild(node);
  1548. return res;
  1549. }
  1550. const handleSelect = (key, bool, node) => {
  1551. setSelected(new Set([key]));
  1552. const descendantKeys = findDescendantKeys(node);
  1553. setSelectedThroughParent(new Set(descendantKeys));
  1554. }
  1555. const renderLabel = ({
  1556. className,
  1557. data,
  1558. onClick,
  1559. expandIcon
  1560. }) => {
  1561. const { label, icon, key } = data;
  1562. const isLeaf = !(data.children && data.children.length);
  1563. const style = {
  1564. backgroundColor: selected.has(key)
  1565. ? 'rgba(var(--semi-blue-0), 1)'
  1566. : selectedThroughParent.has(key)
  1567. ? 'rgba(var(--semi-blue-0), .5)' : 'transparent'
  1568. }
  1569. return (
  1570. <li
  1571. className={className}
  1572. role="treenode"
  1573. onClick={onClick}
  1574. style={style}
  1575. >
  1576. {isLeaf ? null : expandIcon}
  1577. {icon ? icon : null}
  1578. <span>{label}</span>
  1579. </li>
  1580. )
  1581. }
  1582. const treeStyle = {
  1583. width: 260,
  1584. height: 420,
  1585. border: '1px solid var(--semi-color-border)'
  1586. }
  1587. return (
  1588. <Tree
  1589. treeData={treeData1}
  1590. renderFullLabel={renderLabel}
  1591. onSelect={handleSelect}
  1592. style={treeStyle}
  1593. />
  1594. )
  1595. }
  1596. stories.add('renderOuterLable', () => <MutipleHLTree />)
  1597. stories.add('tree without value props', () => (
  1598. <Tree
  1599. treeData={treeDataWithoutValue}
  1600. value="meiguo"
  1601. defaultExpandAll
  1602. onChange={(...args) => console.log(args)}
  1603. />
  1604. ));
  1605. const x = 3;
  1606. const y = 2;
  1607. const z = 1;
  1608. const gData = [];
  1609. const generateData = (_level, _preKey, _tns) => {
  1610. const preKey = _preKey || '0';
  1611. const tns = _tns || gData;
  1612. const children = [];
  1613. for (let i = 0; i < x; i++) {
  1614. const key = `${preKey}-${i}`;
  1615. tns.push({ label: key, key });
  1616. if (i < y) {
  1617. children.push(key);
  1618. }
  1619. }
  1620. if (_level < 0) {
  1621. return tns;
  1622. }
  1623. const level = _level - 1;
  1624. children.forEach((key, index) => {
  1625. tns[index].children = [];
  1626. return generateData(level, key, tns[index].children);
  1627. });
  1628. };
  1629. generateData(z);
  1630. const DnDTree = () => {
  1631. function generateData(x = 3, y = 2, z = 1, gData = []) {
  1632. // x:每一级下的节点总数。y:每级节点里有y个节点、存在子节点。z:树的level层级数(0表示一级)
  1633. function _loop(_level, _preKey, _tns) {
  1634. const preKey = _preKey || '0';
  1635. const tns = _tns || gData;
  1636. const children = [];
  1637. for (let i = 0; i < x; i++) {
  1638. const key = `${preKey}-${i}`;
  1639. tns.push({ label: `${key}`, key: `${key}-key`, value: `${key}-value` });
  1640. if (i < y) {
  1641. children.push(key);
  1642. }
  1643. }
  1644. if (_level < 0) {
  1645. return tns;
  1646. }
  1647. const __level = _level - 1;
  1648. children.forEach((key, index) => {
  1649. tns[index].children = [];
  1650. return _loop(__level, key, tns[index].children);
  1651. });
  1652. return null;
  1653. }
  1654. _loop(z);
  1655. return gData;
  1656. }
  1657. const initialData = generateData();
  1658. const [treeData, setTreeData] = useState(initialData);
  1659. // const [expandedKeys, setExpandedKeys] = useState(['zhongguo']);
  1660. function onDragEnter(info) {
  1661. console.log(info);
  1662. // if in controlled expandedKeys mode
  1663. // setExpandedKeys(info.expandedKeys)
  1664. }
  1665. function onDrop(info) {
  1666. const { dropToGap, node, dragNode } = info;
  1667. const dropKey = node.key;
  1668. const dragKey = dragNode.key;
  1669. const dropPos = node.pos.split('-');
  1670. const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
  1671. const data = [...treeData];
  1672. const loop = (data, key, callback) => {
  1673. data.forEach((item, ind, arr) => {
  1674. if (item.key === key) return callback(item, ind, arr);
  1675. if (item.children) return loop(item.children, key, callback);
  1676. })
  1677. }
  1678. let dragObj;
  1679. loop(data, dragKey, (item, ind, arr) => {
  1680. arr.splice(ind, 1);
  1681. dragObj = item;
  1682. })
  1683. if (!dropToGap) {
  1684. // inset into the dropPosition
  1685. loop(data, dropKey, (item, ind, arr) => {
  1686. item.children = item.children || [];
  1687. item.children.push(dragObj)
  1688. })
  1689. } else if (dropPosition === 1 && node.children && node.expanded) {
  1690. // has children && expanded and drop into the node bottom gap
  1691. // insert to the top 这里我们添加在头部,可以是任意位置
  1692. loop(data, dropKey, item => {
  1693. item.children = item.children || [];
  1694. item.children.unshift(dragObj)
  1695. })
  1696. } else {
  1697. let dropNodeInd;
  1698. let dropNodePosArr;
  1699. loop(data, dropKey, (item, ind, arr) => {
  1700. dropNodePosArr = arr;
  1701. dropNodeInd = ind;
  1702. })
  1703. if (dropPosition === -1) {
  1704. // insert to top
  1705. dropNodePosArr.splice(dropNodeInd, 0, dragObj)
  1706. } else {
  1707. // insert to bottom
  1708. dropNodePosArr.splice(dropNodeInd + 1, 0, dragObj)
  1709. }
  1710. }
  1711. setTreeData(data)
  1712. }
  1713. return <Tree
  1714. treeData={treeData}
  1715. draggable
  1716. //expandedKeys={expandedKeys}
  1717. onDragEnter={onDragEnter}
  1718. onDrop={onDrop}
  1719. />;
  1720. };
  1721. stories.add('draggable Tree', () => <DnDTree />)
  1722. const TestTree = () => {
  1723. return (
  1724. <Tree
  1725. treeData={testData}
  1726. // motion={false}
  1727. style={{ height: '100%' }}
  1728. filterTreeNode
  1729. expandAction="click"
  1730. showFilteredOnly
  1731. />
  1732. );
  1733. };
  1734. stories.add('draggable', () => <TestTree />);
  1735. stories.add('renderFullLabel with draggable', () => {
  1736. const [selected, setSelected] = useState(new Set());
  1737. const [selectedThroughParent, setSelectedThroughParent] = useState(new Set());
  1738. const defaultTreeData = [
  1739. {
  1740. label: '黑色固定按钮',
  1741. key: 'fix-btn-0'
  1742. },
  1743. {
  1744. label: '模块',
  1745. key: 'module-0',
  1746. children: [
  1747. {
  1748. label: '可自由摆放的组件',
  1749. key: 'free-compo-0',
  1750. },
  1751. {
  1752. label: '分栏容器',
  1753. key: 'split-col-0',
  1754. children: [
  1755. {
  1756. label: '按钮组件',
  1757. key: 'btn-0'
  1758. },
  1759. {
  1760. label: '按钮组件',
  1761. key: 'btn-1'
  1762. }
  1763. ]
  1764. },
  1765. ],
  1766. },
  1767. {
  1768. label: '模块',
  1769. key: 'module-1',
  1770. children: [
  1771. {
  1772. label: '自定义组件',
  1773. key: 'cus-0'
  1774. }
  1775. ]
  1776. }
  1777. ]
  1778. const [treeData, setTreeData] = useState(defaultTreeData);
  1779. const onDrop = (info) => {
  1780. const { dropToGap, node, dragNode } = info;
  1781. const dropKey = node.key;
  1782. const dragKey = dragNode.key;
  1783. const dropPos = node.pos.split('-');
  1784. const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
  1785. const data = [...treeData];
  1786. const loop = (data, key, callback) => {
  1787. data.forEach((item, ind, arr) => {
  1788. if (item.key === key) return callback(item, ind, arr);
  1789. if (item.children) return loop(item.children, key, callback);
  1790. })
  1791. }
  1792. let dragObj;
  1793. loop(data, dragKey, (item, ind, arr) => {
  1794. arr.splice(ind, 1);
  1795. dragObj = item;
  1796. })
  1797. if (!dropToGap) {
  1798. loop(data, dropKey, (item, ind, arr) => {
  1799. item.children = item.children || [];
  1800. item.children.push(dragObj)
  1801. })
  1802. } else if (dropPosition === 1 && node.children && node.expanded) {
  1803. loop(data, dropKey, item => {
  1804. item.children = item.children || [];
  1805. item.children.unshift(dragObj)
  1806. })
  1807. } else {
  1808. let dropNodeInd;
  1809. let dropNodePosArr;
  1810. loop(data, dropKey, (item, ind, arr) => {
  1811. dropNodePosArr = arr;
  1812. dropNodeInd = ind;
  1813. })
  1814. if (dropPosition === -1) {
  1815. dropNodePosArr.splice(dropNodeInd, 0, dragObj)
  1816. } else {
  1817. dropNodePosArr.splice(dropNodeInd + 1, 0, dragObj)
  1818. }
  1819. }
  1820. setTreeData(data)
  1821. }
  1822. const findDescendantKeys = (node) => {
  1823. let res = [node.key];
  1824. const findChild = item => {
  1825. if (!item) return;
  1826. const { children } = item;
  1827. if (children && children.length) {
  1828. children.forEach(child => {
  1829. res.push(child.key);
  1830. findChild(child);
  1831. });
  1832. }
  1833. };
  1834. findChild(node);
  1835. return res;
  1836. }
  1837. const handleSelect = (key, bool, node) => {
  1838. setSelected(new Set([key]));
  1839. const descendantKeys = findDescendantKeys(node);
  1840. setSelectedThroughParent(new Set(descendantKeys));
  1841. }
  1842. const renderLabel = ({
  1843. className,
  1844. data,
  1845. onClick,
  1846. expandIcon
  1847. }) => {
  1848. const { label, icon, key } = data;
  1849. const isLeaf = !(data.children && data.children.length);
  1850. const style = {
  1851. backgroundColor: selected.has(key)
  1852. ? 'rgba(var(--semi-blue-0), 1)'
  1853. : selectedThroughParent.has(key)
  1854. ? 'rgba(var(--semi-blue-0), .5)' : 'transparent'
  1855. }
  1856. return (
  1857. <li
  1858. className={className}
  1859. role="treenode"
  1860. onClick={onClick}
  1861. style={style}
  1862. >
  1863. {isLeaf ? <span style={{ width: 24 }}></span> : expandIcon}
  1864. {icon ? icon : null}
  1865. <span>{label}</span>
  1866. </li>
  1867. )
  1868. }
  1869. const treeStyle = {
  1870. height: 420,
  1871. border: '1px solid var(--semi-color-border)'
  1872. }
  1873. return <Tree
  1874. treeData={treeData}
  1875. draggable
  1876. onDrop={onDrop}
  1877. renderFullLabel={renderLabel}
  1878. onSelect={handleSelect}
  1879. style={treeStyle}
  1880. defaultExpandAll
  1881. />;
  1882. }
  1883. );