@ringcentral/spring-ui 1.7.0 → 1.8.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 (233) hide show
  1. package/Alert.js +3 -3
  2. package/Announcement.js +1 -1
  3. package/Autocomplete.js +174 -236
  4. package/Avatar.js +27 -13
  5. package/BottomNavigation.js +0 -3
  6. package/Checkbox.js +0 -2
  7. package/DatePicker.js +5 -13
  8. package/DateUtilsContext.js +0 -1
  9. package/Dialer.js +2 -50
  10. package/Dialog.js +4 -4
  11. package/Dropdown.js +0 -7
  12. package/FocusTrap.js +0 -32
  13. package/InlineEditable.js +0 -4
  14. package/Link.js +1 -1
  15. package/ListItem.js +1 -1
  16. package/ListNavigation.js +0 -6
  17. package/Menu.js +1 -1
  18. package/MenuDivider.js +2 -2
  19. package/MenuFooter.js +4 -4
  20. package/MenuHeader.js +4 -4
  21. package/MenuItem.js +1 -1
  22. package/MenuItemText.js +1 -1
  23. package/PageHeader.js +6 -4
  24. package/Popper.js +0 -1
  25. package/Rating.js +0 -5
  26. package/SingleFilter.js +0 -1
  27. package/Slider.js +1 -4
  28. package/Snackbar.js +0 -14
  29. package/SortableListItem.js +0 -1
  30. package/SplitButton.js +1 -3
  31. package/StatusIndicator.js +1 -1
  32. package/SubMenu.js +0 -4
  33. package/SwipeableDrawer.js +8 -146
  34. package/Switch.js +1 -4
  35. package/Tab.js +7 -8
  36. package/TabContext.js +0 -5
  37. package/TableBody.js +1 -1
  38. package/TableCell.js +0 -6
  39. package/TableRow.js +0 -1
  40. package/Tabs.js +20 -118
  41. package/Text.js +2 -4
  42. package/TimePicker.js +7 -46
  43. package/VirtualizedList.js +2 -30
  44. package/chunks/Alert.js +8 -7
  45. package/chunks/BottomNavigationItem.js +0 -1
  46. package/chunks/Button.js +0 -1
  47. package/chunks/Chip.js +0 -5
  48. package/chunks/Drawer.js +1 -30
  49. package/chunks/ListItem.js +3 -6
  50. package/chunks/Menu.js +3 -3
  51. package/chunks/MenuDivider.js +2 -3
  52. package/chunks/MenuItemText.js +3 -3
  53. package/chunks/MenuList.js +0 -3
  54. package/chunks/PickerTextField.js +0 -1
  55. package/chunks/Popover.js +0 -5
  56. package/chunks/Select.js +2 -39
  57. package/chunks/Squircle.js +0 -7
  58. package/chunks/StatusIndicator.js +1 -0
  59. package/chunks/StepIcon.js +1 -3
  60. package/chunks/StepperContext.js +0 -7
  61. package/chunks/Tooltip.js +0 -36
  62. package/chunks/VirtualizedMenu.js +2 -78
  63. package/chunks/getFade.js +2 -0
  64. package/chunks/useFocusTrapStack.js +0 -8
  65. package/chunks/useHelperTextId.js +0 -24
  66. package/chunks/useListNavigation.js +2 -17
  67. package/chunks/useMenuItemSelect.js +6 -19
  68. package/chunks/useMotionSafeTransition.js +0 -4
  69. package/chunks/useNestedParentMenu.js +0 -2
  70. package/chunks/usePrefersReducedMotion.js +0 -10
  71. package/chunks/useTooltipForceHide.js +0 -4
  72. package/chunks/useTrayNavigate.js +0 -1
  73. package/index.css +392 -120
  74. package/index.js +1 -1
  75. package/package.json +4 -4
  76. package/src/Accordion/Accordion.type.d.ts +0 -21
  77. package/src/AccordionHeader/AccordionHeader.type.d.ts +0 -14
  78. package/src/Alert/Alert.type.d.ts +0 -32
  79. package/src/Animation/components/ExpandCollapseCaret/ExpandCollapseCaret.d.ts +0 -4
  80. package/src/Animation/components/ShowHideEye/ShowHideEye.d.ts +0 -4
  81. package/src/Animation/hooks/useMotionSafeTransition/useMotionSafeTransition.d.ts +0 -4
  82. package/src/Autocomplete/Autocomplete.d.ts +0 -5
  83. package/src/Autocomplete/Autocomplete.type.d.ts +0 -84
  84. package/src/Autocomplete/SuggestionList/SuggestionList.d.ts +5 -89
  85. package/src/Autocomplete/SuggestionList/SuggestionListItem.d.ts +0 -2
  86. package/src/Autocomplete/SuggestionList/utils/SuggestionListItem.d.ts +1 -13
  87. package/src/Autocomplete/SuggestionList/utils/useDynamicHeight.d.ts +0 -6
  88. package/src/Autocomplete/SuggestionList/utils/useHighlightScroll.d.ts +0 -20
  89. package/src/Autocomplete/SuggestionList/utils/useSuggestionList.d.ts +3 -41
  90. package/src/Autocomplete/SuggestionList/utils/useSuggestionListGroup.d.ts +0 -49
  91. package/src/Autocomplete/useAutocomplete.d.ts +1 -62
  92. package/src/Autocomplete/useAutocompleteTag.d.ts +0 -33
  93. package/src/Avatar/Avatar.type.d.ts +0 -58
  94. package/src/AvatarGroup/AvatarGroup.type.d.ts +0 -3
  95. package/src/Backdrop/Backdrop.type.d.ts +0 -4
  96. package/src/Badge/Badge.type.d.ts +0 -33
  97. package/src/Block/Block.type.d.ts +0 -24
  98. package/src/BlockHeader/BlockHeader.type.d.ts +0 -5
  99. package/src/BottomNavigation/BottomNavigation.type.d.ts +0 -34
  100. package/src/BottomNavigationItem/BottomNavigationItem.type.d.ts +0 -39
  101. package/src/Button/Button.type.d.ts +0 -30
  102. package/src/CallButton/CallButton.type.d.ts +0 -4
  103. package/src/Checkbox/Checkbox.type.d.ts +0 -17
  104. package/src/Chip/Chip.type.d.ts +0 -41
  105. package/src/CircularProgressIndicator/CircularProgressIndicator.type.d.ts +0 -19
  106. package/src/DatePicker/Calendar.d.ts +1 -20
  107. package/src/DatePicker/DatePicker.type.d.ts +0 -18
  108. package/src/DatePicker/DatePickerHeader.d.ts +1 -12
  109. package/src/DatePicker/Day.d.ts +0 -7
  110. package/src/DatePicker/Year.d.ts +0 -6
  111. package/src/DatePicker/Years.d.ts +0 -7
  112. package/src/Dialer/DialDelete/DialDelete.d.ts +0 -3
  113. package/src/Dialer/DialPad/DialPad.d.ts +0 -106
  114. package/src/Dialer/DialPad/utils/types.d.ts +0 -5
  115. package/src/Dialer/DialPad/utils/useDialKeyboard.d.ts +0 -5
  116. package/src/Dialer/DialPad/utils/useKeyAudio.d.ts +0 -9
  117. package/src/Dialer/DialPadButton/DialPadButton.d.ts +0 -14
  118. package/src/Dialer/DialTextField/DialTextField.d.ts +0 -23
  119. package/src/Dialer/DialTextField/utils/getDialPadValueOnlyRegex.d.ts +0 -3
  120. package/src/Dialer/DialTextField/utils/useFixedEndSelection.d.ts +0 -3
  121. package/src/Dialog/Dialog.type.d.ts +0 -11
  122. package/src/Divider/Divider.type.d.ts +0 -17
  123. package/src/DragHandle/DragHandle.type.d.ts +0 -4
  124. package/src/Drawer/Drawer.d.ts +0 -28
  125. package/src/Drawer/Drawer.type.d.ts +0 -84
  126. package/src/Dropdown/Dropdown.type.d.ts +0 -64
  127. package/src/EmptyState/EmptyState.type.d.ts +0 -12
  128. package/src/FabButton/FabButton.type.d.ts +0 -5
  129. package/src/FocusTrap/FocusTrap.d.ts +0 -38
  130. package/src/FocusTrap/useFocusTrapStack.d.ts +0 -9
  131. package/src/FormField/FormField.type.d.ts +0 -26
  132. package/src/FormField/useHelperTextId.d.ts +0 -25
  133. package/src/FormLabel/FormLabel.type.d.ts +0 -14
  134. package/src/Icon/Icon.type.d.ts +0 -15
  135. package/src/IconButton/IconButton.type.d.ts +0 -30
  136. package/src/IconButton/IconButtonLabel.type.d.ts +0 -3
  137. package/src/IconButtonGroup/IconButtonGroup.type.d.ts +0 -8
  138. package/src/InlineEditable/InlineEditable.type.d.ts +0 -75
  139. package/src/LinearProgressIndicator/LinearProgressIndicator.type.d.ts +0 -31
  140. package/src/Link/Link.classes.d.ts +1 -1
  141. package/src/Link/Link.type.d.ts +1 -10
  142. package/src/ListItem/ListItem.type.d.ts +0 -41
  143. package/src/ListItemText/ListItemText.type.d.ts +0 -21
  144. package/src/ListNavigation/useListNavigation.d.ts +0 -16
  145. package/src/Menu/Menu.type.d.ts +0 -10
  146. package/src/MenuFooter/MenuFooter.type.d.ts +0 -4
  147. package/src/MenuHeader/MenuHeader.type.d.ts +0 -10
  148. package/src/MenuItem/MenuItem.type.d.ts +0 -19
  149. package/src/MenuItem/MenuItemSelectContext.d.ts +0 -3
  150. package/src/MenuItem/useMenuItemSelect.d.ts +0 -21
  151. package/src/MenuItemText/MenuItemText.type.d.ts +0 -17
  152. package/src/MenuList/MenuList.type.d.ts +0 -4
  153. package/src/MenuList/MenuListContext.d.ts +0 -6
  154. package/src/Modal/InnerModal.type.d.ts +0 -5
  155. package/src/Modal/Modal.type.d.ts +0 -11
  156. package/src/Modal/ModalContext.d.ts +0 -4
  157. package/src/Option/Option.type.d.ts +0 -3
  158. package/src/Overlap/Overlap.type.d.ts +0 -11
  159. package/src/PageHeader/PageHeader.type.d.ts +0 -4
  160. package/src/PickerTextField/PickerTextField.type.d.ts +0 -10
  161. package/src/Popover/Popover.type.d.ts +0 -29
  162. package/src/Popper/Popper.type.d.ts +0 -61
  163. package/src/Radio/Radio.type.d.ts +0 -5
  164. package/src/RadioGroup/RadioGroup.type.d.ts +0 -4
  165. package/src/Rating/Rating.type.d.ts +0 -74
  166. package/src/Select/Select.type.d.ts +0 -84
  167. package/src/SingleFilter/FilterButton/FilterButton.type.d.ts +0 -16
  168. package/src/SingleFilter/SingleFilter.type.d.ts +0 -26
  169. package/src/Skeleton/Skeleton.type.d.ts +0 -1
  170. package/src/Skeleton/SkeletonContainer/SkeletonContainer.classes.d.ts +1 -1
  171. package/src/Slider/Slider.classes.d.ts +1 -5
  172. package/src/Slider/Slider.type.d.ts +0 -104
  173. package/src/Snackbar/Snackbar.type.d.ts +0 -18
  174. package/src/SplitButton/SplitButton.type.d.ts +0 -21
  175. package/src/Squircle/Squircle.type.d.ts +0 -3
  176. package/src/StatusIndicator/StatusIndicator.classes.d.ts +1 -1
  177. package/src/StatusIndicator/StatusIndicator.type.d.ts +1 -9
  178. package/src/Step/Step.type.d.ts +0 -29
  179. package/src/Step/StepContext.d.ts +0 -7
  180. package/src/StepButton/StepButton.type.d.ts +0 -15
  181. package/src/StepContent/StepContent.type.d.ts +0 -7
  182. package/src/StepIcon/StepIcon.type.d.ts +0 -26
  183. package/src/StepLabel/StepLabel.type.d.ts +0 -23
  184. package/src/Stepper/Stepper.type.d.ts +0 -27
  185. package/src/SwipeableDrawer/SwipeableDrawer.d.ts +0 -26
  186. package/src/SwipeableDrawer/SwipeableDrawer.types.d.ts +0 -67
  187. package/src/SwipeableDrawer/hooks/useDrawerGestures.d.ts +0 -110
  188. package/src/SwipeableDrawer/hooks/useElementSizeObserver.d.ts +0 -5
  189. package/src/SwipeableDrawer/hooks/useSnapPoints.d.ts +0 -60
  190. package/src/Switch/Switch.type.d.ts +0 -9
  191. package/src/Tab/Tab.classes.d.ts +3 -2
  192. package/src/Tab/Tab.type.d.ts +0 -29
  193. package/src/TabContext/TabContext.d.ts +0 -4
  194. package/src/TabContext/TabContext.type.d.ts +0 -7
  195. package/src/TabPanel/TabPanel.type.d.ts +0 -10
  196. package/src/Table/Table.type.d.ts +0 -19
  197. package/src/TableBody/TableBody.type.d.ts +0 -3
  198. package/src/TableCell/TableCell.d.ts +0 -4
  199. package/src/TableCell/TableCell.type.d.ts +0 -35
  200. package/src/TableContainer/TableContainer.type.d.ts +0 -7
  201. package/src/TableFooter/TableFooter.type.d.ts +0 -3
  202. package/src/TableHead/TableHead.type.d.ts +0 -6
  203. package/src/TablePagination/TablePagination.type.d.ts +0 -47
  204. package/src/TableRow/TableRow.type.d.ts +0 -17
  205. package/src/Tabs/TabMoreMenu.d.ts +0 -16
  206. package/src/Tabs/TabScrollButton.d.ts +0 -10
  207. package/src/Tabs/Tabs.classes.d.ts +1 -1
  208. package/src/Tabs/Tabs.d.ts +1 -1
  209. package/src/Tabs/Tabs.type.d.ts +2 -36
  210. package/src/Tabs/TabsContext.d.ts +2 -0
  211. package/src/Tabs/hooks/useTabsScroller.d.ts +0 -30
  212. package/src/Tag/Tag.type.d.ts +0 -12
  213. package/src/Text/Text.type.d.ts +0 -13
  214. package/src/TextField/TextField.type.d.ts +0 -64
  215. package/src/Textarea/Textarea.type.d.ts +0 -13
  216. package/src/TimePicker/NumberPicker.type.d.ts +0 -12
  217. package/src/TimePicker/SelectionView.d.ts +0 -6
  218. package/src/TimePicker/TimeButton.d.ts +0 -3
  219. package/src/TimePicker/TimePicker.type.d.ts +0 -11
  220. package/src/TimePicker/ToggleText.type.d.ts +0 -3
  221. package/src/TimePicker/utils/TimeBoundary.d.ts +0 -3
  222. package/src/TimePicker/utils/TimePickerHelper.d.ts +0 -19
  223. package/src/TimePicker/utils/getNumberPickerBoundary.d.ts +0 -3
  224. package/src/Tooltip/TooltipTrigger.a11y.d.ts +0 -9
  225. package/src/Tooltip/TooltipTrigger.type.d.ts +0 -44
  226. package/src/Tooltip/TooltipView.type.d.ts +0 -25
  227. package/src/Tooltip/useTooltipForceHide.d.ts +0 -4
  228. package/src/Tray/Tray.type.d.ts +0 -13
  229. package/src/Tray/TrayContext.d.ts +0 -4
  230. package/src/Tray/hooks/useTray.d.ts +0 -16
  231. package/src/Tray/hooks/useTrayPanel.d.ts +0 -3
  232. package/src/VirtualizedList/VirtualizedList.type.d.ts +0 -27
  233. package/src/VirtualizedMenu/VirtualizedMenu.type.d.ts +0 -17
package/Autocomplete.js CHANGED
@@ -2,12 +2,12 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { forwardRef, useRef, useMemo, useCallback, useEffect, useLayoutEffect, useState, useImperativeHandle } from 'react';
3
3
  import clsx from 'clsx';
4
4
  import { Virtuoso } from 'react-virtuoso';
5
- import { useClasses, usePrevious, useRefState, useEventCallback, logInDev, combineProps, useDepsChange, useControlled, useId, useForceUpdate, useKeyboardMoveFocus, useForkRef, useSleep, useRetry, useChange, getSelectionPosition } from '@ringcentral/spring-base';
6
- import { useThemeProps } from '@ringcentral/spring-theme';
5
+ import { usePrevious, useWindowContext, useRefState, useEventCallback, logInDev, combineProps, useDepsChange, useControlled, useId, useForceUpdate, useKeyboardMoveFocus, useForkRef, useSleep, useRetry, useChange, getSelectionPosition, useClasses } from '@ringcentral/spring-base';
6
+ import { useClassesWithMode, useThemeProps } from '@ringcentral/spring-theme';
7
7
  import { E as ExpandCollapseCaret } from './chunks/ExpandCollapseCaret.js';
8
- import { I as IconButton } from './chunks/IconButtonLabel.js';
9
8
  import { AnimatePresence, motion } from 'framer-motion';
10
9
  import './chunks/Icon.js';
10
+ import { I as IconButton } from './chunks/IconButtonLabel.js';
11
11
  import { Xsm } from '@ringcentral/spring-icon';
12
12
  import { u as usePrefersReducedMotion } from './chunks/usePrefersReducedMotion.js';
13
13
  import { g as getFade } from './chunks/getFade.js';
@@ -28,11 +28,11 @@ import './chunks/Backdrop.js';
28
28
  import './chunks/ShowHideEye.js';
29
29
  import './chunks/useHelperTextId.js';
30
30
 
31
- var SuggestionList$1 = {"sui-suggestion-list-root":"sui-suggestion-list-root","sui-suggestion-list-item":"sui-suggestion-list-item","sui-suggestion-list-readonly":"sui-suggestion-list-readonly","sui-disabled":"sui-disabled","sui-focus-visible":"sui-focus-visible","sui-suggestion-list-selected":"sui-suggestion-list-selected","sui-suggestion-list-highlighted":"sui-suggestion-list-highlighted","sui-suggestion-list-group-title-readonly":"sui-suggestion-list-group-title-readonly","sui-suggestion-list-expand-icon":"sui-suggestion-list-expand-icon"};
31
+ var SuggestionList$1 = {"sui-suggestion-list-root":"sui-suggestion-list-root","sui-suggestion-list-item":"sui-suggestion-list-item","sui-suggestion-list-readonly":"sui-suggestion-list-readonly","sui-disabled":"sui-disabled","sui-focus-visible":"sui-focus-visible","sui-suggestion-list-selected":"sui-suggestion-list-selected","sui-suggestion-list-highlighted":"sui-suggestion-list-highlighted","sui-suggestion-list-group-title-readonly":"sui-suggestion-list-group-title-readonly","sui-suggestion-list-expand-icon":"sui-suggestion-list-expand-icon","sui-compact":"sui-compact"};
32
32
 
33
33
  const SuggestionListItem = forwardRef((props, ref) => {
34
- const { id, label, children, disabled, isGroupTitle = false, isTitleMode = false, highlighted = false, selected = false, expanded = false, expandable = false, expandIconProps, classes, className, role, ...rest } = props;
35
- const cls = useClasses('suggestion-list', classes, className);
34
+ const { id, label, children, disabled, isGroupTitle = false, isTitleMode = false, highlighted = false, selected = false, expanded = false, expandIconProps, classes, className, role, ...rest } = props;
35
+ const cls = useClassesWithMode('suggestion-list', classes, className, ['item']);
36
36
  const readonly = isGroupTitle && isTitleMode;
37
37
  const ariaDisabled = role !== undefined && disabled ? true : undefined;
38
38
  return (jsxs("div", { "aria-disabled": ariaDisabled, role: role, ...rest, id: id, className: cls('item', {
@@ -42,24 +42,23 @@ const SuggestionListItem = forwardRef((props, ref) => {
42
42
  highlighted: highlighted,
43
43
  selected: selected,
44
44
  disabled,
45
- }), children: [label || children, expandable && expandIconProps && (jsx(IconButton, { shape: 'squircle', background: false, color: 'secondary', variant: "contained", size: "small", ...expandIconProps, children: jsx(ExpandCollapseCaret, { expanded: expanded }) }))] }));
45
+ }), children: [label || children, expandIconProps && (jsx(IconButton, { "aria-hidden": "true", role: "presentation", tabIndex: -1, component: "div", shape: 'squircle', background: false, color: 'secondary', variant: "contained", size: "small", ...expandIconProps, children: jsx(ExpandCollapseCaret, { expanded: expanded }) }))] }));
46
46
  });
47
47
 
48
- /**
49
- * auto calculate container height
50
- */
48
+ const isFirstInGroup = (option) => {
49
+ return option === option?.group?.options[0];
50
+ };
51
+
51
52
  const useDynamicHeight = ({ itemCount, maxContainerHeight, onContainerHeightChange, }) => {
52
53
  const prevItemCount = usePrevious(() => itemCount);
53
54
  const fullHeight = maxContainerHeight === '100%';
54
55
  const maxContainerSize = fullHeight ? -1 : maxContainerHeight;
55
56
  const containerHeighRef = useRef(maxContainerSize);
56
57
  if (!fullHeight) {
57
- // * when prev item count is zero, and current is not zero, set hight for vl to trigger totalListHeightChanged to re-change height
58
58
  if (prevItemCount === 0 && itemCount !== 0) {
59
59
  containerHeighRef.current = maxContainerSize;
60
60
  }
61
61
  else if (itemCount === 0) {
62
- // * when item count is zero always height to zero, when zero init
63
62
  containerHeighRef.current = 0;
64
63
  }
65
64
  }
@@ -87,16 +86,16 @@ const useDynamicHeight = ({ itemCount, maxContainerHeight, onContainerHeightChan
87
86
  };
88
87
  };
89
88
 
90
- /**
91
- * scroll into current highlight index
92
- */
93
89
  function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
90
+ const { externalWindow } = useWindowContext();
94
91
  const renderedItemsRef = useRef([]);
95
92
  const scrollerRef = useRef();
96
93
  const scrollToHighlightedIndex = (prevHighlightedIndex, currHighlightedIndex, topHighlightIndex = 0) => {
94
+ const needsScrollReset = prevHighlightedIndex === -1;
97
95
  if (!scrollerRef.current) {
98
96
  if (currHighlightedIndex !== topHighlightIndex) {
99
- requestAnimationFrame(() => {
97
+ const win = externalWindow || window;
98
+ win.requestAnimationFrame(() => {
100
99
  scrollToIndex({
101
100
  index: currHighlightedIndex,
102
101
  align: 'start',
@@ -107,26 +106,28 @@ function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
107
106
  }
108
107
  const scrollElm = scrollerRef.current;
109
108
  const renderedItems = renderedItemsRef.current;
110
- const isBackward = prevHighlightedIndex > currHighlightedIndex;
111
- const isForward = prevHighlightedIndex < currHighlightedIndex;
109
+ const lastHighlightedIndex = needsScrollReset
110
+ ? currHighlightedIndex
111
+ : prevHighlightedIndex;
112
+ const isBackward = lastHighlightedIndex > currHighlightedIndex;
113
+ const isForward = lastHighlightedIndex < currHighlightedIndex;
112
114
  const currentVisibleOffset = {
113
115
  start: scrollElm.scrollTop,
114
116
  stop: scrollElm.scrollTop + containerHeighRef.current,
115
117
  };
116
- // * when highlightedIndex is out of visible range
117
- if (!renderedItems.some((x) => x.index === currHighlightedIndex)) {
118
+ const isInRenderedRange = renderedItems.some((x) => x.index === currHighlightedIndex);
119
+ if (!isInRenderedRange) {
118
120
  scrollToIndex({
119
121
  index: currHighlightedIndex,
120
122
  align: isBackward ? 'start' : 'end',
121
123
  });
122
124
  return;
123
125
  }
124
- // backward
125
126
  if (isBackward) {
126
127
  let firstShouldScrollIndex = currHighlightedIndex;
127
128
  for (let i = renderedItems.length - 1; i >= 0; i--) {
128
129
  const item = renderedItems[i];
129
- if (item.offset <= currentVisibleOffset.start) {
130
+ if (item.offset < currentVisibleOffset.start) {
130
131
  break;
131
132
  }
132
133
  firstShouldScrollIndex = item.index;
@@ -137,18 +138,18 @@ function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
137
138
  align: 'start',
138
139
  });
139
140
  }
140
- // forward
141
141
  }
142
142
  else if (isForward) {
143
143
  let lastShouldScrollIndex = currHighlightedIndex;
144
144
  for (let i = 0; i < renderedItems.length; i++) {
145
145
  const item = renderedItems[i];
146
- if (item.offset >= currentVisibleOffset.stop) {
146
+ const itemBottom = item.offset + item.size;
147
+ if (itemBottom >= currentVisibleOffset.stop) {
147
148
  break;
148
149
  }
149
150
  lastShouldScrollIndex = item.index;
150
151
  }
151
- if (currHighlightedIndex >= lastShouldScrollIndex) {
152
+ if (currHighlightedIndex > lastShouldScrollIndex) {
152
153
  scrollToIndex({
153
154
  index: currHighlightedIndex,
154
155
  align: 'end',
@@ -156,31 +157,45 @@ function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
156
157
  }
157
158
  }
158
159
  else {
159
- scrollToIndex({
160
- index: currHighlightedIndex,
161
- align: 'start',
162
- });
160
+ const currentItem = renderedItems.find((item) => item.index === currHighlightedIndex);
161
+ if (needsScrollReset) {
162
+ if (currHighlightedIndex === topHighlightIndex) {
163
+ if (scrollerRef.current) {
164
+ scrollerRef.current.scrollTop = 0;
165
+ }
166
+ return;
167
+ }
168
+ else {
169
+ scrollToIndex({
170
+ index: currHighlightedIndex,
171
+ align: 'start',
172
+ });
173
+ return;
174
+ }
175
+ }
176
+ if (!currentItem) {
177
+ scrollToIndex({
178
+ index: currHighlightedIndex,
179
+ align: 'start',
180
+ });
181
+ return;
182
+ }
183
+ const itemBottom = currentItem.offset + currentItem.size;
184
+ const isTopVisible = currentItem.offset >= currentVisibleOffset.start;
185
+ const isBottomVisible = itemBottom < currentVisibleOffset.stop;
186
+ const isFullyVisible = isTopVisible && isBottomVisible;
187
+ if (!isFullyVisible) {
188
+ scrollToIndex({
189
+ index: currHighlightedIndex,
190
+ align: 'start',
191
+ });
192
+ }
163
193
  }
164
194
  };
165
195
  return {
166
- /**
167
- * scroller reference
168
- */
169
196
  scrollerRef,
170
- /**
171
- * Scroll to target highlighted index
172
- * @param prevHighlightedIndex previous highlightedIndex
173
- * @param currHighlightedIndex current highlightedIndex
174
- * @param topHighlightIndex top highlighIndex for check should scroll when init
175
- */
176
197
  scrollToHighlightedIndex,
177
- /**
178
- * set to virtuoso `scrollerRef` prop, auto bind inner `scrollerRef`
179
- */
180
198
  scrollerRefFn: (elm) => (scrollerRef.current = elm),
181
- /**
182
- * set to virtuoso `itemsRendered` prop, auto bind inner `renderedItemsRef`
183
- */
184
199
  itemsRendered: (e) => (renderedItemsRef.current = e),
185
200
  };
186
201
  }
@@ -216,11 +231,9 @@ const useAutocompleteGroup = ({ groupBy, options, filteredResult, getExpandIconP
216
231
  e.stopPropagation();
217
232
  });
218
233
  const optionsGroupList = useMemo(() => {
219
- /** key with this group count */
220
234
  if (!groupBy || !options) {
221
235
  return [];
222
236
  }
223
- // used to keep track of key and indexes in the result array
224
237
  const indexBy = new Map();
225
238
  let warn = false;
226
239
  const afterGroupFn = [];
@@ -274,11 +287,8 @@ const useAutocompleteGroup = ({ groupBy, options, filteredResult, getExpandIconP
274
287
  id: `${id}-${group}`,
275
288
  label: group,
276
289
  disabled: true,
277
- // * here cause by self Type reference
278
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
279
290
  group: newGroup,
280
291
  };
281
- // push fn to array, do that after all options be add into group
282
292
  if (getOptionDisabled) {
283
293
  afterGroupFn.push(() => {
284
294
  groupTitleOption.disabled = getOptionDisabled(groupTitleOption);
@@ -319,7 +329,6 @@ const useAutocompleteGroup = ({ groupBy, options, filteredResult, getExpandIconP
319
329
  initGroupExpandedState(groupExpanded);
320
330
  }, [groupExpanded]);
321
331
  const groupExpandedMap = groupExpandedMapRef.current;
322
- // * speared logic with group, prevent calculate every time.
323
332
  const groupedResult = useMemo(() => {
324
333
  const addExpandedResult = Object.entries(groupExpandedMap).reduce((prev, [key, expended]) => {
325
334
  const group = prev.find((x) => x.group === key);
@@ -351,10 +360,8 @@ const isItemCanSelected = (item) => {
351
360
  };
352
361
  const toOptionIdString = (id) => typeof id === 'number' ? String(id) : id;
353
362
  const DEFAULT_GET_OPTION_LABEL = (item) => item?.label || '';
354
- /**
355
- * provide suggestion list with search function and expandable group with virtualized list
356
- */
357
- const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DEFAULT_GET_OPTION_LABEL, filterOptions, disabledItemsHighlightable, options, onInputChange: onInputChangeProp, inputRef, onKeyDown: onKeyDownProp, onSelect, onClear, getOptionDisabled, groupBy, onGroupExpanded, groupVariant, groupExpanded, groupDefaultExpanded, getExpandIconProps, processFilteredResult, }) => {
363
+ const defaultIsOptionEqualToValue = (option, value) => option === value;
364
+ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DEFAULT_GET_OPTION_LABEL, filterOptions, disabledItemsHighlightable, options, onInputChange: onInputChangeProp, inputRef, onKeyDown: onKeyDownProp, onSelect, onClear, getOptionDisabled, groupBy, onGroupExpanded, groupVariant, groupExpanded, groupDefaultExpanded, getExpandIconProps, processFilteredResult, isOptionEqualToValue = defaultIsOptionEqualToValue, }) => {
358
365
  const isTitleMode = groupVariant === 'normal';
359
366
  const [inputValue, setInputValue] = useControlled({
360
367
  controlled: inputValueProp,
@@ -376,12 +383,12 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
376
383
  inputValue,
377
384
  getOptionLabel,
378
385
  selectedItems: [],
386
+ isOptionEqualToValue,
379
387
  });
380
388
  }
381
389
  return items;
382
- }, [filterOptions, getOptionLabel, inputValue]);
390
+ }, [filterOptions, getOptionLabel, inputValue, isOptionEqualToValue]);
383
391
  const filteredResult = useMemo(() => {
384
- // * only when isOpen calculate the filtered result
385
392
  let results = getFilteredItems(options);
386
393
  results = processFilteredResult
387
394
  ? processFilteredResult(results, inputValue)
@@ -454,7 +461,7 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
454
461
  });
455
462
  const getItemProps = ({ item, index = 0, }) => {
456
463
  const currGroup = item.group;
457
- const isGroupTitle = item === currGroup?.options[0];
464
+ const isItemFirstInGroup = isFirstInGroup(item);
458
465
  const itemCount = optionItems.length;
459
466
  const groupOrder = currGroup?.order || 0;
460
467
  const stringId = toOptionIdString(item.id);
@@ -469,8 +476,7 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
469
476
  setHighlightedIndex(index, { reason: 'mouse', reRender: true });
470
477
  }
471
478
  },
472
- // When title mode and is title, skip that posinset
473
- ...(isTitleMode && isGroupTitle
479
+ ...(isTitleMode && isItemFirstInGroup
474
480
  ? {}
475
481
  : {
476
482
  role: 'option',
@@ -509,9 +515,8 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
509
515
  return;
510
516
  if (highlightedIndex !== DEFAULT_HIGHLIGHTED_INDEX$1) {
511
517
  const currOption = optionItems[highlightedIndex];
512
- const isGroupTitle = currOption === currOption.group?.options[0];
513
- if (isGroupTitle) {
514
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
518
+ const isCurrOptionFirstInGroup = isFirstInGroup(currOption);
519
+ if (isCurrOptionFirstInGroup) {
515
520
  const { onClick } = currOption.group.getExpandIconProps();
516
521
  onClick?.(e);
517
522
  }
@@ -520,7 +525,6 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
520
525
  }
521
526
  e.stopPropagation();
522
527
  }
523
- // always preventDefault for not inset all enter into textarea
524
528
  e.preventDefault();
525
529
  break;
526
530
  }
@@ -597,30 +601,53 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
597
601
  changeHighlightedIndexReasonRef,
598
602
  changeHighlightedIndexReason: changeHighlightedIndexReasonRef.current,
599
603
  optionsGroupList,
600
- /** current unique id */
601
604
  id: currUniqueId,
602
605
  getNextFocusableOption,
603
606
  handleF10KeyDown,
604
607
  };
605
608
  };
606
609
 
610
+ const DEFAULT_PADDING = 8;
611
+ const getPaddingValue = (padding, itemCount) => {
612
+ if (itemCount === 0) {
613
+ return 0;
614
+ }
615
+ if (padding === false) {
616
+ return 0;
617
+ }
618
+ if (padding === true) {
619
+ return DEFAULT_PADDING;
620
+ }
621
+ if (typeof padding === 'number') {
622
+ return Math.max(0, padding);
623
+ }
624
+ return DEFAULT_PADDING;
625
+ };
607
626
  const List = forwardRef((props, ref) => {
608
- const { className, context } = props;
627
+ const { className, context, style, ...restProps } = props;
609
628
  const listRef = context?.listRef;
610
629
  const rootClass = context?.rootClass;
630
+ const paddingValue = context?.paddingValue ?? 0;
611
631
  const forkRef = useForkRef(ref, listRef);
612
- return (jsx("div", { ref: forkRef, className: clsx(className, rootClass), "data-suggestion-list": true, ...props }));
632
+ return (jsx("div", { ref: forkRef, ...restProps, className: clsx(className, rootClass), "data-suggestion-list": true, style: {
633
+ ...style,
634
+ ['--sui-suggestion-list-vertical-padding']: `${paddingValue}px`,
635
+ } }));
613
636
  });
614
637
  const SuggestionList = forwardRef((inProps, ref) => {
615
638
  const props = useThemeProps({ props: inProps, name: 'SuggestionList' });
616
- const { highlightedIndex, options, getItemProps, virtualize = true, renderOption, value: selectedOptions, inputValue, groupVariant, groupExpanded, renderGroup, optionsGroupList, getOptionDisabled, getOptionSelected, changeHighlightedIndexReason, isKeepHighlightedIndex, components: componentsProp, onContainerHeightChange, getOptionLabel, padding = 8, maxContainerHeight = '100%', className: classNameProp, classes: classesProp, getSuggestionListProps, ...rest } = props;
639
+ const { highlightedIndex, prevHighlightedIndex, options, getItemProps, virtualize = true, renderOption, value: selectedOptions, inputValue, groupVariant, groupExpanded, renderGroup, optionsGroupList, getOptionDisabled, getOptionSelected, changeHighlightedIndexReason, isKeepHighlightedIndex, components: componentsProp, onContainerHeightChange, getOptionLabel, padding = DEFAULT_PADDING, maxContainerHeight = '100%', className: classNameProp, classes: classesProp, getSuggestionListProps, ...rest } = props;
617
640
  const vlRef = useRef(null);
618
641
  const forkVlRef = useForkRef(ref, vlRef);
619
642
  const isTitleMode = groupVariant === 'normal';
620
643
  const listRef = useRef(null);
621
644
  const itemData = options;
622
645
  const itemCount = options.length;
623
- const cls = useClasses('suggestion-list', classesProp, classNameProp);
646
+ const internalPrevHighlightedIndex = usePrevious(() => highlightedIndex, true);
647
+ const actualPrevHighlightedIndex = prevHighlightedIndex ?? internalPrevHighlightedIndex;
648
+ const cls = useClassesWithMode('suggestion-list', classesProp, classNameProp);
649
+ const paddingValue = getPaddingValue(padding, itemCount);
650
+ const hasItemsRenderedRef = useRef(false);
624
651
  const { totalListHeightChanged, style, containerHeighRef } = useDynamicHeight({
625
652
  itemCount,
626
653
  maxContainerHeight,
@@ -632,43 +659,69 @@ const SuggestionList = forwardRef((inProps, ref) => {
632
659
  }
633
660
  },
634
661
  });
662
+ const handleTotalListHeightChanged = (height) => {
663
+ const adjustedHeight = paddingValue > 0 ? height + paddingValue * 2 : height;
664
+ if (!hasItemsRenderedRef.current &&
665
+ adjustedHeight < containerHeighRef.current) {
666
+ return;
667
+ }
668
+ totalListHeightChanged(adjustedHeight);
669
+ };
635
670
  const { sleep } = useSleep();
636
671
  const { retry: scrollToIndexWithRetry } = useRetry(async (location) => {
637
672
  const toIndex = location.index;
638
673
  if (!virtualize) {
639
- const toElm = listRef.current?.querySelector(`[data-item-index="${toIndex}"]`);
674
+ const scroller = listRef.current;
675
+ const needsScrollReset = prevHighlightedIndex === -1;
676
+ const isLastItem = itemCount > 1 && toIndex === itemCount - 1;
677
+ if (paddingValue > 0 && needsScrollReset && isLastItem && scroller) {
678
+ scroller.scrollTop = scroller.scrollHeight;
679
+ return true;
680
+ }
681
+ const toElm = scroller?.querySelector(`[data-item-index="${toIndex}"]`);
640
682
  toElm?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
641
683
  return true;
642
684
  }
643
- if (location.index === 0 && padding !== undefined) {
685
+ if (paddingValue > 0 &&
686
+ (location.align === 'start' || location.align === 'end')) {
644
687
  location = {
645
688
  ...location,
646
- offset: -(typeof padding === 'number' ? padding : 8),
689
+ offset: paddingValue,
647
690
  };
648
691
  }
649
692
  vlRef.current?.scrollToIndex(location);
650
693
  await sleep(0);
651
- // confirm that scrollInto view
652
694
  const toElm = listRef.current?.querySelector(`[data-item-index="${toIndex}"]`);
653
695
  return !!toElm;
654
696
  }, {
655
697
  retryTimes: 10,
656
698
  intervalTime: 20,
657
699
  });
658
- const { scrollerRef, scrollerRefFn, itemsRendered, scrollToHighlightedIndex, } = useHighlightScroll({
700
+ const { scrollerRef, scrollerRefFn, itemsRendered: itemsRenderedFromHook, scrollToHighlightedIndex, } = useHighlightScroll({
659
701
  containerHeighRef,
660
702
  scrollToIndex: scrollToIndexWithRetry,
661
703
  });
662
- const prevHighlightedIndex = usePrevious(() => highlightedIndex, true);
704
+ const handleItemsRendered = (items) => {
705
+ if (items.length > 0 || itemCount === 0) {
706
+ hasItemsRenderedRef.current = true;
707
+ }
708
+ itemsRenderedFromHook(items);
709
+ };
710
+ useEffect(() => {
711
+ if (itemCount > 0) {
712
+ hasItemsRenderedRef.current = false;
713
+ }
714
+ }, [itemCount]);
663
715
  useLayoutEffect(() => {
664
- if ((!virtualize || vlRef.current) &&
716
+ const shouldScroll = (!virtualize || vlRef.current) &&
665
717
  !isKeepHighlightedIndex &&
666
- // * only scroll when reason is 'keyboard'
667
718
  changeHighlightedIndexReason &&
668
- changeHighlightedIndexReason !== 'mouse') {
669
- scrollToHighlightedIndex(prevHighlightedIndex, highlightedIndex,
670
- // when title group topHighlightIndex to be 1, first item is group title
671
- isTitleMode ? 1 : 0);
719
+ changeHighlightedIndexReason !== 'mouse';
720
+ const firstOption = options[0];
721
+ const isFirstItemGroupTitle = isTitleMode && isFirstInGroup(firstOption);
722
+ const topHighlightIndex = isFirstItemGroupTitle ? 1 : 0;
723
+ if (shouldScroll) {
724
+ scrollToHighlightedIndex(actualPrevHighlightedIndex, highlightedIndex, topHighlightIndex);
672
725
  }
673
726
  });
674
727
  const handleScrolling = (scrolling) => {
@@ -678,12 +731,11 @@ const SuggestionList = forwardRef((inProps, ref) => {
678
731
  list.style.pointerEvents = scrolling ? 'none' : '';
679
732
  };
680
733
  const itemContent = (index, option) => {
681
- const currGroup = option.group;
682
- const isGroupTitle = option === currGroup?.options[0];
734
+ const isOptionFirstInGroup = isFirstInGroup(option);
683
735
  const isFixedGroupExpanded = typeof groupExpanded === 'boolean';
684
- const expandable = !isTitleMode && !isFixedGroupExpanded && isGroupTitle;
736
+ const expandable = !isTitleMode && !isFixedGroupExpanded && isOptionFirstInGroup;
685
737
  const expanded = option.group?.expanded;
686
- const expandIconProps = !expandable
738
+ const expandIconProps = expandable
687
739
  ? option.group?.getExpandIconProps?.({
688
740
  className: cls('expand-icon'),
689
741
  'aria-expanded': expanded,
@@ -704,7 +756,6 @@ const SuggestionList = forwardRef((inProps, ref) => {
704
756
  const selected = getOptionSelected?.(option);
705
757
  const indexInOwnGroup = resultProps.indexInOwnGroup;
706
758
  delete resultProps.indexInOwnGroup;
707
- // * when item is not disabled, that should check outside is that disabled
708
759
  if (!resultProps.freeSolo && !resultProps.disabled && getOptionDisabled) {
709
760
  resultProps.disabled = getOptionDisabled(option);
710
761
  }
@@ -714,7 +765,7 @@ const SuggestionList = forwardRef((inProps, ref) => {
714
765
  index,
715
766
  indexInOwnGroup,
716
767
  };
717
- if (renderGroup && isGroupTitle) {
768
+ if (renderGroup && isOptionFirstInGroup) {
718
769
  return renderGroup(resultProps, {
719
770
  ...state,
720
771
  expanded,
@@ -725,40 +776,33 @@ const SuggestionList = forwardRef((inProps, ref) => {
725
776
  return renderOption(resultProps, state);
726
777
  }
727
778
  const { error, group, freeSolo, key, ...restProps } = resultProps;
728
- return (jsxs(SuggestionListItem, { ...restProps, id: typeof resultProps.id === 'number'
779
+ return (jsx(SuggestionListItem, { ...restProps, id: typeof resultProps.id === 'number'
729
780
  ? `${resultProps.id}`
730
- : resultProps.id, expandable: isGroupTitle, isGroupTitle: isGroupTitle, isTitleMode: isTitleMode, highlighted: highlighted, selected: selected, disabled: resultProps.disabled, label: getOptionLabel ? getOptionLabel(option) : option.label, expandIconProps: expandIconProps, children: [getOptionLabel ? getOptionLabel(option) : option.label, expandIconProps && (jsx(IconButton, { shape: 'squircle', background: false, variant: "contained", size: "small", ...expandIconProps, color: 'secondary', children: jsx(ExpandCollapseCaret, { expanded: Boolean(expanded) }) }))] }, key));
781
+ : resultProps.id, expanded: expanded, isGroupTitle: isOptionFirstInGroup, isTitleMode: isTitleMode, highlighted: highlighted, selected: selected, disabled: resultProps.disabled, label: getOptionLabel ? getOptionLabel(option) : option.label, expandIconProps: expandIconProps }, key));
731
782
  };
732
- const PaddingComponent = (() => {
733
- const paddingValue = padding !== undefined && itemCount > 0
734
- ? typeof padding === 'number'
735
- ? padding
736
- : 8
737
- : 0;
738
- return () => jsx("div", { style: { height: paddingValue } });
739
- })();
740
783
  const components = {
741
784
  List: List,
742
- Header: PaddingComponent,
743
- Footer: PaddingComponent,
744
785
  ...componentsProp,
745
786
  };
746
787
  const rootClass = cls('root');
747
- const context = { listRef, rootClass };
788
+ const context = { listRef, rootClass, paddingValue };
748
789
  return virtualize ? (jsx(Virtuoso, { ref: forkVlRef, totalCount: itemCount, data: itemData, context: context, components: components, itemContent: itemContent, ...getSuggestionListProps(), ...combineProps({
749
790
  scrollerRef: (scrollElm) => {
750
791
  scrollerRefFn(scrollElm);
751
792
  },
752
- itemsRendered,
753
- totalListHeightChanged,
793
+ itemsRendered: handleItemsRendered,
794
+ totalListHeightChanged: handleTotalListHeightChanged,
754
795
  style,
755
796
  isScrolling: handleScrolling,
756
- }, rest) })) : (jsxs(List, { style: { maxHeight: style.height, overflow: 'auto' }, ref: (scrollElm) => {
797
+ }, rest) })) : (jsx(List, { context: context, style: {
798
+ maxHeight: style.height,
799
+ overflow: 'auto',
800
+ }, ref: (scrollElm) => {
757
801
  listRef.current = scrollElm;
758
802
  scrollerRefFn(scrollElm);
759
- }, className: cls('root'), ...getSuggestionListProps(), ...rest, children: [jsx(PaddingComponent, {}), options.map((x, i) => {
760
- return itemContent(i, x);
761
- }), jsx(PaddingComponent, {})] }));
803
+ }, className: cls('root'), ...getSuggestionListProps(), ...rest, children: options.map((x, i) => {
804
+ return itemContent(i, x);
805
+ }) }));
762
806
  });
763
807
  SuggestionList.displayName = 'SuggestionList';
764
808
 
@@ -770,7 +814,6 @@ function stringArrToRegExp(keyToTags) {
770
814
  const TAG_TOKEN = 'rc-chip-';
771
815
  const DEFAULT_LIMIT_CHIPS$1 = 20;
772
816
  const DEFAULT_KEY_TO_CHIPS = [';', ',', '\\n'];
773
- /** @inner inner hook work with useAutocomplete */
774
817
  const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [], onChange: onSelectChange, variant, getOptionLabel = DEFAULT_GET_OPTION_LABEL, onInputChange: onInputChangeProp, freeSolo, multiple, wrapperRef, inputRef, maxFreeSolo = DEFAULT_LIMIT_CHIPS$1, keyToTags = DEFAULT_KEY_TO_CHIPS, onMaxFreeSolo, required, disabled, getStopCreateFreeSolo, onReset, onAddTags, }) => {
775
818
  const isAutocomplete = variant === 'autocomplete';
776
819
  const isSelectedFromAutocompleteRef = useRef(false);
@@ -810,7 +853,6 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
810
853
  if (focus)
811
854
  _focusTag(tagToFocus);
812
855
  });
813
- /** when return `true` mean add item success */
814
856
  const checkAndAddFreeSolo = ({ selectedItem, value, } = {}, e) => {
815
857
  let isAddItem = false;
816
858
  const currentValue = value ?? inputRef.current?.value;
@@ -869,7 +911,6 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
869
911
  onAddTags?.();
870
912
  };
871
913
  const addTagOnSelect = (selectedItem) => {
872
- // * change to uniqueId
873
914
  if (selectedItem.freeSolo) {
874
915
  if (freeSoloCount < maxFreeSolo) {
875
916
  selectedItem.id = uniqueId(TAG_TOKEN);
@@ -895,32 +936,20 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
895
936
  event?.preventDefault();
896
937
  },
897
938
  });
898
- /**
899
- * All Get props methods
900
- */
901
939
  const getTagListBoxProps = (props) => {
902
940
  return {
903
941
  'aria-required': required || false,
904
942
  'aria-disabled': disabled || false,
905
- // TODO: wait for input can complete that.
906
- // 'aria-multiselectable': false,
907
- // role: selectedItems.length > 0 ? 'listbox' : undefined,
908
- // 'aria-orientation': 'horizontal',
909
943
  ...props,
910
944
  };
911
945
  };
912
946
  const getTagProps = ({ index, selectedItem, ...restTagProps }) => {
913
- const tabIndex =
914
- // * when tag is not focus
915
- !focused &&
916
- // * and is first item
947
+ const tabIndex = !focused &&
917
948
  index === 0
918
949
  ? 0
919
950
  : -1;
920
951
  return combineProps({
921
952
  tabIndex,
922
- // TODO: wait for input can complete that.
923
- // role: 'option',
924
953
  role: 'button',
925
954
  key: `${AutocompleteId}-selected-item-${index}`,
926
955
  'data-tag-index': index,
@@ -939,9 +968,7 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
939
968
  case 'Backspace':
940
969
  {
941
970
  const lengthBeforeDelete = tags.length;
942
- focusTag(
943
- // * when length is 1 mean that will be remove all
944
- lengthBeforeDelete === 1
971
+ focusTag(lengthBeforeDelete === 1
945
972
  ? -1
946
973
  : focusedIndex === 0
947
974
  ? 0
@@ -952,9 +979,7 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
952
979
  case 'Delete':
953
980
  {
954
981
  const lengthBeforeDelete = tags.length;
955
- focusTag(
956
- // * when length is 1 mean that will be remove all
957
- lengthBeforeDelete === 1
982
+ focusTag(lengthBeforeDelete === 1
958
983
  ? -1
959
984
  : focusedIndex === tags.length - 1
960
985
  ? focusedIndex - 1
@@ -968,7 +993,6 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
968
993
  }
969
994
  },
970
995
  onDelete: (e) => {
971
- // * only allow left button click
972
996
  if (e.button !== 0)
973
997
  return;
974
998
  removeTag(selectedItem);
@@ -1009,7 +1033,7 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
1009
1033
  const EMPTY_TAG_TOKEN = 'rc-chip-empty';
1010
1034
  const DEFAULT_HIGHLIGHTED_INDEX = -1;
1011
1035
  const DEFAULT_LIMIT_CHIPS = 20;
1012
- const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputValueProp, getOptionLabel = DEFAULT_GET_OPTION_LABEL, keyToTags = DEFAULT_KEY_TO_CHIPS, filterOptions: filterOptionsProp, disabledItemsHighlightable, options, freeSolo, onInputChange: onInputChangeProp, maxFreeSolo = DEFAULT_LIMIT_CHIPS, onMaxFreeSolo, openOnFocus, toggleWithInput, disableCloseOnSelect, initialIsOpen, autoSelect, inputContainerRef, inputRef, wrapperRef, onKeyDown: onKeyDownProp, onChange: onSelectChange, value: selectedItemsProp = [], disabled, renderNoOptions, onClear, autoHighlight, getOptionDisabled, addNoOptionItem, groupBy, onGroupExpanded, groupVariant, groupExpanded, groupDefaultExpanded, getExpandIconProps, required, open: openProp, onOpen, onClose, focused, }) => {
1036
+ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputValueProp, getOptionLabel = DEFAULT_GET_OPTION_LABEL, keyToTags = DEFAULT_KEY_TO_CHIPS, filterOptions: filterOptionsProp, disabledItemsHighlightable, options, freeSolo, onInputChange: onInputChangeProp, maxFreeSolo = DEFAULT_LIMIT_CHIPS, onMaxFreeSolo, openOnFocus, toggleWithInput, disableCloseOnSelect, initialIsOpen, autoSelect, inputContainerRef, inputRef, wrapperRef, onKeyDown: onKeyDownProp, onChange: onSelectChange, value: selectedItemsProp = [], disabled, renderNoOptions, onClear, autoHighlight, getOptionDisabled, addNoOptionItem, groupBy, onGroupExpanded, groupVariant, groupExpanded, groupDefaultExpanded, getExpandIconProps, required, open: openProp, onOpen, onClose, focused, isOptionEqualToValue, }) => {
1013
1037
  const isAutocomplete = variant === 'autocomplete';
1014
1038
  const autoCompleteSelectedIndexRef = useRef(DEFAULT_HIGHLIGHTED_INDEX);
1015
1039
  const AutocompleteId = useId('Autocomplete', true);
@@ -1031,7 +1055,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1031
1055
  const keepHighlightedIndexRef = useRef(false);
1032
1056
  const popperElementRef = useRef(null);
1033
1057
  const { sleep, getSleeping } = useSleep();
1034
- // * when that is autocomplete, that will never be multiple
1035
1058
  const multiple = isAutocomplete ? false : multipleProp;
1036
1059
  const inputContainerScrollToBottom = () => {
1037
1060
  requestAnimationFrame(() => {
@@ -1057,7 +1080,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1057
1080
  multiple,
1058
1081
  required,
1059
1082
  disabled,
1060
- // * when is composition, stop freeSolo create new item
1061
1083
  getStopCreateFreeSolo: () => isCompositionRef.current,
1062
1084
  onReset: () => {
1063
1085
  resetState();
@@ -1076,7 +1098,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1076
1098
  }
1077
1099
  return null;
1078
1100
  };
1079
- // * only when isOpen calculate the filtered result
1080
1101
  noOptionItemRef.current = null;
1081
1102
  if (addNoOptionItem) {
1082
1103
  const item = getInputValueAsItem();
@@ -1093,9 +1114,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1093
1114
  else if (results.length === 0) {
1094
1115
  const item = getInputValueAsItem();
1095
1116
  noOptionItemRef.current = item;
1096
- // * only when not set render no options will auto add item
1097
1117
  if (item && freeSolo && !renderNoOptions) {
1098
- // * when outside not use filter, that will be original array, must use spread
1099
1118
  return [...results, item];
1100
1119
  }
1101
1120
  }
@@ -1130,6 +1149,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1130
1149
  groupBy,
1131
1150
  onGroupExpanded,
1132
1151
  getExpandIconProps,
1152
+ isOptionEqualToValue,
1133
1153
  onSelect: (e, selectedItem) => {
1134
1154
  addTagOnSelect(selectedItem);
1135
1155
  resetState(e);
@@ -1137,10 +1157,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1137
1157
  if (autoHighlight) {
1138
1158
  const currIndex = highlightedIndexRef.current;
1139
1159
  const nextValidIndex = getNextFocusableOption();
1140
- const toIndex =
1141
- // * if that index is bigger than current index or nextValidIndex is last index,
1142
- // * cut 1 (because current item will be remove)
1143
- nextValidIndex > currIndex ||
1160
+ const toIndex = nextValidIndex > currIndex ||
1144
1161
  nextValidIndex === optionItems.length - 1
1145
1162
  ? nextValidIndex - 1
1146
1163
  : nextValidIndex;
@@ -1155,23 +1172,12 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1155
1172
  },
1156
1173
  });
1157
1174
  const getItemProps = (props) => {
1158
- return combineProps(getSuggestionListItemProps(props), {
1159
- onMouseDown: (e) => {
1160
- // `getPopperProps` will prevent change focus when mouse down popper
1161
- // but suggestion item is an exception.
1162
- // so we need stop propagation to make sure focus can be changed
1163
- e.stopPropagation();
1164
- },
1165
- onMouseUp: (e) => {
1166
- focusInput();
1167
- },
1168
- });
1175
+ return getSuggestionListItemProps(props);
1169
1176
  };
1170
1177
  const readOnly = !isAutocomplete && !multiple && tags.length >= 1 ? true : undefined;
1171
1178
  const closeMenu = (e, reason) => {
1172
1179
  keepHighlightedIndexRef.current = false;
1173
1180
  isInputValueChangedRef.current = false;
1174
- // * set to default highlighted
1175
1181
  setHighlightedIndex(DEFAULT_HIGHLIGHTED_INDEX, { reason: 'auto' });
1176
1182
  if (isOpen) {
1177
1183
  if (e && reason) {
@@ -1200,8 +1206,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1200
1206
  const handleInputChange = (newValue, open = true, e) => {
1201
1207
  if (inputValue !== newValue) {
1202
1208
  setHighlightedIndex(DEFAULT_HIGHLIGHTED_INDEX, { reason: 'auto' });
1203
- // !!! Get regexp every time for prevent bug with browser
1204
- // https://stackoverflow.com/questions/3827456/what-is-wrong-with-my-date-regex/3827500#3827500
1205
1209
  if (stringArrToRegExp(keyToTags).test((newValue || '').trim())) {
1206
1210
  const resultHaveAdd = checkAndAddFreeSolo({ value: newValue }, e);
1207
1211
  if (!disableCloseOnSelect) {
@@ -1219,7 +1223,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1219
1223
  return false;
1220
1224
  };
1221
1225
  const resetState = (e) => {
1222
- // * when autocomplete select mode not reset input value
1223
1226
  if (!isSelectedFromAutocompleteRef.current) {
1224
1227
  clearInput();
1225
1228
  }
@@ -1239,18 +1242,15 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1239
1242
  const keepHighlightedIndex = () => {
1240
1243
  keepHighlightedIndexRef.current = true;
1241
1244
  };
1242
- // * when outside options props props change also need set highlightedIndex to default
1243
1245
  useChange(() => {
1244
1246
  const shouldResetHighlightedIndex = !keepHighlightedIndexRef.current;
1245
1247
  if (options !== undefined && shouldResetHighlightedIndex) {
1246
1248
  setHighlightedIndex(DEFAULT_HIGHLIGHTED_INDEX, { reason: 'auto' });
1247
1249
  }
1248
1250
  }, () => options);
1249
- // * check that defaultHighlightedIndex
1250
1251
  const defaultHighlightedIndex = useMemo(() => {
1251
1252
  return autoHighlight ? getNextFocusableOption(0) : -1;
1252
1253
  }, [autoHighlight, getNextFocusableOption]);
1253
- // * only when menu is open set to defaultHighlightedIndex
1254
1254
  if (isOpen) {
1255
1255
  if (highlightedIndexRef.current === DEFAULT_HIGHLIGHTED_INDEX) {
1256
1256
  let toIndex = defaultHighlightedIndex;
@@ -1283,13 +1283,11 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1283
1283
  onInputChangeProp?.(result);
1284
1284
  }
1285
1285
  };
1286
- // * use force update to sync open state when init is open
1287
1286
  useLayoutEffect(() => {
1288
1287
  if (isOpen) {
1289
1288
  forceUpdate();
1290
1289
  }
1291
1290
  handleAutocompleteText();
1292
- // eslint-disable-next-line react-hooks/exhaustive-deps
1293
1291
  }, []);
1294
1292
  const getInputProps = (props) => {
1295
1293
  const suggestionListInputProps = getSuggestionListInputProps(props);
@@ -1301,9 +1299,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1301
1299
  const { position } = getSelectionPosition(inputRef);
1302
1300
  const currText = inputValue ?? '';
1303
1301
  const pasteText = clipboardData.getData('Text') ?? '';
1304
- // * because input can't get next line char(\n), we need get that value in onPaste
1305
- // * get current input result use paste
1306
- // * remember combine current input value, that will be use in onChange
1307
1302
  fromPasteString.current =
1308
1303
  currText.slice(0, position.start) +
1309
1304
  pasteText +
@@ -1313,7 +1308,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1313
1308
  onChange: (e) => {
1314
1309
  const changeValue = fromPasteString.current || e.target.value;
1315
1310
  handleInputChange(changeValue, undefined, e);
1316
- // * when input value clear all, clear selected item
1317
1311
  if (isAutocomplete && changeValue.length === 0) {
1318
1312
  clearTags();
1319
1313
  }
@@ -1324,18 +1318,14 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1324
1318
  setInputFocused(true);
1325
1319
  if (openOnFocus)
1326
1320
  openMenu(e);
1327
- // * when autocomplete mode, always select all text when focus
1328
1321
  if (isAutocomplete) {
1329
1322
  inputRef.current?.select();
1330
1323
  }
1331
- // * reset stopAutoSelect in focus input
1332
1324
  stopAutoSelectRef.current = false;
1333
1325
  blurTags();
1334
1326
  },
1335
1327
  onBlur: (e) => {
1336
1328
  setInputFocused(false);
1337
- // mouse down suggestion item will change focus,
1338
- // but we don't want to close popper in this case
1339
1329
  if (popperElementRef.current?.contains(e.relatedTarget))
1340
1330
  return;
1341
1331
  if (autoSelect && !stopAutoSelectRef.current) {
@@ -1343,7 +1333,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1343
1333
  selectItem(e, optionItems[highlightedIndexRef.current]);
1344
1334
  checkAndAddFreeSolo({}, e);
1345
1335
  }
1346
- // * when blur should restore text when have selected item
1347
1336
  handleAutocompleteText();
1348
1337
  closeMenu(e, 'blur');
1349
1338
  },
@@ -1351,7 +1340,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1351
1340
  isCompositionRef.current = true;
1352
1341
  },
1353
1342
  onCompositionEnd: async () => {
1354
- // sleep for prevent tab in composition
1355
1343
  await sleep(20);
1356
1344
  isCompositionRef.current = false;
1357
1345
  },
@@ -1372,9 +1360,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1372
1360
  switch (e.key) {
1373
1361
  case 'Escape':
1374
1362
  if (isOpen) {
1375
- // Avoid Opera to exit fullscreen mode.
1376
1363
  e.preventDefault();
1377
- // Avoid the Modal to handle the event.
1378
1364
  e.stopPropagation();
1379
1365
  closeMenu(e, 'escape');
1380
1366
  }
@@ -1387,13 +1373,9 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1387
1373
  e.stopPropagation();
1388
1374
  return;
1389
1375
  }
1390
- // * when shift+ tab also not need autoSelect
1391
1376
  if (e.shiftKey && currTagsLength > 0) {
1392
1377
  stopAutoSelectRef.current = true;
1393
1378
  }
1394
- // ! [Browser] when in composition,
1395
- // ! and keydown 'Tab' that will trigger twice keydown,
1396
- // ! must check is that is not in composition mode
1397
1379
  if (!e.shiftKey && !isCompositionRef.current) {
1398
1380
  const currentHighlightItem = optionItems[highlightedIndex];
1399
1381
  if (isOpen && currentHighlightItem) {
@@ -1427,7 +1409,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1427
1409
  selectItem(e, optionItems[highlightedIndex]);
1428
1410
  e.stopPropagation();
1429
1411
  }
1430
- // always preventDefault for not inset all enter into textarea
1431
1412
  e.preventDefault();
1432
1413
  break;
1433
1414
  case 'F10':
@@ -1439,7 +1420,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1439
1420
  e.preventDefault();
1440
1421
  return;
1441
1422
  }
1442
- // * check state for is that should move key in option items
1443
1423
  if (isAutocomplete && tags.length > 0 && !isOpen) {
1444
1424
  openMenu(e);
1445
1425
  e.preventDefault();
@@ -1458,15 +1438,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1458
1438
  },
1459
1439
  onMouseDown: toggleWithInput
1460
1440
  ? (e) => {
1461
- /**
1462
- * If the popup isn't open and `openOnFocus` is disabled we should
1463
- * show the popup. If `openOnFocus` is enabled the `onFocus` handler
1464
- * will take care of opening the popup when necessary.
1465
- *
1466
- * If the popup is open and the user hasn't typed a value we should
1467
- * hide it, but if they have typed a value we shouldn't hide it to
1468
- * ensure the the available results remain visible to the user.
1469
- */
1470
1441
  if (!isOpen || (isOpen && !inputValue)) {
1471
1442
  toggleMenu(e, false);
1472
1443
  }
@@ -1559,7 +1530,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1559
1530
  reset,
1560
1531
  forceUpdate,
1561
1532
  optionsGroupList,
1562
- /** that state of current Autocomplete focused, both tag or input focused */
1563
1533
  focused: focused ?? (tagFocused || inputFocused ? true : undefined),
1564
1534
  id: AutocompleteId,
1565
1535
  inputChanged: isInputValueChangedRef.current,
@@ -1574,9 +1544,7 @@ const ChipSizeMap = {
1574
1544
  medium: 'small',
1575
1545
  };
1576
1546
  const InputComponent = forwardRef(({ startAdornment, containerRef, containerClassName, onContainerClick, ...rest }, ref) => {
1577
- return (
1578
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events
1579
- jsxs("div", { ref: containerRef, className: containerClassName, onClick: onContainerClick, children: [startAdornment, jsx("input", { ...rest, ref: ref })] }));
1547
+ return (jsxs("div", { ref: containerRef, className: containerClassName, onClick: onContainerClick, children: [startAdornment, jsx("input", { ...rest, ref: ref })] }));
1580
1548
  });
1581
1549
  const TextInput = forwardRef(({ renderInput, ...rest }, ref) => {
1582
1550
  if (renderInput) {
@@ -1587,14 +1555,7 @@ const TextInput = forwardRef(({ renderInput, ...rest }, ref) => {
1587
1555
  const Autocomplete = forwardRef((inProps, ref) => {
1588
1556
  const props = useThemeProps({ props: inProps, name: 'Autocomplete' });
1589
1557
  const isAutocomplete = props.variant === 'autocomplete';
1590
- const { inputVariant = 'standard', variant, groupExpanded, onGroupExpanded, groupDefaultExpanded, groupVariant = 'normal', getExpandIconProps, groupBy, value: valueProp, autoHighlight = true, clearBtn = false, toggleButton = false, multiple = false, ClearButtonProps, onClear, ToggleButtonProps, getToggleButtonProps: getToggleButtonPropsProp, inputValue: inputValueProp, onKeyDown: onKeyDownProp, helperText: helperTextProp, options, openOnFocus = true, toggleWithInput = true, getOptionLabel = DEFAULT_GET_OPTION_LABEL, renderInput, label, inputRef: inputRefProp, error, placeholder, showPlaceholderWithTags, freeSolo, keyToTags = DEFAULT_KEY_TO_CHIPS, maxFreeSolo, SuggestionListProps: { virtualize = true, ...SuggestionListProps } = {}, autoSelect, PopperComponent = Popper, PopperProps: { anchorElType = 'root',
1591
- // transition: popperTransition,
1592
- // TransitionComponent = virtualize ? RcFade : RcGrow,
1593
- // transitionDuration: transitionDurationProp = 'auto',
1594
- // TransitionProps: TransitionPropsProp = {},
1595
- ...PopperProps } = {}, initialIsOpen, disabled, required: requiredProp, disableCloseOnSelect = multiple, onChange: onChangeProp, onInputChange: onInputChangeProp, onMaxFreeSolo, FormHelperTextProps, action, filterOptions, renderOption, renderTags, getOptionDisabled, renderGroup, renderNoOptions, inputProps,
1596
- // InputProps: InputPropsProp,
1597
- debug, disabledItemsHighlightable, open: openProp, addNoOptionItem, onOpen, onClose, focused, classes, className, fullWidth = true, size = 'xlarge', ...rest } = props;
1558
+ const { inputVariant = 'standard', variant, groupExpanded, onGroupExpanded, groupDefaultExpanded, groupVariant = 'normal', getExpandIconProps, groupBy, value: valueProp, autoHighlight = true, clearBtn = false, toggleButton = false, multiple = false, ClearButtonProps, onClear, ToggleButtonProps, getToggleButtonProps: getToggleButtonPropsProp, inputValue: inputValueProp, onKeyDown: onKeyDownProp, helperText: helperTextProp, options, openOnFocus = true, toggleWithInput = true, getOptionLabel = DEFAULT_GET_OPTION_LABEL, renderInput, label, inputRef: inputRefProp, error, placeholder, showPlaceholderWithTags, freeSolo, keyToTags = DEFAULT_KEY_TO_CHIPS, maxFreeSolo, SuggestionListProps: { virtualize = true, ...SuggestionListProps } = {}, autoSelect, PopperComponent = Popper, PopperProps: { anchorElType = 'root', ...PopperProps } = {}, initialIsOpen, disabled, required: requiredProp, disableCloseOnSelect = multiple, onChange: onChangeProp, onInputChange: onInputChangeProp, onMaxFreeSolo, FormHelperTextProps, action, filterOptions, renderOption, renderTags, getOptionDisabled, renderGroup, renderNoOptions, inputProps, debug, disabledItemsHighlightable, open: openProp, addNoOptionItem, onOpen, onClose, focused, classes, className, fullWidth = true, size = 'xlarge', isOptionEqualToValue, ...rest } = props;
1598
1559
  const cls = useClasses('autocomplete', classes, className);
1599
1560
  const innerInputRef = useRef(null);
1600
1561
  const textFieldRef = useRef(null);
@@ -1605,12 +1566,7 @@ const Autocomplete = forwardRef((inProps, ref) => {
1605
1566
  const anchorElRef = anchorElType === 'input' ? formFieldContentRef : textFieldRef;
1606
1567
  let oneOfTagError = false;
1607
1568
  const required = requiredProp;
1608
- const { focusInput, optionItems, optionsGroupList, tags: selectedItems, highlightedIndex, getToggleButtonProps, getTagProps, getTagListBoxProps, getSuggestionListProps, getPopperProps, getInputProps, getInputAriaProps,
1609
- // getLabelProps,
1610
- getItemProps, isOpen, inputValue, activeIndex, setActiveIndex, setHighlightedIndex, onInputChange, keepHighlightedIndex, changeHighlightedIndexReason, closeMenu, openMenu, reset, getClearButtonProps, noOptionItem, getNoOptionsProps, isKeepHighlightedIndex,
1611
- // focused: isAutocompleteFocused,
1612
- // autoCompleteSelectedIndex,
1613
- popperElementRef, } = useAutocomplete({
1569
+ const { focusInput, optionItems, optionsGroupList, tags: selectedItems, highlightedIndex, getToggleButtonProps, getTagProps, getTagListBoxProps, getSuggestionListProps, getPopperProps, getInputProps, getInputAriaProps, getItemProps, isOpen, inputValue, activeIndex, setActiveIndex, setHighlightedIndex, onInputChange, keepHighlightedIndex, changeHighlightedIndexReason, closeMenu, openMenu, reset, getClearButtonProps, noOptionItem, getNoOptionsProps, isKeepHighlightedIndex, popperElementRef, } = useAutocomplete({
1614
1570
  focused,
1615
1571
  open: openProp,
1616
1572
  addNoOptionItem,
@@ -1650,6 +1606,7 @@ const Autocomplete = forwardRef((inProps, ref) => {
1650
1606
  onKeyDown: onKeyDownProp,
1651
1607
  disabledItemsHighlightable,
1652
1608
  onGroupExpanded,
1609
+ isOptionEqualToValue,
1653
1610
  });
1654
1611
  const open = Boolean((isOpen || noOptionItem) && textFieldRef.current);
1655
1612
  const { onBlur, ...InputProps } = getInputProps(inputProps);
@@ -1681,7 +1638,6 @@ const Autocomplete = forwardRef((inProps, ref) => {
1681
1638
  const endAdornment = (toggleButton || clearBtn) && (jsxs(Fragment, { children: [clearBtn && (selectedItems.length > 0 || inputValue) && (jsx(IconButton, { shape: 'squircle', background: false, color: 'secondary', variant: "contained", size: "small", className: cls('clear'), symbol: Xsm, ...getClearButtonProps(ClearButtonProps) })), toggleButton && (jsx(IconButton, { "aria-hidden": true, tabIndex: -1, shape: 'squircle', color: 'secondary', background: false, variant: "contained", size: "small", className: cls('chevron', error && 'error-chevron', open && `${inputVariant}-expanded-chevron`), children: jsx(ExpandCollapseCaret, { size: 'small', expanded: open }), ...getToggleButtonProps({
1682
1639
  ...ToggleButtonProps,
1683
1640
  ...getToggleButtonPropsProp?.(open),
1684
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1685
1641
  }) }))] }));
1686
1642
  const TextFieldInputProps = {
1687
1643
  'aria-label': typeof label === 'string' ? label : undefined,
@@ -1704,32 +1660,14 @@ const Autocomplete = forwardRef((inProps, ref) => {
1704
1660
  }));
1705
1661
  const hasTags = selectedItems.length > 0;
1706
1662
  const willRenderNoOptions = !!noOptionItem && !!renderNoOptions;
1707
- // const popperRef: ComponentProps<typeof StyledPopper>['popperRef'] =
1708
- // useRef(null);
1709
- // const handleUpdatePopper = useEventCallback(() => {
1710
- // popperRef.current?.update();
1711
- // });
1712
- const menuChildren =
1713
- // * that root element for animation host
1714
- isOpen && (jsxs(Fragment, { children: [jsx(SuggestionList
1715
- // TODO: deprecated, need to check if it will cause error when variant is 'autocomplete'
1716
- // selectedIndex={isAutocomplete ? autoCompleteSelectedIndex : undefined}
1717
- , {
1718
- // TODO: deprecated, need to check if it will cause error when variant is 'autocomplete'
1719
- // selectedIndex={isAutocomplete ? autoCompleteSelectedIndex : undefined}
1720
- highlightedIndex: highlightedIndex, optionsGroupList: optionsGroupList, options: optionItems, groupVariant: groupVariant, groupExpanded: groupExpanded, renderGroup: renderGroup, renderOption: renderOption, inputValue: inputValue, getItemProps: getItemProps, getSuggestionListProps: getSuggestionListProps, changeHighlightedIndexReason: changeHighlightedIndexReason, getOptionDisabled: getOptionDisabled, isKeepHighlightedIndex: isKeepHighlightedIndex,
1721
- // onContainerHeightChange={handleUpdatePopper}
1722
- maxContainerHeight: 180, getOptionLabel: getOptionLabel, position: "unset", virtualize: virtualize, ...SuggestionListProps }), willRenderNoOptions &&
1663
+ const prevHighlightedIndex = usePrevious(() => highlightedIndex, true);
1664
+ const menuChildren = isOpen && (jsxs(Fragment, { children: [jsx(SuggestionList, { highlightedIndex: highlightedIndex, prevHighlightedIndex: prevHighlightedIndex, optionsGroupList: optionsGroupList, options: optionItems, groupVariant: groupVariant, groupExpanded: groupExpanded, renderGroup: renderGroup, renderOption: renderOption, inputValue: inputValue, getItemProps: getItemProps, getSuggestionListProps: getSuggestionListProps, changeHighlightedIndexReason: changeHighlightedIndexReason, getOptionDisabled: getOptionDisabled, isKeepHighlightedIndex: isKeepHighlightedIndex, maxContainerHeight: 180, getOptionLabel: getOptionLabel, position: "unset", virtualize: virtualize, ...SuggestionListProps }), willRenderNoOptions &&
1723
1665
  renderNoOptions?.(getNoOptionsProps, noOptionItem)] }));
1724
1666
  const isPopperContentEmpty = !isOpen || (!willRenderNoOptions && optionItems.length === 0);
1725
1667
  const popperCls = useClasses('autocomplete-popper', PopperProps?.classes, PopperProps?.className);
1726
- return (jsxs(Fragment, { children: [jsx(TextInput, { renderInput: renderInput,
1727
- // hasTags={hasTags}
1728
- variant: inputVariant, ref: toTextFieldRef, inputRef: inputRef, fullWidth: fullWidth, placeholder: !hasTags || (hasTags && multiple && showPlaceholderWithTags)
1668
+ return (jsxs(Fragment, { children: [jsx(TextInput, { renderInput: renderInput, variant: inputVariant, ref: toTextFieldRef, inputRef: inputRef, fullWidth: fullWidth, placeholder: !hasTags || (hasTags && multiple && showPlaceholderWithTags)
1729
1669
  ? placeholder
1730
- : undefined, label: label, disabled: disabled, required: required,
1731
- // * if below one of tag is error, that main Autocomplete default will be error
1732
- error: error ?? oneOfTagError, FormHelperTextProps: FormHelperTextProps, inputComponent: InputComponent, endAdornment: endAdornment, helperText: helperText, size: size, ...combineProps({
1670
+ : undefined, label: label, disabled: disabled, required: required, error: error ?? oneOfTagError, FormHelperTextProps: FormHelperTextProps, inputComponent: InputComponent, endAdornment: endAdornment, helperText: helperText, size: size, ...combineProps({
1733
1671
  RootProps: {
1734
1672
  contentRef: formFieldContentRef,
1735
1673
  },
@@ -1752,16 +1690,16 @@ const Autocomplete = forwardRef((inProps, ref) => {
1752
1690
  }), children: menuChildren }) })) })] }));
1753
1691
  });
1754
1692
  Autocomplete.displayName = 'SuiAutocomplete';
1755
- /**
1756
- * default Autocomplete filter options method, use with `variant="tags"`
1757
- *
1758
- * - filter options by input value and selected items
1759
- */
1760
- const RcAutocompleteDefaultFilterOptions = (options, { inputValue, getOptionLabel, selectedItems }) => {
1761
- return options.filter((item) => selectedItems.indexOf(item) < 0 &&
1762
- getOptionLabel?.(item)
1693
+ const RcAutocompleteDefaultFilterOptions = (options, { inputValue, getOptionLabel, selectedItems, isOptionEqualToValue }) => {
1694
+ return options.filter((item) => {
1695
+ const isSelected = selectedItems.some((selected) => isOptionEqualToValue(item, selected));
1696
+ if (isSelected)
1697
+ return false;
1698
+ const optionLabel = getOptionLabel?.(item) || '';
1699
+ return optionLabel
1763
1700
  .toLowerCase()
1764
- .startsWith(inputValue?.toLowerCase() || ''));
1701
+ .startsWith(inputValue?.toLowerCase() || '');
1702
+ });
1765
1703
  };
1766
1704
 
1767
- export { Autocomplete, DEFAULT_GET_OPTION_LABEL, DEFAULT_KEY_TO_CHIPS, RcAutocompleteDefaultFilterOptions, SuggestionList, SuggestionListItem, Autocomplete$1 as autocompleteStyles, stringArrToRegExp, SuggestionList$1 as suggestionListStyles, useAutocomplete, useAutocompleteGroup, useAutocompleteTag, useDynamicHeight, useHighlightScroll, useSuggestionList };
1705
+ export { Autocomplete, DEFAULT_GET_OPTION_LABEL, DEFAULT_KEY_TO_CHIPS, DEFAULT_PADDING, RcAutocompleteDefaultFilterOptions, SuggestionList, SuggestionListItem, Autocomplete$1 as autocompleteStyles, getPaddingValue, isFirstInGroup, stringArrToRegExp, SuggestionList$1 as suggestionListStyles, useAutocomplete, useAutocompleteGroup, useAutocompleteTag, useDynamicHeight, useHighlightScroll, useSuggestionList };