@rescui/select 0.15.2 → 0.16.0

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 (95) hide show
  1. package/lib/_virtual/index.css.js +12 -12
  2. package/lib/common-prop-types.d.ts +8 -14
  3. package/lib/common-prop-types.js +4 -3
  4. package/lib/constants.d.ts +6 -0
  5. package/lib/constants.js +7 -0
  6. package/lib/hooks/use-a11y.d.ts +30 -0
  7. package/lib/hooks/use-a11y.js +56 -0
  8. package/lib/hooks/use-actual-size-from-css.d.ts +10 -0
  9. package/lib/hooks/use-actual-size-from-css.js +27 -0
  10. package/lib/hooks/use-focus.d.ts +10 -0
  11. package/lib/hooks/use-focus.js +17 -0
  12. package/lib/hooks/use-hover.d.ts +10 -0
  13. package/lib/hooks/use-hover.js +17 -0
  14. package/lib/hooks/use-label-focus.d.ts +9 -0
  15. package/lib/hooks/use-label-focus.js +22 -0
  16. package/lib/hooks/use-multi-handlers.d.ts +11 -0
  17. package/lib/hooks/use-multi-handlers.js +44 -0
  18. package/lib/hooks/use-options.d.ts +14 -0
  19. package/lib/hooks/use-options.js +90 -0
  20. package/lib/hooks/use-primary-contrast-css-var-transfer.d.ts +11 -0
  21. package/lib/hooks/use-primary-contrast-css-var-transfer.js +29 -0
  22. package/lib/hooks/use-safe-id.d.ts +6 -0
  23. package/lib/hooks/use-safe-id.js +15 -0
  24. package/lib/index.css +713 -304
  25. package/lib/index.d.ts +4 -6
  26. package/lib/index.js +3 -3
  27. package/lib/multiselect.d.ts +3 -0
  28. package/lib/multiselect.js +308 -0
  29. package/lib/native-select.d.ts +4 -0
  30. package/lib/native-select.js +208 -0
  31. package/lib/parts/foldable.js +1 -2
  32. package/lib/parts/form-trigger-wrapper.d.ts +7 -7
  33. package/lib/parts/form-trigger-wrapper.js +16 -34
  34. package/lib/parts/hidden-select.d.ts +13 -0
  35. package/lib/parts/hidden-select.js +45 -0
  36. package/lib/parts/icons.d.ts +17 -0
  37. package/lib/parts/icons.js +69 -0
  38. package/lib/parts/list-box.d.ts +13 -0
  39. package/lib/parts/list-box.js +120 -0
  40. package/lib/parts/multi-trigger.d.ts +12 -0
  41. package/lib/parts/multi-trigger.js +70 -0
  42. package/lib/parts/native-select-options-with-groups.d.ts +8 -0
  43. package/lib/parts/native-select-options-with-groups.js +76 -0
  44. package/lib/parts/popup-content.d.ts +20 -0
  45. package/lib/parts/popup-content.js +68 -0
  46. package/lib/public-api.p.css +543 -307
  47. package/lib/public-api.pcss +543 -307
  48. package/lib/select-basic.d.ts +3 -0
  49. package/lib/select-basic.js +204 -0
  50. package/lib/select-searchable.d.ts +3 -0
  51. package/lib/select-searchable.js +245 -0
  52. package/lib/select.d.ts +27 -91
  53. package/lib/select.js +51 -351
  54. package/lib/styles/common.p.module.css.js +32 -0
  55. package/lib/styles/form-trigger.p.module.css.js +15 -0
  56. package/lib/styles/list-box.p.module.css.js +16 -0
  57. package/lib/types.d.ts +172 -4
  58. package/lib/utils/calculate-max-height-by-items.d.ts +13 -0
  59. package/lib/utils/calculate-max-height-by-items.js +22 -0
  60. package/lib/utils/get-empty-message.d.ts +6 -0
  61. package/lib/utils/get-empty-message.js +32 -0
  62. package/lib/utils/get-option-value.d.ts +2 -0
  63. package/lib/utils/get-option-value.js +11 -0
  64. package/lib/utils/get-real-items-cnt.d.ts +2 -0
  65. package/lib/utils/get-real-items-cnt.js +19 -0
  66. package/lib/utils/get-text-from-nodes.d.ts +2 -0
  67. package/lib/utils/get-text-from-nodes.js +26 -0
  68. package/lib/utils/is-option-a-group.d.ts +2 -0
  69. package/lib/utils/is-option-a-group.js +5 -0
  70. package/lib/utils/item-to-string.d.ts +2 -0
  71. package/lib/utils/item-to-string.js +7 -0
  72. package/lib/utils/merge-props.d.ts +19 -0
  73. package/lib/utils/merge-props.js +104 -0
  74. package/lib/utils/throttle.d.ts +1 -0
  75. package/package.json +6 -6
  76. package/lib/key-codes.d.ts +0 -7
  77. package/lib/key-codes.js +0 -8
  78. package/lib/parts/common-select.p.module.css.js +0 -15
  79. package/lib/parts/form-trigger.p.module.css.js +0 -15
  80. package/lib/parts/multiselect.d.ts +0 -86
  81. package/lib/parts/multiselect.js +0 -455
  82. package/lib/parts/native-select.d.ts +0 -36
  83. package/lib/parts/native-select.js +0 -255
  84. package/lib/parts/native-select.p.module.css.js +0 -9
  85. package/lib/parts/throttle.d.ts +0 -1
  86. package/lib/parts/trigger.d.ts +0 -37
  87. package/lib/parts/trigger.js +0 -255
  88. package/lib/parts/trigger.p.module.css.js +0 -31
  89. package/lib/parts/use-backward-compatible-id.d.ts +0 -4
  90. package/lib/parts/use-backward-compatible-id.js +0 -14
  91. package/lib/parts/use-observable-force-rerender.d.ts +0 -2
  92. package/lib/parts/use-observable-force-rerender.js +0 -16
  93. package/lib/utils.d.ts +0 -22
  94. package/lib/utils.js +0 -199
  95. /package/lib/{parts → utils}/throttle.js +0 -0
package/lib/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- export { default as Select } from './select';
2
- export type { SelectProps } from './select';
3
- export { default as NativeSelect } from './parts/native-select';
4
- export type { NativeSelectProps } from './parts/native-select';
5
- export { default as Multiselect } from './parts/multiselect';
6
- export type { MultiselectProps } from './parts/multiselect';
1
+ export { Select } from './select';
2
+ export { Multiselect } from './multiselect';
3
+ export { NativeSelect } from './native-select';
4
+ export type { SelectProps, MultiselectProps, NativeSelectProps, SelectOption, Key } from './types';
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import './index.css';
2
- export { default as Select } from './select.js';
3
- export { default as NativeSelect } from './parts/native-select.js';
4
- export { default as Multiselect } from './parts/multiselect.js';
2
+ export { Select } from './select.js';
3
+ export { Multiselect } from './multiselect.js';
4
+ export { NativeSelect } from './native-select.js';
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import type { MultiselectProps } from './types';
3
+ export declare function Multiselect({ options, value, 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;
@@ -0,0 +1,308 @@
1
+ "use client";
2
+ import React, { useMemo, useRef } from 'react';
3
+ import cn from 'classnames';
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 { Icons } from './parts/icons.js';
12
+ import { MultiTrigger } from './parts/multi-trigger.js';
13
+ import { HiddenSelect } from './parts/hidden-select.js';
14
+ import { FormTriggerWrapper } from './parts/form-trigger-wrapper.js';
15
+ import { PopupContent } from './parts/popup-content.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;
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,
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 selectedItems = useMemo(() => value ?? [], [value]);
87
+ const theme = useThemeWithUndefined(themeFromProps);
88
+ const triggerRef = useRef(null);
89
+ const menuRef = useRef(null);
90
+ const dropdownRef = useRef(null);
91
+ const {
92
+ selectedMap,
93
+ removeItem: removeSelectedItem,
94
+ addItem: addSelectedItem,
95
+ removeAllItems: reset
96
+ } = useMultiHandlers({
97
+ selectedItems,
98
+ onChange
99
+ });
100
+ const {
101
+ flattenedOptions,
102
+ listBoxItems
103
+ } = useOptions(options);
104
+ const isListBoxEmpty = getRealItemsCnt(listBoxItems) === 0;
105
+ const {
106
+ fieldProps,
107
+ errorMessageProps,
108
+ descriptionProps,
109
+ baseId
110
+ } = useA11y({
111
+ prefix: 'multiselect',
112
+ error,
113
+ description: note,
114
+ isDisabled
115
+ });
116
+ const {
117
+ isOpen,
118
+ getToggleButtonProps,
119
+ getLabelProps,
120
+ getMenuProps,
121
+ highlightedIndex,
122
+ getItemProps,
123
+ setHighlightedIndex
124
+ } = useSelect({
125
+ items: flattenedOptions,
126
+ itemToString,
127
+ itemToKey: getOptionValue,
128
+ id: baseId,
129
+
130
+ onIsOpenChange(newIsOpen) {
131
+ if (newIsOpen) {
132
+ // set the first selected item as a highlighted item if the popup is opened
133
+ const firstSelectedKey = [...selectedMap.keys()][0];
134
+
135
+ if (firstSelectedKey) {
136
+ setHighlightedIndex(flattenedOptions.findIndex(item => firstSelectedKey === getOptionValue(item)));
137
+ }
138
+ }
139
+ },
140
+
141
+ stateReducer,
142
+ // there's no actual selection happening in the hook, we're doing it custom via controlled props.
143
+ selectedItem: null,
144
+ // defining our scroll behavior because on the first menu render the hook
145
+ // doesn't know menuRef and use page as the scroll boundary
146
+ scrollIntoView: (listItemEl, listEl) => {
147
+ scrollIntoView(listItemEl, {
148
+ scrollMode: 'if-needed',
149
+ block: 'nearest',
150
+ boundary: listEl ?? menuRef.current
151
+ });
152
+ },
153
+ onSelectedItemChange: _ref2 => {
154
+ let {
155
+ selectedItem
156
+ } = _ref2;
157
+
158
+ if (!selectedItem) {
159
+ return;
160
+ }
161
+
162
+ const changedValue = getOptionValue(selectedItem);
163
+
164
+ if (selectedMap.has(changedValue)) {
165
+ removeSelectedItem(selectedItem);
166
+ } else {
167
+ addSelectedItem(selectedItem);
168
+ }
169
+ },
170
+
171
+ isItemDisabled(item) {
172
+ return item && item.disabled;
173
+ }
174
+
175
+ });
176
+ const menuProps = getMenuProps({
177
+ ref: menuRef,
178
+ 'aria-multiselectable': isListBoxEmpty ? undefined : 'true'
179
+ }, {
180
+ suppressRefError: true
181
+ });
182
+ const triggerProps = getToggleButtonProps({
183
+ ref: triggerRef,
184
+ // eslint-disable-next-line complexity
185
+ onKeyDown: event => {
186
+ // prevent default behavior of Downshift when pressing Ctrl
187
+ if (event.ctrlKey || event.metaKey) {
188
+ event.preventDownshiftDefault = true;
189
+ return;
190
+ } // shift + arrow up/down selection (when popup is open)
191
+
192
+
193
+ if (isOpen && event.shiftKey && (event.key === 'ArrowUp' || event.key === 'ArrowDown')) {
194
+ const newHighlightedIndex = event.key === 'ArrowUp' ? Math.max(highlightedIndex - 1, 0) : Math.min(highlightedIndex + 1, flattenedOptions.length - 1);
195
+
196
+ if (newHighlightedIndex === highlightedIndex) {
197
+ return;
198
+ }
199
+
200
+ addSelectedItem(flattenedOptions[newHighlightedIndex]);
201
+ } // backspace removing the last selected item (when popup is closed)
202
+
203
+
204
+ if (!isOpen && event.key === 'Backspace') {
205
+ removeSelectedItem(selectedItems[selectedItems.length - 1]);
206
+ } // delete removing all selected items (when popup is closed)
207
+
208
+
209
+ if (!isOpen && event.key === 'Delete') {
210
+ reset();
211
+ }
212
+ },
213
+ // fix screen-reader focus on an opened popup with an empty list
214
+ ...(isOpen && isListBoxEmpty ? {
215
+ 'aria-activedescendant': menuProps.id
216
+ } : {})
217
+ });
218
+ const {
219
+ isFocusedByLabel,
220
+ labelClickProps,
221
+ triggerFocusProps: labelFocusForTriggerProps
222
+ } = useLabelFocus();
223
+ const emptyListMessage = getEmptyMessage({
224
+ isLoading,
225
+ isNothingFound: false,
226
+ noOptionsMessage
227
+ });
228
+ const listBoxState = {
229
+ selectedMap,
230
+ highlightedIndex,
231
+ getItemProps,
232
+ menuProps
233
+ };
234
+ return /*#__PURE__*/React.createElement("div", {
235
+ className: cn(className, styles.root, THEME_STYLES[theme], SIZE_STYLES[size], MODE_STYLES[mode], isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
236
+ id: id,
237
+ style: style,
238
+ "data-test": "multiselect"
239
+ }, /*#__PURE__*/React.createElement(FormTriggerWrapper, {
240
+ theme: theme,
241
+ size: size,
242
+ disabled: isDisabled,
243
+ label: label,
244
+ labelProps: mergeProps(getLabelProps(), labelClickProps),
245
+ boldLabel: boldLabel,
246
+ error: error,
247
+ reserveErrorLine: reserveErrorLine,
248
+ errorMessageProps: errorMessageProps,
249
+ note: note,
250
+ descriptionProps: descriptionProps
251
+ }, /*#__PURE__*/React.createElement(HiddenSelect, {
252
+ name: name,
253
+ value: selectedItems,
254
+ isMultiple: true,
255
+ options: flattenedOptions
256
+ }), /*#__PURE__*/React.createElement(PopupContent, {
257
+ theme: theme,
258
+ size: size,
259
+ mode: mode,
260
+ dropdownRef: dropdownRef,
261
+ triggerRef: triggerRef,
262
+ placement: placement,
263
+ isOpen: isOpen,
264
+ listBoxState: listBoxState,
265
+ maxVisibleItems: maxVisibleItems,
266
+ emptyListMessage: emptyListMessage,
267
+ listBoxItems: listBoxItems,
268
+ dropdownUpdateDeps: [selectedItems],
269
+ trigger: _ref3 => {
270
+ let {
271
+ ref: triggerRefForDropdown
272
+ } = _ref3;
273
+ return /*#__PURE__*/React.createElement("div", {
274
+ className: styles.triggerContainer,
275
+ "data-open": isOpen,
276
+ "data-label-focused": isFocusedByLabel
277
+ }, /*#__PURE__*/React.createElement("div", { ...rest,
278
+ ...mergeProps(fieldProps, // aria-invalid & aria-describedby, rest are overridden by triggerProps
279
+ triggerProps, labelFocusForTriggerProps, {
280
+ ref: triggerRefForDropdown
281
+ }),
282
+ tabIndex: isDisabled ? undefined : 0,
283
+ className: cn(styles.trigger, !isSingleLine && styles.canBeMultiline),
284
+ "data-test": "multiselect__trigger"
285
+ }, /*#__PURE__*/React.createElement(MultiTrigger, {
286
+ selectedItems: selectedItems,
287
+ valueProps: {},
288
+ isSingleLine: isSingleLine,
289
+ isDisabled: isDisabled,
290
+ placeholder: placeholder,
291
+ triggerRef: triggerRef,
292
+ removeSelectedItem: removeSelectedItem
293
+ }), /*#__PURE__*/React.createElement(Icons, {
294
+ isLoading: isLoading,
295
+ canHaveClearIcon: isClearable && !isDisabled && selectedItems.length > 0,
296
+ onClear: () => {
297
+ reset();
298
+ triggerRef.current?.focus({
299
+ focusVisible: false
300
+ });
301
+ },
302
+ triggerId: triggerProps.id
303
+ })));
304
+ }
305
+ })));
306
+ }
307
+
308
+ export { Multiselect };
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { NativeSelectProps } from './types';
3
+ export declare const NativeSelect: React.FC<NativeSelectProps>;
4
+ export default NativeSelect;
@@ -0,0 +1,208 @@
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
+ const group = optionOrGroup;
31
+ group.options?.forEach(checkOption);
32
+ } else {
33
+ checkOption(optionOrGroup);
34
+ }
35
+ });
36
+ return result;
37
+ }
38
+
39
+ const SIZE_STYLES = {
40
+ s: styles.sizeS,
41
+ m: styles.sizeM,
42
+ l: styles.sizeL
43
+ };
44
+ const THEME_STYLES = {
45
+ light: styles.themeLight,
46
+ dark: styles.themeDark
47
+ }; // eslint-disable-next-line complexity
48
+
49
+ const NativeSelect = _ref => {
50
+ let {
51
+ options = [],
52
+ size = 'm',
53
+ theme: themeFromProps,
54
+ className = null,
55
+ id,
56
+ style,
57
+ value,
58
+ onChange,
59
+ placeholder,
60
+ isLoading = false,
61
+ isDisabled = false,
62
+ isClearable = false,
63
+ trigger,
64
+ label,
65
+ note,
66
+ error,
67
+ reserveErrorLine = false,
68
+ noOptionsMessage,
69
+ name,
70
+ boldLabel = true,
71
+ ...rest
72
+ } = _ref;
73
+ const triggerRef = React.useRef(null);
74
+ const {
75
+ labelProps,
76
+ fieldProps,
77
+ errorMessageProps,
78
+ descriptionProps
79
+ } = useA11y({
80
+ prefix: 'native-select',
81
+ error,
82
+ description: note,
83
+ label,
84
+ fieldRef: triggerRef,
85
+ isDisabled
86
+ });
87
+
88
+ const reset = () => onChange(null);
89
+
90
+ const theme = useThemeWithUndefined(themeFromProps);
91
+
92
+ const handleChange = event => {
93
+ const newValue = event.target.value;
94
+ const selectedOption = findSelectedOption(options, newValue);
95
+
96
+ if (onChange) {
97
+ onChange(selectedOption);
98
+ }
99
+ }; // delete it when triggerFunc is migrated to the css-states instead of js-props for hover/focus
100
+ // replace it with ":focus + &" selector in that case
101
+
102
+
103
+ const {
104
+ isFocused,
105
+ focusProps
106
+ } = useFocus({
107
+ isDisabled
108
+ }); // same as above, could be replaced with ":hover + &" selector
109
+
110
+ const {
111
+ isHovered,
112
+ hoverProps
113
+ } = useHover({
114
+ isDisabled
115
+ });
116
+ const emptyListMessage = getEmptyMessage({
117
+ isLoading,
118
+ isNothingFound: false,
119
+ noOptionsMessage
120
+ });
121
+ return /*#__PURE__*/React.createElement("div", {
122
+ className: cn(className, styles.root, SIZE_STYLES[size], THEME_STYLES[theme], styles.classic, isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
123
+ id: id,
124
+ style: style,
125
+ "data-test": "native-select"
126
+ }, /*#__PURE__*/React.createElement(FormTriggerWrapper, {
127
+ theme: theme,
128
+ size: size,
129
+ disabled: isDisabled,
130
+ label: label,
131
+ labelProps: mergeProps(labelProps),
132
+ boldLabel: boldLabel,
133
+ error: error,
134
+ errorMessageProps: errorMessageProps,
135
+ reserveErrorLine: reserveErrorLine,
136
+ note: note,
137
+ descriptionProps: descriptionProps
138
+ }, /*#__PURE__*/React.createElement("div", {
139
+ className: styles.triggerContainer
140
+ }, /*#__PURE__*/React.createElement("select", { ...rest,
141
+ ...mergeProps(fieldProps, focusProps, hoverProps, {
142
+ onKeyDown: event => {
143
+ // backspace and backspace removing the last selected item (when popup is closed)
144
+ if (isClearable && (event.key === 'Backspace' || event.key === 'Delete')) {
145
+ reset();
146
+ }
147
+ }
148
+ }),
149
+ ref: triggerRef,
150
+ "data-test": "native-select_select",
151
+ "data-rs-internal": 'select-native__select',
152
+ className: styles.select,
153
+ disabled: isDisabled ? true : undefined,
154
+ onChange: handleChange,
155
+ name: name,
156
+ value: value?.value ?? ''
157
+ }, /*#__PURE__*/React.createElement(NativeSelectOptionsWithGroups, {
158
+ optionsWithGroups: options,
159
+ placeholder: placeholder,
160
+ emptyListMessage: emptyListMessage
161
+ })), trigger ? trigger({
162
+ focused: isFocused,
163
+ hovered: isHovered,
164
+ selectedLabel: value?.label,
165
+ selectedValue: value?.value,
166
+ placeholder
167
+ }) : /*#__PURE__*/React.createElement("div", {
168
+ className: cn(styles.trigger),
169
+ "data-test": 'native-select_trigger',
170
+ "data-rs-internal": 'select-native-trigger'
171
+ }, /*#__PURE__*/React.createElement("span", {
172
+ className: cn(styles.triggerText, !value?.value && styles.labelNotSelected),
173
+ "data-test": 'native-select_trigger_text',
174
+ "aria-hidden": "true"
175
+ }, value?.label ?? placeholder), /*#__PURE__*/React.createElement(Icons, {
176
+ isLoading: isLoading,
177
+ triggerId: fieldProps.id,
178
+ onClear: () => {
179
+ reset();
180
+ triggerRef.current?.focus({
181
+ focusVisible: false
182
+ });
183
+ },
184
+ canHaveClearIcon: isClearable && !isDisabled && Boolean(value?.value)
185
+ })))));
186
+ };
187
+
188
+ NativeSelect.propTypes = {
189
+ className: PropTypes.string,
190
+ style: PropTypes.object,
191
+ id: PropTypes.string,
192
+ options: PropTypes.arrayOf(PropTypes.oneOfType([nativeOptionType, nativeOptionsGroupType])),
193
+ value: nativeOptionType,
194
+ onChange: PropTypes.func,
195
+ size: PropTypes.oneOf(['m', 's', 'l']),
196
+ theme: PropTypes.oneOf(['light', 'dark']),
197
+ placeholder: PropTypes.string,
198
+ isDisabled: PropTypes.bool,
199
+ isLoading: PropTypes.bool,
200
+ trigger: PropTypes.func,
201
+ error: ErrorMessage.propTypes.children,
202
+ label: PropTypes.node,
203
+ note: PropTypes.node,
204
+ noOptionsMessage: noOptionsMessageType,
205
+ name: PropTypes.string,
206
+ boldLabel: PropTypes.bool
207
+ };
208
+ export { NativeSelect, NativeSelect as default };
@@ -1,6 +1,5 @@
1
- "use client";
2
1
  import React, { Component } from 'react';
3
- import { throttle } from './throttle.js';
2
+ import { throttle } from '../utils/throttle.js';
4
3
 
5
4
  function lastVisibleIndex(lens, maxLen, gap) {
6
5
  let extra = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
@@ -5,29 +5,29 @@ export declare type FormTriggerWrapperProps = {
5
5
  size?: SelectSize;
6
6
  theme?: Theme;
7
7
  className?: string;
8
- id?: string;
9
8
  disabled?: boolean;
10
- errorId?: string;
11
9
  error?: boolean | React.ReactNode;
12
10
  reserveErrorLine?: boolean;
11
+ errorMessageProps?: object;
13
12
  label?: React.ReactNode;
13
+ labelProps?: object;
14
14
  note?: React.ReactNode;
15
- onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
15
+ descriptionProps?: object;
16
16
  boldLabel?: boolean;
17
17
  children?: React.ReactNode;
18
18
  } & React.HTMLAttributes<HTMLDivElement>;
19
- declare const FormTriggerWrapper: React.ForwardRefExoticComponent<{
19
+ export declare const FormTriggerWrapper: React.ForwardRefExoticComponent<{
20
20
  size?: SelectSize;
21
21
  theme?: Theme;
22
22
  className?: string;
23
- id?: string;
24
23
  disabled?: boolean;
25
- errorId?: string;
26
24
  error?: boolean | React.ReactNode;
27
25
  reserveErrorLine?: boolean;
26
+ errorMessageProps?: object;
28
27
  label?: React.ReactNode;
28
+ labelProps?: object;
29
29
  note?: React.ReactNode;
30
- onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
30
+ descriptionProps?: object;
31
31
  boldLabel?: boolean;
32
32
  children?: React.ReactNode;
33
33
  } & React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
@@ -1,9 +1,8 @@
1
- "use client";
2
1
  import React from 'react';
3
2
  import cn from 'classnames';
4
3
  import { useThemeWithUndefined } from '@rescui/ui-contexts';
5
4
  import { shouldRenderErrorMessage, ErrorMessage } from '@rescui/form-field';
6
- import styles from './form-trigger.p.module.css.js';
5
+ import styles from '../styles/form-trigger.p.module.css.js';
7
6
  const SIZE_STYLES = {
8
7
  l: styles.sizeL,
9
8
  m: styles.sizeM,
@@ -13,64 +12,47 @@ const THEME_STYLES = {
13
12
  light: styles.themeLight,
14
13
  dark: styles.themeDark
15
14
  };
16
-
17
- const Label = _ref => {
18
- let {
19
- children,
20
- boldLabel
21
- } = _ref;
22
-
23
- if (!children) {
24
- return null;
25
- } else {
26
- return /*#__PURE__*/React.createElement("div", {
27
- className: styles.label,
28
- "data-rs-internal": boldLabel ? 'select-form-trigger-wrapper__bold-label' : 'select-form-trigger-wrapper__label'
29
- }, children);
30
- }
31
- };
32
-
33
15
  const FormTriggerWrapper = /*#__PURE__*/React.forwardRef( // eslint-disable-next-line complexity
34
- (_ref2, ref) => {
16
+ (_ref, ref) => {
35
17
  let {
36
18
  size,
37
19
  theme: themeFromProps,
38
20
  className,
39
- id,
40
21
  disabled,
41
22
  error,
42
- errorId,
43
23
  reserveErrorLine = false,
24
+ errorMessageProps,
44
25
  label,
26
+ labelProps,
45
27
  note,
28
+ descriptionProps,
46
29
  children,
47
- onKeyDown,
48
30
  boldLabel,
49
31
  ...restProps
50
- } = _ref2;
32
+ } = _ref;
51
33
  const theme = useThemeWithUndefined(themeFromProps);
52
34
  const hasFooter = Boolean(note) || shouldRenderErrorMessage(error, reserveErrorLine);
53
35
  return /*#__PURE__*/React.createElement("div", {
54
36
  className: cn(className, styles.main, SIZE_STYLES[size], THEME_STYLES[theme], Boolean(error) && styles.error, disabled && styles.disabled),
55
- id: id,
56
37
  ref: ref,
57
38
  "data-test": "select-wrapper",
58
39
  "data-rs-internal": 'select-form-trigger-wrapper',
59
40
  ...restProps
60
- }, /*#__PURE__*/React.createElement(Label, {
61
- boldLabel: boldLabel
62
- }, label), /*#__PURE__*/React.createElement("div", {
63
- onKeyDown: onKeyDown
64
- }, children), hasFooter && /*#__PURE__*/React.createElement("div", {
41
+ }, label && /*#__PURE__*/React.createElement("div", {
42
+ className: styles.label,
43
+ "data-rs-internal": boldLabel ? 'select-form-trigger-wrapper__bold-label' : 'select-form-trigger-wrapper__label',
44
+ ...labelProps
45
+ }, label), children, hasFooter && /*#__PURE__*/React.createElement("div", {
65
46
  className: styles.footer
66
47
  }, /*#__PURE__*/React.createElement(ErrorMessage, {
67
- id: errorId,
68
48
  className: styles.errorMessage,
69
- reserveLine: reserveErrorLine
49
+ reserveLine: reserveErrorLine,
50
+ ...errorMessageProps
70
51
  }, error), note && /*#__PURE__*/React.createElement("div", {
71
52
  className: styles.note,
72
- "data-rs-internal": 'select-form-trigger-wrapper__note'
53
+ "data-rs-internal": 'select-form-trigger-wrapper__note',
54
+ ...descriptionProps
73
55
  }, note)));
74
56
  });
75
57
  FormTriggerWrapper.displayName = 'FormTriggerWrapper';
76
- export { FormTriggerWrapper as default };
58
+ export { FormTriggerWrapper, FormTriggerWrapper as default };
@@ -0,0 +1,13 @@
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;