1 | "use strict";
|
2 |
|
3 | exports.__esModule = true;
|
4 | exports.default = void 0;
|
5 |
|
6 | var _classnames = _interopRequireDefault(require("classnames"));
|
7 |
|
8 | var PropTypes = _interopRequireWildcard(require("prop-types"));
|
9 |
|
10 | var React = _interopRequireWildcard(require("react"));
|
11 |
|
12 | var _uncontrollable = require("uncontrollable");
|
13 |
|
14 | var _Icon = require("./Icon");
|
15 |
|
16 | var _Input = _interopRequireDefault(require("./Input"));
|
17 |
|
18 | var _List = _interopRequireDefault(require("./List"));
|
19 |
|
20 | var _FocusListContext = require("./FocusListContext");
|
21 |
|
22 | var _Popup = _interopRequireDefault(require("./Popup"));
|
23 |
|
24 | var _InputAddon = _interopRequireDefault(require("./InputAddon"));
|
25 |
|
26 | var _Widget = _interopRequireDefault(require("./Widget"));
|
27 |
|
28 | var _WidgetPicker = _interopRequireDefault(require("./WidgetPicker"));
|
29 |
|
30 | var _messages = require("./messages");
|
31 |
|
32 | var _A11y = require("./A11y");
|
33 |
|
34 | var CustomPropTypes = _interopRequireWildcard(require("./PropTypes"));
|
35 |
|
36 | var _Accessors = require("./Accessors");
|
37 |
|
38 | var _Filter = require("./Filter");
|
39 |
|
40 | var _useDropdownToggle = _interopRequireDefault(require("./useDropdownToggle"));
|
41 |
|
42 | var _useFocusManager = _interopRequireDefault(require("./useFocusManager"));
|
43 |
|
44 | var _WidgetHelpers = require("./WidgetHelpers");
|
45 |
|
46 | const _excluded = ["id", "className", "containerClassName", "placeholder", "autoFocus", "textField", "dataKey", "autoSelectMatches", "focusFirstItem", "value", "defaultValue", "onChange", "open", "defaultOpen", "onToggle", "filter", "busy", "disabled", "readOnly", "selectIcon", "hideCaret", "hideEmptyPopup", "busySpinner", "dropUp", "tabIndex", "popupTransition", "name", "onSelect", "onKeyDown", "onBlur", "onFocus", "inputProps", "listProps", "groupBy", "renderListItem", "renderListGroup", "optionComponent", "listComponent", "popupComponent", "data", "messages"];
|
47 |
|
48 | function _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); }
|
49 |
|
50 | function _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; }
|
51 |
|
52 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
53 |
|
54 | function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
55 |
|
56 | function _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; }
|
57 |
|
58 | function indexOf(data, searchTerm, text) {
|
59 | if (!searchTerm.trim()) return -1;
|
60 |
|
61 | for (let idx = 0; idx < data.length; idx++) if (text(data[idx]).toLowerCase() === searchTerm) return idx;
|
62 |
|
63 | return -1;
|
64 | }
|
65 |
|
66 | let propTypes = {
|
67 | value: PropTypes.any,
|
68 | onChange: PropTypes.func,
|
69 | open: PropTypes.bool,
|
70 | onToggle: PropTypes.func,
|
71 | renderListItem: PropTypes.func,
|
72 | listComponent: PropTypes.elementType,
|
73 | renderListGroup: PropTypes.func,
|
74 | groupBy: CustomPropTypes.accessor,
|
75 | data: PropTypes.array,
|
76 | dataKey: CustomPropTypes.accessor,
|
77 | textField: CustomPropTypes.accessor,
|
78 | name: PropTypes.string,
|
79 |
|
80 |
|
81 | hideEmptyPopup: PropTypes.bool,
|
82 |
|
83 |
|
84 | hideCaret: PropTypes.bool,
|
85 |
|
86 | |
87 |
|
88 |
|
89 |
|
90 | onSelect: PropTypes.func,
|
91 | autoFocus: PropTypes.bool,
|
92 | disabled: CustomPropTypes.disabled.acceptsArray,
|
93 | readOnly: CustomPropTypes.disabled,
|
94 | busy: PropTypes.bool,
|
95 |
|
96 |
|
97 | selectIcon: PropTypes.node,
|
98 |
|
99 |
|
100 | busySpinner: PropTypes.node,
|
101 | dropUp: PropTypes.bool,
|
102 | popupTransition: PropTypes.elementType,
|
103 | placeholder: PropTypes.string,
|
104 |
|
105 |
|
106 | containerClassName: PropTypes.string,
|
107 | inputProps: PropTypes.object,
|
108 | listProps: PropTypes.object,
|
109 | messages: PropTypes.shape({
|
110 | openCombobox: CustomPropTypes.message,
|
111 | emptyList: CustomPropTypes.message,
|
112 | emptyFilter: CustomPropTypes.message
|
113 | })
|
114 | };
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 | const ComboboxImpl = React.forwardRef(function Combobox(_ref, outerRef) {
|
134 | let {
|
135 | id,
|
136 | className,
|
137 | containerClassName,
|
138 | placeholder,
|
139 | autoFocus,
|
140 | textField,
|
141 | dataKey,
|
142 | autoSelectMatches,
|
143 | focusFirstItem = false,
|
144 | value,
|
145 | defaultValue = '',
|
146 | onChange,
|
147 | open,
|
148 | defaultOpen = false,
|
149 | onToggle,
|
150 | filter = true,
|
151 | busy,
|
152 | disabled,
|
153 | readOnly,
|
154 | selectIcon = _Icon.caretDown,
|
155 | hideCaret,
|
156 | hideEmptyPopup,
|
157 | busySpinner,
|
158 | dropUp,
|
159 | tabIndex,
|
160 | popupTransition,
|
161 | name,
|
162 | onSelect,
|
163 | onKeyDown,
|
164 | onBlur,
|
165 | onFocus,
|
166 | inputProps,
|
167 | listProps,
|
168 | groupBy,
|
169 | renderListItem,
|
170 | renderListGroup,
|
171 | optionComponent,
|
172 | listComponent: ListComponent = _List.default,
|
173 | popupComponent: Popup = _Popup.default,
|
174 | data: rawData = [],
|
175 | messages: userMessages
|
176 | } = _ref,
|
177 | elementProps = _objectWithoutPropertiesLoose(_ref, _excluded);
|
178 |
|
179 | let [currentValue, handleChange] = (0, _uncontrollable.useUncontrolledProp)(value, defaultValue, onChange);
|
180 | const [currentOpen, handleOpen] = (0, _uncontrollable.useUncontrolledProp)(open, defaultOpen, onToggle);
|
181 | const ref = (0, React.useRef)(null);
|
182 | const inputRef = (0, React.useRef)(null);
|
183 | const listRef = (0, React.useRef)(null);
|
184 | const [suggestion, setSuggestion] = (0, React.useState)(null);
|
185 | const shouldFilter = (0, React.useRef)(false);
|
186 | const inputId = (0, _WidgetHelpers.useInstanceId)(id, '_input');
|
187 | const listId = (0, _WidgetHelpers.useInstanceId)(id, '_listbox');
|
188 | const activeId = (0, _WidgetHelpers.useInstanceId)(id, '_listbox_active_option');
|
189 | const accessors = (0, _Accessors.useAccessors)(textField, dataKey);
|
190 | const messages = (0, _messages.useMessagesWithDefaults)(userMessages);
|
191 | const toggle = (0, _useDropdownToggle.default)(currentOpen, handleOpen);
|
192 | const isDisabled = disabled === true;
|
193 | const isReadOnly = !!readOnly;
|
194 | const data = (0, _Filter.useFilteredData)(rawData, filter, shouldFilter.current ? accessors.text(currentValue) : void 0, accessors.text);
|
195 | const selectedItem = (0, React.useMemo)(() => data[accessors.indexOf(data, currentValue)], [data, currentValue, accessors]);
|
196 | const list = (0, _FocusListContext.useFocusList)({
|
197 | activeId,
|
198 | scope: ref,
|
199 | focusFirstItem,
|
200 | anchorItem: currentOpen ? selectedItem : undefined
|
201 | });
|
202 | const [focusEvents, focused] = (0, _useFocusManager.default)(ref, {
|
203 | disabled: isDisabled,
|
204 | onBlur,
|
205 | onFocus
|
206 | }, {
|
207 | didHandle(focused) {
|
208 | if (!focused) {
|
209 | shouldFilter.current = false;
|
210 | toggle.close();
|
211 | setSuggestion(null);
|
212 | list.focus(undefined);
|
213 | } else {
|
214 | focus({
|
215 | preventScroll: true
|
216 | });
|
217 | }
|
218 | }
|
219 |
|
220 | });
|
221 | (0, _A11y.useActiveDescendant)(ref, activeId, currentOpen, [list.getFocused()]);
|
222 | |
223 |
|
224 |
|
225 |
|
226 | const handleClick = e => {
|
227 | if (readOnly || isDisabled) return;
|
228 |
|
229 | e.preventDefault();
|
230 | focus();
|
231 | toggle();
|
232 | };
|
233 |
|
234 | const handleSelect = (data, originalEvent) => {
|
235 | toggle.close();
|
236 | shouldFilter.current = false;
|
237 | setSuggestion(null);
|
238 | (0, _WidgetHelpers.notify)(onSelect, [data, {
|
239 | originalEvent
|
240 | }]);
|
241 | change(data, originalEvent, true);
|
242 | focus({
|
243 | preventScroll: true
|
244 | });
|
245 | };
|
246 |
|
247 | const handleInputKeyDown = ({
|
248 | key
|
249 | }) => {
|
250 | if (key === 'Backspace' || key === 'Delete') {
|
251 | list.focus(null);
|
252 | }
|
253 | };
|
254 |
|
255 | const handleInputChange = event => {
|
256 | let idx = autoSelectMatches ? indexOf(rawData, event.target.value.toLowerCase(), accessors.text) : -1;
|
257 | shouldFilter.current = true;
|
258 | setSuggestion(null);
|
259 | const nextValue = idx === -1 ? event.target.value : rawData[idx];
|
260 | change(nextValue, event);
|
261 | if (!nextValue) toggle.close();else toggle.open();
|
262 | };
|
263 |
|
264 | const handleKeyDown = e => {
|
265 | if (readOnly) return;
|
266 | let {
|
267 | key,
|
268 | altKey,
|
269 | shiftKey
|
270 | } = e;
|
271 | (0, _WidgetHelpers.notify)(onKeyDown, [e]);
|
272 | if (e.defaultPrevented) return;
|
273 |
|
274 | const select = item => item != null && handleSelect(item, e);
|
275 |
|
276 | const setFocused = el => {
|
277 | if (!el) return;
|
278 | setSuggestion(list.toDataItem(el));
|
279 | list.focus(el);
|
280 | };
|
281 |
|
282 | if (key === 'End' && currentOpen && !shiftKey) {
|
283 | e.preventDefault();
|
284 | setFocused(list.last());
|
285 | } else if (key === 'Home' && currentOpen && !shiftKey) {
|
286 | e.preventDefault();
|
287 | setFocused(list.first());
|
288 | } else if (key === 'Escape' && currentOpen) {
|
289 | e.preventDefault();
|
290 | setSuggestion(null);
|
291 | toggle.close();
|
292 | } else if (key === 'Enter' && currentOpen) {
|
293 | e.preventDefault();
|
294 | select(list.getFocused());
|
295 | } else if (key === 'ArrowDown') {
|
296 | e.preventDefault();
|
297 |
|
298 | if (currentOpen) {
|
299 | setFocused(list.next());
|
300 | } else {
|
301 | return toggle.open();
|
302 | }
|
303 | } else if (key === 'ArrowUp') {
|
304 | e.preventDefault();
|
305 | if (altKey) return toggle.close();
|
306 |
|
307 | if (currentOpen) {
|
308 | setFocused(list.prev());
|
309 | }
|
310 | }
|
311 | };
|
312 | |
313 |
|
314 |
|
315 |
|
316 |
|
317 | function focus(opts) {
|
318 | if (inputRef.current) inputRef.current.focus(opts);
|
319 | }
|
320 |
|
321 | function change(nextValue, originalEvent, selected = false) {
|
322 | handleChange(nextValue, {
|
323 | lastValue: currentValue,
|
324 | originalEvent,
|
325 | source: selected ? 'listbox' : 'input'
|
326 | });
|
327 | }
|
328 | |
329 |
|
330 |
|
331 |
|
332 |
|
333 | (0, React.useImperativeHandle)(outerRef, () => ({
|
334 | focus
|
335 | }));
|
336 | let shouldRenderPopup = (0, _WidgetHelpers.useFirstFocusedRender)(focused, currentOpen);
|
337 | let valueItem = accessors.findOrSelf(data, currentValue);
|
338 | let inputValue = accessors.text(suggestion || valueItem);
|
339 | let completeType = filter ? 'list' : 'none';
|
340 | let popupOpen = currentOpen && (!hideEmptyPopup || !!data.length);
|
341 | let inputReadOnly =
|
342 | (inputProps == null ? void 0 : inputProps.readOnly) != null ? inputProps == null ? void 0 : inputProps.readOnly : readOnly;
|
343 | let inputAddon = false;
|
344 |
|
345 | if (!hideCaret) {
|
346 | inputAddon = React.createElement(_InputAddon.default, {
|
347 | busy: busy,
|
348 | icon: selectIcon,
|
349 | spinner: busySpinner,
|
350 | onClick: handleClick,
|
351 | disabled: !!isDisabled || isReadOnly
|
352 | ,
|
353 | label: messages.openCombobox()
|
354 | });
|
355 | } else if (busy) {
|
356 | inputAddon = React.createElement("span", {
|
357 | "aria-hidden": "true",
|
358 | className: "rw-btn rw-picker-caret"
|
359 | }, busySpinner || _Icon.Spinner);
|
360 | }
|
361 |
|
362 | return React.createElement(_Widget.default, _extends({}, elementProps, {
|
363 | ref: ref,
|
364 | open: currentOpen,
|
365 | dropUp: dropUp,
|
366 | focused: focused,
|
367 | disabled: isDisabled,
|
368 | readOnly: isReadOnly
|
369 | }, focusEvents, {
|
370 | onKeyDown: handleKeyDown,
|
371 | className: (0, _classnames.default)(className, 'rw-combobox')
|
372 | }), React.createElement(_WidgetPicker.default, {
|
373 | className: (0, _classnames.default)(containerClassName, hideCaret && 'rw-widget-input', hideCaret && !busy && 'rw-hide-caret')
|
374 | }, React.createElement(_Input.default, _extends({}, inputProps, {
|
375 | role: "combobox",
|
376 | name: name,
|
377 | id: inputId,
|
378 | className: (0, _classnames.default)(
|
379 | inputProps && inputProps.className, 'rw-combobox-input', !hideCaret && 'rw-widget-input'),
|
380 | autoFocus: autoFocus,
|
381 | tabIndex: tabIndex,
|
382 | disabled: isDisabled,
|
383 | readOnly: inputReadOnly,
|
384 | "aria-busy": !!busy,
|
385 | "aria-owns": listId,
|
386 | "aria-autocomplete": completeType,
|
387 | "aria-expanded": currentOpen,
|
388 | "aria-haspopup": true,
|
389 | placeholder: placeholder,
|
390 | value: inputValue,
|
391 | onChange: handleInputChange,
|
392 | onKeyDown: handleInputKeyDown,
|
393 | ref: inputRef
|
394 | })), inputAddon), React.createElement(_FocusListContext.FocusListContext.Provider, {
|
395 | value: list.context
|
396 | }, shouldRenderPopup && React.createElement(Popup, {
|
397 | dropUp: dropUp,
|
398 | open: popupOpen,
|
399 | transition: popupTransition,
|
400 | onEntering: () => listRef.current.scrollIntoView()
|
401 | }, React.createElement(ListComponent, _extends({}, listProps, {
|
402 | id: listId,
|
403 | tabIndex: -1,
|
404 | data: data,
|
405 | groupBy: groupBy,
|
406 | disabled: disabled,
|
407 | accessors: accessors,
|
408 | renderItem: renderListItem,
|
409 | renderGroup: renderListGroup,
|
410 | optionComponent: optionComponent,
|
411 | value: selectedItem,
|
412 | searchTerm: valueItem && accessors.text(valueItem) || '',
|
413 | "aria-hidden": !popupOpen,
|
414 | "aria-labelledby": inputId,
|
415 | "aria-live": popupOpen ? 'polite' : void 0,
|
416 | onChange: (d, meta) => handleSelect(d, meta.originalEvent),
|
417 | ref: listRef,
|
418 | messages: {
|
419 | emptyList: rawData.length ? messages.emptyFilter : messages.emptyList
|
420 | }
|
421 | })))));
|
422 | });
|
423 | ComboboxImpl.displayName = 'Combobox';
|
424 | ComboboxImpl.propTypes = propTypes;
|
425 | var _default = ComboboxImpl;
|
426 | exports.default = _default; |
\ | No newline at end of file |