table.stories.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. import React, { ReactNode, useMemo } from 'react';
  2. import { storiesOf } from '@storybook/react';
  3. import { IllustrationConstruction } from '@douyinfe/semi-illustrations';
  4. import { Fixed, ColumnProps, OnRow, OnHeaderRow, OnGroupedRow, RowKey } from '../interface';
  5. import JSXColumnsNest from './JSXColumnsNest';
  6. import DefaultSortOrder from './DefaultSortOrder';
  7. import BetterScrollbar from './BetterScrollbar';
  8. import Empty from '../../empty';
  9. import Table from '../index';
  10. import FixAllColumnsWithoutWidth from './FixAllColumnsWithoutWidth';
  11. import WarnColumnWithoutDataIndex from './WarnColumnWithoutDataIndex';
  12. const stories = storiesOf('Table', module);
  13. interface MyData {
  14. title?: string;
  15. dataIndex?: string;
  16. width?: number;
  17. render?: Function;
  18. key?: string;
  19. name?: string;
  20. age?: number;
  21. address?: string;
  22. }
  23. const columns: ColumnProps<MyData>[] = [
  24. {
  25. title: 'Name',
  26. dataIndex: 'name',
  27. width: 200,
  28. render: (text: ReactNode) => <a>{text}</a>,
  29. onCell: (record: MyData, index) => {
  30. console.log(record.title, index);
  31. return {};
  32. },
  33. },
  34. {
  35. title: 'Age',
  36. width: 200,
  37. dataIndex: 'age',
  38. },
  39. {
  40. title: 'Address',
  41. dataIndex: 'address',
  42. },
  43. ];
  44. const data: MyData[] = [
  45. {
  46. key: '1',
  47. name: 'John Brown',
  48. age: 32,
  49. address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
  50. },
  51. {
  52. key: '2',
  53. name: 'Jim Green',
  54. age: 42,
  55. address: 'London No. 1 Lake Park',
  56. },
  57. {
  58. key: '3',
  59. name: 'Joe Black',
  60. age: 32,
  61. address: 'Sidney No. 1 Lake Park',
  62. },
  63. {
  64. key: '4',
  65. name: 'Disabled User',
  66. age: 99,
  67. address: 'Sidney No. 1 Lake Park',
  68. },
  69. ];
  70. stories.add('basic table', () => <Table bordered resizable columns={columns} dataSource={data} />);
  71. stories.add(`jsx table`, () => (
  72. <Table dataSource={data} pagination={false}>
  73. <Table.Column
  74. title="Name"
  75. dataIndex="name"
  76. key="name"
  77. render={(text: string) => <a>{text}</a>}
  78. filters={[
  79. {
  80. text: 'London',
  81. value: 'London',
  82. },
  83. {
  84. text: 'New York',
  85. value: 'New York',
  86. },
  87. ]}
  88. />
  89. <Table.Column title="Age" dataIndex="age" key="age" />
  90. <Table.Column title="Address" dataIndex="address" key="address" />
  91. </Table>
  92. ));
  93. stories.add(`jsx nested cloumn`, () => <JSXColumnsNest />);
  94. stories.add(`header merge table`, () => {
  95. const data = useMemo(() => {
  96. const data = [];
  97. for (let i = 0; i < 100; i++) {
  98. let age = (i * 1000) % 149 ;
  99. let name = `Edward King ${i}`;
  100. data.push({
  101. key: '' + i,
  102. company: {
  103. name: 'ByteDance',
  104. address: 'No. 48, Zhichun Road',
  105. },
  106. name,
  107. age,
  108. address: `No ${i + 1}, Zhongguancun Street`,
  109. description: `My name is ${name}, I am ${age} years old, living in No ${i + 1}, Zhongguancun Street`,
  110. });
  111. }
  112. return data;
  113. }, []);
  114. const columns = useMemo(
  115. () => [
  116. {
  117. title: 'Base Information',
  118. fixed: 'left' as Fixed,
  119. children: [
  120. {
  121. title: 'Name',
  122. dataIndex: 'name',
  123. fixed: 'left' as Fixed,
  124. width: 200,
  125. filters: [
  126. {
  127. text: 'Code 45',
  128. value: '45',
  129. },
  130. {
  131. text: 'King 4',
  132. value: 'King 4',
  133. },
  134. ],
  135. onFilter: (value: any, record: any) => record.name.includes(value),
  136. },
  137. {
  138. title: 'Age',
  139. dataIndex: 'age',
  140. fixed: 'left' as Fixed,
  141. width: 100,
  142. sorter: (a: any, b: any) => (a.age - b.age > 0 ? 1 : -1),
  143. },
  144. ],
  145. },
  146. {
  147. title: 'Company Information',
  148. children: [
  149. {
  150. title: 'Company Name',
  151. dataIndex: 'company.name',
  152. },
  153. {
  154. title: 'Company Address',
  155. dataIndex: 'company.address',
  156. },
  157. ],
  158. },
  159. {
  160. title: 'Address',
  161. width: 250,
  162. dataIndex: 'address',
  163. fixed: 'right' as Fixed,
  164. },
  165. ],
  166. []
  167. );
  168. return (
  169. <Table
  170. rowSelection={{ fixed: true, getCheckboxProps: (record) => ({ disabled: record.name === 'semi' }) }}
  171. expandedRowRender={(record: any) => <article>{record.description}</article>}
  172. dataSource={data}
  173. scroll={{ x: '120%', y: 400 }}
  174. onChange={(...args: any) => console.log(args)}
  175. columns={columns}
  176. />
  177. );
  178. });
  179. stories.add('table generic', () => (
  180. <Table<MyData>
  181. columns={columns}
  182. dataSource={data}
  183. rowExpandable={record => {
  184. return record.age > 30 ? true : false;
  185. }}
  186. onHeaderRow={() => ({ onClick: () => {}})}
  187. />
  188. ));
  189. stories.add('table column generic', () => <Table columns={columns} dataSource={data} />);
  190. stories.add('defaultSortOrder', () => <DefaultSortOrder />);
  191. stories.add('expandRowByClick', () => (
  192. <Table<MyData>
  193. expandRowByClick
  194. onExpand={(...args) => {
  195. console.log('click row', ...args);
  196. }}
  197. onExpandedRowsChange={rows => {
  198. console.log('rows change', rows);
  199. }}
  200. expandedRowRender={() => <div>Semi Design</div>}
  201. columns={columns}
  202. dataSource={data}
  203. />
  204. ));
  205. stories.add('onCell/onHeaderCell', () => {
  206. const columns: ColumnProps<MyData>[] = [
  207. {
  208. title: 'Name',
  209. dataIndex: 'name',
  210. width: 200,
  211. render: (text: ReactNode) => <a>{text}</a>,
  212. onCell: (record: MyData, index: number) => {
  213. console.log(`current record name is ${record.title}; row key is ${index}`);
  214. return index % 2 === 0 ? ({
  215. style: { background: 'red' },
  216. onClick: () => console.log(`click ${index}`),
  217. onMouseEnter: () => console.log(`mouse enter ${index}`),
  218. align: 'right',
  219. }) : ({});
  220. },
  221. },
  222. {
  223. title: 'Age',
  224. width: 200,
  225. dataIndex: 'age',
  226. onHeaderCell: (record: MyData, index) => {
  227. console.log(`current record name is ${record.title}; row key is ${index}`);
  228. return ({
  229. style: { background: 'blue' },
  230. onClick: () => console.log(`click ${index}`),
  231. onMouseLeave: () => console.log(`mouse leave ${index}`),
  232. className: `test-header-cell-${index}`,
  233. });
  234. },
  235. },
  236. {
  237. title: 'Address',
  238. dataIndex: 'address',
  239. },
  240. ];
  241. return (
  242. <Table columns={columns} dataSource={data} />
  243. )
  244. });
  245. stories.add('onRow/onHeaderRow', () => {
  246. const onRow: OnRow<any> = (record, index) => {
  247. if (index % 2 === 0) {
  248. return ({
  249. style: {
  250. background: 'var(--semi-color-fill-2)',
  251. },
  252. onClick: () => {
  253. console.log(`click row ${index}`);
  254. }
  255. });
  256. }
  257. };
  258. const onHeaderRow: OnHeaderRow<any> = (record, index) => {
  259. return ({
  260. onClick: () => {
  261. console.log(`click header row ${index}`);
  262. },
  263. className: 'test-header-row',
  264. });
  265. };
  266. const columns: ColumnProps<MyData>[] = [
  267. {
  268. title: 'Name',
  269. dataIndex: 'name',
  270. width: 200,
  271. render: (text: ReactNode) => <a>{text}</a>,
  272. },
  273. {
  274. title: 'Age',
  275. width: 200,
  276. dataIndex: 'age',
  277. },
  278. {
  279. title: 'Address',
  280. dataIndex: 'address',
  281. },
  282. ];
  283. return (
  284. <Table columns={columns} dataSource={data} onRow={onRow} onHeaderRow={onHeaderRow} />
  285. )
  286. });
  287. stories.add('onGroupedRow', () => {
  288. interface DataItem {
  289. city: string;
  290. job: string;
  291. department: string;
  292. }
  293. const rowKey: RowKey<DataItem> = record => `${record.city && record.city.toLowerCase()}-${record.job && record.job.toLowerCase()}`;
  294. const data: DataItem[] = [
  295. { city: 'Beijing', job: 'FE', department: 'IES' },
  296. { city: 'Beijing', job: 'BE', department: 'IES' },
  297. { city: 'Shanghai', job: 'Android', department: 'IES' },
  298. { city: 'Tokyo', job: 'Android', department: 'IES' },
  299. { city: 'Shanghai', job: 'IOS', department: 'EE' },
  300. { city: 'LA', job: 'SE', department: 'EE' },
  301. { city: 'Beijing', job: 'Android', department: 'EE' },
  302. { city: 'Tokyo', job: 'IOS', department: 'EE' },
  303. { city: 'Tokyo', job: 'SE', department: 'DATA' },
  304. { city: 'Shanghai', job: 'BE', department: 'DATA' },
  305. { city: 'LA', job: 'Android', department: 'DATA' },
  306. { city: 'LA', job: 'IOS', department: 'DATA' },
  307. ];
  308. const columns: ColumnProps<DataItem>[] = [
  309. { dataIndex: 'city', title: 'City', width: 400, sorter: (a, b) => (a.city > b.city ? 1 : -1) },
  310. {
  311. dataIndex: 'job',
  312. title: 'Job',
  313. width: 200,
  314. filters: [
  315. { text: 'IOS', value: 'IOS' },
  316. { text: 'Android', value: 'Android' },
  317. ],
  318. onFilter: (value, record) => record.job && record.job.indexOf(value) === 0,
  319. },
  320. { dataIndex: 'department', title: 'Department' },
  321. ];
  322. return (
  323. <div style={{ padding: '20px 0px' }}>
  324. <Table<DataItem>
  325. dataSource={data}
  326. rowKey={rowKey}
  327. groupBy={'city'}
  328. columns={columns}
  329. renderGroupSection={groupKey => <strong>Jobs in {groupKey}:</strong>}
  330. onGroupedRow={(group, index) => {
  331. return {
  332. onClick: e => { console.log(`Grouped row clicked: `, group, index) },
  333. style: { color: 'var(--semi-color-primary)' },
  334. };
  335. }}
  336. clickGroupedRowToExpand
  337. scroll={{ y: 480 }}
  338. />
  339. </div>
  340. );
  341. });
  342. stories.add('empty', () => {
  343. const empty = 'this is a empty placeholder';
  344. const test = (
  345. <div>
  346. <Empty
  347. image={IllustrationConstruction}
  348. title={'功能建设中'}
  349. description="当前功能暂未开放,敬请期待。"
  350. />
  351. </div>
  352. );
  353. return (
  354. <Table columns={columns} dataSource={[]} empty={test} />
  355. );
  356. });
  357. stories.add('better scrollbar', () => <BetterScrollbar />);
  358. stories.add('fix all columns without width', () => <FixAllColumnsWithoutWidth />);
  359. stories.add('warn if column without dataIndex', () => <WarnColumnWithoutDataIndex />);