@ringcentral/spring-ui 1.11.2 → 1.13.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.
- package/Accordion.js +90 -34
- package/AccordionHeader.js +72 -20
- package/Alert.js +120 -28
- package/Animation.js +2 -45
- package/Announcement.js +46 -35
- package/Autocomplete.js +1011 -580
- package/Avatar.js +134 -73
- package/AvatarGroup.js +50 -7
- package/Backdrop.js +45 -7
- package/Badge.js +77 -15
- package/Block.js +34 -12
- package/BlockHeader.js +55 -11
- package/BottomNavigation.js +181 -65
- package/BottomNavigationItem.js +93 -30
- package/Button.js +160 -24
- package/CallButton.js +53 -31
- package/Checkbox.js +88 -26
- package/Chip.js +126 -26
- package/CircularProgressIndicator.js +80 -8
- package/ClickAwayListener.js +4 -1
- package/ComponentsProps.js +1 -0
- package/DatePicker.js +611 -190
- package/DateUtilsContext.js +43 -25
- package/Dialer.js +576 -250
- package/Dialog.js +100 -45
- package/Divider.js +43 -7
- package/DragHandle.js +32 -6
- package/Drawer.js +117 -19
- package/Dropdown.js +154 -74
- package/EmptyState.js +63 -11
- package/FabButton.js +51 -17
- package/FocusTrap.js +109 -12
- package/FormField.js +106 -8
- package/FormLabel.js +81 -7
- package/Icon.js +1 -8
- package/IconButton.js +142 -26
- package/IconButtonGroup.js +35 -12
- package/InlineEditable.js +98 -44
- package/LinearProgressIndicator.js +73 -24
- package/Link.js +40 -11
- package/List.js +54 -9
- package/ListItem.js +152 -23
- package/ListItemText.js +44 -16
- package/ListNavigation.js +272 -20
- package/Menu.js +139 -23
- package/MenuActions.js +37 -12
- package/MenuDivider.js +34 -8
- package/MenuFooter.js +36 -12
- package/MenuHeader.js +54 -15
- package/MenuItem.js +402 -33
- package/MenuItemText.js +51 -8
- package/MenuList.js +87 -34
- package/Modal.js +345 -16
- package/NestedMenuContext.js +183 -11
- package/Option.js +32 -34
- package/Overlap.js +54 -7
- package/PageHeader.js +62 -24
- package/PickerTextField.js +156 -33
- package/Popover.js +262 -21
- package/Popper.js +130 -77
- package/PopperPaper.js +54 -8
- package/Portal.js +6 -1
- package/Radio.js +65 -21
- package/RadioGroup.js +56 -17
- package/Rating.js +223 -87
- package/Select.js +387 -41
- package/SingleFilter.js +148 -77
- package/Skeleton.js +68 -17
- package/Slider.js +168 -69
- package/Snackbar.js +122 -59
- package/SortableList.js +32 -12
- package/SortableListDndContext.js +69 -22
- package/SortableListItem.js +92 -47
- package/SortableVirtualizedList.js +52 -28
- package/SplitButton.js +124 -86
- package/Squircle.js +4 -7
- package/StatusIndicator.js +51 -9
- package/Step.js +63 -38
- package/StepButton.js +51 -23
- package/StepConnector.js +48 -8
- package/StepContent.js +68 -25
- package/StepIcon.js +90 -9
- package/StepLabel.js +90 -14
- package/Stepper.js +65 -23
- package/SubMenu.js +203 -99
- package/SwipeableDrawer.js +439 -194
- package/Switch.js +70 -23
- package/Tab.js +120 -57
- package/TabContext.js +59 -15
- package/TabPanel.js +40 -13
- package/Table.js +60 -17
- package/TableBody.js +42 -12
- package/TableCell.js +84 -50
- package/TableContainer.js +32 -10
- package/TableFooter.js +38 -10
- package/TableHead.js +49 -15
- package/TablePagination.js +153 -77
- package/TableRow.js +60 -21
- package/Tabs.js +593 -268
- package/Tag.js +51 -16
- package/Text.js +68 -37
- package/TextField.js +209 -29
- package/Textarea.js +51 -40
- package/TimePicker.js +490 -230
- package/Tooltip.js +48 -23
- package/Tray.js +237 -13
- package/TrayMenu.js +62 -41
- package/VirtualizedList.js +208 -109
- package/VirtualizedMenu.js +359 -29
- package/VisuallyHidden.js +29 -6
- package/chunks/1250.js +98 -0
- package/chunks/1294.js +126 -0
- package/chunks/2956.js +18 -0
- package/chunks/4476.js +460 -0
- package/chunks/4491.js +10 -0
- package/chunks/4535.js +364 -0
- package/chunks/5047.js +3 -0
- package/chunks/6335.js +24 -0
- package/chunks/7279.js +10 -0
- package/chunks/8011.js +8 -0
- package/chunks/8307.js +56 -0
- package/chunks/8467.js +8 -0
- package/chunks/8809.js +8 -0
- package/chunks/{RadioGroup.context.js → 9551.js} +12 -6
- package/chunks/987.js +8 -0
- package/index.css +2624 -2416
- package/index.js +245 -193
- package/internal/utils/index.d.ts +1 -0
- package/internal/utils/setRef.d.ts +2 -0
- package/package.json +8 -8
- package/src/Alert/Alert.type.d.ts +2 -1
- package/src/Animation/components/Fade/Fade.d.ts +4 -2
- package/src/Animation/components/Grow/Grow.d.ts +4 -2
- package/src/Animation/components/ShowHideEye/ShowHideEye.d.ts +1 -1
- package/src/Animation/components/SlideIn/SlideIn.d.ts +4 -2
- package/src/Animation/components/SlideIn/getSlideIn.d.ts +1 -1
- package/src/Animation/hooks/useMotionSafeTransition/useMotionSafeTransition.d.ts +2 -0
- package/src/Autocomplete/SuggestionList/SuggestionList.d.ts +1 -1
- package/src/Autocomplete/useAutocomplete.d.ts +18 -18
- package/src/Autocomplete/useAutocompleteTag.d.ts +18 -18
- package/src/Badge/Badge.d.ts +2 -1
- package/src/Button/Button.classes.d.ts +1 -1
- package/src/ComponentsProps.d.ts +111 -110
- package/src/DatePicker/DatePickerDataAttributes.d.ts +11 -0
- package/src/DatePicker/utils/DatePickerAriaLabelUtils.d.ts +2 -1
- package/src/DatePicker/utils/DatePickerUtils.d.ts +1 -1
- package/src/Dialer/DialDelete/DialDelete.d.ts +2 -2
- package/src/Dialer/DialPad/DialPad.d.ts +2 -2
- package/src/Dialer/Dialer.d.ts +4 -2
- package/src/Dropdown/Dropdown.type.d.ts +2 -2
- package/src/InlineEditable/InlineEditable.type.d.ts +2 -1
- package/src/ListNavigation/useListNavigation.d.ts +3 -3
- package/src/MenuActions/MenuActions.d.ts +2 -2
- package/src/MenuItem/MenuItem.type.d.ts +1 -0
- package/src/MenuItem/useMenuItem.d.ts +1 -1
- package/src/MenuItem/useVirtualizedMenuItem.d.ts +1 -1
- package/src/MenuList/MenuList.type.d.ts +1 -1
- package/src/MenuList/MenuListContext.d.ts +2 -3
- package/src/Modal/Modal.type.d.ts +1 -0
- package/src/NestedMenuContext/MenuOverlayGroupContext.d.ts +2 -2
- package/src/Popover/Popover.classes.d.ts +1 -1
- package/src/Popover/Popover.internal.d.ts +8 -0
- package/src/Popover/Popover.type.d.ts +1 -0
- package/src/Popper/Popper.type.d.ts +10 -7
- package/src/Rating/utils.d.ts +3 -2
- package/src/Select/Select.type.d.ts +7 -5
- package/src/Slider/Slider.d.ts +2 -2
- package/src/Slider/SliderThumb.d.ts +2 -1
- package/src/Squircle/Squircle.d.ts +1 -1
- package/src/StatusIndicator/StatusIndicator.d.ts +2 -1
- package/src/SubMenu/PopperMenu.type.d.ts +4 -1
- package/src/Table/Table.type.d.ts +3 -0
- package/src/Table/TableContext.d.ts +3 -0
- package/src/Table/TableRowContext.d.ts +7 -0
- package/src/Table/index.d.ts +1 -0
- package/src/TableCell/TableCell.classes.d.ts +1 -1
- package/src/TableFooter/TableFooter.classes.d.ts +1 -1
- package/src/TableFooter/TableFooter.type.d.ts +1 -0
- package/src/TableHead/TableHead.classes.d.ts +1 -1
- package/src/TableHead/TableHead.type.d.ts +1 -0
- package/src/TableRow/TableRow.type.d.ts +2 -0
- package/chunks/AccordionContext.js +0 -6
- package/chunks/Alert.js +0 -48
- package/chunks/AvatarGroup.js +0 -22
- package/chunks/Backdrop.js +0 -18
- package/chunks/Badge.js +0 -32
- package/chunks/BottomNavigationItem.js +0 -36
- package/chunks/Button.js +0 -88
- package/chunks/Chip.js +0 -73
- package/chunks/CircularProgressIndicator.js +0 -36
- package/chunks/Divider.js +0 -19
- package/chunks/DragHandle.js +0 -11
- package/chunks/Drawer.js +0 -32
- package/chunks/ExpandCollapseCaret.js +0 -24
- package/chunks/FormLabel.js +0 -27
- package/chunks/Icon.js +0 -25
- package/chunks/IconButtonLabel.js +0 -68
- package/chunks/List.js +0 -22
- package/chunks/ListItem.js +0 -83
- package/chunks/Menu.js +0 -61
- package/chunks/MenuDivider.js +0 -14
- package/chunks/MenuItemText.js +0 -17
- package/chunks/MenuList.js +0 -46
- package/chunks/Modal.js +0 -212
- package/chunks/Overlap.js +0 -25
- package/chunks/PickerTextField.js +0 -85
- package/chunks/Popover.js +0 -53
- package/chunks/PopperPaper.js +0 -15
- package/chunks/Select.js +0 -220
- package/chunks/ShowHideEye.js +0 -56
- package/chunks/SlideIn.js +0 -19
- package/chunks/SortableArrow.js +0 -73
- package/chunks/Squircle.js +0 -31
- package/chunks/StatusIndicator.js +0 -20
- package/chunks/StepConnector.js +0 -21
- package/chunks/StepIcon.js +0 -43
- package/chunks/StepLabel.js +0 -29
- package/chunks/StepperContext.js +0 -9
- package/chunks/TableContext.js +0 -6
- package/chunks/Tablelvl2Context.js +0 -6
- package/chunks/TabsContext.js +0 -6
- package/chunks/TextField.js +0 -110
- package/chunks/Tooltip.js +0 -217
- package/chunks/VirtualizedMenu.js +0 -164
- package/chunks/VisuallyHidden.js +0 -12
- package/chunks/getFade.js +0 -27
- package/chunks/getGrow.js +0 -70
- package/chunks/getSlideIn.js +0 -30
- package/chunks/hasContent.js +0 -3
- package/chunks/useAnimationFrame.js +0 -15
- package/chunks/useFocusTrapStack.js +0 -36
- package/chunks/useHelperTextId.js +0 -22
- package/chunks/useListNavigation.js +0 -199
- package/chunks/useMenuItemSelect.js +0 -273
- package/chunks/useMotionSafeTransition.js +0 -9
- package/chunks/useNestedMenuItem.js +0 -27
- package/chunks/useNestedParentMenu.js +0 -113
- package/chunks/usePrefersReducedMotion.js +0 -36
- package/chunks/useTooltipForceHide.js +0 -27
- package/chunks/useTrayNavigate.js +0 -150
- package/chunks/withTooltip.js +0 -15
package/MenuList.js
CHANGED
|
@@ -1,34 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useLayoutEffect, useMemo, useRef } from "react";
|
|
3
|
+
import { useClasses, useForkRef, useWindowContext } from "@ringcentral/spring-base";
|
|
4
|
+
import { useThemeProps } from "@ringcentral/spring-theme";
|
|
5
|
+
import { List as List_List } from "./List.js";
|
|
6
|
+
import { useMenuContext } from "./Menu.js";
|
|
7
|
+
import { MenuItemSelectContext, MenuListContext, useMenuItemSelect } from "./MenuItem.js";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
// extracted by css-extract-rspack-plugin
|
|
14
|
+
/* export default */ var MenuList = ({"sui-menu-list-root":"sui-menu-list-root"});
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
const MenuList_MenuList = /*#__PURE__*/ forwardRef((inProps, ref)=>{
|
|
25
|
+
const props = useThemeProps({
|
|
26
|
+
props: inProps,
|
|
27
|
+
name: 'MenuList'
|
|
28
|
+
});
|
|
29
|
+
const { classes, className, children, widget, selectMode = 'single', nowrap, value: valueProp, onChange, autoFocus: autoFocusProp, ...rest } = props;
|
|
30
|
+
const menuContext = useMenuContext();
|
|
31
|
+
const autoFocus = Boolean(autoFocusProp ?? menuContext?.autoFocus);
|
|
32
|
+
const cls = useClasses('menu-list', classes, className);
|
|
33
|
+
const menuListContextValue = useMemo(()=>({
|
|
34
|
+
nowrap
|
|
35
|
+
}), [
|
|
36
|
+
nowrap
|
|
37
|
+
]);
|
|
38
|
+
const { contextValue } = useMenuItemSelect({
|
|
39
|
+
widget,
|
|
40
|
+
selectMode,
|
|
41
|
+
value: valueProp,
|
|
42
|
+
onChange,
|
|
43
|
+
autoFocus
|
|
44
|
+
});
|
|
45
|
+
const actions = useRef(null);
|
|
46
|
+
const listRef = useRef(null);
|
|
47
|
+
const handleListRef = useForkRef(listRef, ref);
|
|
48
|
+
const { document } = useWindowContext();
|
|
49
|
+
useLayoutEffect(()=>{
|
|
50
|
+
if (autoFocus && // ensure item can auto focus correctly
|
|
51
|
+
!listRef.current?.contains(document?.activeElement ?? null)) {
|
|
52
|
+
actions.current?.focus();
|
|
53
|
+
}
|
|
54
|
+
}, [
|
|
55
|
+
autoFocus
|
|
56
|
+
]);
|
|
57
|
+
// Use appropriate role and ARIA attributes based on widget type
|
|
58
|
+
const listRole = widget === 'select' ? 'listbox' : 'menu';
|
|
59
|
+
const listboxProps = widget === 'select' ? {
|
|
60
|
+
'aria-multiselectable': selectMode === 'multiple'
|
|
61
|
+
} : {};
|
|
62
|
+
return /*#__PURE__*/ jsx(List_List, {
|
|
63
|
+
className: cls('root'),
|
|
64
|
+
role: listRole,
|
|
65
|
+
...listboxProps,
|
|
66
|
+
...rest,
|
|
67
|
+
ref: handleListRef,
|
|
68
|
+
actions: actions,
|
|
69
|
+
children: /*#__PURE__*/ jsx(MenuListContext.Provider, {
|
|
70
|
+
value: menuListContextValue,
|
|
71
|
+
children: /*#__PURE__*/ jsx(MenuItemSelectContext.Provider, {
|
|
72
|
+
value: contextValue,
|
|
73
|
+
children: children
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
MenuList_MenuList.displayName = 'SuiMenuList';
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
export { MenuList as menuListStyle, MenuList_MenuList as MenuList };
|
|
87
|
+
export { MenuListContext, useMenuListContext } from "./MenuItem.js";
|
package/Modal.js
CHANGED
|
@@ -1,16 +1,345 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, forwardRef, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { motion } from "framer-motion";
|
|
4
|
+
import { useAriaHideOutside, useBodyScrollLock, useClasses, useEventCallback, useForkRef, useWindowContext } from "@ringcentral/spring-base";
|
|
5
|
+
import { FocusTrap } from "@mui/base";
|
|
6
|
+
import { useTheme, useThemeProps } from "@ringcentral/spring-theme";
|
|
7
|
+
import { Backdrop as Backdrop_Backdrop } from "./Backdrop.js";
|
|
8
|
+
import { Portal } from "./Portal.js";
|
|
9
|
+
import { getFade } from "./chunks/4476.js";
|
|
10
|
+
import { useFocusTrapStack } from "./FocusTrap.js";
|
|
11
|
+
import { usePrefersReducedMotion } from "./chunks/1294.js";
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const ModalContext = createContext(null);
|
|
21
|
+
const useModalContext = ()=>useContext(ModalContext);
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
const createOverlayBranchRegistry = ()=>{
|
|
26
|
+
const branchRefCounts = new Map();
|
|
27
|
+
const listeners = new Set();
|
|
28
|
+
const notify = (node, isRegistered)=>{
|
|
29
|
+
for (const listener of [
|
|
30
|
+
...listeners
|
|
31
|
+
]){
|
|
32
|
+
listener(node, isRegistered);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
getBranches: ()=>new Set(branchRefCounts.keys()),
|
|
37
|
+
register: (node)=>{
|
|
38
|
+
const currentCount = branchRefCounts.get(node) ?? 0;
|
|
39
|
+
branchRefCounts.set(node, currentCount + 1);
|
|
40
|
+
if (currentCount === 0) {
|
|
41
|
+
notify(node, true);
|
|
42
|
+
}
|
|
43
|
+
let isCleanedUp = false;
|
|
44
|
+
return ()=>{
|
|
45
|
+
if (isCleanedUp) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
isCleanedUp = true;
|
|
49
|
+
const currentCount = branchRefCounts.get(node);
|
|
50
|
+
if (!currentCount) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (currentCount > 1) {
|
|
54
|
+
branchRefCounts.set(node, currentCount - 1);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
branchRefCounts.delete(node);
|
|
58
|
+
notify(node, false);
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
subscribe: (listener)=>{
|
|
62
|
+
listeners.add(listener);
|
|
63
|
+
return ()=>{
|
|
64
|
+
listeners.delete(listener);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const useOverlayBranchRegistry = ()=>{
|
|
70
|
+
const registryRef = useRef();
|
|
71
|
+
if (!registryRef.current) {
|
|
72
|
+
registryRef.current = createOverlayBranchRegistry();
|
|
73
|
+
}
|
|
74
|
+
return registryRef.current;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Registers a logical overlay branch with its owner, including owner changes,
|
|
81
|
+
* portal node replacement, deactivation, and unmount cleanup.
|
|
82
|
+
*/ const useOverlayBranch = ({ active, registry })=>{
|
|
83
|
+
const nodeRef = useRef(null);
|
|
84
|
+
const registrationRef = useRef(null);
|
|
85
|
+
const syncRegistration = useCallback((node)=>{
|
|
86
|
+
const registration = registrationRef.current;
|
|
87
|
+
const shouldKeepRegistration = registration && active && registration.node === node && registration.registry === registry;
|
|
88
|
+
if (shouldKeepRegistration) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
registration?.unregister();
|
|
92
|
+
registrationRef.current = null;
|
|
93
|
+
if (active && node && registry) {
|
|
94
|
+
registrationRef.current = {
|
|
95
|
+
node,
|
|
96
|
+
registry,
|
|
97
|
+
unregister: registry.register(node)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}, [
|
|
101
|
+
active,
|
|
102
|
+
registry
|
|
103
|
+
]);
|
|
104
|
+
const setBranchRef = useCallback((node)=>{
|
|
105
|
+
nodeRef.current = node;
|
|
106
|
+
syncRegistration(node);
|
|
107
|
+
}, [
|
|
108
|
+
syncRegistration
|
|
109
|
+
]);
|
|
110
|
+
useLayoutEffect(()=>{
|
|
111
|
+
syncRegistration(nodeRef.current);
|
|
112
|
+
}, [
|
|
113
|
+
syncRegistration
|
|
114
|
+
]);
|
|
115
|
+
useLayoutEffect(()=>()=>{
|
|
116
|
+
registrationRef.current?.unregister();
|
|
117
|
+
registrationRef.current = null;
|
|
118
|
+
}, []);
|
|
119
|
+
return setBranchRef;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Connects one policy consumer to a registry. It subscribes before replaying a
|
|
123
|
+
* snapshot of existing branches so reentrant registrations are not missed.
|
|
124
|
+
* Cleanup removes every currently registered branch from the consumer.
|
|
125
|
+
*/ const useOverlayBranchConsumer = (registry, listener)=>{
|
|
126
|
+
useLayoutEffect(()=>{
|
|
127
|
+
const unsubscribe = registry.subscribe(listener);
|
|
128
|
+
for (const node of registry.getBranches()){
|
|
129
|
+
listener(node, true);
|
|
130
|
+
}
|
|
131
|
+
return ()=>{
|
|
132
|
+
unsubscribe();
|
|
133
|
+
for (const node of registry.getBranches()){
|
|
134
|
+
listener(node, false);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}, [
|
|
138
|
+
listener,
|
|
139
|
+
registry
|
|
140
|
+
]);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
const InnerModal = /*#__PURE__*/ forwardRef((props, ref)=>{
|
|
153
|
+
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;
|
|
154
|
+
const parentModalContext = useModalContext();
|
|
155
|
+
const ownOverlayBranchRegistry = useOverlayBranchRegistry();
|
|
156
|
+
const shouldUseInert = shouldUseInertProp ?? parentModalContext?.shouldUseInert ?? false;
|
|
157
|
+
// Centralized `blocking` defaults: when callers omit these, derive from
|
|
158
|
+
// `blocking`. Explicit values (including `false`) always win.
|
|
159
|
+
const hideBackdrop = hideBackdropProp ?? !blocking;
|
|
160
|
+
const disableBackdropClick = disableBackdropClickProp ?? !blocking;
|
|
161
|
+
const disableEscapeKeyDown = disableEscapeKeyDownProp ?? !blocking;
|
|
162
|
+
const { ariaHideOutsideRef, ariaHideEnabled, setAriaHideOutsideTarget } = useAriaHideOutside({
|
|
163
|
+
enable: blocking && open,
|
|
164
|
+
shouldUseInert
|
|
165
|
+
});
|
|
166
|
+
useOverlayBranchConsumer(ownOverlayBranchRegistry, setAriaHideOutsideTarget);
|
|
167
|
+
// Forward the nearest active blocking owner through non-blocking layers.
|
|
168
|
+
const parentOverlayBranchRegistry = parentModalContext?.overlayBranchRegistry;
|
|
169
|
+
const overlayBranchRegistry = ariaHideEnabled ? ownOverlayBranchRegistry : parentOverlayBranchRegistry;
|
|
170
|
+
// Propagate outside hiding so nested Poppers stay in the available branch.
|
|
171
|
+
const ariaHideEnabledForChildren = ariaHideEnabled || parentModalContext?.ariaHideEnabled === true;
|
|
172
|
+
// Register an open non-blocking overlay with its nearest blocking owner.
|
|
173
|
+
const overlayBranchRef = useOverlayBranch({
|
|
174
|
+
active: !blocking && open,
|
|
175
|
+
registry: parentOverlayBranchRegistry
|
|
176
|
+
});
|
|
177
|
+
const handleRef = useForkRef(ref, ariaHideOutsideRef, overlayBranchRef);
|
|
178
|
+
const cls = useClasses('modal', classes, className);
|
|
179
|
+
const { onClick: externalOnClick, ...restBackdropProps } = backdropProps || {};
|
|
180
|
+
const handleBackdropClick = useEventCallback((event)=>{
|
|
181
|
+
if (disableBackdropClick) return;
|
|
182
|
+
if (event.target !== event.currentTarget) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
externalOnClick?.(event);
|
|
186
|
+
onBackdropClick?.(event);
|
|
187
|
+
onClose?.(event, 'backdropClick');
|
|
188
|
+
});
|
|
189
|
+
return /*#__PURE__*/ jsx(ModalContext.Provider, {
|
|
190
|
+
value: {
|
|
191
|
+
ariaHideEnabled: ariaHideEnabledForChildren,
|
|
192
|
+
overlayBranchRegistry,
|
|
193
|
+
shouldUseInert
|
|
194
|
+
},
|
|
195
|
+
children: /*#__PURE__*/ jsxs(motion.div, {
|
|
196
|
+
...rest,
|
|
197
|
+
...motionProps,
|
|
198
|
+
role: "presentation",
|
|
199
|
+
className: cls('root', {
|
|
200
|
+
'non-blocking': !blocking
|
|
201
|
+
}),
|
|
202
|
+
onKeyDown: (e)=>{
|
|
203
|
+
onKeyDown?.(e);
|
|
204
|
+
if (!disableEscapeKeyDown && e.key === 'Escape' && (isEnabled?.() ?? true)) {
|
|
205
|
+
onEscapeKeyDown?.(e);
|
|
206
|
+
onClose?.(e, 'escapeKeyDown');
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
ref: handleRef,
|
|
210
|
+
children: [
|
|
211
|
+
/*#__PURE__*/ jsx(Backdrop_Backdrop, {
|
|
212
|
+
...restBackdropProps,
|
|
213
|
+
isTransparent: hideBackdrop,
|
|
214
|
+
onClick: handleBackdropClick
|
|
215
|
+
}),
|
|
216
|
+
/*#__PURE__*/ jsx(FocusTrap, {
|
|
217
|
+
open: open,
|
|
218
|
+
isEnabled: isEnabled,
|
|
219
|
+
disableAutoFocus: disableAutoFocus || !blocking,
|
|
220
|
+
disableEnforceFocus: disableEnforceFocus || !blocking,
|
|
221
|
+
disableRestoreFocus: disableRestoreFocus || !blocking,
|
|
222
|
+
children: children
|
|
223
|
+
})
|
|
224
|
+
]
|
|
225
|
+
})
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
InnerModal.displayName = 'SuiInnerModal';
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
// extracted by css-extract-rspack-plugin
|
|
236
|
+
/* export default */ var Modal = ({"sui-modal-root":"sui-modal-root","sui-modal-non-blocking":"sui-modal-non-blocking","sui-backdrop-root":"sui-backdrop-root"});
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
const Modal_Modal = /*#__PURE__*/ forwardRef((inProps, ref)=>{
|
|
248
|
+
const props = useThemeProps({
|
|
249
|
+
props: inProps,
|
|
250
|
+
name: 'Modal'
|
|
251
|
+
});
|
|
252
|
+
const { children, open, container: containerProp, disablePortal, onExitComplete, onAfterClose, disableBackdropAnimation, motionProps, disableScrollLock: disableScrollLockProp, blocking = true, shouldUseInert: themeFallbackShouldUseInert, ...rest } = props;
|
|
253
|
+
const parentModalContext = useModalContext();
|
|
254
|
+
const shouldUseInert = inProps.shouldUseInert ?? parentModalContext?.shouldUseInert ?? themeFallbackShouldUseInert ?? false;
|
|
255
|
+
// When `disableScrollLock` is not provided, derive it from `blocking`:
|
|
256
|
+
// non-blocking overlays should not contribute to body scroll lock by default.
|
|
257
|
+
// Explicit values always win to preserve back-compat.
|
|
258
|
+
const disableScrollLock = disableScrollLockProp ?? !blocking;
|
|
259
|
+
const [shouldRender, setShouldRender] = useState(open);
|
|
260
|
+
const [modalElement, setModalElement] = useState(null);
|
|
261
|
+
const handleRef = useForkRef(setModalElement, ref);
|
|
262
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
263
|
+
const { isEnabled } = useFocusTrapStack({
|
|
264
|
+
open
|
|
265
|
+
});
|
|
266
|
+
useBodyScrollLock(open, modalElement, {
|
|
267
|
+
disabled: disableScrollLock
|
|
268
|
+
});
|
|
269
|
+
useEffect(()=>{
|
|
270
|
+
if (open) {
|
|
271
|
+
setShouldRender(true);
|
|
272
|
+
} else {
|
|
273
|
+
if (disableBackdropAnimation) {
|
|
274
|
+
setShouldRender(false);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}, [
|
|
278
|
+
open,
|
|
279
|
+
disableBackdropAnimation
|
|
280
|
+
]);
|
|
281
|
+
const hasRenderedContentRef = useRef(open);
|
|
282
|
+
const handleAfterClose = useEventCallback(()=>{
|
|
283
|
+
onAfterClose?.();
|
|
284
|
+
});
|
|
285
|
+
useEffect(()=>{
|
|
286
|
+
if (shouldRender) {
|
|
287
|
+
hasRenderedContentRef.current = true;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
// Runs after the commit that removed the content, so consumers can rely on
|
|
291
|
+
// the modal subtree being gone. Guarded so an initially closed modal and
|
|
292
|
+
// repeated effect runs do not report a close that never happened.
|
|
293
|
+
if (hasRenderedContentRef.current) {
|
|
294
|
+
hasRenderedContentRef.current = false;
|
|
295
|
+
handleAfterClose();
|
|
296
|
+
}
|
|
297
|
+
}, [
|
|
298
|
+
shouldRender,
|
|
299
|
+
handleAfterClose
|
|
300
|
+
]);
|
|
301
|
+
const { document } = useWindowContext();
|
|
302
|
+
const container = containerProp ?? document?.body;
|
|
303
|
+
const { scopeProps } = useTheme();
|
|
304
|
+
const onAnimationComplete = (e)=>{
|
|
305
|
+
motionProps?.onAnimationComplete?.(e);
|
|
306
|
+
if (!open) {
|
|
307
|
+
onExitComplete?.();
|
|
308
|
+
setShouldRender(false);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
return shouldRender ? /*#__PURE__*/ jsx(Portal, {
|
|
312
|
+
disablePortal: disablePortal,
|
|
313
|
+
container: container,
|
|
314
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
315
|
+
...scopeProps,
|
|
316
|
+
children: /*#__PURE__*/ jsx(InnerModal, {
|
|
317
|
+
...rest,
|
|
318
|
+
ref: handleRef,
|
|
319
|
+
open: open,
|
|
320
|
+
blocking: blocking,
|
|
321
|
+
shouldUseInert: shouldUseInert,
|
|
322
|
+
isEnabled: isEnabled,
|
|
323
|
+
motionProps: {
|
|
324
|
+
...motionProps ?? getFade({
|
|
325
|
+
prefersReducedMotion,
|
|
326
|
+
toggle: open
|
|
327
|
+
}),
|
|
328
|
+
onAnimationComplete
|
|
329
|
+
},
|
|
330
|
+
children: children
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
}) : null;
|
|
334
|
+
});
|
|
335
|
+
Modal_Modal.displayName = 'SuiModal';
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
export { InnerModal, Modal as modalStyles, ModalContext, Modal_Modal as Modal, useModalContext, useOverlayBranch };
|
package/NestedMenuContext.js
CHANGED
|
@@ -1,24 +1,196 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { useEventCallback } from '@ringcentral/spring-base';
|
|
4
|
-
import { useEffect } from 'react';
|
|
5
|
-
export { u as useNestedMenuItem } from './chunks/useNestedMenuItem.js';
|
|
1
|
+
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { useEventCallback } from "@ringcentral/spring-base";
|
|
6
3
|
|
|
7
|
-
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const NestedMenuContext = /*#__PURE__*/ createContext(null);
|
|
7
|
+
const useNestedMenuContext = ()=>{
|
|
8
|
+
return useContext(NestedMenuContext);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const useNestedChildMenu = (props)=>{
|
|
8
17
|
const { open, closeMenu, getAnchorElement, id } = props;
|
|
9
18
|
const context = useNestedMenuContext();
|
|
10
19
|
const { registOpenedSubMenu } = context ?? {};
|
|
11
|
-
const closeMenuMemo = useEventCallback((options)
|
|
12
|
-
useEffect(()
|
|
20
|
+
const closeMenuMemo = useEventCallback((options)=>closeMenu(options));
|
|
21
|
+
useEffect(()=>{
|
|
13
22
|
if (open) {
|
|
14
23
|
return registOpenedSubMenu?.({
|
|
15
24
|
anchorId: id,
|
|
16
25
|
getAnchorElement,
|
|
17
|
-
closeSubMenu: closeMenuMemo
|
|
26
|
+
closeSubMenu: closeMenuMemo
|
|
18
27
|
});
|
|
19
28
|
}
|
|
20
29
|
return undefined;
|
|
21
|
-
}, [
|
|
30
|
+
}, [
|
|
31
|
+
closeMenuMemo,
|
|
32
|
+
getAnchorElement,
|
|
33
|
+
id,
|
|
34
|
+
open,
|
|
35
|
+
registOpenedSubMenu
|
|
36
|
+
]);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const useNestedMenuItem = (props)=>{
|
|
43
|
+
const context = useNestedMenuContext();
|
|
44
|
+
const { hovered, id } = props;
|
|
45
|
+
const { isPointerMovingToSubMenu: isPointerMovingToSubMenuContext, onPointerGraceIntentChange, registHoveredItem } = context ?? {};
|
|
46
|
+
const requestItemHover = useCallback((event, options)=>{
|
|
47
|
+
const canApplyHover = registHoveredItem?.(id, event, options);
|
|
48
|
+
return canApplyHover ?? true;
|
|
49
|
+
}, [
|
|
50
|
+
id,
|
|
51
|
+
registHoveredItem
|
|
52
|
+
]);
|
|
53
|
+
useEffect(()=>{
|
|
54
|
+
if (hovered) {
|
|
55
|
+
requestItemHover();
|
|
56
|
+
}
|
|
57
|
+
}, [
|
|
58
|
+
hovered,
|
|
59
|
+
requestItemHover
|
|
60
|
+
]);
|
|
61
|
+
const isPointerMovingToSubMenu = useCallback((event, intent)=>{
|
|
62
|
+
return isPointerMovingToSubMenuContext?.(event, intent) ?? false;
|
|
63
|
+
}, [
|
|
64
|
+
isPointerMovingToSubMenuContext
|
|
65
|
+
]);
|
|
66
|
+
return {
|
|
67
|
+
isPointerMovingToSubMenu,
|
|
68
|
+
onPointerGraceIntentChange,
|
|
69
|
+
requestItemHover
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
const getPointFromPointerEvent = (event)=>({
|
|
75
|
+
x: event.clientX,
|
|
76
|
+
y: event.clientY
|
|
77
|
+
});
|
|
78
|
+
const isPointInPolygon = (point, polygon)=>{
|
|
79
|
+
let inside = false;
|
|
80
|
+
for(let i = 0, j = polygon.length - 1; i < polygon.length; j = i++){
|
|
81
|
+
const pointI = polygon[i];
|
|
82
|
+
const pointJ = polygon[j];
|
|
83
|
+
const intersects = pointI.y > point.y !== pointJ.y > point.y && point.x < (pointJ.x - pointI.x) * (point.y - pointI.y) / (pointJ.y - pointI.y) + pointI.x;
|
|
84
|
+
if (intersects) {
|
|
85
|
+
inside = !inside;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return inside;
|
|
22
89
|
};
|
|
90
|
+
const isPointerInGraceArea = (event, area)=>{
|
|
91
|
+
if (!area) return false;
|
|
92
|
+
return isPointInPolygon(getPointFromPointerEvent(event), area);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
const useNestedParentMenu = (props)=>{
|
|
98
|
+
const openedSubMenuSymbolRef = useRef(null);
|
|
99
|
+
const pointerGraceIntentRef = useRef(null);
|
|
100
|
+
const pointerDirRef = useRef('right');
|
|
101
|
+
const lastPointerXRef = useRef(0);
|
|
102
|
+
const { open } = props;
|
|
103
|
+
const onPointerGraceIntentChange = useCallback((intent)=>{
|
|
104
|
+
pointerGraceIntentRef.current = intent;
|
|
105
|
+
}, []);
|
|
106
|
+
const isPointerMovingToSubMenu = useCallback((event, intentArg)=>{
|
|
107
|
+
const intent = intentArg === undefined ? pointerGraceIntentRef.current : intentArg;
|
|
108
|
+
const isMovingTowards = pointerDirRef.current === intent?.side;
|
|
109
|
+
return isMovingTowards && isPointerInGraceArea(event, intent?.area);
|
|
110
|
+
}, []);
|
|
111
|
+
const onContentPointerMove = useCallback((event)=>{
|
|
112
|
+
const pointerXHasChanged = lastPointerXRef.current !== event.clientX;
|
|
113
|
+
if (pointerXHasChanged) {
|
|
114
|
+
pointerDirRef.current = event.clientX > lastPointerXRef.current ? 'right' : 'left';
|
|
115
|
+
lastPointerXRef.current = event.clientX;
|
|
116
|
+
}
|
|
117
|
+
}, []);
|
|
118
|
+
const onContentClickCapture = useCallback((event)=>{
|
|
119
|
+
const target = event.target;
|
|
120
|
+
const openedSubMenu = openedSubMenuSymbolRef.current;
|
|
121
|
+
if (!target || !event.currentTarget.contains(target)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (openedSubMenu?.getAnchorElement?.()?.contains(target)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
openedSubMenu?.closeSubMenu();
|
|
128
|
+
}, []);
|
|
129
|
+
const contextValue = useMemo(()=>{
|
|
130
|
+
return {
|
|
131
|
+
registHoveredItem: (id, event, options)=>{
|
|
132
|
+
// Close opened SubMenu if hovering on a different item
|
|
133
|
+
const symbol = openedSubMenuSymbolRef.current;
|
|
134
|
+
if (!symbol || id === symbol.anchorId) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (event && isPointerMovingToSubMenu(event)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (options?.closeOpenedSubMenu ?? true) {
|
|
141
|
+
symbol.closeSubMenu();
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
},
|
|
145
|
+
registOpenedSubMenu: (menuItemSymbol)=>{
|
|
146
|
+
openedSubMenuSymbolRef.current?.closeSubMenu();
|
|
147
|
+
openedSubMenuSymbolRef.current = menuItemSymbol;
|
|
148
|
+
// This cleanup is returned to useNestedChildMenu's useEffect.
|
|
149
|
+
// It runs when:
|
|
150
|
+
// (a) the effect re-runs (open goes false -> true), or
|
|
151
|
+
// (b) the component unmounts.
|
|
152
|
+
// `menuItemSymbol` here is the value captured by closure at registration time -
|
|
153
|
+
// it never changes. `openedSubMenuSymbolRef.current` is the live ref value at
|
|
154
|
+
// cleanup time, which may have been replaced by a newer symbol.
|
|
155
|
+
return ()=>{
|
|
156
|
+
if (openedSubMenuSymbolRef.current === menuItemSymbol) {
|
|
157
|
+
openedSubMenuSymbolRef.current = null;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
isPointerMovingToSubMenu,
|
|
162
|
+
onPointerGraceIntentChange
|
|
163
|
+
};
|
|
164
|
+
}, [
|
|
165
|
+
isPointerMovingToSubMenu,
|
|
166
|
+
onPointerGraceIntentChange
|
|
167
|
+
]);
|
|
168
|
+
// Ensure that all menus can be visually closed at the same time
|
|
169
|
+
useLayoutEffect(()=>{
|
|
170
|
+
if (!open) {
|
|
171
|
+
openedSubMenuSymbolRef.current?.closeSubMenu();
|
|
172
|
+
openedSubMenuSymbolRef.current = null;
|
|
173
|
+
onPointerGraceIntentChange(null);
|
|
174
|
+
}
|
|
175
|
+
}, [
|
|
176
|
+
onPointerGraceIntentChange,
|
|
177
|
+
open
|
|
178
|
+
]);
|
|
179
|
+
return {
|
|
180
|
+
contentClickHandlers: {
|
|
181
|
+
onClickCapture: onContentClickCapture
|
|
182
|
+
},
|
|
183
|
+
contentPointerHandlers: {
|
|
184
|
+
onPointerMove: onContentPointerMove
|
|
185
|
+
},
|
|
186
|
+
contextValue,
|
|
187
|
+
getHaveOpenedSubMenu: ()=>Boolean(openedSubMenuSymbolRef.current)
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
23
195
|
|
|
24
|
-
export { useNestedChildMenu, useNestedMenuContext };
|
|
196
|
+
export { NestedMenuContext, useNestedChildMenu, useNestedMenuContext, useNestedMenuItem, useNestedParentMenu };
|