UNPKG

2.9 kBJavaScriptView Raw
1import React, { Fragment, useMemo } from 'react';
2import { array, func, object, oneOf, oneOfType, string } from 'prop-types';
3
4import iterable from '../validators/iterable';
5import Item from './item';
6import { useListState } from './useListState';
7
8/**
9 * The **Items** component is a container holding all the items
10 *
11 * @typedef Items
12 * @kind functional component
13 *
14 * @param {props} props
15 *
16 * @returns{React.Element} A React component container for all the items in list.
17 */
18const Items = props => {
19 const {
20 getItemKey,
21 initialSelection,
22 items,
23 onSelectionChange,
24 renderItem,
25 selectionModel
26 } = props;
27
28 const [state, api] = useListState({
29 getItemKey,
30 initialSelection,
31 onSelectionChange,
32 selectionModel
33 });
34 const { cursor, hasFocus, selectedKeys } = state;
35 const { removeFocus, setFocus, updateSelectedKeys } = api;
36
37 const children = useMemo(() => {
38 return Array.from(items, (item, index) => {
39 const key = getItemKey(item, index);
40
41 return (
42 <Item
43 hasFocus={hasFocus && cursor === key}
44 isSelected={selectedKeys.has(key)}
45 item={item}
46 itemIndex={index}
47 key={key}
48 onBlur={removeFocus}
49 render={renderItem}
50 setFocus={setFocus}
51 uniqueId={key}
52 updateSelectedKeys={updateSelectedKeys}
53 />
54 );
55 });
56 }, [
57 cursor,
58 getItemKey,
59 hasFocus,
60 items,
61 removeFocus,
62 renderItem,
63 selectedKeys,
64 setFocus,
65 updateSelectedKeys
66 ]);
67
68 return <Fragment>{children}</Fragment>;
69};
70
71/**
72 * props for {@link Items}
73 *
74 * @typedef props
75 *
76 * @property {func} getItemKey item key value getter
77 * @property {array | object} initialSelection A single or list of objects that should start off selected
78 * @property {iterable} items An iterable that yields `[key, item]` pairs such as an ES2015 Map
79 * @property {func} onSelectionChange A callback that fires when the selection state changes
80 * @property {func | string} renderItem A render prop for the list item elements. A tagname string, such as `"div"`, is also valid
81 * @property {checkbox | radio} selectionModel A string corresponding to a selection model
82 */
83Items.propTypes = {
84 getItemKey: func.isRequired,
85 initialSelection: oneOfType([array, object]),
86 items: iterable.isRequired,
87 onSelectionChange: func,
88 renderItem: oneOfType([func, string]),
89 selectionModel: oneOf(['checkbox', 'radio'])
90};
91
92/**
93 * default props for {@link Items}
94 *
95 * @typedef @defaultProps
96 */
97Items.defaultProps = {
98 getItemKey: ({ id }) => id,
99 selectionModel: 'radio'
100};
101
102export default Items;