table.stories.tsx 11 KB

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