@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/chunks/Select.js CHANGED
@@ -26,7 +26,6 @@ const useSelect = (props) => {
26
26
  },
27
27
  onKeyDown: (e) => {
28
28
  if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
29
- // prevent scroll
30
29
  e.preventDefault();
31
30
  handleOpen(true);
32
31
  }
@@ -86,7 +85,6 @@ const Select = forwardRef((inProps, ref) => {
86
85
  }
87
86
  });
88
87
  useEffect(() => {
89
- // close menu when disabled
90
88
  if (disabled) {
91
89
  handleOpen(false);
92
90
  }
@@ -108,7 +106,6 @@ const Select = forwardRef((inProps, ref) => {
108
106
  if (getSelectedIndex)
109
107
  return getSelectedIndex(value);
110
108
  if (Array.isArray(value)) {
111
- // For multiple selection, focus on the last selected item
112
109
  const lastSelectedItem = value.at(-1);
113
110
  return lastSelectedItem ? data.indexOf(lastSelectedItem) : -1;
114
111
  }
@@ -117,45 +114,17 @@ const Select = forwardRef((inProps, ref) => {
117
114
  return true;
118
115
  });
119
116
  const handleMenuListChange = useEventCallback((newValue) => {
120
- // for uncontrolled mode
121
117
  setValue(newValue);
122
118
  if (inputRef.current) {
123
- /**
124
- * Programatically trigger the onChange event of the native input element.
125
- * Doing this means we can avoid cloning another event to mimic the ChangeEvent.
126
- */
127
- /**
128
- * Set the value property of the input element, avoiding React's overridden setter.
129
- * This will cause the input element to update its value and fire the onChange event,
130
- * `handleInputChange` will then call onChange
131
- */
132
119
  Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set?.call(inputRef.current, newValue);
133
120
  const event = new Event('input', { bubbles: true });
134
- /**
135
- * When `selectMode` is `multiple`, the default `event.target.value` type is `string`,
136
- * but it should actually be `string[]`. Since browsers do not natively support this,
137
- * we need to override the `value` property to ensure it correctly reflects an array.
138
- *
139
- * Why do we need `Object.defineProperty` to override `event.target.value`?
140
- * - The `target` property of an event object is read-only, so we cannot modify it directly.
141
- * - `Object.defineProperty` allows us to override `event.target`, but it requires returning
142
- * an object from the getter.
143
- * - To dynamically override only the `value` property while preserving all other properties
144
- * and methods of the input element, we use a `Proxy`.
145
- *
146
- * How does this approach help?
147
- * - Ensures `event.target.value` correctly returns a `string[]` instead of a `string`.
148
- * - Keeps the event object behaving as expected when accessed by event handlers.
149
- * - Preserves other native properties (`name`, `id`, `type`, etc.) and methods
150
- * (`focus()`, `blur()`, etc.), preventing potential "Illegal Invocation" errors.
151
- */
152
121
  Object.defineProperty(event, 'target', {
153
122
  configurable: true,
154
123
  get: () => {
155
124
  return new Proxy(inputRef.current, {
156
125
  get(obj, prop) {
157
126
  if (prop === 'value') {
158
- return newValue; // override 'value'
127
+ return newValue;
159
128
  }
160
129
  return obj[prop];
161
130
  },
@@ -169,10 +138,6 @@ const Select = forwardRef((inProps, ref) => {
169
138
  open,
170
139
  handleOpen,
171
140
  });
172
- /**
173
- * The non-virtualized Menu/MenuList components have the necessary contexts
174
- * baked in. For the virtualized Menu, we need to provide the context values.
175
- */
176
141
  const { contextValue: virtualizedContextValue } = useMenuItemSelect({
177
142
  value,
178
143
  onChange: handleMenuListChange,
@@ -224,9 +189,7 @@ const Select = forwardRef((inProps, ref) => {
224
189
  prefersReducedMotion: prefersReducedMotion,
225
190
  }), children: children }) }) }));
226
191
  }
227
- return (jsxs(Fragment, { children: [jsxs(FormField, { disabled: disabled, required: required, variant: variant, error: error,
228
- // Make sure the focus style doesn't disappear when the Menu is in its close transition
229
- focused: open || (!open && !didMenuExit), htmlFor: id, label: label, labelProps: {
192
+ return (jsxs(Fragment, { children: [jsxs(FormField, { disabled: disabled, required: required, variant: variant, error: error, focused: open || (!open && !didMenuExit), htmlFor: id, label: label, labelProps: {
230
193
  id: labelId,
231
194
  }, ref: ref, contentRef: formFieldContentRef, helperText: helperText, FormHelperTextProps: { id: helperTextId, ...FormHelperTextProps }, className: cls('root', { error }), classes: {
232
195
  outlined: cls('outlined'),
@@ -7,17 +7,10 @@ const SQUIRCLE_PATH = 'M 0.5 0 C 0.879 0 1 0.121 1 0.5 C 1 0.879 0.879 1 0.5 1 C
7
7
  const Squircle = forwardRef((inProps, ref) => {
8
8
  const props = useThemeProps({ props: inProps, name: 'Squircle' });
9
9
  const { component = 'div', focusVisible, active, children: childrenProp, className, classes, interactive = true, fillShape: fillShapeProp = false, ...rest } = props;
10
- /**
11
- * If the children passed to this component have a conditionally rendered
12
- * element, using toArray will ensure that any falsy children are removed.
13
- * Otherwise fillShape will always be false even if only 1 truthy child
14
- * is passed to this component.
15
- */
16
10
  const children = React.Children.toArray(childrenProp);
17
11
  const firstChild = children[0];
18
12
  const fillShape = fillShapeProp &&
19
13
  firstChild &&
20
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
14
  isValidElement(firstChild);
22
15
  const cls = useClasses('squircle', classes, className);
23
16
  const clipId = useId('sui-squircle-clip', true);
@@ -7,6 +7,7 @@ import { I as Icon } from './Icon.js';
7
7
  const IconSizeMap = {
8
8
  large: 'small',
9
9
  medium: 'xsmall',
10
+ small: 'xsmall',
10
11
  };
11
12
  const StatusIndicator = (inProps) => {
12
13
  const props = useThemeProps({ props: inProps, name: 'StatusIndicator' });
@@ -5,9 +5,7 @@ import { AlertFilledMd, AlertMd, CheckBoldMd, CheckMd } from '@ringcentral/sprin
5
5
  import { useThemeProps } from '@ringcentral/spring-theme';
6
6
  import { I as Icon } from './Icon.js';
7
7
 
8
- const StepIcon = forwardRef(
9
- // @ts-ignore
10
- (inProps, ref) => {
8
+ const StepIcon = forwardRef((inProps, ref) => {
11
9
  const props = useThemeProps({ props: inProps, name: 'StepIcon' });
12
10
  const { classes, className, children, active = false, completed = false, error = false, disabled = false, variant = 'contained', icon, symbol, ...rest } = props;
13
11
  const cls = useClasses('step-icon', classes, className);
@@ -1,13 +1,6 @@
1
1
  import { createContext, useContext } from 'react';
2
2
 
3
- /**
4
- * Provides information about the current step in Stepper.
5
- */
6
3
  const StepContext = createContext({});
7
- /**
8
- * Returns the current StepContext or an empty object if no StepContext
9
- * has been defined in the component tree.
10
- */
11
4
  const useStepContext = () => useContext(StepContext);
12
5
 
13
6
  const StepperContext = createContext({});
package/chunks/Tooltip.js CHANGED
@@ -10,15 +10,6 @@ import { g as getFade } from './getFade.js';
10
10
  import { Popper } from '../Popper.js';
11
11
  import { P as PopperPaper } from './PopperPaper.js';
12
12
 
13
- /**
14
- * Accessibility naming strategy:
15
- * - Default (label mode): `title` is treated as an accessible label
16
- * - string `title` → `aria-label`
17
- * - React element `title` → `aria-labelledby` while the tooltip is open
18
- * - Description mode (`describeChild = true`): `title` is treated as an accessible description
19
- * - when closed → native `title` attribute
20
- * - when open → `aria-describedby` pointing to the tooltip id
21
- */
22
13
  const ARIA_DESCRIBEDBY = 'aria-describedby';
23
14
  const ARIA_LABEL = 'aria-label';
24
15
  const ARIA_LABELLEDBY = 'aria-labelledby';
@@ -47,49 +38,33 @@ function computeTooltipA11y({ title, describeChild, triggerWhenDisabled, open, t
47
38
  });
48
39
  }
49
40
  if (describeChild) {
50
- // Description mode: tooltip acts as an accessible description
51
- // When closed: add title attribute (unless user provided their own)
52
- // When open: swap to aria-describedby
53
41
  if (!hasAriaDescribedBy) {
54
42
  if (!hasUserTitle) {
55
- // Only set tooltip title if user hasn't provided one
56
43
  nameOrDescProps.title =
57
44
  !open && titleIsString ? title : null;
58
45
  }
59
46
  else if (open) {
60
- // If user provided a title and tooltip is open, remove native title to prevent duplicate
61
47
  nameOrDescProps.title = null;
62
48
  }
63
49
  nameOrDescProps[ARIA_DESCRIBEDBY] = open ? tooltipId : null;
64
50
  }
65
51
  }
66
52
  else {
67
- // Label mode (default): tooltip acts as an accessible label
68
- // Use aria-label for strings, aria-labelledby for React elements
69
53
  if (titleIsString && !hasAriaLabel) {
70
54
  nameOrDescProps[ARIA_LABEL] = title;
71
- // For string titles, Tooltip fully owns the label; always remove native title
72
55
  nameOrDescProps.title = null;
73
56
  }
74
57
  else if (!titleIsString && !hasAriaLabelledBy && title) {
75
- // Only set aria-labelledby if title is truthy (React element exists)
76
58
  nameOrDescProps[ARIA_LABELLEDBY] = open ? tooltipId : null;
77
- // Only remove native title when tooltip is open to prevent duplicate tooltips.
78
- // When closed, leave existing title as a fallback accessible name.
79
59
  if (open) {
80
60
  nameOrDescProps.title = null;
81
61
  }
82
62
  }
83
63
  else if (open) {
84
- // Tooltip is open but we're not providing a label (e.g. child already has aria-label);
85
- // still remove native title to avoid double tooltips.
86
64
  nameOrDescProps.title = null;
87
65
  }
88
66
  }
89
67
  if (triggerWhenDisabled) {
90
- // When open and child does not already have aria-describedby: use tooltip id,
91
- // and always remove native title on the disabled control to avoid double tooltips.
92
- // When closed and title is a string: use native title as a fallback for SR on disabled.
93
68
  if (open) {
94
69
  if (!hasAriaDescribedBy) {
95
70
  disabledOverrides[ARIA_DESCRIBEDBY] = tooltipId;
@@ -149,15 +124,10 @@ const TooltipTrigger = (props, ref) => {
149
124
  onOpenStateChange?.(e, false);
150
125
  };
151
126
  useEventListener(anchorRef, 'mouseenter', (e) => {
152
- // Ensures touch devices do not trigger the tooltip, mouseleave will never be fired and the tooltip will be stuck open
153
127
  if (didInitiateWithTouch.current) {
154
- // Immediately reset the flag, touchstart will fire again on the next tap and will set the flag back to true
155
128
  didInitiateWithTouch.current = false;
156
129
  return;
157
130
  }
158
- // Remove the title ahead of time from the trigger.
159
- // We don't want to wait for the next render commit.
160
- // We would risk displaying two tooltips at the same time (native + this one).
161
131
  if (anchorRef.current) {
162
132
  anchorRef.current.removeAttribute('title');
163
133
  }
@@ -174,22 +144,17 @@ const TooltipTrigger = (props, ref) => {
174
144
  useEventListener(anchorRef, 'focus', (e) => {
175
145
  if (disableFocusListener)
176
146
  return;
177
- // handleFocusVisible only support react event type, but it only need target event
178
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
179
147
  handleFocusVisible(e);
180
148
  if (isFocusVisibleRef.current === true) {
181
149
  handleOpen(e);
182
150
  }
183
151
  });
184
152
  useEventListener(anchorRef, 'blur', (e) => {
185
- // handleBlurVisible only support react event type, but this param is useless
186
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
187
153
  handleBlurVisible(e);
188
154
  if (isFocusVisibleRef.current === false) {
189
155
  handleClose(e);
190
156
  }
191
157
  });
192
- // Handle Escape key to close tooltip
193
158
  useEventListener(open ? document : null, 'keydown', (e) => {
194
159
  if (e.key === 'Escape') {
195
160
  handleClose(e);
@@ -241,7 +206,6 @@ const Tooltip = forwardRef((inProps, ref) => {
241
206
  const props = useThemeProps({ props: inProps, name: 'Tooltip' });
242
207
  const { children, open: openProp, delay, onOpenStateChange, title, disableFocusListener, disableBackdropAnimation, triggerWhenDisabled, triggerWrapperProps, PopperProps, describeChild = false, ...rest } = props;
243
208
  const renderTooltip = (open, getAnchorEl, tooltipId) => {
244
- // hides '', null/undefined, false, NaN)
245
209
  const effectiveOpen = open && !(!title && title !== 0);
246
210
  const content = effectiveOpen ? (jsx(TooltipView, { disableInteractions: openProp === undefined, ...rest, PopperProps: { ...PopperProps, id: tooltipId }, anchorEl: getAnchorEl, ref: ref, children: title })) : null;
247
211
  return disableBackdropAnimation ? (jsx(Fragment, { children: content })) : (jsx(AnimatePresence, { children: content }));
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { createContext, useContext, useRef, useEffect, forwardRef, useState, useMemo } from 'react';
2
+ import { createContext, useContext, useRef, useLayoutEffect, forwardRef, useState, useMemo, useEffect } from 'react';
3
3
  import { useForkRef, combineProps, useClasses, useEventCallback } from '@ringcentral/spring-base';
4
4
  import { useThemeProps } from '@ringcentral/spring-theme';
5
5
  import clsx from 'clsx';
@@ -14,7 +14,11 @@ const VirtualizedMenuList = (props) => {
14
14
  const actions = useRef(null);
15
15
  const handleListActions = useForkRef(actions, actionsProp);
16
16
  const listRef = useRef(null);
17
- useEffect(() => {
17
+ const virtualizedMenuContext = useVirtualizedMenuContext();
18
+ useLayoutEffect(() => {
19
+ if (!virtualizedMenuContext?.open) {
20
+ return;
21
+ }
18
22
  const initialFocus = typeof initialFocusProps === 'function'
19
23
  ? initialFocusProps()
20
24
  : initialFocusProps;
@@ -24,21 +28,21 @@ const VirtualizedMenuList = (props) => {
24
28
  else if (typeof initialFocus === 'number') {
25
29
  actions.current?.focusByIndex(initialFocus);
26
30
  }
27
- // eslint-disable-next-line react-hooks/exhaustive-deps
28
- }, []); // only excute effect when menu list mounted
31
+ }, [virtualizedMenuContext?.open]);
29
32
  return (jsx(VirtualizedList, { actions: handleListActions, ...rest, ListProps: combineProps({
30
33
  role: 'menu',
31
34
  }, rest.ListProps), ref: listRef, totalListHeightChanged: totalListHeightChangedProp, children: children }));
32
35
  };
33
36
 
37
+ const MENU_VERTICAL_PADDING = 8;
34
38
  const VirtualizedMenu = forwardRef((inProps, ref) => {
35
39
  const props = useThemeProps({ props: inProps, name: 'VirtualizedMenu' });
36
40
  const { classes, className, children, open, onClose, data, totalCount, isItemDisabled, VirtualizedListProps, popperActions: popperActionsProp, initialFocus = true, maxHeight, PopperProps, ...rest } = props;
37
41
  const popperPaperContentRef = useRef(null);
38
42
  const paperContentContainerRef = useRef(null);
39
- const waitForListHeightComputeCallsCount = useRef(0);
43
+ const hasItemsRenderedRef = useRef(false);
40
44
  const [waitForHeightCompute, setWaitForHeightCompute] = useState(true);
41
- const [menuHeight, setMenuHeight] = useState(0);
45
+ const [menuHeight, setMenuHeight] = useState(MENU_VERTICAL_PADDING * 2);
42
46
  const [deferPendingVirtualizedListActions, setDeferPendingVirtualizedListActions,] = useState(true);
43
47
  const computedListHeight = useRef(-1);
44
48
  const availableHeight = useRef(-1);
@@ -71,66 +75,25 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
71
75
  if (!popperPaperContentRef.current)
72
76
  return;
73
77
  popperPaperContentRef.current.style.maxHeight = `${availableHeight.current}px`;
74
- /**
75
- * Reset the paper content container height to `auto`, otherwise the virtuoso scroller
76
- * will start misbehaving. We only need to set the height of the container during the
77
- * initial list height computation to ensure the Popover places it appropriately.
78
- */
79
78
  if (paperContentContainerRef.current) {
80
79
  paperContentContainerRef.current.style.height = `auto`;
81
80
  }
82
81
  });
83
82
  const handleTotalListHeightChanged = useEventCallback((listHeight) => {
84
- /**
85
- * As the VirtualizedList has components (Header/Footer used for vertical padding), the
86
- * first 2 calls to `totalListHeightChanged` after triggering the Menu to open will have
87
- * only computed the height of those components and not the full list. The next calls
88
- * will include the actual list height. We ignore this call to prevent the menu from
89
- * flickering between positions/performing any other unnecessary computations. We also
90
- * need to know the entire list height to be able to choose the correct placement.
91
- *
92
- * If we didn't do this, we'd compute the available height prematurely based on an
93
- * incorrect initial placement, and the height parameter in further calls to
94
- * `handleTotalListHeightChanged` would be the adjusted height of the popover for
95
- * the available space in the viewport and not the actual height of the list. For
96
- * example, if the user set the `placement` prop to `top` but had a very long list
97
- * which could not fit above the anchor element, the menu could initially appear
98
- * above the input despite the fact its best placement is below. The user would
99
- * then see this placement change when re-opening the menu or scrolling, where the
100
- * Popover would auto-update the position and then choose the correct placement.
101
- */
102
- if (waitForListHeightComputeCallsCount.current < 2) {
103
- waitForListHeightComputeCallsCount.current += 1;
83
+ if (!hasItemsRenderedRef.current) {
104
84
  return;
105
85
  }
106
- computedListHeight.current = listHeight;
107
- /**
108
- * Set the height of the paper content container to the height of the list. This is
109
- * necessary to ensure the Popover determines the correct amount of space needed for
110
- * the list. If we set the height directly on the list element it would cause an
111
- * expensive rerender and if we didn't do either the computed available height
112
- * for the Popover would not be correct.
113
- */
86
+ const adjustedHeight = listHeight + MENU_VERTICAL_PADDING * 2
87
+ ;
88
+ computedListHeight.current = adjustedHeight;
114
89
  if (paperContentContainerRef.current) {
115
- paperContentContainerRef.current.style.height = `${listHeight}px`;
90
+ paperContentContainerRef.current.style.height = `${adjustedHeight}px`;
116
91
  }
117
- // Update the Menu height now we've correctly computed the list height
118
92
  updateMenuHeight();
119
- // Update the Popper position after the list height has been computed
120
93
  popperActions.current?.update();
121
- // No need to wait for the height compute once we have the list height
122
94
  if (waitForHeightCompute) {
123
- /**
124
- * Perform all pending actions once we know the list height has settled. This is necessary
125
- * as those pending actions expect the list to have fully rendered before they can be ran.
126
- */
127
95
  requestAnimationFrame(() => {
128
96
  setDeferPendingVirtualizedListActions(false);
129
- /**
130
- * Wait for the next repaint to ensure the pending actions have been completed and the height
131
- * has been computed and painted. If we didn't do this, the menu could flicker if the initial
132
- * scroll position was set to a value that would cause the list to scroll down.
133
- */
134
97
  requestAnimationFrame(() => {
135
98
  setWaitForHeightCompute(false);
136
99
  });
@@ -138,11 +101,7 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
138
101
  }
139
102
  });
140
103
  const handleAvailableHeightChange = useEventCallback((value) => {
141
- /**
142
- * If we haven't yet computed the height of the virtualized list, we need to ignore
143
- * the available height as the value will be for when the list has not yet fully rendered.
144
- */
145
- if (computedListHeight.current === -1) {
104
+ if (computedListHeight.current === -1 || !hasItemsRenderedRef.current) {
146
105
  return;
147
106
  }
148
107
  availableHeight.current = value;
@@ -150,34 +109,21 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
150
109
  updatePopoverHeight();
151
110
  });
152
111
  useEffect(() => {
153
- /**
154
- * Reset the computed values when the Menu is closed, we'll recompute them when it's reopened
155
- */
156
112
  if (!open) {
157
- waitForListHeightComputeCallsCount.current = 0;
158
- computedListHeight.current = -1;
159
- availableHeight.current = -1;
113
+ hasItemsRenderedRef.current = false;
160
114
  }
161
- /**
162
- * Hide the menu immediately after being triggered to open to allow time to compute the rendered
163
- * list height. We need to do this to avoid a potential flicker when the menu first renders, as
164
- * the virtualized list may not have rendered yet, but its adorning components may have. This may
165
- * cause the menu to have a different initial placement than it would have after the list has
166
- * rendered, for example if the user has chosen a preferred `top` placement but the menu cannot
167
- * actually fit within the space above the anchor element.
168
- *
169
- * This is only necessary for the initial render. After the menu has found its correct placement,
170
- * we can rely on the Popover to auto-update its placement and size as needed in response to list
171
- * height changes/window resize events.
172
- *
173
- * In the `handleTotalListHeightChanged` callback we then reset this flag once we know the total list
174
- * has actually rendered, so the first place the user sees the menu is in its correct position after
175
- * all other height computation has been performed.
176
- */
177
115
  if (open) {
178
- setWaitForHeightCompute(true);
179
- setDeferPendingVirtualizedListActions(true);
180
- // Reset the max height of the popper paper content to ensure the list is not constrained
116
+ if (computedListHeight.current !== -1) {
117
+ updateMenuHeight();
118
+ setWaitForHeightCompute(false);
119
+ setDeferPendingVirtualizedListActions(false);
120
+ popperActions.current?.update();
121
+ }
122
+ else {
123
+ setMenuHeight(MENU_VERTICAL_PADDING * 2);
124
+ setWaitForHeightCompute(true);
125
+ setDeferPendingVirtualizedListActions(true);
126
+ }
181
127
  if (popperPaperContentRef.current) {
182
128
  popperPaperContentRef.current.style.maxHeight = 'none';
183
129
  }
@@ -185,21 +131,24 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
185
131
  }, [open]);
186
132
  return (jsx(Popover, { bordered: true, PopperProps: { ...PopperProps, padding: popperPadding }, ...rest, open: open, className: clsx(cls('root'), waitForHeightCompute && 'opacity-0'), PopperPaperProps: {
187
133
  contentRef: popperPaperContentRef,
188
- }, onClose: onClose, onAvailableHeightChange: handleAvailableHeightChange, ref: ref,
189
- // disable animation. The Grow animation will cause vl height calculate incorrectly
190
- motionProps: { variants: undefined }, actions: handlePopperActions, children: jsx("div", { className: cls('paper'), children: jsx("div", { ref: paperContentContainerRef, className: cls('paper-content-container'), children: jsx(VirtualizedMenuContext.Provider, { value: menuContextValue, children: jsx(VirtualizedMenuList, { data: data, totalCount: totalCount, isReady: !deferPendingVirtualizedListActions, isItemDisabled: isItemDisabled, initialFocus: initialFocus, style: { height: menuHeight }, ...combineProps(VirtualizedListProps, {
191
- components: {
192
- /**
193
- * Use Header/Footer components to add padding to the top and bottom of the
194
- * list. We need to do this as Virtuoso doesn't support padding on the list
195
- * due to how it uses padding/margin to simulate scrolling. Passing a List
196
- * wrapper component also doesn't work as the list height computation
197
- * doesn't account for the padding around the wrapper element.
198
- */
199
- Header: VirtualizedListVerticalPadding,
200
- Footer: VirtualizedListVerticalPadding,
201
- },
134
+ }, onClose: onClose, onAvailableHeightChange: handleAvailableHeightChange, ref: ref, motionProps: { variants: undefined }, actions: handlePopperActions, children: jsx("div", { className: cls('paper'), children: jsx("div", { ref: paperContentContainerRef, className: cls('paper-content-container'), children: jsx(VirtualizedMenuContext.Provider, { value: menuContextValue, children: jsx(VirtualizedMenuList, { data: data, totalCount: totalCount, isReady: !deferPendingVirtualizedListActions, isItemDisabled: isItemDisabled, initialFocus: initialFocus, style: { height: menuHeight }, ...combineProps(VirtualizedListProps, {
135
+ ListProps: combineProps(VirtualizedListProps?.ListProps, {
136
+ className: cls('list'),
137
+ style: {
138
+ ['--sui-virtualized-menu-vertical-padding']: `${MENU_VERTICAL_PADDING}px`,
139
+ },
140
+ }),
202
141
  totalListHeightChanged: handleTotalListHeightChanged,
142
+ itemsRendered: (items) => {
143
+ if (totalCount === 0 ||
144
+ (totalCount === undefined &&
145
+ data !== undefined &&
146
+ data.length === 0) ||
147
+ (items && items.length > 0)) {
148
+ hasItemsRenderedRef.current = true;
149
+ }
150
+ VirtualizedListProps?.itemsRendered?.(items);
151
+ },
203
152
  onKeyDown: (e) => {
204
153
  if (e.key === 'Tab') {
205
154
  e.preventDefault();
@@ -208,9 +157,6 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
208
157
  },
209
158
  }), children: children }) }) }) }) }));
210
159
  });
211
- function VirtualizedListVerticalPadding() {
212
- return jsx("div", { className: "h-2" });
213
- }
214
160
  VirtualizedMenu.displayName = 'SuiVirtualizedMenu';
215
161
 
216
162
  export { VirtualizedMenuContext as V, VirtualizedMenu as a, VirtualizedMenuList as b, useVirtualizedMenuContext as u };
package/chunks/getFade.js CHANGED
@@ -16,6 +16,10 @@ const getFade = ({ toggle = true, prefersReducedMotion = false, toggleOnTransiti
16
16
  transition: prefersReducedMotion
17
17
  ? motionTransition.instant
18
18
  : toggleOffTransition || motionTransition['haste-01-slow'],
19
+ pointerEvents: 'none',
20
+ transitionEnd: {
21
+ pointerEvents: undefined,
22
+ },
19
23
  },
20
24
  },
21
25
  });
@@ -2,19 +2,12 @@ import { useEffect } from 'react';
2
2
  import { useWindowContext, useId, useEventCallback } from '@ringcentral/spring-base';
3
3
 
4
4
  const FOCUS_TRAP_STACK = '__SUI_FOCUS_TRAP_STACK__';
5
- // use global to ensure the work in the same window
6
5
  const getFocusTrapStack = (global) => {
7
- // @ts-ignore
8
6
  if (!global[FOCUS_TRAP_STACK]) {
9
- // @ts-ignore
10
7
  global[FOCUS_TRAP_STACK] = [];
11
8
  }
12
- // @ts-ignore
13
9
  return global[FOCUS_TRAP_STACK];
14
10
  };
15
- /**
16
- * Hook to manage focus trap stack for proper layering and focus management
17
- */
18
11
  const useFocusTrapStack = ({ open, }) => {
19
12
  const { globalThis } = useWindowContext();
20
13
  const id = useId();
@@ -30,7 +23,6 @@ const useFocusTrapStack = ({ open, }) => {
30
23
  stack.splice(index, 1);
31
24
  }
32
25
  };
33
- // eslint-disable-next-line react-hooks/exhaustive-deps
34
26
  }, [open]);
35
27
  const isEnabled = useEventCallback(() => {
36
28
  const stack = getFocusTrapStack(globalThis);
@@ -12,34 +12,10 @@ const FormField = forwardRef((inProps, ref) => {
12
12
  });
13
13
  FormField.displayName = 'SuiFormField';
14
14
 
15
- /**
16
- * Hook to generate consistent helper text IDs for form field accessibility
17
- *
18
- * Follows the pattern: `${id}-helper-text`
19
- *
20
- * @param options Configuration options
21
- * @returns Generated helper text ID or undefined if no helper text
22
- *
23
- * @example
24
- * ```tsx
25
- * const Select = ({ helperText, FormHelperTextProps, ...props }) => {
26
- * const id = useId(idProp);
27
- * const helperTextId = useHelperTextId({ helperText, id, FormHelperTextProps });
28
- *
29
- * return (
30
- * <FormField FormHelperTextProps={{ id: helperTextId, ...FormHelperTextProps }}>
31
- * <button aria-describedby={helperTextId}>
32
- * </FormField>
33
- * );
34
- * };
35
- * ```
36
- */
37
15
  const useHelperTextId = ({ helperText, id, FormHelperTextProps, }) => {
38
- // Only generate ID if helper text exists
39
16
  if (!helperText) {
40
17
  return undefined;
41
18
  }
42
- // Use existing ID if provided, otherwise generate standard pattern
43
19
  return FormHelperTextProps?.id || `${id}-helper-text`;
44
20
  };
45
21
 
@@ -14,26 +14,19 @@ const useListNavigation = (props) => {
14
14
  const skipEnforceFocusRef = useRef(false);
15
15
  const focusList = () => {
16
16
  skipEnforceFocusRef.current = true;
17
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
18
17
  listRef.current.focus();
19
18
  };
20
19
  const focusTabBoundary = () => {
21
20
  skipEnforceFocusRef.current = true;
22
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
23
21
  sentinelTabBoundaryRef.current.focus();
24
22
  };
25
23
  const itemActions = useMemo(() => ({
26
- // Prevent cache invalidation
27
- // eslint-disable-next-line sonarjs/no-identical-functions
28
24
  onTab: () => {
29
25
  skipEnforceFocusRef.current = true;
30
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
31
26
  sentinelTabBoundaryRef.current.focus();
32
27
  },
33
- // eslint-disable-next-line sonarjs/no-identical-functions
34
28
  onShiftTab: () => {
35
29
  skipEnforceFocusRef.current = true;
36
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
37
30
  listRef.current.focus();
38
31
  },
39
32
  updateFocusedItem: (el) => {
@@ -48,9 +41,7 @@ const useListNavigation = (props) => {
48
41
  });
49
42
  useImperativeHandle(actions, () => ({
50
43
  focus: focusFirstItem,
51
- }),
52
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
- []);
44
+ }), []);
54
45
  const sentinelFocusHandler = (e) => {
55
46
  if (e.target === e.currentTarget) {
56
47
  const skipEnforceFocus = skipEnforceFocusRef.current;
@@ -63,9 +54,7 @@ const useListNavigation = (props) => {
63
54
  };
64
55
  const searchAndFocusItemHandler = (searchElementOption) => {
65
56
  return searchAndFocusItemHandlerProp(searchElementOption, {
66
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
67
57
  sentinelEnd: sentinelArrowNavRef.current,
68
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
69
58
  list: listRef.current,
70
59
  });
71
60
  };
@@ -96,7 +85,6 @@ const useListNavigation = (props) => {
96
85
  }
97
86
  }
98
87
  else {
99
- // cover case about all item are disabled
100
88
  if (e.target === e.currentTarget && key === 'Tab' && !e.shiftKey) {
101
89
  focusTabBoundary();
102
90
  }
@@ -125,16 +113,16 @@ const useListNavigation = (props) => {
125
113
  return (jsxs(ListNavigationContext.Provider, { value: itemActions, children: [items, jsx("div", { "aria-hidden": "true", ref: sentinelArrowNavRef })] }));
126
114
  };
127
115
  const renderTabBoundary = () => {
128
- return (jsx("div", {
129
- // make sentinel end always render in scroller viewport center to
130
- // prevent scroll when focus to sentinel end
131
- style: { position: 'fixed', bottom: '50%' }, ref: sentinelTabBoundaryRef, tabIndex: 0, onFocus: sentinelFocusHandler }));
116
+ return (jsx("div", { style: { position: 'fixed', bottom: '50%' }, ref: sentinelTabBoundaryRef, tabIndex: 0, onFocus: sentinelFocusHandler }));
132
117
  };
133
118
  return { renderItems, renderTabBoundary, getListProps, listRef };
134
119
  };
135
120
  const isUnfocusable = (el) => el.matches('.sui-disabled, :disabled, hr, [role="separator"], [disabled]');
136
121
  const defaultSearchAndFocusItem = (searchElementOption, helperElements) => {
137
122
  const { list, sentinelEnd } = helperElements;
123
+ if (list.firstElementChild === sentinelEnd) {
124
+ return { focused: false };
125
+ }
138
126
  const getFirstItem = () => {
139
127
  const firstItem = list.firstElementChild;
140
128
  if (firstItem === sentinelEnd) {