@ringcentral/spring-ui 1.7.0 → 1.9.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 (282) hide show
  1. package/Alert.js +3 -3
  2. package/Announcement.js +1 -1
  3. package/Autocomplete.js +216 -243
  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 +18 -6
  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/Modal.js +1 -1
  24. package/PageHeader.js +6 -4
  25. package/Popper.js +0 -1
  26. package/Rating.js +0 -5
  27. package/SingleFilter.js +0 -1
  28. package/Slider.js +1 -4
  29. package/Snackbar.js +0 -14
  30. package/SortableListItem.js +0 -1
  31. package/SplitButton.js +1 -3
  32. package/StatusIndicator.js +1 -1
  33. package/StepButton.js +2 -3
  34. package/StepContent.js +3 -8
  35. package/SubMenu.js +0 -4
  36. package/SwipeableDrawer.js +37 -162
  37. package/Switch.js +1 -4
  38. package/Tab.js +7 -8
  39. package/TabContext.js +0 -5
  40. package/TableBody.js +1 -1
  41. package/TableCell.js +0 -6
  42. package/TableRow.js +2 -4
  43. package/Tabs.js +22 -121
  44. package/Text.js +2 -4
  45. package/TimePicker.js +7 -46
  46. package/VirtualizedList.js +6 -39
  47. package/VirtualizedMenu.js +1 -1
  48. package/chunks/Alert.js +8 -7
  49. package/chunks/BottomNavigationItem.js +0 -1
  50. package/chunks/Button.js +0 -1
  51. package/chunks/Chip.js +0 -5
  52. package/chunks/Drawer.js +1 -30
  53. package/chunks/ListItem.js +3 -6
  54. package/chunks/Menu.js +6 -5
  55. package/chunks/MenuDivider.js +2 -3
  56. package/chunks/MenuItemText.js +3 -3
  57. package/chunks/MenuList.js +3 -6
  58. package/chunks/Modal.js +1 -1
  59. package/chunks/PickerTextField.js +0 -1
  60. package/chunks/Popover.js +0 -5
  61. package/chunks/Select.js +2 -39
  62. package/chunks/Squircle.js +0 -7
  63. package/chunks/StatusIndicator.js +1 -0
  64. package/chunks/StepIcon.js +1 -3
  65. package/chunks/StepperContext.js +0 -7
  66. package/chunks/Tooltip.js +0 -36
  67. package/chunks/VirtualizedMenu.js +45 -99
  68. package/chunks/getFade.js +4 -0
  69. package/chunks/useFocusTrapStack.js +0 -8
  70. package/chunks/useHelperTextId.js +0 -24
  71. package/chunks/useListNavigation.js +5 -17
  72. package/chunks/useMenuItemSelect.js +9 -22
  73. package/chunks/useMotionSafeTransition.js +0 -4
  74. package/chunks/useNestedParentMenu.js +5 -18
  75. package/chunks/usePrefersReducedMotion.js +6 -12
  76. package/chunks/useTooltipForceHide.js +0 -4
  77. package/chunks/useTrayNavigate.js +0 -1
  78. package/index.css +434 -135
  79. package/index.js +1 -1
  80. package/package.json +4 -4
  81. package/src/Accordion/Accordion.d.ts +1 -1
  82. package/src/Accordion/Accordion.type.d.ts +0 -21
  83. package/src/AccordionHeader/AccordionHeader.d.ts +1 -1
  84. package/src/AccordionHeader/AccordionHeader.type.d.ts +0 -14
  85. package/src/Alert/Alert.d.ts +1 -1
  86. package/src/Alert/Alert.type.d.ts +0 -32
  87. package/src/Animation/components/ExpandCollapseCaret/ExpandCollapseCaret.d.ts +0 -4
  88. package/src/Animation/components/ShowHideEye/ShowHideEye.d.ts +0 -4
  89. package/src/Animation/hooks/useMotionSafeTransition/useMotionSafeTransition.d.ts +0 -4
  90. package/src/Autocomplete/Autocomplete.d.ts +0 -5
  91. package/src/Autocomplete/Autocomplete.type.d.ts +0 -84
  92. package/src/Autocomplete/SuggestionList/SuggestionList.d.ts +5 -89
  93. package/src/Autocomplete/SuggestionList/SuggestionListItem.d.ts +0 -2
  94. package/src/Autocomplete/SuggestionList/utils/SuggestionListItem.d.ts +1 -13
  95. package/src/Autocomplete/SuggestionList/utils/useDynamicHeight.d.ts +0 -6
  96. package/src/Autocomplete/SuggestionList/utils/useHighlightScroll.d.ts +4 -23
  97. package/src/Autocomplete/SuggestionList/utils/useSuggestionList.d.ts +3 -41
  98. package/src/Autocomplete/SuggestionList/utils/useSuggestionListGroup.d.ts +0 -49
  99. package/src/Autocomplete/useAutocomplete.d.ts +5 -66
  100. package/src/Autocomplete/useAutocompleteTag.d.ts +3 -36
  101. package/src/Avatar/Avatar.type.d.ts +0 -58
  102. package/src/AvatarGroup/AvatarGroup.type.d.ts +0 -3
  103. package/src/Backdrop/Backdrop.type.d.ts +0 -4
  104. package/src/Badge/Badge.type.d.ts +0 -33
  105. package/src/Block/Block.type.d.ts +0 -24
  106. package/src/BlockHeader/BlockHeader.type.d.ts +0 -5
  107. package/src/BottomNavigation/BottomNavigation.type.d.ts +0 -34
  108. package/src/BottomNavigationItem/BottomNavigationItem.type.d.ts +0 -39
  109. package/src/Button/Button.type.d.ts +0 -30
  110. package/src/CallButton/CallButton.type.d.ts +0 -4
  111. package/src/Checkbox/Checkbox.type.d.ts +0 -17
  112. package/src/Chip/Chip.type.d.ts +0 -41
  113. package/src/CircularProgressIndicator/CircularProgressIndicator.d.ts +1 -1
  114. package/src/CircularProgressIndicator/CircularProgressIndicator.type.d.ts +0 -19
  115. package/src/DatePicker/Calendar.d.ts +1 -20
  116. package/src/DatePicker/DatePicker.type.d.ts +0 -18
  117. package/src/DatePicker/DatePickerHeader.d.ts +1 -12
  118. package/src/DatePicker/Day.d.ts +1 -8
  119. package/src/DatePicker/Year.d.ts +1 -7
  120. package/src/DatePicker/Years.d.ts +0 -7
  121. package/src/Dialer/DialDelete/DialDelete.d.ts +0 -3
  122. package/src/Dialer/DialPad/DialPad.d.ts +0 -106
  123. package/src/Dialer/DialPad/utils/types.d.ts +0 -5
  124. package/src/Dialer/DialPad/utils/useDialKeyboard.d.ts +0 -5
  125. package/src/Dialer/DialPad/utils/useKeyAudio.d.ts +0 -9
  126. package/src/Dialer/DialPadButton/DialPadButton.d.ts +0 -14
  127. package/src/Dialer/DialTextField/DialTextField.d.ts +0 -23
  128. package/src/Dialer/DialTextField/utils/getDialPadValueOnlyRegex.d.ts +0 -3
  129. package/src/Dialer/DialTextField/utils/useFixedEndSelection.d.ts +0 -3
  130. package/src/Dialog/Dialog.classes.d.ts +1 -1
  131. package/src/Dialog/Dialog.d.ts +1 -1
  132. package/src/Dialog/Dialog.type.d.ts +3 -11
  133. package/src/Divider/Divider.type.d.ts +0 -17
  134. package/src/DragHandle/DragHandle.type.d.ts +0 -4
  135. package/src/Drawer/Drawer.d.ts +1 -29
  136. package/src/Drawer/Drawer.type.d.ts +0 -84
  137. package/src/Dropdown/Dropdown.type.d.ts +0 -64
  138. package/src/EmptyState/EmptyState.d.ts +1 -1
  139. package/src/EmptyState/EmptyState.type.d.ts +0 -12
  140. package/src/FabButton/FabButton.type.d.ts +0 -5
  141. package/src/FocusTrap/FocusTrap.d.ts +0 -38
  142. package/src/FocusTrap/useFocusTrapStack.d.ts +0 -9
  143. package/src/FormField/FormField.type.d.ts +0 -26
  144. package/src/FormField/useHelperTextId.d.ts +0 -25
  145. package/src/FormLabel/FormLabel.d.ts +1 -1
  146. package/src/FormLabel/FormLabel.type.d.ts +0 -14
  147. package/src/Icon/Icon.d.ts +1 -1
  148. package/src/Icon/Icon.type.d.ts +0 -15
  149. package/src/IconButton/IconButton.type.d.ts +0 -30
  150. package/src/IconButton/IconButtonLabel.d.ts +1 -1
  151. package/src/IconButton/IconButtonLabel.type.d.ts +0 -3
  152. package/src/IconButtonGroup/IconButtonGroup.type.d.ts +0 -8
  153. package/src/InlineEditable/InlineEditable.type.d.ts +0 -75
  154. package/src/LinearProgressIndicator/LinearProgressIndicator.type.d.ts +0 -31
  155. package/src/Link/Link.classes.d.ts +1 -1
  156. package/src/Link/Link.type.d.ts +1 -10
  157. package/src/ListItem/ListItem.type.d.ts +0 -41
  158. package/src/ListItemText/ListItemText.d.ts +1 -1
  159. package/src/ListItemText/ListItemText.type.d.ts +0 -21
  160. package/src/ListNavigation/useListNavigation.d.ts +0 -16
  161. package/src/Menu/Menu.d.ts +1 -1
  162. package/src/Menu/Menu.type.d.ts +0 -10
  163. package/src/MenuFooter/MenuFooter.type.d.ts +0 -4
  164. package/src/MenuHeader/MenuHeader.type.d.ts +0 -10
  165. package/src/MenuItem/MenuItem.d.ts +1 -1
  166. package/src/MenuItem/MenuItem.type.d.ts +0 -19
  167. package/src/MenuItem/MenuItemSelectContext.d.ts +0 -3
  168. package/src/MenuItem/useMenuItemSelect.d.ts +0 -21
  169. package/src/MenuItemText/MenuItemText.d.ts +1 -1
  170. package/src/MenuItemText/MenuItemText.type.d.ts +0 -17
  171. package/src/MenuList/MenuList.type.d.ts +0 -4
  172. package/src/MenuList/MenuListContext.d.ts +0 -6
  173. package/src/Modal/InnerModal.d.ts +2 -2
  174. package/src/Modal/InnerModal.type.d.ts +0 -5
  175. package/src/Modal/Modal.classes.d.ts +1 -1
  176. package/src/Modal/Modal.d.ts +3 -3
  177. package/src/Modal/Modal.type.d.ts +0 -11
  178. package/src/Modal/ModalContext.d.ts +0 -4
  179. package/src/NestedMenuContext/NestedMenuContext.d.ts +1 -1
  180. package/src/Option/Option.d.ts +1 -1
  181. package/src/Option/Option.type.d.ts +0 -3
  182. package/src/Overlap/Overlap.type.d.ts +0 -11
  183. package/src/PageHeader/PageHeader.type.d.ts +0 -4
  184. package/src/PickerTextField/PickerTextField.type.d.ts +0 -10
  185. package/src/Popover/Popover.d.ts +1 -1
  186. package/src/Popover/Popover.type.d.ts +0 -29
  187. package/src/Popper/Popper.d.ts +1 -1
  188. package/src/Popper/Popper.type.d.ts +0 -61
  189. package/src/PopperPaper/PopperPaper.d.ts +1 -1
  190. package/src/Radio/Radio.type.d.ts +0 -5
  191. package/src/RadioGroup/RadioGroup.d.ts +1 -1
  192. package/src/RadioGroup/RadioGroup.type.d.ts +0 -4
  193. package/src/Rating/Rating.d.ts +1 -1
  194. package/src/Rating/Rating.type.d.ts +0 -74
  195. package/src/Rating/RatingItem.d.ts +1 -1
  196. package/src/Select/Select.type.d.ts +0 -84
  197. package/src/SingleFilter/FilterButton/FilterButton.d.ts +1 -1
  198. package/src/SingleFilter/FilterButton/FilterButton.type.d.ts +0 -16
  199. package/src/SingleFilter/SingleFilter.d.ts +1 -1
  200. package/src/SingleFilter/SingleFilter.type.d.ts +0 -26
  201. package/src/Skeleton/Skeleton.type.d.ts +0 -1
  202. package/src/Skeleton/SkeletonContainer/SkeletonContainer.classes.d.ts +1 -1
  203. package/src/Slider/Slider.classes.d.ts +1 -5
  204. package/src/Slider/Slider.d.ts +2 -2
  205. package/src/Slider/Slider.type.d.ts +0 -104
  206. package/src/Snackbar/Snackbar.type.d.ts +0 -18
  207. package/src/SortableListItem/SortableListItemOverlay.d.ts +1 -1
  208. package/src/SplitButton/SplitButton.d.ts +1 -1
  209. package/src/SplitButton/SplitButton.type.d.ts +0 -21
  210. package/src/Squircle/Squircle.type.d.ts +0 -3
  211. package/src/StatusIndicator/StatusIndicator.classes.d.ts +1 -1
  212. package/src/StatusIndicator/StatusIndicator.type.d.ts +1 -9
  213. package/src/Step/Step.type.d.ts +0 -29
  214. package/src/Step/StepContext.d.ts +0 -7
  215. package/src/StepButton/StepButton.type.d.ts +0 -15
  216. package/src/StepContent/StepContent.d.ts +1 -1
  217. package/src/StepContent/StepContent.type.d.ts +0 -7
  218. package/src/StepIcon/StepIcon.type.d.ts +0 -26
  219. package/src/StepLabel/StepLabel.d.ts +1 -1
  220. package/src/StepLabel/StepLabel.type.d.ts +0 -23
  221. package/src/Stepper/Stepper.type.d.ts +0 -27
  222. package/src/SubMenu/PopperMenu.d.ts +1 -1
  223. package/src/SubMenu/SubMenu.d.ts +1 -1
  224. package/src/SwipeableDrawer/SwipeableDrawer.d.ts +1 -27
  225. package/src/SwipeableDrawer/SwipeableDrawer.types.d.ts +0 -67
  226. package/src/SwipeableDrawer/hooks/useDrawerGestures.d.ts +0 -110
  227. package/src/SwipeableDrawer/hooks/useElementSizeObserver.d.ts +0 -5
  228. package/src/SwipeableDrawer/hooks/useSnapPoints.d.ts +0 -60
  229. package/src/Switch/Switch.type.d.ts +0 -9
  230. package/src/Tab/Tab.classes.d.ts +3 -2
  231. package/src/Tab/Tab.d.ts +1 -1
  232. package/src/Tab/Tab.type.d.ts +0 -29
  233. package/src/TabContext/TabContext.d.ts +0 -4
  234. package/src/TabContext/TabContext.type.d.ts +0 -7
  235. package/src/TabPanel/TabPanel.d.ts +1 -1
  236. package/src/TabPanel/TabPanel.type.d.ts +0 -10
  237. package/src/Table/Table.type.d.ts +0 -19
  238. package/src/TableBody/TableBody.type.d.ts +0 -3
  239. package/src/TableCell/TableCell.d.ts +0 -4
  240. package/src/TableCell/TableCell.type.d.ts +0 -35
  241. package/src/TableContainer/TableContainer.type.d.ts +0 -7
  242. package/src/TableFooter/TableFooter.type.d.ts +0 -3
  243. package/src/TableHead/TableHead.type.d.ts +0 -6
  244. package/src/TablePagination/TablePagination.type.d.ts +0 -47
  245. package/src/TableRow/TableRow.type.d.ts +0 -17
  246. package/src/Tabs/TabMoreMenu.d.ts +0 -16
  247. package/src/Tabs/TabScrollButton.d.ts +1 -11
  248. package/src/Tabs/Tabs.classes.d.ts +1 -1
  249. package/src/Tabs/Tabs.d.ts +1 -1
  250. package/src/Tabs/Tabs.type.d.ts +2 -36
  251. package/src/Tabs/TabsContext.d.ts +2 -0
  252. package/src/Tabs/hooks/useTabsScroller.d.ts +0 -30
  253. package/src/Tag/Tag.d.ts +1 -1
  254. package/src/Tag/Tag.type.d.ts +0 -12
  255. package/src/Text/Text.type.d.ts +0 -13
  256. package/src/TextField/TextField.type.d.ts +0 -64
  257. package/src/Textarea/Textarea.d.ts +1 -1
  258. package/src/Textarea/Textarea.type.d.ts +0 -13
  259. package/src/TimePicker/NumberPicker.d.ts +1 -1
  260. package/src/TimePicker/NumberPicker.type.d.ts +0 -12
  261. package/src/TimePicker/SelectionView.d.ts +0 -6
  262. package/src/TimePicker/TimeButton.d.ts +1 -4
  263. package/src/TimePicker/TimePicker.type.d.ts +0 -11
  264. package/src/TimePicker/ToggleText.d.ts +1 -1
  265. package/src/TimePicker/ToggleText.type.d.ts +0 -3
  266. package/src/TimePicker/utils/TimeBoundary.d.ts +0 -3
  267. package/src/TimePicker/utils/TimePickerHelper.d.ts +0 -19
  268. package/src/TimePicker/utils/getNumberPickerBoundary.d.ts +0 -3
  269. package/src/Tooltip/TooltipTrigger.a11y.d.ts +0 -9
  270. package/src/Tooltip/TooltipTrigger.type.d.ts +0 -44
  271. package/src/Tooltip/TooltipView.type.d.ts +0 -25
  272. package/src/Tooltip/useTooltipForceHide.d.ts +0 -4
  273. package/src/Tray/Tray.d.ts +1 -1
  274. package/src/Tray/Tray.type.d.ts +0 -13
  275. package/src/Tray/TrayContext.d.ts +0 -4
  276. package/src/Tray/hooks/useTray.d.ts +0 -16
  277. package/src/Tray/hooks/useTrayPanel.d.ts +0 -3
  278. package/src/TrayMenu/TrayMenu.d.ts +1 -1
  279. package/src/TrayMenu/TrayMenuItem.d.ts +1 -1
  280. package/src/VirtualizedList/VirtualizedList.type.d.ts +0 -27
  281. package/src/VirtualizedMenu/VirtualizedMenu.classes.d.ts +1 -1
  282. 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, useRefState, useEventCallback, logInDev, combineProps, useDepsChange, useControlled, useId, useForceUpdate, useKeyboardMoveFocus, useForkRef, useVirtuosoExternalWindow, 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,46 +86,55 @@ const useDynamicHeight = ({ itemCount, maxContainerHeight, onContainerHeightChan
87
86
  };
88
87
  };
89
88
 
90
- /**
91
- * scroll into current highlight index
92
- */
93
- function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
89
+ function useHighlightScroll({ virtualize = true, containerHeighRef, scrollToIndex, }) {
94
90
  const renderedItemsRef = useRef([]);
95
91
  const scrollerRef = useRef();
96
92
  const scrollToHighlightedIndex = (prevHighlightedIndex, currHighlightedIndex, topHighlightIndex = 0) => {
93
+ const needsScrollReset = prevHighlightedIndex === -1;
97
94
  if (!scrollerRef.current) {
98
95
  if (currHighlightedIndex !== topHighlightIndex) {
99
- requestAnimationFrame(() => {
100
- scrollToIndex({
101
- index: currHighlightedIndex,
102
- align: 'start',
103
- });
96
+ scrollToIndex({
97
+ index: currHighlightedIndex,
98
+ align: 'start',
104
99
  });
105
100
  }
106
101
  return;
107
102
  }
108
103
  const scrollElm = scrollerRef.current;
104
+ if (!virtualize) {
105
+ if (needsScrollReset && currHighlightedIndex === topHighlightIndex) {
106
+ scrollElm.scrollTop = 0;
107
+ return;
108
+ }
109
+ scrollToIndex({
110
+ index: currHighlightedIndex,
111
+ align: 'start',
112
+ });
113
+ return;
114
+ }
109
115
  const renderedItems = renderedItemsRef.current;
110
- const isBackward = prevHighlightedIndex > currHighlightedIndex;
111
- const isForward = prevHighlightedIndex < currHighlightedIndex;
116
+ const lastHighlightedIndex = needsScrollReset
117
+ ? currHighlightedIndex
118
+ : prevHighlightedIndex;
119
+ const isBackward = lastHighlightedIndex > currHighlightedIndex;
120
+ const isForward = lastHighlightedIndex < currHighlightedIndex;
112
121
  const currentVisibleOffset = {
113
122
  start: scrollElm.scrollTop,
114
123
  stop: scrollElm.scrollTop + containerHeighRef.current,
115
124
  };
116
- // * when highlightedIndex is out of visible range
117
- if (!renderedItems.some((x) => x.index === currHighlightedIndex)) {
125
+ const isInRenderedRange = renderedItems.some((x) => x.index === currHighlightedIndex);
126
+ if (!isInRenderedRange) {
118
127
  scrollToIndex({
119
128
  index: currHighlightedIndex,
120
129
  align: isBackward ? 'start' : 'end',
121
130
  });
122
131
  return;
123
132
  }
124
- // backward
125
133
  if (isBackward) {
126
134
  let firstShouldScrollIndex = currHighlightedIndex;
127
135
  for (let i = renderedItems.length - 1; i >= 0; i--) {
128
136
  const item = renderedItems[i];
129
- if (item.offset <= currentVisibleOffset.start) {
137
+ if (item.offset < currentVisibleOffset.start) {
130
138
  break;
131
139
  }
132
140
  firstShouldScrollIndex = item.index;
@@ -137,18 +145,18 @@ function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
137
145
  align: 'start',
138
146
  });
139
147
  }
140
- // forward
141
148
  }
142
149
  else if (isForward) {
143
150
  let lastShouldScrollIndex = currHighlightedIndex;
144
151
  for (let i = 0; i < renderedItems.length; i++) {
145
152
  const item = renderedItems[i];
146
- if (item.offset >= currentVisibleOffset.stop) {
153
+ const itemBottom = item.offset + item.size;
154
+ if (itemBottom >= currentVisibleOffset.stop) {
147
155
  break;
148
156
  }
149
157
  lastShouldScrollIndex = item.index;
150
158
  }
151
- if (currHighlightedIndex >= lastShouldScrollIndex) {
159
+ if (currHighlightedIndex > lastShouldScrollIndex) {
152
160
  scrollToIndex({
153
161
  index: currHighlightedIndex,
154
162
  align: 'end',
@@ -156,31 +164,45 @@ function useHighlightScroll({ containerHeighRef, scrollToIndex, }) {
156
164
  }
157
165
  }
158
166
  else {
159
- scrollToIndex({
160
- index: currHighlightedIndex,
161
- align: 'start',
162
- });
167
+ const currentItem = renderedItems.find((item) => item.index === currHighlightedIndex);
168
+ if (needsScrollReset) {
169
+ if (currHighlightedIndex === topHighlightIndex) {
170
+ if (scrollerRef.current) {
171
+ scrollerRef.current.scrollTop = 0;
172
+ }
173
+ return;
174
+ }
175
+ else {
176
+ scrollToIndex({
177
+ index: currHighlightedIndex,
178
+ align: 'start',
179
+ });
180
+ return;
181
+ }
182
+ }
183
+ if (!currentItem) {
184
+ scrollToIndex({
185
+ index: currHighlightedIndex,
186
+ align: 'start',
187
+ });
188
+ return;
189
+ }
190
+ const itemBottom = currentItem.offset + currentItem.size;
191
+ const isTopVisible = currentItem.offset >= currentVisibleOffset.start;
192
+ const isBottomVisible = itemBottom < currentVisibleOffset.stop;
193
+ const isFullyVisible = isTopVisible && isBottomVisible;
194
+ if (!isFullyVisible) {
195
+ scrollToIndex({
196
+ index: currHighlightedIndex,
197
+ align: 'start',
198
+ });
199
+ }
163
200
  }
164
201
  };
165
202
  return {
166
- /**
167
- * scroller reference
168
- */
169
203
  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
204
  scrollToHighlightedIndex,
177
- /**
178
- * set to virtuoso `scrollerRef` prop, auto bind inner `scrollerRef`
179
- */
180
205
  scrollerRefFn: (elm) => (scrollerRef.current = elm),
181
- /**
182
- * set to virtuoso `itemsRendered` prop, auto bind inner `renderedItemsRef`
183
- */
184
206
  itemsRendered: (e) => (renderedItemsRef.current = e),
185
207
  };
186
208
  }
@@ -216,11 +238,9 @@ const useAutocompleteGroup = ({ groupBy, options, filteredResult, getExpandIconP
216
238
  e.stopPropagation();
217
239
  });
218
240
  const optionsGroupList = useMemo(() => {
219
- /** key with this group count */
220
241
  if (!groupBy || !options) {
221
242
  return [];
222
243
  }
223
- // used to keep track of key and indexes in the result array
224
244
  const indexBy = new Map();
225
245
  let warn = false;
226
246
  const afterGroupFn = [];
@@ -274,11 +294,8 @@ const useAutocompleteGroup = ({ groupBy, options, filteredResult, getExpandIconP
274
294
  id: `${id}-${group}`,
275
295
  label: group,
276
296
  disabled: true,
277
- // * here cause by self Type reference
278
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
279
297
  group: newGroup,
280
298
  };
281
- // push fn to array, do that after all options be add into group
282
299
  if (getOptionDisabled) {
283
300
  afterGroupFn.push(() => {
284
301
  groupTitleOption.disabled = getOptionDisabled(groupTitleOption);
@@ -319,7 +336,6 @@ const useAutocompleteGroup = ({ groupBy, options, filteredResult, getExpandIconP
319
336
  initGroupExpandedState(groupExpanded);
320
337
  }, [groupExpanded]);
321
338
  const groupExpandedMap = groupExpandedMapRef.current;
322
- // * speared logic with group, prevent calculate every time.
323
339
  const groupedResult = useMemo(() => {
324
340
  const addExpandedResult = Object.entries(groupExpandedMap).reduce((prev, [key, expended]) => {
325
341
  const group = prev.find((x) => x.group === key);
@@ -351,10 +367,8 @@ const isItemCanSelected = (item) => {
351
367
  };
352
368
  const toOptionIdString = (id) => typeof id === 'number' ? String(id) : id;
353
369
  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, }) => {
370
+ const defaultIsOptionEqualToValue = (option, value) => option === value;
371
+ 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
372
  const isTitleMode = groupVariant === 'normal';
359
373
  const [inputValue, setInputValue] = useControlled({
360
374
  controlled: inputValueProp,
@@ -376,12 +390,12 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
376
390
  inputValue,
377
391
  getOptionLabel,
378
392
  selectedItems: [],
393
+ isOptionEqualToValue,
379
394
  });
380
395
  }
381
396
  return items;
382
- }, [filterOptions, getOptionLabel, inputValue]);
397
+ }, [filterOptions, getOptionLabel, inputValue, isOptionEqualToValue]);
383
398
  const filteredResult = useMemo(() => {
384
- // * only when isOpen calculate the filtered result
385
399
  let results = getFilteredItems(options);
386
400
  results = processFilteredResult
387
401
  ? processFilteredResult(results, inputValue)
@@ -454,7 +468,7 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
454
468
  });
455
469
  const getItemProps = ({ item, index = 0, }) => {
456
470
  const currGroup = item.group;
457
- const isGroupTitle = item === currGroup?.options[0];
471
+ const isItemFirstInGroup = isFirstInGroup(item);
458
472
  const itemCount = optionItems.length;
459
473
  const groupOrder = currGroup?.order || 0;
460
474
  const stringId = toOptionIdString(item.id);
@@ -469,8 +483,7 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
469
483
  setHighlightedIndex(index, { reason: 'mouse', reRender: true });
470
484
  }
471
485
  },
472
- // When title mode and is title, skip that posinset
473
- ...(isTitleMode && isGroupTitle
486
+ ...(isTitleMode && isItemFirstInGroup
474
487
  ? {}
475
488
  : {
476
489
  role: 'option',
@@ -509,9 +522,8 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
509
522
  return;
510
523
  if (highlightedIndex !== DEFAULT_HIGHLIGHTED_INDEX$1) {
511
524
  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
525
+ const isCurrOptionFirstInGroup = isFirstInGroup(currOption);
526
+ if (isCurrOptionFirstInGroup) {
515
527
  const { onClick } = currOption.group.getExpandIconProps();
516
528
  onClick?.(e);
517
529
  }
@@ -520,7 +532,6 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
520
532
  }
521
533
  e.stopPropagation();
522
534
  }
523
- // always preventDefault for not inset all enter into textarea
524
535
  e.preventDefault();
525
536
  break;
526
537
  }
@@ -597,30 +608,54 @@ const useSuggestionList = ({ id, inputValue: inputValueProp, getOptionLabel = DE
597
608
  changeHighlightedIndexReasonRef,
598
609
  changeHighlightedIndexReason: changeHighlightedIndexReasonRef.current,
599
610
  optionsGroupList,
600
- /** current unique id */
601
611
  id: currUniqueId,
602
612
  getNextFocusableOption,
603
613
  handleF10KeyDown,
604
614
  };
605
615
  };
606
616
 
617
+ const DEFAULT_PADDING = 8;
618
+ const getPaddingValue = (padding, itemCount) => {
619
+ if (itemCount === 0) {
620
+ return 0;
621
+ }
622
+ if (padding === false) {
623
+ return 0;
624
+ }
625
+ if (padding === true) {
626
+ return DEFAULT_PADDING;
627
+ }
628
+ if (typeof padding === 'number') {
629
+ return Math.max(0, padding);
630
+ }
631
+ return DEFAULT_PADDING;
632
+ };
607
633
  const List = forwardRef((props, ref) => {
608
- const { className, context } = props;
634
+ const { className, context, style, ...restProps } = props;
609
635
  const listRef = context?.listRef;
610
636
  const rootClass = context?.rootClass;
637
+ const paddingValue = context?.paddingValue ?? 0;
611
638
  const forkRef = useForkRef(ref, listRef);
612
- return (jsx("div", { ref: forkRef, className: clsx(className, rootClass), "data-suggestion-list": true, ...props }));
639
+ return (jsx("div", { ref: forkRef, ...restProps, className: clsx(className, rootClass), "data-suggestion-list": true, style: {
640
+ ...style,
641
+ ['--sui-suggestion-list-vertical-padding']: `${paddingValue}px`,
642
+ } }));
613
643
  });
614
644
  const SuggestionList = forwardRef((inProps, ref) => {
615
645
  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;
646
+ 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
647
  const vlRef = useRef(null);
618
648
  const forkVlRef = useForkRef(ref, vlRef);
619
649
  const isTitleMode = groupVariant === 'normal';
620
650
  const listRef = useRef(null);
621
651
  const itemData = options;
622
652
  const itemCount = options.length;
623
- const cls = useClasses('suggestion-list', classesProp, classNameProp);
653
+ const externalWindowProps = useVirtuosoExternalWindow();
654
+ const internalPrevHighlightedIndex = usePrevious(() => highlightedIndex, true);
655
+ const actualPrevHighlightedIndex = prevHighlightedIndex ?? internalPrevHighlightedIndex;
656
+ const cls = useClassesWithMode('suggestion-list', classesProp, classNameProp);
657
+ const paddingValue = getPaddingValue(padding, itemCount);
658
+ const hasItemsRenderedRef = useRef(false);
624
659
  const { totalListHeightChanged, style, containerHeighRef } = useDynamicHeight({
625
660
  itemCount,
626
661
  maxContainerHeight,
@@ -632,43 +667,96 @@ const SuggestionList = forwardRef((inProps, ref) => {
632
667
  }
633
668
  },
634
669
  });
670
+ const handleTotalListHeightChanged = (height) => {
671
+ const adjustedHeight = paddingValue > 0 ? height + paddingValue * 2 : height;
672
+ if (!hasItemsRenderedRef.current &&
673
+ adjustedHeight < containerHeighRef.current) {
674
+ return;
675
+ }
676
+ totalListHeightChanged(adjustedHeight);
677
+ };
635
678
  const { sleep } = useSleep();
636
679
  const { retry: scrollToIndexWithRetry } = useRetry(async (location) => {
637
680
  const toIndex = location.index;
638
681
  if (!virtualize) {
639
- const toElm = listRef.current?.querySelector(`[data-item-index="${toIndex}"]`);
640
- toElm?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
682
+ const scroller = listRef.current;
683
+ const needsScrollReset = prevHighlightedIndex === -1;
684
+ const isLastItem = itemCount > 1 && toIndex === itemCount - 1;
685
+ if (paddingValue > 0 && needsScrollReset && isLastItem && scroller) {
686
+ scroller.scrollTop = scroller.scrollHeight;
687
+ return true;
688
+ }
689
+ const toElm = scroller?.querySelector(`[data-item-index="${toIndex}"]`);
690
+ if (!toElm || !scroller) {
691
+ return false;
692
+ }
693
+ const scrollerRect = scroller.getBoundingClientRect();
694
+ const elementRect = toElm.getBoundingClientRect();
695
+ const scrollerTop = scrollerRect.top;
696
+ const scrollerBottom = scrollerRect.bottom;
697
+ const elementTop = elementRect.top;
698
+ const elementBottom = elementRect.bottom;
699
+ const isFullyVisible = elementTop >= scrollerTop && elementBottom <= scrollerBottom;
700
+ if (!isFullyVisible) {
701
+ let scrollOffset = 0;
702
+ if (elementTop < scrollerTop) {
703
+ scrollOffset = toElm.offsetTop - paddingValue;
704
+ }
705
+ else if (elementBottom > scrollerBottom) {
706
+ scrollOffset =
707
+ toElm.offsetTop -
708
+ scroller.clientHeight +
709
+ toElm.offsetHeight +
710
+ paddingValue;
711
+ }
712
+ scroller.scrollTo({
713
+ top: scrollOffset,
714
+ behavior: 'auto',
715
+ });
716
+ }
641
717
  return true;
642
718
  }
643
- if (location.index === 0 && padding !== undefined) {
719
+ if (paddingValue > 0 &&
720
+ (location.align === 'start' || location.align === 'end')) {
644
721
  location = {
645
722
  ...location,
646
- offset: -(typeof padding === 'number' ? padding : 8),
723
+ offset: paddingValue,
647
724
  };
648
725
  }
649
726
  vlRef.current?.scrollToIndex(location);
650
727
  await sleep(0);
651
- // confirm that scrollInto view
652
728
  const toElm = listRef.current?.querySelector(`[data-item-index="${toIndex}"]`);
653
729
  return !!toElm;
654
730
  }, {
655
731
  retryTimes: 10,
656
732
  intervalTime: 20,
657
733
  });
658
- const { scrollerRef, scrollerRefFn, itemsRendered, scrollToHighlightedIndex, } = useHighlightScroll({
734
+ const { scrollerRef, scrollerRefFn, itemsRendered: itemsRenderedFromHook, scrollToHighlightedIndex, } = useHighlightScroll({
735
+ virtualize,
659
736
  containerHeighRef,
660
737
  scrollToIndex: scrollToIndexWithRetry,
661
738
  });
662
- const prevHighlightedIndex = usePrevious(() => highlightedIndex, true);
739
+ const handleItemsRendered = (items) => {
740
+ if (items.length > 0 || itemCount === 0) {
741
+ hasItemsRenderedRef.current = true;
742
+ }
743
+ itemsRenderedFromHook(items);
744
+ };
745
+ useEffect(() => {
746
+ if (itemCount > 0) {
747
+ hasItemsRenderedRef.current = false;
748
+ }
749
+ }, [itemCount]);
663
750
  useLayoutEffect(() => {
664
- if ((!virtualize || vlRef.current) &&
751
+ const shouldScroll = (!virtualize || vlRef.current) &&
665
752
  !isKeepHighlightedIndex &&
666
- // * only scroll when reason is 'keyboard'
667
753
  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);
754
+ changeHighlightedIndexReason !== 'mouse';
755
+ const firstOption = options[0];
756
+ const isFirstItemGroupTitle = isTitleMode && isFirstInGroup(firstOption);
757
+ const topHighlightIndex = isFirstItemGroupTitle ? 1 : 0;
758
+ if (shouldScroll) {
759
+ scrollToHighlightedIndex(actualPrevHighlightedIndex, highlightedIndex, topHighlightIndex);
672
760
  }
673
761
  });
674
762
  const handleScrolling = (scrolling) => {
@@ -678,12 +766,11 @@ const SuggestionList = forwardRef((inProps, ref) => {
678
766
  list.style.pointerEvents = scrolling ? 'none' : '';
679
767
  };
680
768
  const itemContent = (index, option) => {
681
- const currGroup = option.group;
682
- const isGroupTitle = option === currGroup?.options[0];
769
+ const isOptionFirstInGroup = isFirstInGroup(option);
683
770
  const isFixedGroupExpanded = typeof groupExpanded === 'boolean';
684
- const expandable = !isTitleMode && !isFixedGroupExpanded && isGroupTitle;
771
+ const expandable = !isTitleMode && !isFixedGroupExpanded && isOptionFirstInGroup;
685
772
  const expanded = option.group?.expanded;
686
- const expandIconProps = !expandable
773
+ const expandIconProps = expandable
687
774
  ? option.group?.getExpandIconProps?.({
688
775
  className: cls('expand-icon'),
689
776
  'aria-expanded': expanded,
@@ -704,7 +791,6 @@ const SuggestionList = forwardRef((inProps, ref) => {
704
791
  const selected = getOptionSelected?.(option);
705
792
  const indexInOwnGroup = resultProps.indexInOwnGroup;
706
793
  delete resultProps.indexInOwnGroup;
707
- // * when item is not disabled, that should check outside is that disabled
708
794
  if (!resultProps.freeSolo && !resultProps.disabled && getOptionDisabled) {
709
795
  resultProps.disabled = getOptionDisabled(option);
710
796
  }
@@ -714,7 +800,7 @@ const SuggestionList = forwardRef((inProps, ref) => {
714
800
  index,
715
801
  indexInOwnGroup,
716
802
  };
717
- if (renderGroup && isGroupTitle) {
803
+ if (renderGroup && isOptionFirstInGroup) {
718
804
  return renderGroup(resultProps, {
719
805
  ...state,
720
806
  expanded,
@@ -725,40 +811,33 @@ const SuggestionList = forwardRef((inProps, ref) => {
725
811
  return renderOption(resultProps, state);
726
812
  }
727
813
  const { error, group, freeSolo, key, ...restProps } = resultProps;
728
- return (jsxs(SuggestionListItem, { ...restProps, id: typeof resultProps.id === 'number'
814
+ return (jsx(SuggestionListItem, { ...restProps, id: typeof resultProps.id === 'number'
729
815
  ? `${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));
816
+ : 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
817
  };
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
818
  const components = {
741
819
  List: List,
742
- Header: PaddingComponent,
743
- Footer: PaddingComponent,
744
820
  ...componentsProp,
745
821
  };
746
822
  const rootClass = cls('root');
747
- const context = { listRef, rootClass };
748
- return virtualize ? (jsx(Virtuoso, { ref: forkVlRef, totalCount: itemCount, data: itemData, context: context, components: components, itemContent: itemContent, ...getSuggestionListProps(), ...combineProps({
823
+ const context = { listRef, rootClass, paddingValue };
824
+ return virtualize ? (jsx(Virtuoso, { ref: forkVlRef, totalCount: itemCount, data: itemData, context: context, components: components, itemContent: itemContent, ...externalWindowProps, ...getSuggestionListProps(), ...combineProps({
749
825
  scrollerRef: (scrollElm) => {
750
826
  scrollerRefFn(scrollElm);
751
827
  },
752
- itemsRendered,
753
- totalListHeightChanged,
828
+ itemsRendered: handleItemsRendered,
829
+ totalListHeightChanged: handleTotalListHeightChanged,
754
830
  style,
755
831
  isScrolling: handleScrolling,
756
- }, rest) })) : (jsxs(List, { style: { maxHeight: style.height, overflow: 'auto' }, ref: (scrollElm) => {
832
+ }, rest) })) : (jsx(List, { context: context, style: {
833
+ maxHeight: style.height,
834
+ overflow: 'auto',
835
+ }, ref: (scrollElm) => {
757
836
  listRef.current = scrollElm;
758
837
  scrollerRefFn(scrollElm);
759
- }, className: cls('root'), ...getSuggestionListProps(), ...rest, children: [jsx(PaddingComponent, {}), options.map((x, i) => {
760
- return itemContent(i, x);
761
- }), jsx(PaddingComponent, {})] }));
838
+ }, className: cls('root'), ...getSuggestionListProps(), ...rest, children: options.map((x, i) => {
839
+ return itemContent(i, x);
840
+ }) }));
762
841
  });
763
842
  SuggestionList.displayName = 'SuggestionList';
764
843
 
@@ -770,7 +849,6 @@ function stringArrToRegExp(keyToTags) {
770
849
  const TAG_TOKEN = 'rc-chip-';
771
850
  const DEFAULT_LIMIT_CHIPS$1 = 20;
772
851
  const DEFAULT_KEY_TO_CHIPS = [';', ',', '\\n'];
773
- /** @inner inner hook work with useAutocomplete */
774
852
  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
853
  const isAutocomplete = variant === 'autocomplete';
776
854
  const isSelectedFromAutocompleteRef = useRef(false);
@@ -810,7 +888,6 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
810
888
  if (focus)
811
889
  _focusTag(tagToFocus);
812
890
  });
813
- /** when return `true` mean add item success */
814
891
  const checkAndAddFreeSolo = ({ selectedItem, value, } = {}, e) => {
815
892
  let isAddItem = false;
816
893
  const currentValue = value ?? inputRef.current?.value;
@@ -869,7 +946,6 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
869
946
  onAddTags?.();
870
947
  };
871
948
  const addTagOnSelect = (selectedItem) => {
872
- // * change to uniqueId
873
949
  if (selectedItem.freeSolo) {
874
950
  if (freeSoloCount < maxFreeSolo) {
875
951
  selectedItem.id = uniqueId(TAG_TOKEN);
@@ -895,32 +971,20 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
895
971
  event?.preventDefault();
896
972
  },
897
973
  });
898
- /**
899
- * All Get props methods
900
- */
901
974
  const getTagListBoxProps = (props) => {
902
975
  return {
903
976
  'aria-required': required || false,
904
977
  '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
978
  ...props,
910
979
  };
911
980
  };
912
981
  const getTagProps = ({ index, selectedItem, ...restTagProps }) => {
913
- const tabIndex =
914
- // * when tag is not focus
915
- !focused &&
916
- // * and is first item
982
+ const tabIndex = !focused &&
917
983
  index === 0
918
984
  ? 0
919
985
  : -1;
920
986
  return combineProps({
921
987
  tabIndex,
922
- // TODO: wait for input can complete that.
923
- // role: 'option',
924
988
  role: 'button',
925
989
  key: `${AutocompleteId}-selected-item-${index}`,
926
990
  'data-tag-index': index,
@@ -939,9 +1003,7 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
939
1003
  case 'Backspace':
940
1004
  {
941
1005
  const lengthBeforeDelete = tags.length;
942
- focusTag(
943
- // * when length is 1 mean that will be remove all
944
- lengthBeforeDelete === 1
1006
+ focusTag(lengthBeforeDelete === 1
945
1007
  ? -1
946
1008
  : focusedIndex === 0
947
1009
  ? 0
@@ -952,9 +1014,7 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
952
1014
  case 'Delete':
953
1015
  {
954
1016
  const lengthBeforeDelete = tags.length;
955
- focusTag(
956
- // * when length is 1 mean that will be remove all
957
- lengthBeforeDelete === 1
1017
+ focusTag(lengthBeforeDelete === 1
958
1018
  ? -1
959
1019
  : focusedIndex === tags.length - 1
960
1020
  ? focusedIndex - 1
@@ -968,7 +1028,6 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
968
1028
  }
969
1029
  },
970
1030
  onDelete: (e) => {
971
- // * only allow left button click
972
1031
  if (e.button !== 0)
973
1032
  return;
974
1033
  removeTag(selectedItem);
@@ -1009,7 +1068,7 @@ const useAutocompleteTag = ({ id: AutocompleteId, value: selectedItemsProp = [],
1009
1068
  const EMPTY_TAG_TOKEN = 'rc-chip-empty';
1010
1069
  const DEFAULT_HIGHLIGHTED_INDEX = -1;
1011
1070
  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, }) => {
1071
+ 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
1072
  const isAutocomplete = variant === 'autocomplete';
1014
1073
  const autoCompleteSelectedIndexRef = useRef(DEFAULT_HIGHLIGHTED_INDEX);
1015
1074
  const AutocompleteId = useId('Autocomplete', true);
@@ -1031,7 +1090,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1031
1090
  const keepHighlightedIndexRef = useRef(false);
1032
1091
  const popperElementRef = useRef(null);
1033
1092
  const { sleep, getSleeping } = useSleep();
1034
- // * when that is autocomplete, that will never be multiple
1035
1093
  const multiple = isAutocomplete ? false : multipleProp;
1036
1094
  const inputContainerScrollToBottom = () => {
1037
1095
  requestAnimationFrame(() => {
@@ -1057,7 +1115,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1057
1115
  multiple,
1058
1116
  required,
1059
1117
  disabled,
1060
- // * when is composition, stop freeSolo create new item
1061
1118
  getStopCreateFreeSolo: () => isCompositionRef.current,
1062
1119
  onReset: () => {
1063
1120
  resetState();
@@ -1076,7 +1133,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1076
1133
  }
1077
1134
  return null;
1078
1135
  };
1079
- // * only when isOpen calculate the filtered result
1080
1136
  noOptionItemRef.current = null;
1081
1137
  if (addNoOptionItem) {
1082
1138
  const item = getInputValueAsItem();
@@ -1093,9 +1149,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1093
1149
  else if (results.length === 0) {
1094
1150
  const item = getInputValueAsItem();
1095
1151
  noOptionItemRef.current = item;
1096
- // * only when not set render no options will auto add item
1097
1152
  if (item && freeSolo && !renderNoOptions) {
1098
- // * when outside not use filter, that will be original array, must use spread
1099
1153
  return [...results, item];
1100
1154
  }
1101
1155
  }
@@ -1130,6 +1184,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1130
1184
  groupBy,
1131
1185
  onGroupExpanded,
1132
1186
  getExpandIconProps,
1187
+ isOptionEqualToValue,
1133
1188
  onSelect: (e, selectedItem) => {
1134
1189
  addTagOnSelect(selectedItem);
1135
1190
  resetState(e);
@@ -1137,10 +1192,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1137
1192
  if (autoHighlight) {
1138
1193
  const currIndex = highlightedIndexRef.current;
1139
1194
  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 ||
1195
+ const toIndex = nextValidIndex > currIndex ||
1144
1196
  nextValidIndex === optionItems.length - 1
1145
1197
  ? nextValidIndex - 1
1146
1198
  : nextValidIndex;
@@ -1155,23 +1207,12 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1155
1207
  },
1156
1208
  });
1157
1209
  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
- });
1210
+ return getSuggestionListItemProps(props);
1169
1211
  };
1170
1212
  const readOnly = !isAutocomplete && !multiple && tags.length >= 1 ? true : undefined;
1171
1213
  const closeMenu = (e, reason) => {
1172
1214
  keepHighlightedIndexRef.current = false;
1173
1215
  isInputValueChangedRef.current = false;
1174
- // * set to default highlighted
1175
1216
  setHighlightedIndex(DEFAULT_HIGHLIGHTED_INDEX, { reason: 'auto' });
1176
1217
  if (isOpen) {
1177
1218
  if (e && reason) {
@@ -1200,8 +1241,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1200
1241
  const handleInputChange = (newValue, open = true, e) => {
1201
1242
  if (inputValue !== newValue) {
1202
1243
  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
1244
  if (stringArrToRegExp(keyToTags).test((newValue || '').trim())) {
1206
1245
  const resultHaveAdd = checkAndAddFreeSolo({ value: newValue }, e);
1207
1246
  if (!disableCloseOnSelect) {
@@ -1219,7 +1258,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1219
1258
  return false;
1220
1259
  };
1221
1260
  const resetState = (e) => {
1222
- // * when autocomplete select mode not reset input value
1223
1261
  if (!isSelectedFromAutocompleteRef.current) {
1224
1262
  clearInput();
1225
1263
  }
@@ -1239,18 +1277,15 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1239
1277
  const keepHighlightedIndex = () => {
1240
1278
  keepHighlightedIndexRef.current = true;
1241
1279
  };
1242
- // * when outside options props props change also need set highlightedIndex to default
1243
1280
  useChange(() => {
1244
1281
  const shouldResetHighlightedIndex = !keepHighlightedIndexRef.current;
1245
1282
  if (options !== undefined && shouldResetHighlightedIndex) {
1246
1283
  setHighlightedIndex(DEFAULT_HIGHLIGHTED_INDEX, { reason: 'auto' });
1247
1284
  }
1248
1285
  }, () => options);
1249
- // * check that defaultHighlightedIndex
1250
1286
  const defaultHighlightedIndex = useMemo(() => {
1251
1287
  return autoHighlight ? getNextFocusableOption(0) : -1;
1252
1288
  }, [autoHighlight, getNextFocusableOption]);
1253
- // * only when menu is open set to defaultHighlightedIndex
1254
1289
  if (isOpen) {
1255
1290
  if (highlightedIndexRef.current === DEFAULT_HIGHLIGHTED_INDEX) {
1256
1291
  let toIndex = defaultHighlightedIndex;
@@ -1283,13 +1318,11 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1283
1318
  onInputChangeProp?.(result);
1284
1319
  }
1285
1320
  };
1286
- // * use force update to sync open state when init is open
1287
1321
  useLayoutEffect(() => {
1288
1322
  if (isOpen) {
1289
1323
  forceUpdate();
1290
1324
  }
1291
1325
  handleAutocompleteText();
1292
- // eslint-disable-next-line react-hooks/exhaustive-deps
1293
1326
  }, []);
1294
1327
  const getInputProps = (props) => {
1295
1328
  const suggestionListInputProps = getSuggestionListInputProps(props);
@@ -1301,9 +1334,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1301
1334
  const { position } = getSelectionPosition(inputRef);
1302
1335
  const currText = inputValue ?? '';
1303
1336
  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
1337
  fromPasteString.current =
1308
1338
  currText.slice(0, position.start) +
1309
1339
  pasteText +
@@ -1313,7 +1343,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1313
1343
  onChange: (e) => {
1314
1344
  const changeValue = fromPasteString.current || e.target.value;
1315
1345
  handleInputChange(changeValue, undefined, e);
1316
- // * when input value clear all, clear selected item
1317
1346
  if (isAutocomplete && changeValue.length === 0) {
1318
1347
  clearTags();
1319
1348
  }
@@ -1324,18 +1353,14 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1324
1353
  setInputFocused(true);
1325
1354
  if (openOnFocus)
1326
1355
  openMenu(e);
1327
- // * when autocomplete mode, always select all text when focus
1328
1356
  if (isAutocomplete) {
1329
1357
  inputRef.current?.select();
1330
1358
  }
1331
- // * reset stopAutoSelect in focus input
1332
1359
  stopAutoSelectRef.current = false;
1333
1360
  blurTags();
1334
1361
  },
1335
1362
  onBlur: (e) => {
1336
1363
  setInputFocused(false);
1337
- // mouse down suggestion item will change focus,
1338
- // but we don't want to close popper in this case
1339
1364
  if (popperElementRef.current?.contains(e.relatedTarget))
1340
1365
  return;
1341
1366
  if (autoSelect && !stopAutoSelectRef.current) {
@@ -1343,7 +1368,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1343
1368
  selectItem(e, optionItems[highlightedIndexRef.current]);
1344
1369
  checkAndAddFreeSolo({}, e);
1345
1370
  }
1346
- // * when blur should restore text when have selected item
1347
1371
  handleAutocompleteText();
1348
1372
  closeMenu(e, 'blur');
1349
1373
  },
@@ -1351,7 +1375,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1351
1375
  isCompositionRef.current = true;
1352
1376
  },
1353
1377
  onCompositionEnd: async () => {
1354
- // sleep for prevent tab in composition
1355
1378
  await sleep(20);
1356
1379
  isCompositionRef.current = false;
1357
1380
  },
@@ -1372,9 +1395,7 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1372
1395
  switch (e.key) {
1373
1396
  case 'Escape':
1374
1397
  if (isOpen) {
1375
- // Avoid Opera to exit fullscreen mode.
1376
1398
  e.preventDefault();
1377
- // Avoid the Modal to handle the event.
1378
1399
  e.stopPropagation();
1379
1400
  closeMenu(e, 'escape');
1380
1401
  }
@@ -1387,13 +1408,9 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1387
1408
  e.stopPropagation();
1388
1409
  return;
1389
1410
  }
1390
- // * when shift+ tab also not need autoSelect
1391
1411
  if (e.shiftKey && currTagsLength > 0) {
1392
1412
  stopAutoSelectRef.current = true;
1393
1413
  }
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
1414
  if (!e.shiftKey && !isCompositionRef.current) {
1398
1415
  const currentHighlightItem = optionItems[highlightedIndex];
1399
1416
  if (isOpen && currentHighlightItem) {
@@ -1427,7 +1444,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1427
1444
  selectItem(e, optionItems[highlightedIndex]);
1428
1445
  e.stopPropagation();
1429
1446
  }
1430
- // always preventDefault for not inset all enter into textarea
1431
1447
  e.preventDefault();
1432
1448
  break;
1433
1449
  case 'F10':
@@ -1439,7 +1455,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1439
1455
  e.preventDefault();
1440
1456
  return;
1441
1457
  }
1442
- // * check state for is that should move key in option items
1443
1458
  if (isAutocomplete && tags.length > 0 && !isOpen) {
1444
1459
  openMenu(e);
1445
1460
  e.preventDefault();
@@ -1458,15 +1473,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1458
1473
  },
1459
1474
  onMouseDown: toggleWithInput
1460
1475
  ? (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
1476
  if (!isOpen || (isOpen && !inputValue)) {
1471
1477
  toggleMenu(e, false);
1472
1478
  }
@@ -1559,7 +1565,6 @@ const useAutocomplete = ({ multiple: multipleProp, variant, inputValue: inputVal
1559
1565
  reset,
1560
1566
  forceUpdate,
1561
1567
  optionsGroupList,
1562
- /** that state of current Autocomplete focused, both tag or input focused */
1563
1568
  focused: focused ?? (tagFocused || inputFocused ? true : undefined),
1564
1569
  id: AutocompleteId,
1565
1570
  inputChanged: isInputValueChangedRef.current,
@@ -1574,9 +1579,7 @@ const ChipSizeMap = {
1574
1579
  medium: 'small',
1575
1580
  };
1576
1581
  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 })] }));
1582
+ return (jsxs("div", { ref: containerRef, className: containerClassName, onClick: onContainerClick, children: [startAdornment, jsx("input", { ...rest, ref: ref })] }));
1580
1583
  });
1581
1584
  const TextInput = forwardRef(({ renderInput, ...rest }, ref) => {
1582
1585
  if (renderInput) {
@@ -1587,14 +1590,7 @@ const TextInput = forwardRef(({ renderInput, ...rest }, ref) => {
1587
1590
  const Autocomplete = forwardRef((inProps, ref) => {
1588
1591
  const props = useThemeProps({ props: inProps, name: 'Autocomplete' });
1589
1592
  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;
1593
+ 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
1594
  const cls = useClasses('autocomplete', classes, className);
1599
1595
  const innerInputRef = useRef(null);
1600
1596
  const textFieldRef = useRef(null);
@@ -1605,12 +1601,7 @@ const Autocomplete = forwardRef((inProps, ref) => {
1605
1601
  const anchorElRef = anchorElType === 'input' ? formFieldContentRef : textFieldRef;
1606
1602
  let oneOfTagError = false;
1607
1603
  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({
1604
+ 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
1605
  focused,
1615
1606
  open: openProp,
1616
1607
  addNoOptionItem,
@@ -1650,6 +1641,7 @@ const Autocomplete = forwardRef((inProps, ref) => {
1650
1641
  onKeyDown: onKeyDownProp,
1651
1642
  disabledItemsHighlightable,
1652
1643
  onGroupExpanded,
1644
+ isOptionEqualToValue,
1653
1645
  });
1654
1646
  const open = Boolean((isOpen || noOptionItem) && textFieldRef.current);
1655
1647
  const { onBlur, ...InputProps } = getInputProps(inputProps);
@@ -1681,7 +1673,6 @@ const Autocomplete = forwardRef((inProps, ref) => {
1681
1673
  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
1674
  ...ToggleButtonProps,
1683
1675
  ...getToggleButtonPropsProp?.(open),
1684
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1685
1676
  }) }))] }));
1686
1677
  const TextFieldInputProps = {
1687
1678
  'aria-label': typeof label === 'string' ? label : undefined,
@@ -1704,32 +1695,14 @@ const Autocomplete = forwardRef((inProps, ref) => {
1704
1695
  }));
1705
1696
  const hasTags = selectedItems.length > 0;
1706
1697
  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 &&
1698
+ const prevHighlightedIndex = usePrevious(() => highlightedIndex, true);
1699
+ 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
1700
  renderNoOptions?.(getNoOptionsProps, noOptionItem)] }));
1724
1701
  const isPopperContentEmpty = !isOpen || (!willRenderNoOptions && optionItems.length === 0);
1725
1702
  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)
1703
+ return (jsxs(Fragment, { children: [jsx(TextInput, { renderInput: renderInput, variant: inputVariant, ref: toTextFieldRef, inputRef: inputRef, fullWidth: fullWidth, placeholder: !hasTags || (hasTags && multiple && showPlaceholderWithTags)
1729
1704
  ? 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({
1705
+ : undefined, label: label, disabled: disabled, required: required, error: error ?? oneOfTagError, FormHelperTextProps: FormHelperTextProps, inputComponent: InputComponent, endAdornment: endAdornment, helperText: helperText, size: size, ...combineProps({
1733
1706
  RootProps: {
1734
1707
  contentRef: formFieldContentRef,
1735
1708
  },
@@ -1752,16 +1725,16 @@ const Autocomplete = forwardRef((inProps, ref) => {
1752
1725
  }), children: menuChildren }) })) })] }));
1753
1726
  });
1754
1727
  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)
1728
+ const RcAutocompleteDefaultFilterOptions = (options, { inputValue, getOptionLabel, selectedItems, isOptionEqualToValue }) => {
1729
+ return options.filter((item) => {
1730
+ const isSelected = selectedItems.some((selected) => isOptionEqualToValue(item, selected));
1731
+ if (isSelected)
1732
+ return false;
1733
+ const optionLabel = getOptionLabel?.(item) || '';
1734
+ return optionLabel
1763
1735
  .toLowerCase()
1764
- .startsWith(inputValue?.toLowerCase() || ''));
1736
+ .startsWith(inputValue?.toLowerCase() || '');
1737
+ });
1765
1738
  };
1766
1739
 
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 };
1740
+ 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 };