UNPKG

7.83 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4exports.useHandleSelect = useHandleSelect;
5exports.default = exports.useScrollFocusedIntoView = void 0;
6
7var _classnames = _interopRequireDefault(require("classnames"));
8
9var _propTypes = _interopRequireDefault(require("prop-types"));
10
11var _react = _interopRequireWildcard(require("react"));
12
13var _ListOption = _interopRequireDefault(require("./ListOption"));
14
15var _ListOptionGroup = _interopRequireDefault(require("./ListOptionGroup"));
16
17var _messages = require("./messages");
18
19var CustomPropTypes = _interopRequireWildcard(require("./PropTypes"));
20
21var _ = require("./_");
22
23var _WidgetHelpers = require("./WidgetHelpers");
24
25var _useMutationObserver = _interopRequireDefault(require("@restart/hooks/useMutationObserver"));
26
27var _useCallbackRef = _interopRequireDefault(require("@restart/hooks/useCallbackRef"));
28
29var _useMergedRefs = _interopRequireDefault(require("@restart/hooks/useMergedRefs"));
30
31const _excluded = ["multiple", "data", "value", "onChange", "accessors", "className", "messages", "disabled", "renderItem", "renderGroup", "searchTerm", "groupBy", "elementRef", "optionComponent", "renderList"];
32
33function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
34
35function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
36
37function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
38
39function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
40
41const whitelist = ['style', 'className', 'role', 'id', 'autocomplete', 'size', 'tabIndex', 'maxLength', 'name'];
42const whitelistRegex = [/^aria-/, /^data-/, /^on[A-Z]\w+/];
43
44function pickElementProps(props) {
45 const result = {};
46 Object.keys(props).forEach(key => {
47 if (whitelist.indexOf(key) !== -1 || whitelistRegex.some(r => !!key.match(r))) result[key] = props[key];
48 });
49 return result;
50}
51
52const propTypes = {
53 data: _propTypes.default.array,
54 dataKey: CustomPropTypes.accessor,
55 textField: CustomPropTypes.accessor,
56 onSelect: _propTypes.default.func,
57 onMove: _propTypes.default.func,
58 onHoverOption: _propTypes.default.func,
59 optionComponent: _propTypes.default.elementType,
60 renderItem: _propTypes.default.func,
61 renderGroup: _propTypes.default.func,
62 focusedItem: _propTypes.default.any,
63 selectedItem: _propTypes.default.any,
64 searchTerm: _propTypes.default.string,
65 disabled: CustomPropTypes.disabled.acceptsArray,
66 messages: _propTypes.default.shape({
67 emptyList: _propTypes.default.func.isRequired
68 })
69};
70
71const useScrollFocusedIntoView = (element, observeChanges = false) => {
72 const scrollIntoView = (0, _react.useCallback)(() => {
73 if (!element) return;
74 let selectedItem = element.querySelector('[data-rw-focused]');
75
76 if (selectedItem && selectedItem.scrollIntoView) {
77 selectedItem.scrollIntoView({
78 block: 'nearest',
79 inline: 'nearest'
80 });
81 }
82 }, [element]);
83 (0, _useMutationObserver.default)(observeChanges ? element : null, {
84 subtree: true,
85 attributes: true,
86 attributeFilter: ['data-rw-focused']
87 }, scrollIntoView);
88 return scrollIntoView;
89};
90
91exports.useScrollFocusedIntoView = useScrollFocusedIntoView;
92
93function useHandleSelect(multiple, dataItems, onChange) {
94 return (dataItem, event) => {
95 if (multiple === false) {
96 onChange(dataItem, {
97 dataItem,
98 lastValue: dataItems[0],
99 originalEvent: event
100 });
101 return;
102 }
103
104 const checked = dataItems.includes(dataItem);
105 onChange(checked ? dataItems.filter(d => d !== dataItem) : [...dataItems, dataItem], {
106 dataItem,
107 lastValue: dataItems,
108 action: checked ? 'remove' : 'insert',
109 originalEvent: event
110 });
111 };
112}
113
114const List = /*#__PURE__*/_react.default.forwardRef(function List(_ref, outerRef) {
115 var _elementProps$role;
116
117 let {
118 multiple = false,
119 data = [],
120 value,
121 onChange,
122 accessors,
123 className,
124 messages,
125 disabled,
126 renderItem,
127 renderGroup,
128 searchTerm,
129 groupBy,
130 elementRef,
131 optionComponent: Option = _ListOption.default,
132 renderList
133 } = _ref,
134 props = _objectWithoutPropertiesLoose(_ref, _excluded);
135
136 const id = (0, _WidgetHelpers.useInstanceId)();
137 const dataItems = (0, _.makeArray)(value, multiple);
138 const groupedData = (0, _react.useMemo)(() => groupBy ? (0, _.groupBySortedKeys)(groupBy, data) : undefined, [data, groupBy]);
139 const [element, ref] = (0, _useCallbackRef.default)();
140 const disabledItems = (0, _.toItemArray)(disabled);
141 const {
142 emptyList
143 } = (0, _messages.useMessagesWithDefaults)(messages);
144 const divRef = (0, _useMergedRefs.default)(ref, elementRef);
145 const handleSelect = useHandleSelect(multiple, dataItems, onChange);
146 const scrollIntoView = useScrollFocusedIntoView(element, true);
147 let elementProps = pickElementProps(props);
148 (0, _react.useImperativeHandle)(outerRef, () => ({
149 scrollIntoView
150 }), [scrollIntoView]);
151
152 function renderOption(item, idx) {
153 const textValue = accessors.text(item);
154 const itemIsDisabled = disabledItems.includes(item);
155 const itemIsSelected = dataItems.includes(item);
156 return /*#__PURE__*/_react.default.createElement(Option, {
157 dataItem: item,
158 key: `item_${idx}`,
159 searchTerm: searchTerm,
160 onSelect: handleSelect,
161 disabled: itemIsDisabled,
162 selected: itemIsSelected
163 }, renderItem ? renderItem({
164 item,
165 searchTerm,
166 index: idx,
167 text: textValue,
168 // TODO: probably remove
169 value: accessors.value(item),
170 disabled: itemIsDisabled
171 }) : textValue);
172 }
173
174 const items = groupedData ? groupedData.map(([group, items], idx) => /*#__PURE__*/_react.default.createElement("div", {
175 role: "group",
176 key: `group_${idx}`
177 }, /*#__PURE__*/_react.default.createElement(_ListOptionGroup.default, null, renderGroup ? renderGroup({
178 group
179 }) : group), items.map(renderOption))) : data.map(renderOption);
180 const rootProps = Object.assign({
181 id,
182 tabIndex: 0,
183 ref: divRef
184 }, elementProps, {
185 'aria-multiselectable': !!multiple,
186 className: (0, _classnames.default)(className, 'rw-list'),
187 role: (_elementProps$role = elementProps.role) != null ? _elementProps$role : 'listbox',
188 children: _react.default.Children.count(items) ? items : /*#__PURE__*/_react.default.createElement("div", {
189 className: "rw-list-empty"
190 }, emptyList())
191 });
192 return renderList ? renderList(rootProps) : /*#__PURE__*/_react.default.createElement("div", rootProps);
193});
194
195List.displayName = 'List';
196List.propTypes = propTypes;
197var _default = List;
198exports.default = _default;
\No newline at end of file