@ringcentral/spring-ui 1.11.1 → 1.12.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 (174) hide show
  1. package/AccordionHeader.js +4 -2
  2. package/Animation.js +10 -9
  3. package/Autocomplete.js +7 -2
  4. package/BlockHeader.js +3 -1
  5. package/DatePicker.js +5 -3
  6. package/Dialer.js +36 -21
  7. package/Dialog.js +4 -3
  8. package/Dropdown.js +8 -4
  9. package/EmptyState.js +3 -1
  10. package/FormField.js +2 -0
  11. package/ListItem.js +1 -0
  12. package/ListItemText.js +9 -3
  13. package/MenuHeader.js +5 -1
  14. package/MenuItem.js +3 -0
  15. package/MenuItemText.js +2 -0
  16. package/MenuList.js +3 -0
  17. package/Option.js +4 -1
  18. package/PickerTextField.js +2 -0
  19. package/Popper.js +28 -25
  20. package/Rating.js +2 -2
  21. package/Select.js +4 -0
  22. package/SingleFilter.js +4 -0
  23. package/Slider.js +3 -2
  24. package/SortableListItem.js +1 -0
  25. package/SortableVirtualizedList.js +11 -10
  26. package/SplitButton.js +4 -0
  27. package/Squircle.js +2 -2
  28. package/StepContent.js +1 -1
  29. package/SubMenu.js +4 -0
  30. package/SwipeableDrawer.js +16 -18
  31. package/TableCell.js +1 -1
  32. package/TablePagination.js +4 -0
  33. package/Tabs.js +11 -5
  34. package/TextField.js +2 -0
  35. package/Textarea.js +2 -0
  36. package/TimePicker.js +3 -1
  37. package/TrayMenu.js +3 -0
  38. package/VirtualizedList.js +7 -5
  39. package/VirtualizedMenu.js +1 -0
  40. package/chunks/Alert.js +2 -2
  41. package/chunks/Badge.js +1 -1
  42. package/chunks/Drawer.js +3 -2
  43. package/chunks/MenuItemText.js +3 -1
  44. package/chunks/MenuList.js +2 -1
  45. package/chunks/Modal.js +132 -9
  46. package/chunks/Popover.js +13 -5
  47. package/chunks/Select.js +26 -21
  48. package/chunks/SlideIn.js +2 -1
  49. package/chunks/Squircle.js +2 -2
  50. package/chunks/VirtualizedMenu.js +5 -5
  51. package/chunks/composeEventHandlers.js +10 -0
  52. package/chunks/getSlideIn.js +2 -2
  53. package/chunks/hasContent.js +3 -0
  54. package/chunks/useAnimationFrame.js +15 -0
  55. package/chunks/useFocusTrapStack.js +3 -1
  56. package/chunks/useHelperTextId.js +4 -2
  57. package/chunks/useMenuItemSelect.js +37 -26
  58. package/index.css +205 -172
  59. package/index.js +4 -0
  60. package/internal/hooks/index.d.ts +1 -0
  61. package/internal/hooks/useAnimationFrame.d.ts +4 -0
  62. package/internal/utils/hasContent.d.ts +2 -0
  63. package/internal/utils/index.d.ts +3 -0
  64. package/internal/utils/setRef.d.ts +1 -0
  65. package/package.json +8 -8
  66. package/src/Accordion/Accordion.d.ts +1 -1
  67. package/src/AccordionHeader/AccordionHeader.d.ts +1 -1
  68. package/src/Alert/Alert.type.d.ts +2 -1
  69. package/src/Animation/components/Fade/Fade.d.ts +4 -2
  70. package/src/Animation/components/Grow/Grow.d.ts +4 -2
  71. package/src/Animation/components/ShowHideEye/ShowHideEye.d.ts +1 -1
  72. package/src/Animation/components/SlideIn/SlideIn.d.ts +4 -2
  73. package/src/Animation/components/SlideIn/getSlideIn.d.ts +1 -1
  74. package/src/Announcement/Announcement.d.ts +1 -1
  75. package/src/Autocomplete/SuggestionList/SuggestionList.d.ts +1 -1
  76. package/src/Autocomplete/SuggestionList/SuggestionListItem.d.ts +1 -1
  77. package/src/Autocomplete/SuggestionList/utils/useSuggestionList.d.ts +1 -1
  78. package/src/Autocomplete/useAutocomplete.d.ts +74 -50
  79. package/src/Autocomplete/useAutocompleteTag.d.ts +68 -44
  80. package/src/Backdrop/Backdrop.d.ts +1 -1
  81. package/src/Badge/Badge.d.ts +2 -2
  82. package/src/BottomNavigation/BottomNavigationGroup/BottomNavigationGroup.d.ts +1 -1
  83. package/src/CircularProgressIndicator/CircularProgressIndicator.d.ts +1 -1
  84. package/src/DatePicker/DatePicker.d.ts +1 -1
  85. package/src/DatePicker/Day.d.ts +1 -1
  86. package/src/DatePicker/Year.d.ts +1 -1
  87. package/src/DatePicker/utils/DatePickerAriaLabelUtils.d.ts +2 -1
  88. package/src/Dialer/DialDelete/DialDelete.d.ts +2 -2
  89. package/src/Dialer/DialPad/DialPad.d.ts +2 -2
  90. package/src/Dialer/DialTextField/DialTextField.d.ts +1 -1
  91. package/src/Dialer/Dialer.d.ts +4 -2
  92. package/src/Dialog/Dialog.d.ts +4 -4
  93. package/src/Drawer/Drawer.d.ts +1 -1
  94. package/src/Dropdown/Dropdown.type.d.ts +2 -2
  95. package/src/EmptyState/EmptyState.d.ts +1 -1
  96. package/src/FormField/FormField.d.ts +1 -1
  97. package/src/FormLabel/FormLabel.d.ts +1 -1
  98. package/src/Icon/Icon.d.ts +1 -1
  99. package/src/IconButton/IconButtonLabel.d.ts +1 -1
  100. package/src/InlineEditable/InlineEditable.type.d.ts +2 -1
  101. package/src/LinearProgressIndicator/LinearProgressIndicator.d.ts +1 -1
  102. package/src/List/List.d.ts +1 -1
  103. package/src/ListItem/ListItem.d.ts +1 -1
  104. package/src/ListItemText/ListItemText.d.ts +1 -1
  105. package/src/ListNavigation/useListNavigation.d.ts +3 -3
  106. package/src/Menu/Menu.d.ts +1 -1
  107. package/src/MenuActions/MenuActions.d.ts +3 -3
  108. package/src/MenuDivider/MenuDivider.d.ts +1 -1
  109. package/src/MenuFooter/MenuFooter.d.ts +1 -1
  110. package/src/MenuHeader/MenuHeader.d.ts +1 -1
  111. package/src/MenuItem/MenuItem.d.ts +1 -1
  112. package/src/MenuItem/useMenuItem.d.ts +1 -1
  113. package/src/MenuItem/useVirtualizedMenuItem.d.ts +1 -1
  114. package/src/MenuItemText/MenuItemText.d.ts +1 -1
  115. package/src/MenuList/MenuList.type.d.ts +1 -1
  116. package/src/Modal/InnerModal.d.ts +2 -16
  117. package/src/Modal/InnerModal.type.d.ts +1 -0
  118. package/src/Modal/Modal.d.ts +2 -21
  119. package/src/Modal/ModalContext.d.ts +3 -0
  120. package/src/Modal/OverlayBranchRegistry.d.ts +8 -0
  121. package/src/Modal/useOverlayBranch.d.ts +8 -0
  122. package/src/NestedMenuContext/MenuOverlayGroupContext.d.ts +2 -2
  123. package/src/Option/Option.d.ts +1 -1
  124. package/src/PageHeader/PageHeader.d.ts +5 -5
  125. package/src/PickerTextField/PickerTextField.d.ts +1 -1
  126. package/src/Popover/Popover.d.ts +1 -1
  127. package/src/Popper/Popper.d.ts +1 -1
  128. package/src/Popper/Popper.type.d.ts +10 -7
  129. package/src/PopperPaper/PopperPaper.d.ts +1 -1
  130. package/src/RadioGroup/RadioGroup.d.ts +1 -1
  131. package/src/Rating/Rating.d.ts +1 -1
  132. package/src/Rating/RatingItem.d.ts +1 -1
  133. package/src/Rating/utils.d.ts +3 -3
  134. package/src/Select/Select.type.d.ts +1 -1
  135. package/src/SingleFilter/FilterButton/FilterButton.d.ts +1 -1
  136. package/src/SingleFilter/SingleFilter.d.ts +1 -1
  137. package/src/Skeleton/Skeleton.d.ts +1 -1
  138. package/src/Slider/Slider.d.ts +2 -2
  139. package/src/Slider/SliderThumb.d.ts +2 -2
  140. package/src/Snackbar/Snackbar.d.ts +1 -1
  141. package/src/Snackbar/SnackbarContent/SnackbarContent.d.ts +1 -1
  142. package/src/SortableListItem/SortableListItem.d.ts +1 -1
  143. package/src/SortableListItem/SortableListItemOverlay.d.ts +1 -1
  144. package/src/SplitButton/SplitButton.d.ts +1 -1
  145. package/src/Squircle/Squircle.d.ts +1 -1
  146. package/src/StatusIndicator/StatusIndicator.d.ts +2 -2
  147. package/src/StepConnector/StepConnector.d.ts +1 -1
  148. package/src/StepContent/StepContent.d.ts +1 -1
  149. package/src/StepIcon/StepIcon.d.ts +1 -1
  150. package/src/StepLabel/StepLabel.d.ts +1 -1
  151. package/src/SubMenu/PopperMenu.d.ts +1 -1
  152. package/src/SubMenu/PopperMenu.type.d.ts +4 -1
  153. package/src/SubMenu/SubMenu.d.ts +1 -1
  154. package/src/SwipeableDrawer/SwipeableDrawer.d.ts +1 -1
  155. package/src/Tab/Tab.d.ts +1 -1
  156. package/src/TabPanel/TabPanel.d.ts +1 -1
  157. package/src/TableFooter/TableFooter.d.ts +1 -1
  158. package/src/Tabs/TabMoreMenu.d.ts +1 -1
  159. package/src/Tabs/TabScrollButton.d.ts +1 -1
  160. package/src/Tabs/Tabs.d.ts +1 -1
  161. package/src/Tag/Tag.d.ts +1 -1
  162. package/src/TextField/TextField.d.ts +1 -1
  163. package/src/Textarea/Textarea.d.ts +1 -1
  164. package/src/TimePicker/NumberPicker.d.ts +1 -1
  165. package/src/TimePicker/TimeButton.d.ts +1 -1
  166. package/src/TimePicker/ToggleText.d.ts +1 -1
  167. package/src/Tray/Tray.d.ts +1 -1
  168. package/src/Tray/TrayPanel.d.ts +1 -1
  169. package/src/TrayMenu/TrayMenu.d.ts +1 -1
  170. package/src/TrayMenu/TrayMenuItem.d.ts +1 -1
  171. package/src/VirtualizedList/VirtuosoComponents.d.ts +4 -4
  172. package/src/VisuallyHidden/VisuallyHidden.d.ts +1 -1
  173. package/src/internal/utils/index.d.ts +0 -1
  174. /package/{src/internal → internal}/utils/composeEventHandlers.d.ts +0 -0
package/chunks/Badge.js CHANGED
@@ -20,7 +20,7 @@ const Badge = (inProps) => {
20
20
  : count
21
21
  : undefined;
22
22
  const toOrigin = useMemo(() => kebabCase(anchorOrigin), [anchorOrigin]);
23
- const overlapMode = children || forceOverlap;
23
+ const overlapMode = Boolean(children || forceOverlap);
24
24
  return (jsxs("span", { className: cls('root', {
25
25
  absolute: !children && forceOverlap,
26
26
  }), ...rest, children: [children, jsx(AnimatePresence, { initial: false, children: invisible ||
package/chunks/Drawer.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { forwardRef } from 'react';
3
3
  import { motion } from 'framer-motion';
4
- import { useClasses } from '@ringcentral/spring-base';
4
+ import { useClasses, useForkRef } from '@ringcentral/spring-base';
5
5
  import { useThemeProps, motionTransition } from '@ringcentral/spring-theme';
6
6
  import clsx from 'clsx';
7
7
  import './Icon.js';
@@ -23,9 +23,10 @@ const Drawer = forwardRef((inProps, ref) => {
23
23
  toggleOnTransition: motionTransition['neutral-01-fast'],
24
24
  toggleOffTransition: motionTransition['neutral-01-fast'],
25
25
  });
26
+ const handleBodyRef = useForkRef(ref, bodyProps?.ref);
26
27
  return (jsx(Modal, { open: open, onClose: onClose, blocking: blocking, className: clsx(cls('root', `anchor-${anchor}`, {
27
28
  'non-blocking': !blocking,
28
- })), ...rest, children: jsxs(motion.div, { role: "dialog", "aria-modal": blocking, ...slideInProps, ...bodyProps, ref: ref, className: clsx(cls('body', `body-${anchor}`), bodyProps?.className), tabIndex: blocking ? -1 : undefined, children: [header && (jsx("div", { ref: headerRef, ...headerProps, className: clsx(cls('header'), headerProps?.className), children: header })), jsx("div", { ref: contentRef, className: cls('content'), children: children }), footer && (jsx("div", { ref: footerRef, className: cls('footer'), children: footer }))] }) }));
29
+ })), ...rest, children: jsxs(motion.div, { role: "dialog", "aria-modal": blocking, ...slideInProps, ...bodyProps, ref: handleBodyRef, className: clsx(cls('body', `body-${anchor}`), bodyProps?.className), tabIndex: bodyProps?.tabIndex ?? (blocking ? -1 : undefined), children: [header && (jsx("div", { ref: headerRef, ...headerProps, className: clsx(cls('header'), headerProps?.className), children: header })), jsx("div", { ref: contentRef, className: cls('content'), children: children }), footer && (jsx("div", { ref: footerRef, className: cls('footer'), children: footer }))] }) }));
29
30
  });
30
31
  Drawer.displayName = 'SuiDrawer';
31
32
 
@@ -2,6 +2,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { forwardRef } from 'react';
3
3
  import { getTitle } from '@ringcentral/spring-base';
4
4
  import { useThemeProps, useClassesWithMode } from '@ringcentral/spring-theme';
5
+ import { h as hasContent } from './hasContent.js';
6
+ import '@mui/utils';
5
7
 
6
8
  const MenuItemText = forwardRef((inProps, ref) => {
7
9
  const props = useThemeProps({ props: inProps, name: 'MenuItemText' });
@@ -9,7 +11,7 @@ const MenuItemText = forwardRef((inProps, ref) => {
9
11
  const cls = useClassesWithMode('menu-item-text', classes, className);
10
12
  const primaryContent = primary ?? primaryText ?? children;
11
13
  const secondaryContent = info ?? infoText;
12
- return (jsxs("div", { className: cls('root'), ...rest, ref: ref, children: [jsx("span", { className: cls('primary-text'), title: getTitle(primaryContent), children: primaryContent }), secondaryContent && (jsx("span", { className: cls('info-text'), title: getTitle(secondaryContent), children: secondaryContent }))] }));
14
+ return (jsxs("div", { className: cls('root'), ...rest, ref: ref, children: [jsx("span", { className: cls('primary-text'), title: getTitle(primaryContent), children: primaryContent }), hasContent(secondaryContent) && (jsx("span", { className: cls('info-text'), title: getTitle(secondaryContent), children: secondaryContent }))] }));
13
15
  });
14
16
  MenuItemText.displayName = 'SuiMenuItemText';
15
17
 
@@ -5,6 +5,7 @@ import { useThemeProps } from '@ringcentral/spring-theme';
5
5
  import { L as List } from './List.js';
6
6
  import { u as useMenuContext } from './Menu.js';
7
7
  import { c as useMenuItemSelect, e as MenuListContext, a as MenuItemSelectContext } from './useMenuItemSelect.js';
8
+ import '@mui/utils';
8
9
  import 'tabbable';
9
10
  import './useListNavigation.js';
10
11
  import '../VirtualizedList.js';
@@ -13,7 +14,7 @@ const MenuList = forwardRef((inProps, ref) => {
13
14
  const props = useThemeProps({ props: inProps, name: 'MenuList' });
14
15
  const { classes, className, children, widget, selectMode = 'single', nowrap, value: valueProp, onChange, autoFocus: autoFocusProp, ...rest } = props;
15
16
  const menuContext = useMenuContext();
16
- const autoFocus = Boolean(autoFocusProp || menuContext?.autoFocus);
17
+ const autoFocus = Boolean(autoFocusProp ?? menuContext?.autoFocus);
17
18
  const cls = useClasses('menu-list', classes, className);
18
19
  const menuListContextValue = useMemo(() => ({
19
20
  nowrap,
package/chunks/Modal.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { createContext, useContext, forwardRef, useState, useEffect } from 'react';
2
+ import { createContext, useContext, useRef, useCallback, useLayoutEffect, forwardRef, useState, useEffect } from 'react';
3
3
  import { useAriaHideOutside, useForkRef, useClasses, useEventCallback, useBodyScrollLock, useWindowContext } from '@ringcentral/spring-base';
4
4
  import { useThemeProps, useTheme } from '@ringcentral/spring-theme';
5
5
  import { FocusTrap, Portal } from '@mui/base';
@@ -13,15 +13,129 @@ import { B as Backdrop } from './Backdrop.js';
13
13
  const ModalContext = createContext(null);
14
14
  const useModalContext = () => useContext(ModalContext);
15
15
 
16
+ const createOverlayBranchRegistry = () => {
17
+ const branchRefCounts = new Map();
18
+ const listeners = new Set();
19
+ const notify = (node, isRegistered) => {
20
+ for (const listener of [...listeners]) {
21
+ listener(node, isRegistered);
22
+ }
23
+ };
24
+ return {
25
+ getBranches: () => new Set(branchRefCounts.keys()),
26
+ register: (node) => {
27
+ const currentCount = branchRefCounts.get(node) ?? 0;
28
+ branchRefCounts.set(node, currentCount + 1);
29
+ if (currentCount === 0) {
30
+ notify(node, true);
31
+ }
32
+ let isCleanedUp = false;
33
+ return () => {
34
+ if (isCleanedUp) {
35
+ return;
36
+ }
37
+ isCleanedUp = true;
38
+ const currentCount = branchRefCounts.get(node);
39
+ if (!currentCount) {
40
+ return;
41
+ }
42
+ if (currentCount > 1) {
43
+ branchRefCounts.set(node, currentCount - 1);
44
+ return;
45
+ }
46
+ branchRefCounts.delete(node);
47
+ notify(node, false);
48
+ };
49
+ },
50
+ subscribe: (listener) => {
51
+ listeners.add(listener);
52
+ return () => {
53
+ listeners.delete(listener);
54
+ };
55
+ },
56
+ };
57
+ };
58
+ const useOverlayBranchRegistry = () => {
59
+ const registryRef = useRef();
60
+ if (!registryRef.current) {
61
+ registryRef.current = createOverlayBranchRegistry();
62
+ }
63
+ return registryRef.current;
64
+ };
65
+
66
+ const useOverlayBranch = ({ active, registry, }) => {
67
+ const nodeRef = useRef(null);
68
+ const registrationRef = useRef(null);
69
+ const syncRegistration = useCallback((node) => {
70
+ const registration = registrationRef.current;
71
+ const shouldKeepRegistration = registration &&
72
+ active &&
73
+ registration.node === node &&
74
+ registration.registry === registry;
75
+ if (shouldKeepRegistration) {
76
+ return;
77
+ }
78
+ registration?.unregister();
79
+ registrationRef.current = null;
80
+ if (active && node && registry) {
81
+ registrationRef.current = {
82
+ node,
83
+ registry,
84
+ unregister: registry.register(node),
85
+ };
86
+ }
87
+ }, [active, registry]);
88
+ const setBranchRef = useCallback((node) => {
89
+ nodeRef.current = node;
90
+ syncRegistration(node);
91
+ }, [syncRegistration]);
92
+ useLayoutEffect(() => {
93
+ syncRegistration(nodeRef.current);
94
+ }, [syncRegistration]);
95
+ useLayoutEffect(() => () => {
96
+ registrationRef.current?.unregister();
97
+ registrationRef.current = null;
98
+ }, []);
99
+ return setBranchRef;
100
+ };
101
+ const useOverlayBranchConsumer = (registry, listener) => {
102
+ useLayoutEffect(() => {
103
+ const unsubscribe = registry.subscribe(listener);
104
+ for (const node of registry.getBranches()) {
105
+ listener(node, true);
106
+ }
107
+ return () => {
108
+ unsubscribe();
109
+ for (const node of registry.getBranches()) {
110
+ listener(node, false);
111
+ }
112
+ };
113
+ }, [listener, registry]);
114
+ };
115
+
16
116
  const InnerModal = forwardRef((props, ref) => {
17
- const { hideBackdrop: hideBackdropProp, children, motionProps, disableBackdropClick: disableBackdropClickProp, onBackdropClick, disableEscapeKeyDown: disableEscapeKeyDownProp, onEscapeKeyDown, onClose, onKeyDown, disableAutoFocus, disableEnforceFocus, disableRestoreFocus, classes, className, backdropProps, open, isEnabled, blocking = true, ...rest } = props;
117
+ const { hideBackdrop: hideBackdropProp, children, motionProps, disableBackdropClick: disableBackdropClickProp, onBackdropClick, disableEscapeKeyDown: disableEscapeKeyDownProp, onEscapeKeyDown, onClose, onKeyDown, disableAutoFocus, disableEnforceFocus, disableRestoreFocus, classes, className, backdropProps, open, isEnabled, blocking = true, shouldUseInert: shouldUseInertProp, ...rest } = props;
118
+ const parentModalContext = useModalContext();
119
+ const ownOverlayBranchRegistry = useOverlayBranchRegistry();
120
+ const shouldUseInert = shouldUseInertProp ?? parentModalContext?.shouldUseInert ?? false;
18
121
  const hideBackdrop = hideBackdropProp ?? !blocking;
19
122
  const disableBackdropClick = disableBackdropClickProp ?? !blocking;
20
123
  const disableEscapeKeyDown = disableEscapeKeyDownProp ?? !blocking;
21
- const { ariaHideOutsideRef, ariaHideEnabled } = useAriaHideOutside({
22
- enable: blocking,
124
+ const { ariaHideOutsideRef, ariaHideEnabled, setAriaHideOutsideTarget } = useAriaHideOutside({
125
+ enable: blocking && open,
126
+ shouldUseInert,
127
+ });
128
+ useOverlayBranchConsumer(ownOverlayBranchRegistry, setAriaHideOutsideTarget);
129
+ const parentOverlayBranchRegistry = parentModalContext?.overlayBranchRegistry;
130
+ const overlayBranchRegistry = ariaHideEnabled
131
+ ? ownOverlayBranchRegistry
132
+ : parentOverlayBranchRegistry;
133
+ const ariaHideEnabledForChildren = ariaHideEnabled || parentModalContext?.ariaHideEnabled === true;
134
+ const overlayBranchRef = useOverlayBranch({
135
+ active: !blocking && open,
136
+ registry: parentOverlayBranchRegistry,
23
137
  });
24
- const handleRef = useForkRef(ref, ariaHideOutsideRef);
138
+ const handleRef = useForkRef(ref, ariaHideOutsideRef, overlayBranchRef);
25
139
  const cls = useClasses('modal', classes, className);
26
140
  const { onClick: externalOnClick, ...restBackdropProps } = backdropProps || {};
27
141
  const handleBackdropClick = useEventCallback((event) => {
@@ -34,7 +148,11 @@ const InnerModal = forwardRef((props, ref) => {
34
148
  onBackdropClick?.(event);
35
149
  onClose?.(event, 'backdropClick');
36
150
  });
37
- return (jsx(ModalContext.Provider, { value: { ariaHideEnabled }, children: jsxs(motion.div, { ...rest, ...motionProps, role: "presentation", className: cls('root', { 'non-blocking': !blocking }), onKeyDown: (e) => {
151
+ return (jsx(ModalContext.Provider, { value: {
152
+ ariaHideEnabled: ariaHideEnabledForChildren,
153
+ overlayBranchRegistry,
154
+ shouldUseInert,
155
+ }, children: jsxs(motion.div, { ...rest, ...motionProps, role: "presentation", className: cls('root', { 'non-blocking': !blocking }), onKeyDown: (e) => {
38
156
  onKeyDown?.(e);
39
157
  if (!disableEscapeKeyDown &&
40
158
  e.key === 'Escape' &&
@@ -48,7 +166,12 @@ InnerModal.displayName = 'SuiInnerModal';
48
166
 
49
167
  const Modal = forwardRef((inProps, ref) => {
50
168
  const props = useThemeProps({ props: inProps, name: 'Modal' });
51
- const { children, open, container: containerProp, disablePortal, onExitComplete, disableBackdropAnimation, motionProps, disableScrollLock: disableScrollLockProp, blocking = true, ...rest } = props;
169
+ const { children, open, container: containerProp, disablePortal, onExitComplete, disableBackdropAnimation, motionProps, disableScrollLock: disableScrollLockProp, blocking = true, shouldUseInert: themeFallbackShouldUseInert, ...rest } = props;
170
+ const parentModalContext = useModalContext();
171
+ const shouldUseInert = inProps.shouldUseInert ??
172
+ parentModalContext?.shouldUseInert ??
173
+ themeFallbackShouldUseInert ??
174
+ false;
52
175
  const disableScrollLock = disableScrollLockProp ?? !blocking;
53
176
  const [shouldRender, setShouldRender] = useState(open);
54
177
  const [modalElement, setModalElement] = useState(null);
@@ -78,11 +201,11 @@ const Modal = forwardRef((inProps, ref) => {
78
201
  setShouldRender(false);
79
202
  }
80
203
  };
81
- return shouldRender ? (jsx(Portal, { disablePortal: disablePortal, container: container, children: jsx("div", { ...scopeProps, children: jsx(InnerModal, { ...rest, ref: handleRef, open: open, blocking: blocking, isEnabled: isEnabled, motionProps: {
204
+ return shouldRender ? (jsx(Portal, { disablePortal: disablePortal, container: container, children: jsx("div", { ...scopeProps, children: jsx(InnerModal, { ...rest, ref: handleRef, open: open, blocking: blocking, shouldUseInert: shouldUseInert, isEnabled: isEnabled, motionProps: {
82
205
  ...(motionProps ?? getFade({ prefersReducedMotion, toggle: open })),
83
206
  onAnimationComplete,
84
207
  }, children: children }) }) })) : null;
85
208
  });
86
209
  Modal.displayName = 'SuiModal';
87
210
 
88
- export { InnerModal as I, Modal as M, ModalContext as a, useModalContext as u };
211
+ export { InnerModal as I, Modal as M, ModalContext as a, useOverlayBranch as b, useModalContext as u };
package/chunks/Popover.js CHANGED
@@ -19,15 +19,23 @@ const Popover = forwardRef((inProps, ref) => {
19
19
  const handlePaperContentRef = useForkRef(popperPaperPropsProp?.contentRef, paperContentRef);
20
20
  const prefersReducedMotion = usePrefersReducedMotion();
21
21
  return (jsx(Modal, { ...rest, className: cls('root', 'popper'), ref: ref, motionProps: null, hideBackdrop: true, children: jsx(Popper, { arrowHeight: variant === 'standard' ? 0 : 10, arrowPadding: 12, offset: variant === 'standard' ? 2 : 4, ...combineProps({
22
+ tether: false,
22
23
  middlewares: [
23
24
  size({
24
25
  padding: PopperProps?.padding,
25
- apply({ availableHeight, availableWidth, }) {
26
+ apply({ availableHeight, availableWidth, elements, }) {
26
27
  onAvailableHeightChange?.(availableHeight);
27
- if (paperContentRef.current) {
28
- paperContentRef.current.style.maxHeight = `${availableHeight}px`;
29
- paperContentRef.current.style.maxWidth = `${availableWidth}px`;
28
+ const content = paperContentRef.current;
29
+ if (!content) {
30
+ return;
30
31
  }
32
+ const decorationHeight = elements.floating.offsetHeight - content.offsetHeight;
33
+ const decorationWidth = elements.floating.offsetWidth - content.offsetWidth;
34
+ const maxHeight = Math.max(0, availableHeight - decorationHeight);
35
+ content.style.maxWidth = `${Math.max(0, availableWidth - decorationWidth)}px`;
36
+ content.style.maxHeight = '';
37
+ content.style.maxHeight =
38
+ maxHeight < content.scrollHeight ? `${maxHeight}px` : '';
31
39
  },
32
40
  }),
33
41
  ],
@@ -45,7 +53,7 @@ const Popover = forwardRef((inProps, ref) => {
45
53
  }),
46
54
  };
47
55
  }
48
- return (jsx(PopperPaper, { contentRef: handlePaperContentRef, arrowRef: arrowRef, arrowStyle: arrowStyle, ...combineProps(combineProps(motionProps, popperPaperProps), popperPaperPropsProp), children: children }));
56
+ return (jsx(PopperPaper, { arrowRef: arrowRef, arrowStyle: arrowStyle, ...combineProps(combineProps(motionProps, popperPaperProps), popperPaperPropsProp), contentRef: handlePaperContentRef, children: children }));
49
57
  } }) }));
50
58
  });
51
59
  Popover.displayName = 'SuiPopover';
package/chunks/Select.js CHANGED
@@ -7,6 +7,8 @@ import 'framer-motion';
7
7
  import { u as usePrefersReducedMotion } from './usePrefersReducedMotion.js';
8
8
  import { g as getGrow } from './getGrow.js';
9
9
  import './Icon.js';
10
+ import { h as hasContent } from './hasContent.js';
11
+ import '@mui/utils';
10
12
  import { u as useHelperTextId, F as FormField } from './useHelperTextId.js';
11
13
  import { M as Menu, a as MenuContext } from './Menu.js';
12
14
  import { c as useMenuItemSelect, a as MenuItemSelectContext } from './useMenuItemSelect.js';
@@ -148,37 +150,40 @@ const Select = forwardRef((inProps, ref) => {
148
150
  close: handleClose,
149
151
  autoFocus: true,
150
152
  }), [handleClose]);
151
- const selectorProps = getButtonProps(selectorPropsProp);
153
+ const selectorProps = getButtonProps(combineProps({
154
+ onMouseDown: (event) => {
155
+ if (disabled || event.button !== 0)
156
+ return;
157
+ event.preventDefault();
158
+ event.currentTarget.focus();
159
+ },
160
+ }, selectorPropsProp));
152
161
  const selectedValue = value !== null || displayEmpty ? renderValue(value) : null;
153
162
  const valueId = `${id}-value`;
154
163
  const labelId = `${id}-label`;
155
164
  let menu = null;
165
+ const baseMenuClasses = { paper: cls('menu') };
166
+ const basePopperProps = { offset: 4, matchAnchorWidth: true };
167
+ const popperProps = combineProps(basePopperProps, !virtualize
168
+ ? MenuProps?.PopperProps
169
+ : virtualizedMenuPropsProp?.PopperProps);
170
+ const menuClasses = popperProps.matchAnchorWidth
171
+ ? combineClasses(baseMenuClasses, { paper: 'min-w-0' })
172
+ : baseMenuClasses;
173
+ const onExitComplete = () => {
174
+ setDidMenuExit(true);
175
+ };
156
176
  const baseMenuProps = {
157
- onExitComplete: () => {
158
- setDidMenuExit(true);
159
- },
177
+ onExitComplete,
160
178
  placement: DEFAULT_PLACEMENT,
161
179
  open,
162
180
  anchorEl,
163
- PopperProps: {
164
- offset: 4,
165
- matchAnchorWidth: true,
166
- },
167
- classes: {
168
- paper: cls('menu'),
169
- },
181
+ PopperProps: basePopperProps,
182
+ classes: menuClasses,
170
183
  onClose: handleClose,
171
184
  };
172
- const popperProps = combineProps(baseMenuProps.PopperProps, !virtualize
173
- ? MenuProps?.PopperProps
174
- : virtualizedMenuPropsProp?.PopperProps);
175
- if (popperProps.matchAnchorWidth) {
176
- baseMenuProps.classes = combineClasses(baseMenuProps.classes, {
177
- paper: 'min-w-0',
178
- });
179
- }
180
185
  if (!virtualize) {
181
- menu = (jsx(Menu, { ...baseMenuProps, ...MenuProps, PopperProps: popperProps, classes: combineClasses(baseMenuProps.classes, MenuProps?.classes), motionProps: getYAxisGrowMotion({
186
+ menu = (jsx(Menu, { ...baseMenuProps, ...MenuProps, PopperProps: popperProps, classes: combineClasses(menuClasses, MenuProps?.classes), motionProps: getYAxisGrowMotion({
182
187
  placement: MenuProps?.placement,
183
188
  prefersReducedMotion: prefersReducedMotion,
184
189
  }), children: jsx(MenuList, { value: value, onChange: handleMenuListChange, nowrap: false, widget: "select", selectMode: selectMode, ...getListboxProps(), children: children }) }));
@@ -198,7 +203,7 @@ const Select = forwardRef((inProps, ref) => {
198
203
  content: cls('content'),
199
204
  }, size: size, ...rest, children: [jsxs("button", { className: cls('selector', `${variant}-selector`, `${variant}-selector-${size}`, {
200
205
  expanded: open,
201
- }), type: 'button', disabled: disabled, "aria-labelledby": label ? `${labelId} ${valueId}` : valueId, "aria-describedby": helperTextId, ...selectorProps, id: id, children: [selectedValue ? (jsx("span", { id: valueId, "aria-live": "polite", className: cls('value'), title: getTitle(selectedValue), children: selectedValue })) : (jsx("span", { id: valueId, className: cls('placeholder'), title: getTitle(placeholder), children: placeholder })), jsx(Squircle, { className: cls('chevron'), interactive: false, children: jsx(ExpandCollapseCaret, { size: 'small', expanded: open }) })] }), jsx("input", { ref: inputRef, name: name, value: `${value}`, disabled: disabled, className: cls('native-input'), tabIndex: -1, "aria-hidden": true, "aria-invalid": error, onChange: handleInputChange, ...inputProps })] }), anchorEl && menu] }));
206
+ }), disabled: disabled, "aria-labelledby": label ? `${labelId} ${valueId}` : valueId, "aria-describedby": helperTextId, ...selectorProps, id: id, type: "button", children: [hasContent(selectedValue) ? (jsx("span", { id: valueId, "aria-live": "polite", className: cls('value'), title: getTitle(selectedValue), children: selectedValue })) : (jsx("span", { id: valueId, className: cls('placeholder'), title: getTitle(placeholder), children: placeholder })), jsx(Squircle, { className: cls('chevron'), interactive: false, children: jsx(ExpandCollapseCaret, { size: 'small', expanded: open }) })] }), jsx("input", { ref: inputRef, name: name, value: `${value}`, disabled: disabled, className: cls('native-input'), tabIndex: -1, "aria-hidden": true, "aria-invalid": error, onChange: handleInputChange, ...inputProps })] }), anchorEl && menu] }));
202
207
  });
203
208
  Select.displayName = 'SuiSelect';
204
209
  function getYAxisGrowMotion(params) {
package/chunks/SlideIn.js CHANGED
@@ -5,7 +5,7 @@ import '@ringcentral/spring-theme';
5
5
  import { g as getSlideIn } from './getSlideIn.js';
6
6
 
7
7
  const SlideIn = (props) => {
8
- const { toggle, toggleOnTransition, toggleOffTransition, children, from = 'right', ...rest } = props;
8
+ const { toggle, toggleOnTransition, toggleOffTransition, transition, children, from = 'right', ...rest } = props;
9
9
  const prefersReducedMotion = usePrefersReducedMotion();
10
10
  return (jsx(motion.div, { ...getSlideIn({
11
11
  toggle,
@@ -13,6 +13,7 @@ const SlideIn = (props) => {
13
13
  prefersReducedMotion,
14
14
  toggleOnTransition,
15
15
  toggleOffTransition,
16
+ transition,
16
17
  }), ...rest, children: children }));
17
18
  };
18
19
 
@@ -16,11 +16,11 @@ const Squircle = forwardRef((inProps, ref) => {
16
16
  const clipId = useId('sui-squircle-clip', true);
17
17
  const showFocusRing = interactive && focusVisible;
18
18
  const Root = component;
19
- return (jsxs(Root, { className: cls('root', { active, interactive }), ...rest, ref: ref, children: [jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "0", height: "0", viewBox: "0 0 1 1", children: jsx("defs", { children: jsx("clipPath", { id: clipId, clipPathUnits: "objectBoundingBox", children: jsx("path", { d: SQUIRCLE_PATH }) }) }) }), !fillShape && (jsx("svg", { className: cls('content'), xmlns: "http://www.w3.org/2000/svg", viewBox: '0 0 1 1', children: jsx("path", { clipPath: `url(#${clipId})`, d: SQUIRCLE_PATH, vectorEffect: "non-scaling-stroke" }) })), showFocusRing && (jsx("svg", { className: cls('ring'), xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 1 1", overflow: "visible", children: jsx("path", { d: SQUIRCLE_PATH, fillOpacity: 0, vectorEffect: "non-scaling-stroke" }) })), fillShape
19
+ return (jsxs(Root, { className: cls('root', { active, interactive }), ...rest, ref: ref, children: [jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "0", height: "0", viewBox: "0 0 1 1", style: { position: 'absolute' }, "aria-hidden": true, children: jsx("defs", { children: jsx("clipPath", { id: clipId, clipPathUnits: "objectBoundingBox", children: jsx("path", { d: SQUIRCLE_PATH }) }) }) }), !fillShape && (jsx("svg", { className: cls('content'), xmlns: "http://www.w3.org/2000/svg", viewBox: '0 0 1 1', children: jsx("path", { clipPath: `url(#${clipId})`, d: SQUIRCLE_PATH, vectorEffect: "non-scaling-stroke" }) })), showFocusRing && (jsx("svg", { className: cls('ring'), xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 1 1", overflow: "visible", children: jsx("path", { d: SQUIRCLE_PATH, fillOpacity: 0, vectorEffect: "non-scaling-stroke" }) })), fillShape
20
20
  ? cloneElement(firstChild, {
21
21
  style: {
22
22
  ...firstChild.props.style,
23
- with: '100%',
23
+ width: '100%',
24
24
  height: '100%',
25
25
  clipPath: `url(#${clipId})`,
26
26
  },
@@ -3,6 +3,7 @@ import { createContext, useContext, useRef, useLayoutEffect, forwardRef, useStat
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';
6
+ import { u as useAnimationFrame } from './useAnimationFrame.js';
6
7
  import { P as Popover } from './Popover.js';
7
8
  import { VirtualizedList } from '../VirtualizedList.js';
8
9
 
@@ -37,7 +38,7 @@ const VirtualizedMenuList = (props) => {
37
38
  const MENU_VERTICAL_PADDING = 8;
38
39
  const VirtualizedMenu = forwardRef((inProps, ref) => {
39
40
  const props = useThemeProps({ props: inProps, name: 'VirtualizedMenu' });
40
- const { classes, className, children, open, onClose, data, totalCount, isItemDisabled, VirtualizedListProps, popperActions: popperActionsProp, initialFocus = true, maxHeight, PopperProps, ...rest } = props;
41
+ const { classes, className, children, open, onClose, data, totalCount, isItemDisabled, actions, VirtualizedListProps, popperActions: popperActionsProp, initialFocus = true, maxHeight, PopperProps, ...rest } = props;
41
42
  const popperPaperContentRef = useRef(null);
42
43
  const paperContentContainerRef = useRef(null);
43
44
  const hasItemsRenderedRef = useRef(false);
@@ -58,6 +59,7 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
58
59
  : (padding ?? 16);
59
60
  const popperActions = useRef(null);
60
61
  const handlePopperActions = useForkRef(popperActions, popperActionsProp);
62
+ const { requestAnimationFrame } = useAnimationFrame();
61
63
  const menuContextValue = useMemo(() => {
62
64
  return { open };
63
65
  }, [open]);
@@ -72,9 +74,6 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
72
74
  setMenuHeight(computedMenuHeight);
73
75
  });
74
76
  const updatePopoverHeight = useEventCallback(() => {
75
- if (!popperPaperContentRef.current)
76
- return;
77
- popperPaperContentRef.current.style.maxHeight = `${availableHeight.current}px`;
78
77
  if (paperContentContainerRef.current) {
79
78
  paperContentContainerRef.current.style.height = `auto`;
80
79
  }
@@ -131,7 +130,8 @@ const VirtualizedMenu = forwardRef((inProps, ref) => {
131
130
  }, [open]);
132
131
  return (jsx(Popover, { bordered: true, PopperProps: { ...PopperProps, padding: popperPadding }, ...rest, open: open, className: clsx(cls('root'), waitForHeightCompute && 'opacity-0'), PopperPaperProps: {
133
132
  contentRef: popperPaperContentRef,
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, {
133
+ }, 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, actions: actions, ...combineProps(VirtualizedListProps, {
134
+ style: { height: menuHeight },
135
135
  ListProps: combineProps(VirtualizedListProps?.ListProps, {
136
136
  className: cls('list'),
137
137
  style: {
@@ -0,0 +1,10 @@
1
+ const composeEventHandlers = (externalEventHandler, internalEventHandler, options = {}) => (event, ...args) => {
2
+ const { checkForDefaultPrevented = true } = options;
3
+ externalEventHandler?.(event, ...args);
4
+ if (checkForDefaultPrevented && event.defaultPrevented) {
5
+ return;
6
+ }
7
+ internalEventHandler?.(event, ...args);
8
+ };
9
+
10
+ export { composeEventHandlers as c };
@@ -2,7 +2,7 @@ import { motionTransition } from '@ringcentral/spring-theme';
2
2
 
3
3
  const horizontal = ['right', 'left'];
4
4
  const plus = ['right', 'bottom'];
5
- const getSlideIn = ({ toggle = true, from = 'right', prefersReducedMotion = false, toggleOnTransition, toggleOffTransition, } = {}) => {
5
+ const getSlideIn = ({ toggle = true, from = 'right', prefersReducedMotion = false, toggleOnTransition, toggleOffTransition, transition, } = {}) => {
6
6
  const axis = horizontal.includes(from) ? 'x' : 'y';
7
7
  const invisibleValue = plus.includes(from) ? '100%' : '-100%';
8
8
  return {
@@ -23,7 +23,7 @@ const getSlideIn = ({ toggle = true, from = 'right', prefersReducedMotion = fals
23
23
  },
24
24
  transition: prefersReducedMotion
25
25
  ? motionTransition.instant
26
- : motionTransition['spring-01-fast'],
26
+ : (transition ?? motionTransition['spring-01-fast']),
27
27
  };
28
28
  };
29
29
 
@@ -0,0 +1,3 @@
1
+ const hasContent = (content) => Boolean(content) || content === 0;
2
+
3
+ export { hasContent as h };
@@ -0,0 +1,15 @@
1
+ import { useMemo } from 'react';
2
+ import { useWindowContext } from '@ringcentral/spring-base';
3
+
4
+ function useAnimationFrame() {
5
+ const { externalWindow, globalThis: contextGlobal } = useWindowContext();
6
+ return useMemo(() => {
7
+ const contextWindow = externalWindow ?? contextGlobal;
8
+ return {
9
+ requestAnimationFrame: (callback) => contextWindow.requestAnimationFrame(callback),
10
+ cancelAnimationFrame: (handle) => contextWindow.cancelAnimationFrame(handle),
11
+ };
12
+ }, [externalWindow, contextGlobal]);
13
+ }
14
+
15
+ export { useAnimationFrame as u };
@@ -14,7 +14,9 @@ const useFocusTrapStack = ({ open, }) => {
14
14
  useEffect(() => {
15
15
  if (open) {
16
16
  const stack = getFocusTrapStack(globalThis);
17
- stack.push(id);
17
+ if (stack.indexOf(id) < 0) {
18
+ stack.push(id);
19
+ }
18
20
  }
19
21
  return () => {
20
22
  const stack = getFocusTrapStack(globalThis);
@@ -3,17 +3,19 @@ import { forwardRef } from 'react';
3
3
  import clsx from 'clsx';
4
4
  import { useClasses } from '@ringcentral/spring-base';
5
5
  import { useThemeProps } from '@ringcentral/spring-theme';
6
+ import { h as hasContent } from './hasContent.js';
7
+ import '@mui/utils';
6
8
 
7
9
  const FormField = forwardRef((inProps, ref) => {
8
10
  const props = useThemeProps({ props: inProps, name: 'FormField' });
9
11
  const { classes, className, children, htmlFor, label, labelProps, helperText, required, disabled, error, variant = 'standard', size = 'xlarge', contentRef, contentProps, focused, FormHelperTextProps, ...rest } = props;
10
12
  const cls = useClasses('form-field', classes, className);
11
- return (jsxs("div", { ...rest, ref: ref, className: cls('root', variant, { disabled, error, focused }), "aria-disabled": disabled, children: [label && (jsxs("label", { htmlFor: htmlFor, ...labelProps, className: clsx(cls('label', `${variant}-label`, error && 'error-label'), labelProps?.className), children: [label, required ? ' *' : ''] })), jsxs("div", { className: cls('container', error && 'error-container'), children: [jsx("div", { className: cls('content', size, `${size}-content`, `${variant}-${size}`, `${variant}-content`, error && 'error-content', error && `error-${variant}-content`), ref: contentRef, ...contentProps, children: children }), jsx("div", { className: cls('focus-effect', `${variant}-focus-effect`, error && 'error-focus-effect') })] }), helperText && (jsx("div", { ...FormHelperTextProps, className: clsx(cls('helper-text', error && 'error-helper-text'), FormHelperTextProps?.className), children: helperText }))] }));
13
+ return (jsxs("div", { ...rest, ref: ref, className: cls('root', variant, { disabled, error, focused }), "aria-disabled": disabled, children: [hasContent(label) && (jsxs("label", { htmlFor: htmlFor, ...labelProps, className: clsx(cls('label', `${variant}-label`, error && 'error-label'), labelProps?.className), children: [label, required ? ' *' : ''] })), jsxs("div", { className: cls('container', error && 'error-container'), children: [jsx("div", { className: cls('content', size, `${size}-content`, `${variant}-${size}`, `${variant}-content`, error && 'error-content', error && `error-${variant}-content`), ref: contentRef, ...contentProps, children: children }), jsx("div", { className: cls('focus-effect', `${variant}-focus-effect`, error && 'error-focus-effect') })] }), hasContent(helperText) && (jsx("div", { ...FormHelperTextProps, className: clsx(cls('helper-text', error && 'error-helper-text'), FormHelperTextProps?.className), children: helperText }))] }));
12
14
  });
13
15
  FormField.displayName = 'SuiFormField';
14
16
 
15
17
  const useHelperTextId = ({ helperText, id, FormHelperTextProps, }) => {
16
- if (!helperText) {
18
+ if (!hasContent(helperText)) {
17
19
  return undefined;
18
20
  }
19
21
  return FormHelperTextProps?.id || `${id}-helper-text`;