@rescui/select 0.15.1-RUI-280-Update-select-component-downshift-2f40ef205.67 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/lib/_virtual/index.css.js +12 -12
  2. package/lib/common-prop-types.d.ts +14 -9
  3. package/lib/common-prop-types.js +3 -4
  4. package/lib/index.css +432 -808
  5. package/lib/index.d.ts +6 -4
  6. package/lib/index.js +3 -3
  7. package/lib/key-codes.d.ts +7 -0
  8. package/lib/key-codes.js +8 -0
  9. package/lib/parts/common-select.p.module.css.js +15 -0
  10. package/lib/parts/foldable.js +2 -1
  11. package/lib/parts/form-trigger-wrapper.d.ts +7 -7
  12. package/lib/parts/form-trigger-wrapper.js +34 -16
  13. package/lib/parts/form-trigger.p.module.css.js +15 -0
  14. package/lib/parts/multiselect.d.ts +86 -0
  15. package/lib/parts/multiselect.js +455 -0
  16. package/lib/parts/native-select.d.ts +36 -0
  17. package/lib/parts/native-select.js +255 -0
  18. package/lib/parts/native-select.p.module.css.js +9 -0
  19. package/lib/parts/throttle.d.ts +1 -0
  20. package/lib/parts/trigger.d.ts +37 -0
  21. package/lib/parts/trigger.js +255 -0
  22. package/lib/parts/trigger.p.module.css.js +31 -0
  23. package/lib/parts/use-observable-force-rerender.d.ts +2 -0
  24. package/lib/parts/use-observable-force-rerender.js +16 -0
  25. package/lib/public-api.p.css +309 -545
  26. package/lib/public-api.pcss +309 -545
  27. package/lib/select.d.ts +91 -27
  28. package/lib/select.js +351 -51
  29. package/lib/types.d.ts +4 -167
  30. package/lib/utils.d.ts +22 -0
  31. package/lib/utils.js +199 -0
  32. package/package.json +12 -12
  33. package/lib/constants.d.ts +0 -6
  34. package/lib/constants.js +0 -7
  35. package/lib/hooks/use-a11y.d.ts +0 -29
  36. package/lib/hooks/use-a11y.js +0 -53
  37. package/lib/hooks/use-focus.d.ts +0 -10
  38. package/lib/hooks/use-focus.js +0 -17
  39. package/lib/hooks/use-hover.d.ts +0 -10
  40. package/lib/hooks/use-hover.js +0 -17
  41. package/lib/hooks/use-label-focus.d.ts +0 -9
  42. package/lib/hooks/use-label-focus.js +0 -22
  43. package/lib/hooks/use-multi-handlers.d.ts +0 -11
  44. package/lib/hooks/use-multi-handlers.js +0 -48
  45. package/lib/hooks/use-options.d.ts +0 -13
  46. package/lib/hooks/use-options.js +0 -89
  47. package/lib/multiselect.d.ts +0 -3
  48. package/lib/multiselect.js +0 -312
  49. package/lib/native-select.d.ts +0 -4
  50. package/lib/native-select.js +0 -211
  51. package/lib/parts/hidden-select.d.ts +0 -13
  52. package/lib/parts/hidden-select.js +0 -45
  53. package/lib/parts/icons.d.ts +0 -17
  54. package/lib/parts/icons.js +0 -69
  55. package/lib/parts/list-box.d.ts +0 -11
  56. package/lib/parts/list-box.js +0 -116
  57. package/lib/parts/multi-trigger.d.ts +0 -12
  58. package/lib/parts/multi-trigger.js +0 -74
  59. package/lib/parts/native-select-options-with-groups.d.ts +0 -8
  60. package/lib/parts/native-select-options-with-groups.js +0 -76
  61. package/lib/select-basic.d.ts +0 -3
  62. package/lib/select-basic.js +0 -203
  63. package/lib/select-searchable.d.ts +0 -3
  64. package/lib/select-searchable.js +0 -250
  65. package/lib/styles/common.p.module.css.js +0 -31
  66. package/lib/styles/form-trigger.p.module.css.js +0 -15
  67. package/lib/styles/list-box.p.module.css.js +0 -14
  68. package/lib/utils/calculate-max-height-by-items.d.ts +0 -13
  69. package/lib/utils/calculate-max-height-by-items.js +0 -22
  70. package/lib/utils/get-empty-message.d.ts +0 -6
  71. package/lib/utils/get-empty-message.js +0 -32
  72. package/lib/utils/get-option-value.d.ts +0 -2
  73. package/lib/utils/get-option-value.js +0 -11
  74. package/lib/utils/get-real-items-cnt.d.ts +0 -2
  75. package/lib/utils/get-real-items-cnt.js +0 -19
  76. package/lib/utils/get-text-from-nodes.d.ts +0 -2
  77. package/lib/utils/get-text-from-nodes.js +0 -28
  78. package/lib/utils/is-option-a-group.d.ts +0 -2
  79. package/lib/utils/is-option-a-group.js +0 -5
  80. package/lib/utils/item-to-string.d.ts +0 -2
  81. package/lib/utils/item-to-string.js +0 -7
  82. package/lib/utils/merge-props.d.ts +0 -29
  83. package/lib/utils/merge-props.js +0 -106
  84. package/lib/utils/throttle.d.ts +0 -1
  85. /package/lib/{utils → parts}/throttle.js +0 -0
  86. /package/lib/{hooks → parts}/use-backward-compatible-id.d.ts +0 -0
  87. /package/lib/{hooks → parts}/use-backward-compatible-id.js +0 -0
@@ -1,48 +0,0 @@
1
- import { useRef, useMemo, useCallback } from 'react';
2
- import { getOptionValue } from '../utils/get-option-value.js';
3
-
4
- const useMultiHandlers = _ref => {
5
- let {
6
- selectedItems,
7
- onChange
8
- } = _ref;
9
- const onChangeRef = useRef(null);
10
- onChangeRef.current = onChange;
11
- const selectedMap = useMemo(() => new Map(selectedItems.map(item => [getOptionValue(item), item])), [selectedItems]);
12
- const addItem = useCallback(item => {
13
- var _onChangeRef$current;
14
-
15
- if (selectedMap.has(getOptionValue(item))) {
16
- return;
17
- }
18
-
19
- (_onChangeRef$current = onChangeRef.current) === null || _onChangeRef$current === void 0 || _onChangeRef$current.call(onChangeRef, [...selectedMap.values(), item]);
20
- }, [selectedMap]);
21
- const removeItem = useCallback(item => {
22
- var _onChangeRef$current2;
23
-
24
- const key = getOptionValue(item);
25
- (_onChangeRef$current2 = onChangeRef.current) === null || _onChangeRef$current2 === void 0 || _onChangeRef$current2.call(onChangeRef, [...selectedMap.entries()].filter(_ref2 => {
26
- let [k] = _ref2;
27
- return k !== key;
28
- }).map(_ref3 => {
29
- let [, v] = _ref3;
30
- return v;
31
- }));
32
- }, [selectedMap]);
33
-
34
- const removeAllItems = () => {
35
- var _onChangeRef$current3;
36
-
37
- (_onChangeRef$current3 = onChangeRef.current) === null || _onChangeRef$current3 === void 0 || _onChangeRef$current3.call(onChangeRef, []);
38
- };
39
-
40
- return {
41
- selectedMap,
42
- addItem,
43
- removeItem,
44
- removeAllItems
45
- };
46
- };
47
-
48
- export { useMultiHandlers };
@@ -1,13 +0,0 @@
1
- /// <reference types="react" />
2
- import type { SelectOptionOrGroup, SelectOption, ListBoxItem } from '../types';
3
- /**
4
- * Convert an array of options with possible groups to the flat array of options, stripping them of the groups.
5
- * Also creating a list for ListBox component with indexes and keys.
6
- * Supports filtering by returning the setFilterString function.
7
- * @param options
8
- */
9
- export declare const useOptions: (options: SelectOptionOrGroup[]) => {
10
- setFilterString: import("react").Dispatch<import("react").SetStateAction<string>>;
11
- flattenedOptions: SelectOption[];
12
- listBoxItems: ListBoxItem[];
13
- };
@@ -1,89 +0,0 @@
1
- import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
2
- import { useState, useMemo } from 'react';
3
- import { isOptionAGroup } from '../utils/is-option-a-group.js';
4
- import { getTextFromNodes } from '../utils/get-text-from-nodes.js';
5
- import { getOptionValue } from '../utils/get-option-value.js';
6
-
7
- const createFilter = substring => {
8
- if (substring.length === 0) {
9
- return () => true;
10
- }
11
-
12
- const lowerSubstring = substring.toLowerCase();
13
- return string => {
14
- var _context;
15
-
16
- return _includesInstanceProperty(_context = string.toLowerCase()).call(_context, lowerSubstring);
17
- };
18
- };
19
- /**
20
- * Convert an array of options with possible groups to the flat array of options, stripping them of the groups.
21
- * Also creating a list for ListBox component with indexes and keys.
22
- * Supports filtering by returning the setFilterString function.
23
- * @param options
24
- */
25
-
26
-
27
- const useOptions = options => {
28
- const [filterString, setFilterString] = useState('');
29
- const filterFn = useMemo(() => createFilter(filterString), [filterString]);
30
- const processedOptions = useMemo(() => {
31
- const flattenedOptions = [];
32
- const listBoxItems = [];
33
- let index = 0;
34
-
35
- const createOptionItem = option => {
36
- return { ...option,
37
- index: index++,
38
- type: 'option',
39
- key: getOptionValue(option)
40
- };
41
- };
42
-
43
- options.forEach((optionOrGroup, arrayIndex) => {
44
- if (isOptionAGroup(optionOrGroup)) {
45
- const group = optionOrGroup;
46
-
47
- if (!group.options || group.options.length === 0) {
48
- return;
49
- } // Render as Group (with or without label)
50
-
51
-
52
- const groupLabelText = group.label ? getTextFromNodes(group.label) : ''; // Use a special prefix that's unlikely to collide with user values
53
-
54
- const groupKey = `\0__rs_select_group_${arrayIndex}_${groupLabelText}`;
55
- const listBoxGroupItem = { ...group,
56
- type: 'group',
57
- options: [],
58
- key: groupKey
59
- };
60
- group.options.forEach(option => {
61
- if (filterFn(getTextFromNodes(option.label))) {
62
- flattenedOptions.push(option);
63
- listBoxGroupItem.options.push(createOptionItem(option));
64
- }
65
- });
66
-
67
- if (listBoxGroupItem.options.length > 0) {
68
- listBoxItems.push(listBoxGroupItem);
69
- }
70
-
71
- return;
72
- }
73
-
74
- if (filterFn(getTextFromNodes(optionOrGroup.label))) {
75
- flattenedOptions.push(optionOrGroup);
76
- listBoxItems.push(createOptionItem(optionOrGroup));
77
- }
78
- });
79
- return {
80
- flattenedOptions,
81
- listBoxItems
82
- };
83
- }, [options, filterFn]);
84
- return { ...processedOptions,
85
- setFilterString
86
- };
87
- };
88
-
89
- export { useOptions };
@@ -1,3 +0,0 @@
1
- /// <reference types="react" />
2
- import type { MultiselectProps } from './types';
3
- export declare function Multiselect({ options, value: selectedItems, onChange, error, label, note, size, mode, theme: themeFromProps, placement, isSingleLine, boldLabel, reserveErrorLine, maxVisibleItems, isClearable, isLoading, isDisabled, name, noOptionsMessage, className, id, style, placeholder, ...rest }: MultiselectProps): JSX.Element;
@@ -1,312 +0,0 @@
1
- import React, { useEffect } from 'react';
2
- import cn from 'classnames';
3
- import { Dropdown } from '@rescui/dropdown';
4
- import { useSelect } from 'downshift';
5
- import { useThemeWithUndefined } from '@rescui/ui-contexts';
6
- import scrollIntoView from 'scroll-into-view-if-needed';
7
- import { useLabelFocus } from './hooks/use-label-focus.js';
8
- import { useOptions } from './hooks/use-options.js';
9
- import { useMultiHandlers } from './hooks/use-multi-handlers.js';
10
- import { useA11y } from './hooks/use-a11y.js';
11
- import { ListBox } from './parts/list-box.js';
12
- import { Icons } from './parts/icons.js';
13
- import { MultiTrigger } from './parts/multi-trigger.js';
14
- import { HiddenSelect } from './parts/hidden-select.js';
15
- import { FormTriggerWrapper } from './parts/form-trigger-wrapper.js';
16
- import { getEmptyMessage } from './utils/get-empty-message.js';
17
- import { mergeProps } from './utils/merge-props.js';
18
- import { itemToString } from './utils/item-to-string.js';
19
- import { getOptionValue } from './utils/get-option-value.js';
20
- import { getRealItemsCnt } from './utils/get-real-items-cnt.js';
21
- import styles from './styles/common.p.module.css.js';
22
- const THEME_STYLES = {
23
- light: styles.themeLight,
24
- dark: styles.themeDark
25
- };
26
- const SIZE_STYLES = {
27
- s: styles.sizeS,
28
- m: styles.sizeM,
29
- l: styles.sizeL
30
- };
31
- const MODE_STYLES = {
32
- classic: styles.classic,
33
- rock: styles.rock
34
- };
35
-
36
- const stateReducer = (state, actionAndChanges) => {
37
- const {
38
- changes,
39
- type
40
- } = actionAndChanges; // console.log(type, state, changes);
41
-
42
- switch (type) {
43
- case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
44
- case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
45
- case useSelect.stateChangeTypes.ItemClick:
46
- return { ...changes,
47
- isOpen: true,
48
- highlightedIndex: state.highlightedIndex
49
- };
50
-
51
- default:
52
- return { ...changes,
53
- selectedItem: null
54
- };
55
- }
56
- }; // eslint-disable-next-line complexity
57
-
58
-
59
- function Multiselect(_ref) {
60
- let {
61
- options = [],
62
- value: selectedItems = [],
63
- onChange,
64
- error,
65
- label,
66
- note,
67
- size = 'm',
68
- mode = 'classic',
69
- theme: themeFromProps,
70
- placement = 'bottom',
71
- isSingleLine = false,
72
- boldLabel = true,
73
- reserveErrorLine = false,
74
- maxVisibleItems = 5,
75
- isClearable = false,
76
- isLoading = false,
77
- isDisabled = false,
78
- name,
79
- noOptionsMessage,
80
- className,
81
- id,
82
- style,
83
- placeholder,
84
- ...rest
85
- } = _ref;
86
- const theme = useThemeWithUndefined(themeFromProps);
87
- const triggerRef = React.useRef(null);
88
- const menuRef = React.useRef(null);
89
- const dropdownRef = React.useRef(null);
90
- const {
91
- selectedMap,
92
- removeItem: removeSelectedItem,
93
- addItem: addSelectedItem,
94
- removeAllItems: reset
95
- } = useMultiHandlers({
96
- selectedItems,
97
- onChange
98
- });
99
- const {
100
- flattenedOptions,
101
- listBoxItems
102
- } = useOptions(options);
103
- const isListBoxEmpty = getRealItemsCnt(listBoxItems) === 0;
104
- const {
105
- fieldProps,
106
- errorMessageProps,
107
- descriptionProps,
108
- baseId
109
- } = useA11y({
110
- prefix: 'multiselect',
111
- error,
112
- description: note
113
- });
114
- const {
115
- isOpen,
116
- getToggleButtonProps,
117
- getLabelProps,
118
- getMenuProps,
119
- highlightedIndex,
120
- getItemProps,
121
- setHighlightedIndex
122
- } = useSelect({
123
- items: flattenedOptions,
124
- itemToString,
125
- id: baseId,
126
-
127
- onIsOpenChange(newIsOpen) {
128
- if (newIsOpen) {
129
- // set the first selected item as a highlighted item if the popup is opened
130
- const firstSelectedKey = [...selectedMap.keys()][0];
131
-
132
- if (firstSelectedKey) {
133
- setHighlightedIndex(flattenedOptions.findIndex(item => firstSelectedKey === getOptionValue(item)));
134
- }
135
- }
136
- },
137
-
138
- stateReducer,
139
- // there's no actual selection happening in the hook, we're doing it custom via controlled props.
140
- selectedItem: null,
141
- // defining our scroll behavior because on the first menu render the hook
142
- // doesn't know menuRef and use page as the scroll boundary
143
- scrollIntoView: (listItemEl, listEl) => {
144
- scrollIntoView(listItemEl, {
145
- scrollMode: 'if-needed',
146
- block: 'nearest',
147
- boundary: listEl ?? menuRef.current
148
- });
149
- },
150
- onSelectedItemChange: _ref2 => {
151
- let {
152
- selectedItem
153
- } = _ref2;
154
-
155
- if (!selectedItem) {
156
- return;
157
- }
158
-
159
- const changedValue = getOptionValue(selectedItem);
160
-
161
- if (selectedMap.has(changedValue)) {
162
- removeSelectedItem(selectedItem);
163
- } else {
164
- addSelectedItem(selectedItem);
165
- }
166
- },
167
-
168
- isItemDisabled(item) {
169
- return item && item.disabled;
170
- }
171
-
172
- });
173
- const menuProps = getMenuProps({
174
- ref: menuRef,
175
- 'aria-multiselectable': isListBoxEmpty ? undefined : 'true'
176
- }, {
177
- suppressRefError: true
178
- });
179
- const triggerProps = getToggleButtonProps({
180
- ref: triggerRef,
181
- // eslint-disable-next-line complexity
182
- onKeyDown: event => {
183
- // shift + arrow up/down selection (when popup is open)
184
- if (isOpen && event.shiftKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {
185
- const newHighlightedIndex = event.key === 'ArrowUp' ? Math.max(highlightedIndex - 1, 0) : Math.min(highlightedIndex + 1, flattenedOptions.length - 1);
186
-
187
- if (newHighlightedIndex === highlightedIndex) {
188
- return;
189
- }
190
-
191
- addSelectedItem(flattenedOptions[newHighlightedIndex]);
192
- } // backspace removing the last selected item (when popup is closed)
193
-
194
-
195
- if (!isOpen && event.key === 'Backspace') {
196
- removeSelectedItem(selectedItems[selectedItems.length - 1]);
197
- } // delete removing all selected items (when popup is closed)
198
-
199
-
200
- if (!isOpen && event.key === 'Delete') {
201
- reset();
202
- }
203
- },
204
- // fix screen-reader focus on an opened popup with an empty list
205
- ...(isOpen && isListBoxEmpty ? {
206
- 'aria-activedescendant': menuProps.id
207
- } : {})
208
- }); // recalculate the popup position after a possible trigger height change
209
-
210
- useEffect(() => {
211
- if (dropdownRef.current) {
212
- dropdownRef.current.scheduleUpdate();
213
- }
214
- }, [selectedItems]);
215
- const {
216
- isFocusedByLabel,
217
- labelClickProps,
218
- triggerFocusProps: labelFocusForTriggerProps
219
- } = useLabelFocus();
220
- const emptyListMessage = getEmptyMessage({
221
- isLoading,
222
- isNothingFound: false,
223
- noOptionsMessage
224
- });
225
- const listBoxState = {
226
- selectedMap,
227
- selectionMode: 'multiple',
228
- highlightedIndex,
229
- getItemProps,
230
- menuProps
231
- };
232
- return /*#__PURE__*/React.createElement("div", {
233
- className: cn(className, styles.root, THEME_STYLES[theme], SIZE_STYLES[size], MODE_STYLES[mode], isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
234
- id: id,
235
- style: style,
236
- "data-test": "multiselect"
237
- }, /*#__PURE__*/React.createElement(FormTriggerWrapper, {
238
- theme: theme,
239
- size: size,
240
- disabled: isDisabled,
241
- label: label,
242
- labelProps: mergeProps(getLabelProps(), labelClickProps),
243
- boldLabel: boldLabel,
244
- error: error,
245
- reserveErrorLine: reserveErrorLine,
246
- errorMessageProps: errorMessageProps,
247
- note: note,
248
- descriptionProps: descriptionProps
249
- }, /*#__PURE__*/React.createElement(HiddenSelect, {
250
- name: name,
251
- value: selectedItems,
252
- isMultiple: true,
253
- options: flattenedOptions
254
- }), /*#__PURE__*/React.createElement(Dropdown, {
255
- mode: mode,
256
- theme: theme,
257
- ref: dropdownRef,
258
- placement: placement,
259
- maxWidth: "trigger",
260
- minWidth: "trigger",
261
- isOpen: isOpen,
262
- cancelCloseAnimation: true,
263
- disableFocusLock: true,
264
- trigger: _ref3 => {
265
- let {
266
- ref: triggerRefForDropdown
267
- } = _ref3;
268
- return /*#__PURE__*/React.createElement("div", {
269
- className: styles.triggerContainer,
270
- "data-open": isOpen,
271
- "data-label-focused": isFocusedByLabel
272
- }, /*#__PURE__*/React.createElement("div", { ...rest,
273
- ...mergeProps(fieldProps, // aria-invalid & aria-describedby, rest are overridden by triggerProps
274
- triggerProps, labelFocusForTriggerProps, {
275
- ref: triggerRefForDropdown
276
- }),
277
- className: cn(styles.trigger, !isSingleLine && styles.canBeMultiline),
278
- "data-open": isOpen,
279
- "data-label-focused": isFocusedByLabel,
280
- "data-test": "multiselect__trigger"
281
- }, /*#__PURE__*/React.createElement(MultiTrigger, {
282
- selectedItems: selectedItems,
283
- valueProps: {},
284
- isSingleLine: isSingleLine,
285
- isDisabled: isDisabled,
286
- placeholder: placeholder,
287
- triggerRef: triggerRef,
288
- removeSelectedItem: removeSelectedItem
289
- }), /*#__PURE__*/React.createElement(Icons, {
290
- isLoading: isLoading,
291
- canHaveClearIcon: isClearable && !isDisabled && selectedItems.length > 0,
292
- onClear: () => {
293
- var _triggerRef$current;
294
-
295
- reset();
296
- (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
297
- focusVisible: false
298
- });
299
- },
300
- triggerId: triggerProps.id
301
- })));
302
- }
303
- }, /*#__PURE__*/React.createElement(ListBox, {
304
- state: listBoxState,
305
- size: size,
306
- maxVisibleItems: maxVisibleItems,
307
- emptyListMessage: emptyListMessage,
308
- items: listBoxItems
309
- }))));
310
- }
311
-
312
- export { Multiselect };
@@ -1,4 +0,0 @@
1
- import React from 'react';
2
- import type { NativeSelectProps } from './types';
3
- export declare const NativeSelect: React.FC<NativeSelectProps>;
4
- export default NativeSelect;
@@ -1,211 +0,0 @@
1
- "use client";
2
- import React from 'react';
3
- import PropTypes from 'prop-types';
4
- import cn from 'classnames';
5
- import { useThemeWithUndefined } from '@rescui/ui-contexts';
6
- import { ErrorMessage } from '@rescui/form-field';
7
- import { nativeOptionType, nativeOptionsGroupType, noOptionsMessageType } from './common-prop-types.js';
8
- import { useA11y } from './hooks/use-a11y.js';
9
- import { useHover } from './hooks/use-hover.js';
10
- import { useFocus } from './hooks/use-focus.js';
11
- import { FormTriggerWrapper } from './parts/form-trigger-wrapper.js';
12
- import { NativeSelectOptionsWithGroups } from './parts/native-select-options-with-groups.js';
13
- import { Icons } from './parts/icons.js';
14
- import { isOptionAGroup } from './utils/is-option-a-group.js';
15
- import { getEmptyMessage } from './utils/get-empty-message.js';
16
- import { mergeProps } from './utils/merge-props.js';
17
- import styles from './styles/common.p.module.css.js';
18
-
19
- function findSelectedOption(options, selectedValue) {
20
- let result = null;
21
-
22
- const checkOption = option => {
23
- if (result === null || option.value === selectedValue) {
24
- result = option;
25
- }
26
- };
27
-
28
- options.forEach(optionOrGroup => {
29
- if (isOptionAGroup(optionOrGroup)) {
30
- var _group$options;
31
-
32
- const group = optionOrGroup;
33
- (_group$options = group.options) === null || _group$options === void 0 || _group$options.forEach(checkOption);
34
- } else {
35
- checkOption(optionOrGroup);
36
- }
37
- });
38
- return result;
39
- }
40
-
41
- const SIZE_STYLES = {
42
- s: styles.sizeS,
43
- m: styles.sizeM,
44
- l: styles.sizeL
45
- };
46
- const THEME_STYLES = {
47
- light: styles.themeLight,
48
- dark: styles.themeDark
49
- }; // eslint-disable-next-line complexity
50
-
51
- const NativeSelect = _ref => {
52
- let {
53
- options = [],
54
- size = 'm',
55
- theme: themeFromProps,
56
- className = null,
57
- id,
58
- style,
59
- value,
60
- onChange,
61
- placeholder,
62
- isLoading = false,
63
- isDisabled = false,
64
- isClearable = false,
65
- trigger,
66
- label,
67
- note,
68
- error,
69
- reserveErrorLine = false,
70
- noOptionsMessage,
71
- name,
72
- boldLabel = true,
73
- ...rest
74
- } = _ref;
75
- const triggerRef = React.useRef(null);
76
- const {
77
- labelProps,
78
- fieldProps,
79
- errorMessageProps,
80
- descriptionProps
81
- } = useA11y({
82
- prefix: 'native-select',
83
- error,
84
- description: note,
85
- label,
86
- fieldRef: triggerRef
87
- });
88
-
89
- const reset = () => onChange(null);
90
-
91
- const theme = useThemeWithUndefined(themeFromProps);
92
-
93
- const handleChange = event => {
94
- const newValue = event.target.value;
95
- const selectedOption = findSelectedOption(options, newValue);
96
-
97
- if (onChange) {
98
- onChange(selectedOption);
99
- }
100
- }; // delete it when triggerFunc is migrated to the css-states instead of js-props for hover/focus
101
- // replace it with ":focus + &" selector in that case
102
-
103
-
104
- const {
105
- isFocused,
106
- focusProps
107
- } = useFocus({
108
- isDisabled
109
- }); // same as above, could be replaced with ":hover + &" selector
110
-
111
- const {
112
- isHovered,
113
- hoverProps
114
- } = useHover({
115
- isDisabled
116
- });
117
- const emptyListMessage = getEmptyMessage({
118
- isLoading,
119
- isNothingFound: false,
120
- noOptionsMessage
121
- });
122
- return /*#__PURE__*/React.createElement("div", {
123
- className: cn(className, styles.root, SIZE_STYLES[size], THEME_STYLES[theme], styles.classic, isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
124
- id: id,
125
- style: style,
126
- "data-test": "native-select"
127
- }, /*#__PURE__*/React.createElement(FormTriggerWrapper, {
128
- theme: theme,
129
- size: size,
130
- disabled: isDisabled,
131
- label: label,
132
- labelProps: mergeProps(labelProps),
133
- boldLabel: boldLabel,
134
- error: error,
135
- errorMessageProps: errorMessageProps,
136
- reserveErrorLine: reserveErrorLine,
137
- note: note,
138
- descriptionProps: descriptionProps
139
- }, /*#__PURE__*/React.createElement("div", {
140
- className: styles.triggerContainer
141
- }, /*#__PURE__*/React.createElement("select", { ...rest,
142
- ...mergeProps(fieldProps, focusProps, hoverProps, {
143
- onKeyDown: event => {
144
- // backspace and backspace removing the last selected item (when popup is closed)
145
- if (isClearable && (event.key === 'Backspace' || event.key === 'Delete')) {
146
- reset();
147
- }
148
- }
149
- }),
150
- ref: triggerRef,
151
- "data-test": "native-select_select",
152
- "data-rs-internal": 'select-native__select',
153
- className: styles.select,
154
- disabled: isDisabled ? true : undefined,
155
- onChange: handleChange,
156
- name: name,
157
- value: (value === null || value === void 0 ? void 0 : value.value) ?? ''
158
- }, /*#__PURE__*/React.createElement(NativeSelectOptionsWithGroups, {
159
- optionsWithGroups: options,
160
- placeholder: placeholder,
161
- emptyListMessage: emptyListMessage
162
- })), trigger ? trigger({
163
- focused: isFocused,
164
- hovered: isHovered,
165
- selectedLabel: value === null || value === void 0 ? void 0 : value.label,
166
- selectedValue: value === null || value === void 0 ? void 0 : value.value,
167
- placeholder
168
- }) : /*#__PURE__*/React.createElement("div", {
169
- className: cn(styles.trigger),
170
- "data-test": 'native-select_trigger',
171
- "data-rs-internal": 'select-native-trigger'
172
- }, /*#__PURE__*/React.createElement("span", {
173
- className: cn(styles.triggerText, !(value !== null && value !== void 0 && value.value) && styles.labelNotSelected),
174
- "data-test": 'native-select_trigger_text',
175
- "aria-hidden": "true"
176
- }, (value === null || value === void 0 ? void 0 : value.label) ?? placeholder), /*#__PURE__*/React.createElement(Icons, {
177
- isLoading: isLoading,
178
- triggerId: fieldProps.id,
179
- onClear: () => {
180
- var _triggerRef$current;
181
-
182
- reset();
183
- (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
184
- focusVisible: false
185
- });
186
- },
187
- canHaveClearIcon: isClearable && !isDisabled && Boolean(value === null || value === void 0 ? void 0 : value.value)
188
- })))));
189
- };
190
-
191
- NativeSelect.propTypes = {
192
- className: PropTypes.string,
193
- style: PropTypes.object,
194
- id: PropTypes.string,
195
- options: PropTypes.arrayOf(PropTypes.oneOfType([nativeOptionType, nativeOptionsGroupType])),
196
- value: nativeOptionType,
197
- onChange: PropTypes.func,
198
- size: PropTypes.oneOf(['m', 's', 'l']),
199
- theme: PropTypes.oneOf(['light', 'dark']),
200
- placeholder: PropTypes.string,
201
- isDisabled: PropTypes.bool,
202
- isLoading: PropTypes.bool,
203
- trigger: PropTypes.func,
204
- error: ErrorMessage.propTypes.children,
205
- label: PropTypes.node,
206
- note: PropTypes.node,
207
- noOptionsMessage: noOptionsMessageType,
208
- name: PropTypes.string,
209
- boldLabel: PropTypes.bool
210
- };
211
- export { NativeSelect, NativeSelect as default };
@@ -1,13 +0,0 @@
1
- /// <reference types="react" />
2
- import type { SelectOption } from '../types';
3
- export declare type HiddenSelectProps = {
4
- name?: string;
5
- options: SelectOption[];
6
- } & ({
7
- value: SelectOption[];
8
- isMultiple: true;
9
- } | {
10
- value: SelectOption;
11
- isMultiple: false;
12
- });
13
- export declare const HiddenSelect: ({ name, options, value, isMultiple }: HiddenSelectProps) => JSX.Element;