1 | import React, { useMemo, useCallback } from 'react';
|
2 | import {
|
3 | array,
|
4 | func,
|
5 | object,
|
6 | oneOf,
|
7 | oneOfType,
|
8 | shape,
|
9 | string
|
10 | } from 'prop-types';
|
11 |
|
12 | import fromRenderProp from '../util/fromRenderProp';
|
13 | import iterable from '../validators/iterable';
|
14 | import Items from './items';
|
15 |
|
16 | /**
|
17 | * The **List** component maps a collection of data objects into an array of elements.
|
18 | * It also manages the selection and focus of those elements.
|
19 | *
|
20 | * @typedef List
|
21 | * @kind functional component
|
22 | *
|
23 | * @param {props} props React Component props
|
24 | *
|
25 | * @returns{React.Element} A React component that displays list data.
|
26 | */
|
27 | const List = props => {
|
28 | const {
|
29 | classes,
|
30 | getItemKey,
|
31 | initialSelection,
|
32 | items,
|
33 | render,
|
34 | renderItem,
|
35 | onSelectionChange,
|
36 | selectionModel,
|
37 | ...restProps
|
38 | } = props;
|
39 |
|
40 | const customProps = {
|
41 | classes,
|
42 | getItemKey,
|
43 | items,
|
44 | onSelectionChange,
|
45 | selectionModel
|
46 | };
|
47 |
|
48 | const handleSelectionChange = useCallback(
|
49 | selection => {
|
50 | if (onSelectionChange) {
|
51 | onSelectionChange(selection);
|
52 | }
|
53 | },
|
54 | [onSelectionChange]
|
55 | );
|
56 |
|
57 | const Root = useMemo(
|
58 | () => fromRenderProp(render, Object.keys(customProps)),
|
59 | [render, customProps]
|
60 | );
|
61 |
|
62 | return (
|
63 | <Root className={classes.root} {...customProps} {...restProps}>
|
64 | <Items
|
65 | getItemKey={getItemKey}
|
66 | initialSelection={initialSelection}
|
67 | items={items}
|
68 | renderItem={renderItem}
|
69 | selectionModel={selectionModel}
|
70 | onSelectionChange={handleSelectionChange}
|
71 | />
|
72 | </Root>
|
73 | );
|
74 | };
|
75 |
|
76 | /**
|
77 | * props for {@link List}
|
78 | *
|
79 | * @typedef props
|
80 | *
|
81 | * @property {Object} classes css classes prop for List
|
82 | * @property {string} classes.root css classes for List root container
|
83 | * @property {func} getItemKey item key value getter
|
84 | * @property {array | object} initialSelection A single or list of objects that should start off selected
|
85 | * @property {iterable} items An iterable that yields `[key, item]` pairs such as an ES2015 Map
|
86 | * @property {func | string} render A render prop for the list element. A tagname string, such as `"div"`, is also valid.
|
87 | * @property {func | string} renderItem A render prop for the list item elements. A tagname string, such as `"div"`, is also valid
|
88 | * @property {func} onSelectionChange A callback that fires when the selection state changes
|
89 | * @property {checkbox | radio} selectionModel A string corresponding to a selection model
|
90 | */
|
91 | List.propTypes = {
|
92 | classes: shape({
|
93 | root: string
|
94 | }),
|
95 | getItemKey: func.isRequired,
|
96 | initialSelection: oneOfType([array, object]),
|
97 | items: iterable.isRequired,
|
98 | render: oneOfType([func, string]).isRequired,
|
99 | renderItem: oneOfType([func, string]),
|
100 | onSelectionChange: func,
|
101 | selectionModel: oneOf(['checkbox', 'radio'])
|
102 | };
|
103 |
|
104 | /**
|
105 | * default props for {@link List}
|
106 | *
|
107 | * @typedef defaultProps
|
108 | */
|
109 | List.defaultProps = {
|
110 | classes: {},
|
111 | getItemKey: ({ id }) => id,
|
112 | items: [],
|
113 | render: 'div',
|
114 | renderItem: 'div',
|
115 | selectionModel: 'radio'
|
116 | };
|
117 |
|
118 | export default List;
|