1 | import React, {Component} from 'react';
|
2 | import {storiesOf} from '@storybook/html';
|
3 |
|
4 | import reactDecorator from '../../.storybook/react-decorator';
|
5 |
|
6 | import {Grid, Row, Col} from '../grid/grid';
|
7 | import Link from '../link/link';
|
8 | import Pager from '../pager/pager';
|
9 | import Button from '../button/button';
|
10 |
|
11 | import Table from './table';
|
12 | import MultiTable from './multitable';
|
13 | import Selection from './selection';
|
14 |
|
15 | storiesOf('Components|Table', module).
|
16 | addParameters({
|
17 | notes: 'Interactive table with selection and keyboard navigation support.'
|
18 | }).
|
19 | addDecorator(reactDecorator()).
|
20 | add('basic', () => {
|
21 | const mock = require('./table.examples.json');
|
22 |
|
23 | const PAGE_SIZE = 7;
|
24 | const TOTAL = mock.length;
|
25 |
|
26 | class TableDemo extends Component {
|
27 | state = {
|
28 | data: [],
|
29 | selection: new Selection(),
|
30 | caption: undefined,
|
31 | selectable: true,
|
32 | draggable: true,
|
33 | page: 1,
|
34 | pageSize: PAGE_SIZE,
|
35 | total: TOTAL,
|
36 | sortKey: 'country',
|
37 | sortOrder: true,
|
38 | loading: false
|
39 | }
|
40 |
|
41 | componentDidMount() {
|
42 | this.loadPage();
|
43 | }
|
44 |
|
45 | componentDidUpdate(prevProps, prevState) {
|
46 | const {page, sortKey, sortOrder} = this.state;
|
47 | if (
|
48 | page !== prevState.page ||
|
49 | sortKey !== prevState.sortKey ||
|
50 | sortOrder !== prevState.sortOrder
|
51 | ) {
|
52 | this.loadPage();
|
53 | }
|
54 | }
|
55 |
|
56 | columns = [
|
57 | {
|
58 | id: 'country',
|
59 | title: 'Country',
|
60 | sortable: true
|
61 | },
|
62 |
|
63 | {
|
64 | id: 'id',
|
65 | title: 'ID',
|
66 | rightAlign: true
|
67 | },
|
68 |
|
69 | {
|
70 | id: 'city',
|
71 | title: 'City',
|
72 | sortable: true
|
73 | },
|
74 |
|
75 | {
|
76 | id: 'url',
|
77 | title: 'URL',
|
78 | getValue: ({url}) => <Link href={url}>{url}</Link>
|
79 | }
|
80 | ]
|
81 |
|
82 | onSort = ({column: {id: sortKey}, order: sortOrder}) => {
|
83 | this.setState({sortKey, sortOrder});
|
84 | }
|
85 |
|
86 | onPageChange = page => {
|
87 | this.setState({page});
|
88 | }
|
89 |
|
90 | isItemSelectable(item) {
|
91 | return item.id !== 14;
|
92 | }
|
93 |
|
94 | loadPage = () => {
|
95 | const {page, pageSize, sortKey, sortOrder} = this.state;
|
96 |
|
97 | let data = [...mock];
|
98 | data.sort((a, b) => a[sortKey].localeCompare(b[sortKey]) * (sortOrder ? 1 : -1));
|
99 | data = data.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
|
100 |
|
101 | const selection = new Selection({data, isItemSelectable: this.isItemSelectable});
|
102 |
|
103 | this.setState({data, selection});
|
104 | }
|
105 |
|
106 | render() {
|
107 | const {
|
108 | data, caption, selectable, draggable, loading, page,
|
109 | pageSize, total, selection, sortKey, sortOrder
|
110 | } = this.state;
|
111 |
|
112 | return (
|
113 | <div>
|
114 | <Table
|
115 | data={data}
|
116 | columns={this.columns}
|
117 | selection={selection}
|
118 | onSelect={newSelection => this.setState({selection: newSelection})}
|
119 | onReorder={({data: newData}) => this.setState({data: newData})}
|
120 | loading={loading}
|
121 | onSort={this.onSort}
|
122 | sortKey={sortKey}
|
123 | sortOrder={sortOrder}
|
124 | caption={caption}
|
125 | selectable={selectable}
|
126 | isItemSelectable={this.isItemSelectable}
|
127 | draggable={draggable}
|
128 | autofocus
|
129 | />
|
130 |
|
131 | <Grid>
|
132 | <Row>
|
133 | <Col>
|
134 | <Pager
|
135 | total={total}
|
136 | pageSize={pageSize}
|
137 | currentPage={page}
|
138 | disablePageSizeSelector
|
139 | onPageChange={this.onPageChange}
|
140 | />
|
141 | </Col>
|
142 | </Row>
|
143 |
|
144 | <Row>
|
145 | <Col>
|
146 | Active items: {[...selection.getActive()].map(item => item.country).join(', ')}
|
147 | </Col>
|
148 | </Row>
|
149 |
|
150 | <Row>
|
151 | <Col>
|
152 | <Button
|
153 | onClick={() => this.setState({data: [...data]})}
|
154 | >Recreate data array</Button>
|
155 | {' '}
|
156 | <span id="button-non-selectable">
|
157 | {
|
158 | selectable
|
159 | ? (
|
160 | <Button
|
161 | onClick={() => this.setState({selectable: false})}
|
162 | >Non-selectable</Button>
|
163 | ) : (
|
164 | <Button
|
165 | onClick={() => this.setState({selectable: true})}
|
166 | >Selectable</Button>
|
167 | )
|
168 | }
|
169 | </span>
|
170 |
|
171 | {' '}
|
172 | {draggable
|
173 | ? (
|
174 | <Button
|
175 | onClick={() => this.setState({draggable: false})}
|
176 | >Non-draggable</Button>
|
177 | ) : (
|
178 | <Button
|
179 | onClick={() => this.setState({draggable: true})}
|
180 | >Draggable</Button>
|
181 | )
|
182 | }
|
183 | {' '}
|
184 |
|
185 | <span id="button-with-a-caption">
|
186 | {' '}
|
187 | {
|
188 | caption
|
189 | ? (
|
190 | <Button
|
191 | onClick={() => this.setState({caption: undefined})}
|
192 | >Without a caption</Button>
|
193 | ) : (
|
194 | <Button
|
195 | onClick={() => this.setState({caption: 'Countries'})}
|
196 | >With a caption</Button>
|
197 | )
|
198 | }
|
199 | {' '}
|
200 | </span>
|
201 | {' '}
|
202 |
|
203 | {
|
204 | loading
|
205 | ? <Button onClick={() => this.setState({loading: false})}>Not loading</Button>
|
206 | : <Button onClick={() => this.setState({loading: true})}>Loading</Button>
|
207 | }
|
208 | </Col>
|
209 | </Row>
|
210 |
|
211 | {page === 1 && data.length > 5 && (
|
212 | <Row>
|
213 | <Col>
|
214 | <span id="button-select-bulgaria">{
|
215 | selection.isSelected(data[3])
|
216 | ? (
|
217 | <Button
|
218 | onClick={() => this.setState({selection: selection.deselect(data[3])})}
|
219 | >Deselect {data[3].country}</Button>
|
220 | ) : (
|
221 | <Button
|
222 | onClick={() => this.setState({selection: selection.select(data[3])})}
|
223 | >Select {data[3].country}</Button>
|
224 | )
|
225 | }
|
226 | </span>
|
227 |
|
228 | <span id="button-select-finland">{' '}
|
229 | {selection.isSelected(data[5])
|
230 | ? (
|
231 | <Button
|
232 | onClick={() => this.setState({selection: selection.deselect(data[5])})}
|
233 | >Deselect {data[5].country}
|
234 | </Button>
|
235 | ) : (
|
236 | <Button
|
237 | onClick={() => this.setState({selection: selection.select(data[5])})}
|
238 | >Select {data[5].country}</Button>
|
239 | )
|
240 | }</span>
|
241 | </Col>
|
242 | </Row>
|
243 | )}
|
244 | </Grid>
|
245 | </div>
|
246 | );
|
247 | }
|
248 | }
|
249 |
|
250 | return <TableDemo/>;
|
251 | }).
|
252 | add('multi table', () => {
|
253 | const mock = require('./table.examples2.json');
|
254 |
|
255 | const data1 = mock.continents;
|
256 | const data2 = mock.countries;
|
257 |
|
258 | class TableDemo extends Component {
|
259 | state = {
|
260 | selection1: new Selection({data: data1}),
|
261 | selection2: new Selection({data: data2})
|
262 | };
|
263 |
|
264 | columns1 = [
|
265 | {
|
266 | id: 'continent',
|
267 | title: 'Continent'
|
268 | },
|
269 | {
|
270 | id: 'url',
|
271 | title: 'URL'
|
272 | }
|
273 | ]
|
274 |
|
275 | columns2 = [
|
276 | {
|
277 | id: 'country',
|
278 | title: 'Country'
|
279 | },
|
280 | {
|
281 | id: 'city',
|
282 | title: 'City'
|
283 | },
|
284 | {
|
285 | id: 'url',
|
286 | title: 'URL'
|
287 | }
|
288 | ]
|
289 |
|
290 | render() {
|
291 | return (
|
292 | <MultiTable>
|
293 | <Table
|
294 | data={data1}
|
295 | columns={this.columns1}
|
296 | caption="Continents"
|
297 | selection={this.state.selection1}
|
298 | onSelect={selection => this.setState({selection1: selection})}
|
299 | />
|
300 |
|
301 | <Table
|
302 | data={data2}
|
303 | columns={this.columns2}
|
304 | caption="Countries"
|
305 | autofocus
|
306 | selection={this.state.selection2}
|
307 | onSelect={selection => this.setState({selection2: selection})}
|
308 | />
|
309 | </MultiTable>
|
310 | );
|
311 | }
|
312 | }
|
313 |
|
314 | return <TableDemo/>;
|
315 | });
|