@rescui/select 0.15.1-RUI-280-Update-select-component-separate-components-e772abaa1.56 → 0.15.1-RUI-280-Update-select-component-downshift-2f40ef205.67

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 (70) 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-focus.d.ts +10 -0
  9. package/lib/hooks/use-focus.js +17 -0
  10. package/lib/hooks/use-hover.d.ts +10 -0
  11. package/lib/hooks/use-hover.js +17 -0
  12. package/lib/hooks/use-label-focus.d.ts +1 -3
  13. package/lib/hooks/use-label-focus.js +3 -9
  14. package/lib/hooks/use-multi-handlers.d.ts +11 -0
  15. package/lib/hooks/use-multi-handlers.js +48 -0
  16. package/lib/hooks/use-options.d.ts +13 -0
  17. package/lib/hooks/use-options.js +89 -0
  18. package/lib/index.css +423 -1195
  19. package/lib/multiselect.d.ts +3 -29
  20. package/lib/multiselect.js +250 -180
  21. package/lib/native-select.js +75 -48
  22. package/lib/parts/hidden-select.d.ts +13 -0
  23. package/lib/parts/hidden-select.js +45 -0
  24. package/lib/parts/icons.js +2 -8
  25. package/lib/parts/list-box.d.ts +7 -15
  26. package/lib/parts/list-box.js +50 -82
  27. package/lib/parts/multi-trigger.d.ts +5 -4
  28. package/lib/parts/multi-trigger.js +27 -15
  29. package/lib/public-api.p.css +368 -126
  30. package/lib/public-api.pcss +368 -126
  31. package/lib/select-basic.d.ts +2 -2
  32. package/lib/select-basic.js +160 -103
  33. package/lib/select-searchable.d.ts +2 -2
  34. package/lib/select-searchable.js +205 -127
  35. package/lib/select.d.ts +1 -1
  36. package/lib/select.js +38 -31
  37. package/lib/styles/common.p.module.css.js +28 -24
  38. package/lib/styles/form-trigger.p.module.css.js +12 -12
  39. package/lib/styles/list-box.p.module.css.js +11 -13
  40. package/lib/types.d.ts +26 -27
  41. package/lib/utils/get-real-items-cnt.d.ts +2 -2
  42. package/lib/utils/get-real-items-cnt.js +8 -10
  43. package/lib/utils/item-to-string.d.ts +2 -0
  44. package/lib/utils/item-to-string.js +7 -0
  45. package/lib/utils/merge-props.d.ts +29 -0
  46. package/lib/utils/merge-props.js +106 -0
  47. package/package.json +11 -23
  48. package/lib/hooks/use-css-context-transfer.d.ts +0 -14
  49. package/lib/hooks/use-css-context-transfer.js +0 -40
  50. package/lib/hooks/use-multi-option-serialization.d.ts +0 -10
  51. package/lib/hooks/use-multi-option-serialization.js +0 -82
  52. package/lib/hooks/use-observable-force-rerender.d.ts +0 -2
  53. package/lib/hooks/use-observable-force-rerender.js +0 -16
  54. package/lib/hooks/use-option-serialization.d.ts +0 -10
  55. package/lib/hooks/use-option-serialization.js +0 -59
  56. package/lib/parts/native-select-trigger.d.ts +0 -18
  57. package/lib/parts/native-select-trigger.js +0 -54
  58. package/lib/parts/popover.d.ts +0 -12
  59. package/lib/parts/popover.js +0 -64
  60. package/lib/parts/popup-content.d.ts +0 -19
  61. package/lib/parts/popup-content.js +0 -76
  62. package/lib/styles/native-select-trigger.p.module.css.js +0 -17
  63. package/lib/styles/native-select.p.module.css.js +0 -9
  64. package/lib/styles/popover.p.module.css.js +0 -10
  65. package/lib/utils/convert-options.d.ts +0 -3
  66. package/lib/utils/convert-options.js +0 -52
  67. package/lib/utils/convert-placement.d.ts +0 -3
  68. package/lib/utils/convert-placement.js +0 -22
  69. package/lib/utils/css-vars-utils.d.ts +0 -3
  70. package/lib/utils/css-vars-utils.js +0 -20
@@ -1,20 +1,20 @@
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';
10
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
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';
12
14
  import { isOptionAGroup } from './utils/is-option-a-group.js';
13
15
  import { getEmptyMessage } from './utils/get-empty-message.js';
14
- import { useLabelFocus } from './hooks/use-label-focus.js';
15
- import { NativeSelectTrigger } from './parts/native-select-trigger.js';
16
- import { NativeSelectOptionsWithGroups } from './parts/native-select-options-with-groups.js';
17
- import styles from './styles/native-select.p.module.css.js';
16
+ import { mergeProps } from './utils/merge-props.js';
17
+ import styles from './styles/common.p.module.css.js';
18
18
 
19
19
  function findSelectedOption(options, selectedValue) {
20
20
  let result = null;
@@ -42,6 +42,10 @@ const SIZE_STYLES = {
42
42
  s: styles.sizeS,
43
43
  m: styles.sizeM,
44
44
  l: styles.sizeL
45
+ };
46
+ const THEME_STYLES = {
47
+ light: styles.themeLight,
48
+ dark: styles.themeDark
45
49
  }; // eslint-disable-next-line complexity
46
50
 
47
51
  const NativeSelect = _ref => {
@@ -57,6 +61,7 @@ const NativeSelect = _ref => {
57
61
  placeholder,
58
62
  isLoading = false,
59
63
  isDisabled = false,
64
+ isClearable = false,
60
65
  trigger,
61
66
  label,
62
67
  note,
@@ -65,20 +70,25 @@ const NativeSelect = _ref => {
65
70
  noOptionsMessage,
66
71
  name,
67
72
  boldLabel = true,
68
- ...ariaRestProps
73
+ ...rest
69
74
  } = _ref;
75
+ const triggerRef = React.useRef(null);
70
76
  const {
71
77
  labelProps,
72
78
  fieldProps,
73
- descriptionProps,
74
- errorMessageProps
75
- } = useField({ ...ariaRestProps,
76
- label,
79
+ errorMessageProps,
80
+ descriptionProps
81
+ } = useA11y({
82
+ prefix: 'native-select',
83
+ error,
77
84
  description: note,
78
- errorMessage: error
85
+ label,
86
+ fieldRef: triggerRef
79
87
  });
88
+
89
+ const reset = () => onChange(null);
90
+
80
91
  const theme = useThemeWithUndefined(themeFromProps);
81
- const [isHovered, setIsHovered] = useState(false);
82
92
 
83
93
  const handleChange = event => {
84
94
  const newValue = event.target.value;
@@ -87,28 +97,30 @@ const NativeSelect = _ref => {
87
97
  if (onChange) {
88
98
  onChange(selectedOption);
89
99
  }
90
- };
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
+
91
103
 
92
- const triggerRef = React.useRef(null);
93
104
  const {
94
- isFocusVisible,
105
+ isFocused,
95
106
  focusProps
96
- } = useFocusRing({
97
- within: true
98
- });
107
+ } = useFocus({
108
+ isDisabled
109
+ }); // same as above, could be replaced with ":hover + &" selector
110
+
99
111
  const {
100
- isFocusedByLabel,
101
- labelClickProps,
102
- triggerFocusProps: labelFocusForTriggerProps
103
- } = useLabelFocus(triggerRef);
104
- const isFocused = isFocusedByLabel || isFocusVisible;
112
+ isHovered,
113
+ hoverProps
114
+ } = useHover({
115
+ isDisabled
116
+ });
105
117
  const emptyListMessage = getEmptyMessage({
106
118
  isLoading,
107
119
  isNothingFound: false,
108
120
  noOptionsMessage
109
121
  });
110
122
  return /*#__PURE__*/React.createElement("div", {
111
- className: cn(className, styles.main, SIZE_STYLES[size]),
123
+ className: cn(className, styles.root, SIZE_STYLES[size], THEME_STYLES[theme], styles.classic, isDisabled ? styles.disabled : styles.enabled, Boolean(error) && styles.error),
112
124
  id: id,
113
125
  style: style,
114
126
  "data-test": "native-select"
@@ -117,7 +129,7 @@ const NativeSelect = _ref => {
117
129
  size: size,
118
130
  disabled: isDisabled,
119
131
  label: label,
120
- labelProps: mergeProps(labelClickProps, labelProps),
132
+ labelProps: mergeProps(labelProps),
121
133
  boldLabel: boldLabel,
122
134
  error: error,
123
135
  errorMessageProps: errorMessageProps,
@@ -125,26 +137,15 @@ const NativeSelect = _ref => {
125
137
  note: note,
126
138
  descriptionProps: descriptionProps
127
139
  }, /*#__PURE__*/React.createElement("div", {
128
- 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)
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
+ }
148
149
  }),
149
150
  ref: triggerRef,
150
151
  "data-test": "native-select_select",
@@ -158,6 +159,32 @@ const NativeSelect = _ref => {
158
159
  optionsWithGroups: options,
159
160
  placeholder: placeholder,
160
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)
161
188
  })))));
162
189
  };
163
190
 
@@ -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.visuallyHidden
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 };
@@ -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';
@@ -14,10 +13,6 @@ const ClearOrLoading = _ref => {
14
13
  triggerId,
15
14
  className
16
15
  } = _ref;
17
- const {
18
- isFocusVisible,
19
- focusProps
20
- } = useFocusRing();
21
16
 
22
17
  if (isLoading) {
23
18
  return /*#__PURE__*/React.createElement(LoadingOutlineIcon, {
@@ -31,7 +26,7 @@ const ClearOrLoading = _ref => {
31
26
  } else if (canHaveClearIcon) {
32
27
  return /*#__PURE__*/React.createElement("button", {
33
28
  type: "button",
34
- className: cn(className, styles.icon, styles.clearIcon, isFocusVisible && styles.clearIconFocusVisible),
29
+ className: cn(className, styles.icon, styles.clearIcon),
35
30
  "data-test": "clear-icon",
36
31
  onClick: e => {
37
32
  e.stopPropagation();
@@ -41,8 +36,7 @@ const ClearOrLoading = _ref => {
41
36
  onMouseDown: e => e.stopPropagation(),
42
37
  onKeyDown: e => e.stopPropagation(),
43
38
  "aria-label": "Clear",
44
- "aria-controls": triggerId,
45
- ...focusProps
39
+ "aria-controls": triggerId
46
40
  }, /*#__PURE__*/React.createElement(CloseOutlineIcon, {
47
41
  "data-render-all-sizes": true
48
42
  }));
@@ -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,