@rescui/select 0.15.1-RUI-280-Update-select-component-separate-components-e772abaa1.56 → 0.15.1-RUI-280-Update-select-component-downshift-cd2a98813.66

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 (65) hide show
  1. package/lib/_virtual/index.css.js +12 -12
  2. package/lib/constants.d.ts +0 -1
  3. package/lib/constants.js +1 -2
  4. package/lib/hooks/use-a11y.d.ts +29 -0
  5. package/lib/hooks/use-a11y.js +53 -0
  6. package/lib/hooks/use-backward-compatible-id.d.ts +4 -0
  7. package/lib/hooks/use-backward-compatible-id.js +14 -0
  8. package/lib/hooks/use-label-focus.d.ts +1 -3
  9. package/lib/hooks/use-label-focus.js +3 -9
  10. package/lib/hooks/use-multi-handlers.d.ts +11 -0
  11. package/lib/hooks/use-multi-handlers.js +48 -0
  12. package/lib/hooks/use-options.d.ts +13 -0
  13. package/lib/hooks/use-options.js +89 -0
  14. package/lib/index.css +323 -371
  15. package/lib/multiselect.d.ts +3 -29
  16. package/lib/multiselect.js +249 -174
  17. package/lib/native-select.js +67 -46
  18. package/lib/parts/hidden-select.d.ts +13 -0
  19. package/lib/parts/hidden-select.js +45 -0
  20. package/lib/parts/icons.d.ts +3 -1
  21. package/lib/parts/icons.js +11 -14
  22. package/lib/parts/list-box.d.ts +7 -15
  23. package/lib/parts/list-box.js +50 -82
  24. package/lib/parts/multi-trigger.d.ts +5 -4
  25. package/lib/parts/multi-trigger.js +27 -15
  26. package/lib/parts/native-select-trigger.d.ts +6 -8
  27. package/lib/parts/native-select-trigger.js +14 -23
  28. package/lib/select-basic.d.ts +2 -2
  29. package/lib/select-basic.js +161 -97
  30. package/lib/select-searchable.d.ts +2 -2
  31. package/lib/select-searchable.js +208 -122
  32. package/lib/select.d.ts +1 -1
  33. package/lib/select.js +38 -31
  34. package/lib/styles/common.p.module.css.js +25 -24
  35. package/lib/styles/form-trigger.p.module.css.js +12 -12
  36. package/lib/styles/list-box.p.module.css.js +11 -13
  37. package/lib/styles/native-select-trigger.p.module.css.js +15 -14
  38. package/lib/styles/native-select.p.module.css.js +6 -6
  39. package/lib/types.d.ts +26 -27
  40. package/lib/utils/get-real-items-cnt.d.ts +2 -2
  41. package/lib/utils/get-real-items-cnt.js +8 -10
  42. package/lib/utils/item-to-string.d.ts +2 -0
  43. package/lib/utils/item-to-string.js +7 -0
  44. package/lib/utils/merge-props.d.ts +29 -0
  45. package/lib/utils/merge-props.js +106 -0
  46. package/package.json +13 -22
  47. package/lib/hooks/use-css-context-transfer.d.ts +0 -14
  48. package/lib/hooks/use-css-context-transfer.js +0 -40
  49. package/lib/hooks/use-multi-option-serialization.d.ts +0 -10
  50. package/lib/hooks/use-multi-option-serialization.js +0 -82
  51. package/lib/hooks/use-observable-force-rerender.d.ts +0 -2
  52. package/lib/hooks/use-observable-force-rerender.js +0 -16
  53. package/lib/hooks/use-option-serialization.d.ts +0 -10
  54. package/lib/hooks/use-option-serialization.js +0 -59
  55. package/lib/parts/popover.d.ts +0 -12
  56. package/lib/parts/popover.js +0 -64
  57. package/lib/parts/popup-content.d.ts +0 -19
  58. package/lib/parts/popup-content.js +0 -76
  59. package/lib/styles/popover.p.module.css.js +0 -10
  60. package/lib/utils/convert-options.d.ts +0 -3
  61. package/lib/utils/convert-options.js +0 -52
  62. package/lib/utils/convert-placement.d.ts +0 -3
  63. package/lib/utils/convert-placement.js +0 -22
  64. package/lib/utils/css-vars-utils.d.ts +0 -3
  65. package/lib/utils/css-vars-utils.js +0 -20
@@ -1,19 +1,18 @@
1
1
  "use client";
2
- import React, { useState } from 'react';
2
+ import React from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import cn from 'classnames';
5
5
  import { useThemeWithUndefined } from '@rescui/ui-contexts';
6
6
  import { ErrorMessage } from '@rescui/form-field';
7
- import { useField } from '@react-aria/label';
8
- import { useFocusRing } from '@react-aria/focus';
9
- import { mergeProps } from '@react-aria/utils';
7
+ import { useFocus, useHover } from 'react-aria';
10
8
  import { nativeOptionType, nativeOptionsGroupType, noOptionsMessageType } from './common-prop-types.js';
9
+ import { useA11y } from './hooks/use-a11y.js';
11
10
  import { FormTriggerWrapper } from './parts/form-trigger-wrapper.js';
12
- import { isOptionAGroup } from './utils/is-option-a-group.js';
13
- import { getEmptyMessage } from './utils/get-empty-message.js';
14
- import { useLabelFocus } from './hooks/use-label-focus.js';
15
11
  import { NativeSelectTrigger } from './parts/native-select-trigger.js';
16
12
  import { NativeSelectOptionsWithGroups } from './parts/native-select-options-with-groups.js';
13
+ import { isOptionAGroup } from './utils/is-option-a-group.js';
14
+ import { getEmptyMessage } from './utils/get-empty-message.js';
15
+ import { mergeProps } from './utils/merge-props.js';
17
16
  import styles from './styles/native-select.p.module.css.js';
18
17
 
19
18
  function findSelectedOption(options, selectedValue) {
@@ -57,6 +56,7 @@ const NativeSelect = _ref => {
57
56
  placeholder,
58
57
  isLoading = false,
59
58
  isDisabled = false,
59
+ isClearable = false,
60
60
  trigger,
61
61
  label,
62
62
  note,
@@ -65,20 +65,25 @@ const NativeSelect = _ref => {
65
65
  noOptionsMessage,
66
66
  name,
67
67
  boldLabel = true,
68
- ...ariaRestProps
68
+ ...rest
69
69
  } = _ref;
70
+ const triggerRef = React.useRef(null);
70
71
  const {
71
72
  labelProps,
72
73
  fieldProps,
73
- descriptionProps,
74
- errorMessageProps
75
- } = useField({ ...ariaRestProps,
76
- label,
74
+ errorMessageProps,
75
+ descriptionProps
76
+ } = useA11y({
77
+ prefix: 'native-select',
78
+ error,
77
79
  description: note,
78
- errorMessage: error
80
+ label,
81
+ fieldRef: triggerRef
79
82
  });
83
+
84
+ const reset = () => onChange(null);
85
+
80
86
  const theme = useThemeWithUndefined(themeFromProps);
81
- const [isHovered, setIsHovered] = useState(false);
82
87
 
83
88
  const handleChange = event => {
84
89
  const newValue = event.target.value;
@@ -87,21 +92,24 @@ const NativeSelect = _ref => {
87
92
  if (onChange) {
88
93
  onChange(selectedOption);
89
94
  }
90
- };
95
+ }; // delete it when triggerFunc is migrated to the css-states instead of js-props for hover/focus
96
+ // replace it with ":focus + &" selector in that case
91
97
 
92
- const triggerRef = React.useRef(null);
98
+
99
+ const [isFocused, setIsFocused] = React.useState(false);
93
100
  const {
94
- isFocusVisible,
95
101
  focusProps
96
- } = useFocusRing({
97
- within: true
98
- });
102
+ } = useFocus({
103
+ isDisabled,
104
+ onFocusChange: setIsFocused
105
+ }); // same as above, could be replaced with ":hover + &" selector
106
+
99
107
  const {
100
- isFocusedByLabel,
101
- labelClickProps,
102
- triggerFocusProps: labelFocusForTriggerProps
103
- } = useLabelFocus(triggerRef);
104
- const isFocused = isFocusedByLabel || isFocusVisible;
108
+ isHovered,
109
+ hoverProps
110
+ } = useHover({
111
+ isDisabled
112
+ });
105
113
  const emptyListMessage = getEmptyMessage({
106
114
  isLoading,
107
115
  isNothingFound: false,
@@ -117,7 +125,7 @@ const NativeSelect = _ref => {
117
125
  size: size,
118
126
  disabled: isDisabled,
119
127
  label: label,
120
- labelProps: mergeProps(labelClickProps, labelProps),
128
+ labelProps: mergeProps(labelProps),
121
129
  boldLabel: boldLabel,
122
130
  error: error,
123
131
  errorMessageProps: errorMessageProps,
@@ -126,25 +134,14 @@ const NativeSelect = _ref => {
126
134
  descriptionProps: descriptionProps
127
135
  }, /*#__PURE__*/React.createElement("div", {
128
136
  className: styles.wrapper
129
- }, trigger ? trigger({
130
- focused: isFocused,
131
- hovered: isHovered,
132
- selectedLabel: value === null || value === void 0 ? void 0 : value.label,
133
- selectedValue: value === null || value === void 0 ? void 0 : value.value,
134
- placeholder
135
- }) : /*#__PURE__*/React.createElement(NativeSelectTrigger, {
136
- value: value,
137
- isLoading: isLoading,
138
- isFocused: isFocused,
139
- isHovered: isHovered,
140
- isDisabled: isDisabled,
141
- size: size,
142
- theme: theme,
143
- hasError: Boolean(error),
144
- placeholder: placeholder
145
- }), /*#__PURE__*/React.createElement("select", { ...mergeProps(fieldProps, focusProps, labelFocusForTriggerProps, {
146
- onMouseEnter: () => setIsHovered(true),
147
- onMouseLeave: () => setIsHovered(false)
137
+ }, /*#__PURE__*/React.createElement("select", { ...rest,
138
+ ...mergeProps(fieldProps, focusProps, hoverProps, {
139
+ onKeyDown: event => {
140
+ // backspace and backspace removing the last selected item (when popup is closed)
141
+ if (isClearable && (event.key === 'Backspace' || event.key === 'Delete')) {
142
+ reset();
143
+ }
144
+ }
148
145
  }),
149
146
  ref: triggerRef,
150
147
  "data-test": "native-select_select",
@@ -158,7 +155,31 @@ const NativeSelect = _ref => {
158
155
  optionsWithGroups: options,
159
156
  placeholder: placeholder,
160
157
  emptyListMessage: emptyListMessage
161
- })))));
158
+ })), trigger ? trigger({
159
+ focused: isFocused,
160
+ hovered: isHovered,
161
+ selectedLabel: value === null || value === void 0 ? void 0 : value.label,
162
+ selectedValue: value === null || value === void 0 ? void 0 : value.value,
163
+ placeholder
164
+ }) : /*#__PURE__*/React.createElement(NativeSelectTrigger, {
165
+ value: value,
166
+ isLoading: isLoading,
167
+ isDisabled: isDisabled,
168
+ isClearable: isClearable,
169
+ triggerId: fieldProps.id,
170
+ onClear: () => {
171
+ var _triggerRef$current;
172
+
173
+ reset();
174
+ (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
175
+ focusVisible: false
176
+ });
177
+ },
178
+ size: size,
179
+ theme: theme,
180
+ hasError: Boolean(error),
181
+ placeholder: placeholder
182
+ }))));
162
183
  };
163
184
 
164
185
  NativeSelect.propTypes = {
@@ -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;
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import styles from '../styles/common.p.module.css.js';
3
+
4
+ const HiddenSelect = _ref => {
5
+ let {
6
+ name,
7
+ options,
8
+ value,
9
+ isMultiple
10
+ } = _ref;
11
+ const selectProps = {
12
+ name,
13
+ 'aria-hidden': true,
14
+ readOnly: true,
15
+ tabIndex: -1
16
+ };
17
+
18
+ if (isMultiple) {
19
+ selectProps.multiple = true;
20
+
21
+ if (value && value.length !== 0) {
22
+ selectProps.value = value.map(v => String(v.value));
23
+ }
24
+ } else if (value) {
25
+ const singleValue = value;
26
+ selectProps.value = singleValue.value;
27
+ }
28
+
29
+ const arrayValue = isMultiple ? value : [value]; // merge options with value in case the provided value is not included in options
30
+
31
+ const allItems = Array.from( // map will deduplicate options by values
32
+ new Map((!value ? options : [...options, ...arrayValue]).map(item => [item.value, item])).values());
33
+ return /*#__PURE__*/React.createElement("div", {
34
+ className: styles.hiddenSelect
35
+ }, /*#__PURE__*/React.createElement("select", { ...selectProps
36
+ }, /*#__PURE__*/React.createElement("option", {
37
+ value: "",
38
+ label: '\u00A0'
39
+ }, '\u00A0'), allItems.map(option => /*#__PURE__*/React.createElement("option", {
40
+ key: option.value,
41
+ value: option.value
42
+ }, option.label))));
43
+ };
44
+
45
+ export { HiddenSelect };
@@ -5,6 +5,7 @@ declare type ClearOrLoadingProps = {
5
5
  onClearClick: () => void;
6
6
  triggerId?: string;
7
7
  className?: string;
8
+ customStylesMap?: Record<string, string>;
8
9
  };
9
10
  export declare const ClearOrLoading: React.FC<ClearOrLoadingProps>;
10
11
  export declare type IconsProps = {
@@ -12,6 +13,7 @@ export declare type IconsProps = {
12
13
  canHaveClearIcon?: boolean;
13
14
  onClear?: () => void;
14
15
  triggerId?: string;
16
+ customStylesMap?: Record<string, string>;
15
17
  };
16
- export declare const Icons: ({ isLoading, canHaveClearIcon, onClear, triggerId }: IconsProps) => JSX.Element;
18
+ export declare const Icons: ({ isLoading, canHaveClearIcon, onClear, triggerId, customStylesMap: styles }: IconsProps) => JSX.Element;
17
19
  export {};
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
2
  import cn from 'classnames';
3
- import { useFocusRing } from '@react-aria/focus';
4
3
  import CloseOutlineIcon from '../_virtual/close-outline.js';
5
4
  import LoadingOutlineIcon from '../_virtual/loading-outline.js';
6
5
  import DownOutlineIcon from '../_virtual/down-outline.js';
@@ -12,26 +11,23 @@ const ClearOrLoading = _ref => {
12
11
  canHaveClearIcon,
13
12
  onClearClick,
14
13
  triggerId,
15
- className
14
+ className,
15
+ customStylesMap: styles$1 = styles
16
16
  } = _ref;
17
- const {
18
- isFocusVisible,
19
- focusProps
20
- } = useFocusRing();
21
17
 
22
18
  if (isLoading) {
23
19
  return /*#__PURE__*/React.createElement(LoadingOutlineIcon, {
24
20
  style: {
25
21
  pointerEvents: 'none'
26
22
  },
27
- className: cn(className, styles.icon),
23
+ className: cn(className, styles$1.icon),
28
24
  "data-test": "loading-icon",
29
25
  "data-render-all-sizes": true
30
26
  });
31
27
  } else if (canHaveClearIcon) {
32
28
  return /*#__PURE__*/React.createElement("button", {
33
29
  type: "button",
34
- className: cn(className, styles.icon, styles.clearIcon, isFocusVisible && styles.clearIconFocusVisible),
30
+ className: cn(className, styles$1.icon, styles$1.clearIcon),
35
31
  "data-test": "clear-icon",
36
32
  onClick: e => {
37
33
  e.stopPropagation();
@@ -41,8 +37,7 @@ const ClearOrLoading = _ref => {
41
37
  onMouseDown: e => e.stopPropagation(),
42
38
  onKeyDown: e => e.stopPropagation(),
43
39
  "aria-label": "Clear",
44
- "aria-controls": triggerId,
45
- ...focusProps
40
+ "aria-controls": triggerId
46
41
  }, /*#__PURE__*/React.createElement(CloseOutlineIcon, {
47
42
  "data-render-all-sizes": true
48
43
  }));
@@ -56,17 +51,19 @@ const Icons = _ref2 => {
56
51
  isLoading,
57
52
  canHaveClearIcon,
58
53
  onClear,
59
- triggerId
54
+ triggerId,
55
+ customStylesMap: styles$1 = styles
60
56
  } = _ref2;
61
57
  return /*#__PURE__*/React.createElement("div", {
62
- className: styles.iconsWrapper
58
+ className: styles$1.iconsWrapper
63
59
  }, /*#__PURE__*/React.createElement(ClearOrLoading, {
64
60
  isLoading: isLoading,
65
61
  canHaveClearIcon: canHaveClearIcon,
66
62
  onClearClick: onClear,
67
- triggerId: triggerId
63
+ triggerId: triggerId,
64
+ customStylesMap: styles$1
68
65
  }), /*#__PURE__*/React.createElement(DownOutlineIcon, {
69
- className: styles.toggle,
66
+ className: styles$1.toggle,
70
67
  "data-test": "toggle-icon",
71
68
  "data-render-all-sizes": true
72
69
  }));
@@ -1,19 +1,11 @@
1
- import React from 'react';
2
- import type { ListState } from '@react-stately/list';
3
- import type { AriaListBoxOptions } from '@react-aria/listbox';
4
- import type { SelectSize, SelectMode } from '../types';
5
- export declare type ListBoxProps<T extends object> = {
6
- listBoxRef?: React.RefObject<HTMLUListElement>;
7
- state: ListState<T>;
8
- ariaListBoxProps?: AriaListBoxOptions<T>;
1
+ /// <reference types="react" />
2
+ import { SelectSize, ListBoxItem, ListBoxState } from '../types';
3
+ export declare type ListBoxProps = {
4
+ state: ListBoxState;
5
+ items: ListBoxItem[];
9
6
  size?: SelectSize;
10
- mode?: SelectMode;
11
7
  className?: string;
12
8
  maxVisibleItems?: number;
13
- selectionMode?: 'single' | 'multiple';
14
- };
15
- export declare function ListBox<T extends object>({ listBoxRef: listBoxRefFromProps, state, ariaListBoxProps, size, mode, maxVisibleItems, selectionMode }: ListBoxProps<T>): JSX.Element;
16
- export declare type EmptyListBoxProps<T extends object> = {
17
9
  emptyListMessage: string;
18
- } & Omit<ListBoxProps<T>, 'state'>;
19
- export declare const EmptyListBox: <T extends object>({ emptyListMessage, ...props }: EmptyListBoxProps<T>) => JSX.Element;
10
+ };
11
+ export declare function ListBox({ state, items, size, maxVisibleItems, emptyListMessage }: ListBoxProps): JSX.Element;
@@ -1,18 +1,10 @@
1
1
  import React, { useRef } from 'react';
2
2
  import cn from 'classnames';
3
- import { useListState } from '@react-stately/list';
4
- import { Item } from '@react-stately/collections';
5
- import { useListBox, useOption, useListBoxSection } from '@react-aria/listbox';
6
- import { mergeProps } from '@react-aria/utils';
7
3
  import styles from '../styles/list-box.p.module.css.js';
8
4
  import { calculateMaxHeightByItems } from '../utils/calculate-max-height-by-items.js';
9
5
  import { getRealItemsCnt } from '../utils/get-real-items-cnt.js';
10
- import { VIRTUAL_ITEMS_SECTION_KEY } from '../constants.js';
6
+ import { getTextFromNodes } from '../utils/get-text-from-nodes.js';
11
7
  import CheckOutlineIcon from '../_virtual/check-outline.js';
12
- const MODE_STYLES = {
13
- classic: styles.modeClassic,
14
- rock: styles.modeRock
15
- };
16
8
  const SIZE_STYLES = {
17
9
  s: styles.sizeS,
18
10
  m: styles.sizeM,
@@ -22,66 +14,65 @@ const SIZE_STYLES = {
22
14
  function Option(_ref) {
23
15
  let {
24
16
  item,
25
- state,
26
- selectionMode
17
+ state
27
18
  } = _ref;
28
19
  // Get props for the option element
29
20
  const ref = useRef(null);
30
21
  const {
31
- optionProps,
32
- isSelected,
33
- isFocused,
34
- isDisabled
35
- } = useOption({
36
- key: item.key
37
- }, state, ref);
38
- return /*#__PURE__*/React.createElement("li", { ...mergeProps(optionProps),
39
- ref: ref,
22
+ selectedMap,
23
+ selectionMode,
24
+ getItemProps,
25
+ highlightedIndex
26
+ } = state;
27
+ const index = item.index;
28
+ const isSelected = selectedMap.has(item.key);
29
+ const isHighlighted = highlightedIndex === item.index;
30
+ const isDisabled = item.disabled;
31
+ return /*#__PURE__*/React.createElement("li", { ...getItemProps({
32
+ item,
33
+ index,
34
+ 'aria-selected': isSelected,
35
+ 'tab-index': isHighlighted ? 0 : -1,
36
+ ref
37
+ }),
40
38
  className: cn(styles.item, isSelected && styles.selected, isDisabled && styles.disabled),
41
39
  "data-rs-internal": "select-list-box__item",
42
- "data-focused": isFocused,
40
+ "data-focused": isHighlighted,
43
41
  "data-test": `select-options-list__item_${item.key}`
44
- }, /*#__PURE__*/React.createElement("span", null, item.rendered), selectionMode === 'multiple' && /*#__PURE__*/React.createElement(CheckOutlineIcon, {
42
+ }, /*#__PURE__*/React.createElement("span", null, item.label), selectionMode === 'multiple' && /*#__PURE__*/React.createElement(CheckOutlineIcon, {
45
43
  "data-rs-internal": "select-list-box__check-icon",
46
44
  className: cn(styles.checkIcon, isSelected && styles.visible)
47
45
  }));
48
46
  }
49
47
 
50
- function ListBoxSection(_ref2) {
48
+ function ListBoxGroup(_ref2) {
51
49
  let {
52
- section,
53
- state,
50
+ item,
54
51
  isFirst,
55
- selectionMode
52
+ state
56
53
  } = _ref2;
57
- const {
58
- itemProps,
59
- headingProps,
60
- groupProps
61
- } = useListBoxSection({
62
- heading: section.rendered,
63
- 'aria-label': section['aria-label']
64
- });
65
- const hasHeading = section.rendered !== null && section.rendered !== undefined;
54
+ const hasHeading = item.label !== null && item.label !== undefined;
66
55
  const hasDivider = !isFirst && !hasHeading; // If the section is not the first, add a divider for visual separation
67
56
 
68
57
  return /*#__PURE__*/React.createElement(React.Fragment, null, hasDivider && /*#__PURE__*/React.createElement("hr", {
69
58
  className: styles.divider
70
- }), /*#__PURE__*/React.createElement("li", { ...itemProps
59
+ }), /*#__PURE__*/React.createElement("li", {
60
+ role: "presentation"
71
61
  }, hasHeading && /*#__PURE__*/React.createElement("span", {
72
62
  className: styles.groupHeader,
73
- ...headingProps,
63
+ role: "presentation",
74
64
  "data-rs-internal": "select-list-box__group-header"
75
- }, section.rendered), /*#__PURE__*/React.createElement("ul", { ...groupProps,
65
+ }, item.label), /*#__PURE__*/React.createElement("ul", {
66
+ role: "group",
67
+ "aria-label": hasHeading ? getTextFromNodes(item.label) : undefined,
76
68
  style: {
77
69
  padding: 0,
78
70
  listStyle: 'none'
79
71
  }
80
- }, [...state.collection.getChildren(section.key)].map(node => /*#__PURE__*/React.createElement(Option, {
81
- key: node.key,
82
- item: node,
83
- state: state,
84
- selectionMode: selectionMode
72
+ }, item.options.map(option => /*#__PURE__*/React.createElement(Option, {
73
+ key: option.key,
74
+ item: option,
75
+ state: state
85
76
  })))));
86
77
  }
87
78
 
@@ -89,60 +80,37 @@ function ListBox(_ref3) {
89
80
  var _items$find;
90
81
 
91
82
  let {
92
- listBoxRef: listBoxRefFromProps,
93
83
  state,
94
- ariaListBoxProps,
84
+ items,
95
85
  size,
96
- mode,
97
86
  maxVisibleItems = 5,
98
- selectionMode
87
+ emptyListMessage
99
88
  } = _ref3;
100
- const ref = useRef(null);
101
- const listBoxRef = listBoxRefFromProps ?? ref;
102
89
  const {
103
- listBoxProps
104
- } = useListBox(ariaListBoxProps, state, listBoxRef);
105
- const items = [...state.collection].filter(item => item.key !== VIRTUAL_ITEMS_SECTION_KEY);
106
- const firstSectionKey = (_items$find = items.find(item => item.type === 'section')) === null || _items$find === void 0 ? void 0 : _items$find.key;
107
- const itemsCount = getRealItemsCnt(state);
108
- return /*#__PURE__*/React.createElement("ul", { ...listBoxProps,
109
- className: cn(styles.listBox, MODE_STYLES[mode], SIZE_STYLES[size]),
110
- ref: listBoxRef,
90
+ menuProps
91
+ } = state;
92
+ const firstGroupKey = (_items$find = items.find(item => item.type === 'group')) === null || _items$find === void 0 ? void 0 : _items$find.key;
93
+ const itemsCount = getRealItemsCnt(items);
94
+ return /*#__PURE__*/React.createElement("ul", { ...menuProps,
95
+ className: cn(styles.listBox, SIZE_STYLES[size]),
111
96
  style: {
112
97
  '--_rs-select-list-box-max-height-by-items': calculateMaxHeightByItems(itemsCount, maxVisibleItems)
113
98
  },
114
99
  "data-rs-internal": "select-list-box",
115
100
  "data-test": "select-options-list"
116
- }, items.map(item => item.type === 'section' ? /*#__PURE__*/React.createElement(ListBoxSection, {
101
+ }, itemsCount === 0 ? /*#__PURE__*/React.createElement("li", {
102
+ className: cn(styles.item, styles.disabled),
103
+ "data-rs-internal": "select-list-box__item"
104
+ }, /*#__PURE__*/React.createElement("span", null, emptyListMessage)) : items.map(item => item.type === 'group' ? /*#__PURE__*/React.createElement(ListBoxGroup, {
117
105
  key: item.key,
118
- section: item,
106
+ item: item,
119
107
  state: state,
120
- isFirst: item.key === firstSectionKey,
121
- selectionMode: selectionMode
108
+ isFirst: item.key === firstGroupKey
122
109
  }) : /*#__PURE__*/React.createElement(Option, {
123
110
  key: item.key,
124
111
  item: item,
125
- state: state,
126
- selectionMode: selectionMode
112
+ state: state
127
113
  })));
128
114
  }
129
115
 
130
- const EmptyListBox = _ref4 => {
131
- let {
132
- emptyListMessage,
133
- ...props
134
- } = _ref4;
135
- const emptyListState = useListState({
136
- children: [/*#__PURE__*/React.createElement(Item, {
137
- key: "no-results",
138
- textValue: emptyListMessage
139
- }, emptyListMessage)],
140
- disabledKeys: ['no-results'],
141
- selectionMode: 'none'
142
- });
143
- return /*#__PURE__*/React.createElement(ListBox, { ...props,
144
- state: emptyListState
145
- });
146
- };
147
-
148
- export { EmptyListBox, ListBox };
116
+ export { ListBox };
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
- import type { SelectState } from '@react-stately/select';
3
- export interface MultiTriggerProps<T extends object> {
4
- state: SelectState<T, 'multiple'>;
2
+ import type { SelectOption } from '../types';
3
+ export interface MultiTriggerProps {
4
+ selectedItems: SelectOption[];
5
+ removeSelectedItem: (item: SelectOption) => void;
5
6
  valueProps: object;
6
7
  isSingleLine: boolean;
7
8
  isDisabled: boolean;
8
9
  placeholder?: string;
9
10
  triggerRef?: React.RefObject<HTMLDivElement>;
10
11
  }
11
- export declare function MultiTrigger<T extends object>({ state, valueProps, isSingleLine, isDisabled, placeholder, triggerRef }: MultiTriggerProps<T>): JSX.Element;
12
+ export declare function MultiTrigger({ selectedItems, valueProps, isSingleLine, isDisabled, placeholder, triggerRef, removeSelectedItem }: MultiTriggerProps): JSX.Element;
@@ -3,18 +3,20 @@ import cn from 'classnames';
3
3
  import { RemovableTag, Tag } from '@rescui/tag';
4
4
  import styles from '../styles/common.p.module.css.js';
5
5
  import { getTextFromNodes } from '../utils/get-text-from-nodes.js';
6
+ import { getOptionValue } from '../utils/get-option-value.js';
6
7
  import Foldable from './foldable.js';
7
8
 
8
9
  function MultiTrigger(_ref) {
9
10
  let {
10
- state,
11
+ selectedItems,
11
12
  valueProps,
12
13
  isSingleLine,
13
14
  isDisabled,
14
15
  placeholder,
15
- triggerRef
16
+ triggerRef,
17
+ removeSelectedItem
16
18
  } = _ref;
17
- const hasValue = state.selectedItems.length > 0;
19
+ const hasValue = selectedItems.length > 0;
18
20
 
19
21
  if (!hasValue) {
20
22
  return /*#__PURE__*/React.createElement("div", { ...valueProps,
@@ -23,25 +25,35 @@ function MultiTrigger(_ref) {
23
25
  }, placeholder);
24
26
  }
25
27
 
26
- const handleRemoveItem = key => {
27
- var _triggerRef$current;
28
-
29
- state.setValue([...state.selectedItems].map(item => item.key).filter(itemKey => itemKey !== key));
30
- (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus();
31
- };
32
-
33
- const tags = [...state.selectedItems].map(item => {
34
- const key = item.key;
28
+ const tags = selectedItems.map(option => {
29
+ const key = getOptionValue(option);
35
30
  return /*#__PURE__*/React.createElement(RemovableTag, {
36
31
  key: key,
32
+ tabIndex: -1,
37
33
  "data-test": `selected-tag-${key}`,
38
34
  className: styles.tag,
39
35
  disabled: isDisabled,
40
- onRemoveClick: () => handleRemoveItem(key),
36
+ onRemoveClick: () => {
37
+ var _triggerRef$current;
38
+
39
+ removeSelectedItem(option);
40
+ (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 || _triggerRef$current.focus({
41
+ focusVisible: false
42
+ });
43
+ },
41
44
  "data-rs-internal": "select-trigger__removable-tag",
42
45
  wrap: !isSingleLine,
43
- "aria-label": getTextFromNodes(item.rendered)
44
- }, item.rendered);
46
+ "aria-label": getTextFromNodes(option.label),
47
+ onFocus: e => {
48
+ if (e.target.getAttribute('tabindex') === '-1') {
49
+ var _triggerRef$current2;
50
+
51
+ (_triggerRef$current2 = triggerRef.current) === null || _triggerRef$current2 === void 0 || _triggerRef$current2.focus({
52
+ focusVisible: false
53
+ });
54
+ }
55
+ }
56
+ }, option.label);
45
57
  });
46
58
  return /*#__PURE__*/React.createElement("div", { ...valueProps,
47
59
  className: styles.multi,
@@ -1,18 +1,16 @@
1
1
  /// <reference types="react" />
2
2
  import type { Theme } from '@rescui/ui-contexts';
3
- import { Key, SelectSize } from '../types';
3
+ import { NativeSelectOption, SelectSize } from '../types';
4
4
  export declare type NativeSelectDefaultTriggerProps = {
5
- isFocused: boolean;
6
- isHovered: boolean;
7
5
  isLoading: boolean;
8
6
  isDisabled: boolean;
7
+ isClearable: boolean;
9
8
  size: SelectSize;
10
9
  theme?: Theme;
11
10
  hasError: boolean;
12
11
  placeholder?: string;
13
- value: {
14
- value?: Key;
15
- label: string;
16
- };
12
+ value: NativeSelectOption;
13
+ onClear?: () => void;
14
+ triggerId?: string;
17
15
  };
18
- export declare const NativeSelectTrigger: ({ isFocused, isHovered, isLoading, isDisabled, hasError, size, theme, placeholder, value }: NativeSelectDefaultTriggerProps) => JSX.Element;
16
+ export declare const NativeSelectTrigger: ({ isLoading, isDisabled, isClearable, hasError, size, theme, placeholder, value, onClear, triggerId }: NativeSelectDefaultTriggerProps) => JSX.Element;