@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.
- package/Alert.js +3 -3
- package/Announcement.js +1 -1
- package/Autocomplete.js +216 -243
- package/Avatar.js +27 -13
- package/BottomNavigation.js +0 -3
- package/Checkbox.js +0 -2
- package/DatePicker.js +5 -13
- package/DateUtilsContext.js +0 -1
- package/Dialer.js +2 -50
- package/Dialog.js +18 -6
- package/Dropdown.js +0 -7
- package/FocusTrap.js +0 -32
- package/InlineEditable.js +0 -4
- package/Link.js +1 -1
- package/ListItem.js +1 -1
- package/ListNavigation.js +0 -6
- package/Menu.js +1 -1
- package/MenuDivider.js +2 -2
- package/MenuFooter.js +4 -4
- package/MenuHeader.js +4 -4
- package/MenuItem.js +1 -1
- package/MenuItemText.js +1 -1
- package/Modal.js +1 -1
- package/PageHeader.js +6 -4
- package/Popper.js +0 -1
- package/Rating.js +0 -5
- package/SingleFilter.js +0 -1
- package/Slider.js +1 -4
- package/Snackbar.js +0 -14
- package/SortableListItem.js +0 -1
- package/SplitButton.js +1 -3
- package/StatusIndicator.js +1 -1
- package/StepButton.js +2 -3
- package/StepContent.js +3 -8
- package/SubMenu.js +0 -4
- package/SwipeableDrawer.js +37 -162
- package/Switch.js +1 -4
- package/Tab.js +7 -8
- package/TabContext.js +0 -5
- package/TableBody.js +1 -1
- package/TableCell.js +0 -6
- package/TableRow.js +2 -4
- package/Tabs.js +22 -121
- package/Text.js +2 -4
- package/TimePicker.js +7 -46
- package/VirtualizedList.js +6 -39
- package/VirtualizedMenu.js +1 -1
- package/chunks/Alert.js +8 -7
- package/chunks/BottomNavigationItem.js +0 -1
- package/chunks/Button.js +0 -1
- package/chunks/Chip.js +0 -5
- package/chunks/Drawer.js +1 -30
- package/chunks/ListItem.js +3 -6
- package/chunks/Menu.js +6 -5
- package/chunks/MenuDivider.js +2 -3
- package/chunks/MenuItemText.js +3 -3
- package/chunks/MenuList.js +3 -6
- package/chunks/Modal.js +1 -1
- package/chunks/PickerTextField.js +0 -1
- package/chunks/Popover.js +0 -5
- package/chunks/Select.js +2 -39
- package/chunks/Squircle.js +0 -7
- package/chunks/StatusIndicator.js +1 -0
- package/chunks/StepIcon.js +1 -3
- package/chunks/StepperContext.js +0 -7
- package/chunks/Tooltip.js +0 -36
- package/chunks/VirtualizedMenu.js +45 -99
- package/chunks/getFade.js +4 -0
- package/chunks/useFocusTrapStack.js +0 -8
- package/chunks/useHelperTextId.js +0 -24
- package/chunks/useListNavigation.js +5 -17
- package/chunks/useMenuItemSelect.js +9 -22
- package/chunks/useMotionSafeTransition.js +0 -4
- package/chunks/useNestedParentMenu.js +5 -18
- package/chunks/usePrefersReducedMotion.js +6 -12
- package/chunks/useTooltipForceHide.js +0 -4
- package/chunks/useTrayNavigate.js +0 -1
- package/index.css +434 -135
- package/index.js +1 -1
- package/package.json +4 -4
- package/src/Accordion/Accordion.d.ts +1 -1
- package/src/Accordion/Accordion.type.d.ts +0 -21
- package/src/AccordionHeader/AccordionHeader.d.ts +1 -1
- package/src/AccordionHeader/AccordionHeader.type.d.ts +0 -14
- package/src/Alert/Alert.d.ts +1 -1
- package/src/Alert/Alert.type.d.ts +0 -32
- package/src/Animation/components/ExpandCollapseCaret/ExpandCollapseCaret.d.ts +0 -4
- package/src/Animation/components/ShowHideEye/ShowHideEye.d.ts +0 -4
- package/src/Animation/hooks/useMotionSafeTransition/useMotionSafeTransition.d.ts +0 -4
- package/src/Autocomplete/Autocomplete.d.ts +0 -5
- package/src/Autocomplete/Autocomplete.type.d.ts +0 -84
- package/src/Autocomplete/SuggestionList/SuggestionList.d.ts +5 -89
- package/src/Autocomplete/SuggestionList/SuggestionListItem.d.ts +0 -2
- package/src/Autocomplete/SuggestionList/utils/SuggestionListItem.d.ts +1 -13
- package/src/Autocomplete/SuggestionList/utils/useDynamicHeight.d.ts +0 -6
- package/src/Autocomplete/SuggestionList/utils/useHighlightScroll.d.ts +4 -23
- package/src/Autocomplete/SuggestionList/utils/useSuggestionList.d.ts +3 -41
- package/src/Autocomplete/SuggestionList/utils/useSuggestionListGroup.d.ts +0 -49
- package/src/Autocomplete/useAutocomplete.d.ts +5 -66
- package/src/Autocomplete/useAutocompleteTag.d.ts +3 -36
- package/src/Avatar/Avatar.type.d.ts +0 -58
- package/src/AvatarGroup/AvatarGroup.type.d.ts +0 -3
- package/src/Backdrop/Backdrop.type.d.ts +0 -4
- package/src/Badge/Badge.type.d.ts +0 -33
- package/src/Block/Block.type.d.ts +0 -24
- package/src/BlockHeader/BlockHeader.type.d.ts +0 -5
- package/src/BottomNavigation/BottomNavigation.type.d.ts +0 -34
- package/src/BottomNavigationItem/BottomNavigationItem.type.d.ts +0 -39
- package/src/Button/Button.type.d.ts +0 -30
- package/src/CallButton/CallButton.type.d.ts +0 -4
- package/src/Checkbox/Checkbox.type.d.ts +0 -17
- package/src/Chip/Chip.type.d.ts +0 -41
- package/src/CircularProgressIndicator/CircularProgressIndicator.d.ts +1 -1
- package/src/CircularProgressIndicator/CircularProgressIndicator.type.d.ts +0 -19
- package/src/DatePicker/Calendar.d.ts +1 -20
- package/src/DatePicker/DatePicker.type.d.ts +0 -18
- package/src/DatePicker/DatePickerHeader.d.ts +1 -12
- package/src/DatePicker/Day.d.ts +1 -8
- package/src/DatePicker/Year.d.ts +1 -7
- package/src/DatePicker/Years.d.ts +0 -7
- package/src/Dialer/DialDelete/DialDelete.d.ts +0 -3
- package/src/Dialer/DialPad/DialPad.d.ts +0 -106
- package/src/Dialer/DialPad/utils/types.d.ts +0 -5
- package/src/Dialer/DialPad/utils/useDialKeyboard.d.ts +0 -5
- package/src/Dialer/DialPad/utils/useKeyAudio.d.ts +0 -9
- package/src/Dialer/DialPadButton/DialPadButton.d.ts +0 -14
- package/src/Dialer/DialTextField/DialTextField.d.ts +0 -23
- package/src/Dialer/DialTextField/utils/getDialPadValueOnlyRegex.d.ts +0 -3
- package/src/Dialer/DialTextField/utils/useFixedEndSelection.d.ts +0 -3
- package/src/Dialog/Dialog.classes.d.ts +1 -1
- package/src/Dialog/Dialog.d.ts +1 -1
- package/src/Dialog/Dialog.type.d.ts +3 -11
- package/src/Divider/Divider.type.d.ts +0 -17
- package/src/DragHandle/DragHandle.type.d.ts +0 -4
- package/src/Drawer/Drawer.d.ts +1 -29
- package/src/Drawer/Drawer.type.d.ts +0 -84
- package/src/Dropdown/Dropdown.type.d.ts +0 -64
- package/src/EmptyState/EmptyState.d.ts +1 -1
- package/src/EmptyState/EmptyState.type.d.ts +0 -12
- package/src/FabButton/FabButton.type.d.ts +0 -5
- package/src/FocusTrap/FocusTrap.d.ts +0 -38
- package/src/FocusTrap/useFocusTrapStack.d.ts +0 -9
- package/src/FormField/FormField.type.d.ts +0 -26
- package/src/FormField/useHelperTextId.d.ts +0 -25
- package/src/FormLabel/FormLabel.d.ts +1 -1
- package/src/FormLabel/FormLabel.type.d.ts +0 -14
- package/src/Icon/Icon.d.ts +1 -1
- package/src/Icon/Icon.type.d.ts +0 -15
- package/src/IconButton/IconButton.type.d.ts +0 -30
- package/src/IconButton/IconButtonLabel.d.ts +1 -1
- package/src/IconButton/IconButtonLabel.type.d.ts +0 -3
- package/src/IconButtonGroup/IconButtonGroup.type.d.ts +0 -8
- package/src/InlineEditable/InlineEditable.type.d.ts +0 -75
- package/src/LinearProgressIndicator/LinearProgressIndicator.type.d.ts +0 -31
- package/src/Link/Link.classes.d.ts +1 -1
- package/src/Link/Link.type.d.ts +1 -10
- package/src/ListItem/ListItem.type.d.ts +0 -41
- package/src/ListItemText/ListItemText.d.ts +1 -1
- package/src/ListItemText/ListItemText.type.d.ts +0 -21
- package/src/ListNavigation/useListNavigation.d.ts +0 -16
- package/src/Menu/Menu.d.ts +1 -1
- package/src/Menu/Menu.type.d.ts +0 -10
- package/src/MenuFooter/MenuFooter.type.d.ts +0 -4
- package/src/MenuHeader/MenuHeader.type.d.ts +0 -10
- package/src/MenuItem/MenuItem.d.ts +1 -1
- package/src/MenuItem/MenuItem.type.d.ts +0 -19
- package/src/MenuItem/MenuItemSelectContext.d.ts +0 -3
- package/src/MenuItem/useMenuItemSelect.d.ts +0 -21
- package/src/MenuItemText/MenuItemText.d.ts +1 -1
- package/src/MenuItemText/MenuItemText.type.d.ts +0 -17
- package/src/MenuList/MenuList.type.d.ts +0 -4
- package/src/MenuList/MenuListContext.d.ts +0 -6
- package/src/Modal/InnerModal.d.ts +2 -2
- package/src/Modal/InnerModal.type.d.ts +0 -5
- package/src/Modal/Modal.classes.d.ts +1 -1
- package/src/Modal/Modal.d.ts +3 -3
- package/src/Modal/Modal.type.d.ts +0 -11
- package/src/Modal/ModalContext.d.ts +0 -4
- package/src/NestedMenuContext/NestedMenuContext.d.ts +1 -1
- package/src/Option/Option.d.ts +1 -1
- package/src/Option/Option.type.d.ts +0 -3
- package/src/Overlap/Overlap.type.d.ts +0 -11
- package/src/PageHeader/PageHeader.type.d.ts +0 -4
- package/src/PickerTextField/PickerTextField.type.d.ts +0 -10
- package/src/Popover/Popover.d.ts +1 -1
- package/src/Popover/Popover.type.d.ts +0 -29
- package/src/Popper/Popper.d.ts +1 -1
- package/src/Popper/Popper.type.d.ts +0 -61
- package/src/PopperPaper/PopperPaper.d.ts +1 -1
- package/src/Radio/Radio.type.d.ts +0 -5
- package/src/RadioGroup/RadioGroup.d.ts +1 -1
- package/src/RadioGroup/RadioGroup.type.d.ts +0 -4
- package/src/Rating/Rating.d.ts +1 -1
- package/src/Rating/Rating.type.d.ts +0 -74
- package/src/Rating/RatingItem.d.ts +1 -1
- package/src/Select/Select.type.d.ts +0 -84
- package/src/SingleFilter/FilterButton/FilterButton.d.ts +1 -1
- package/src/SingleFilter/FilterButton/FilterButton.type.d.ts +0 -16
- package/src/SingleFilter/SingleFilter.d.ts +1 -1
- package/src/SingleFilter/SingleFilter.type.d.ts +0 -26
- package/src/Skeleton/Skeleton.type.d.ts +0 -1
- package/src/Skeleton/SkeletonContainer/SkeletonContainer.classes.d.ts +1 -1
- package/src/Slider/Slider.classes.d.ts +1 -5
- package/src/Slider/Slider.d.ts +2 -2
- package/src/Slider/Slider.type.d.ts +0 -104
- package/src/Snackbar/Snackbar.type.d.ts +0 -18
- package/src/SortableListItem/SortableListItemOverlay.d.ts +1 -1
- package/src/SplitButton/SplitButton.d.ts +1 -1
- package/src/SplitButton/SplitButton.type.d.ts +0 -21
- package/src/Squircle/Squircle.type.d.ts +0 -3
- package/src/StatusIndicator/StatusIndicator.classes.d.ts +1 -1
- package/src/StatusIndicator/StatusIndicator.type.d.ts +1 -9
- package/src/Step/Step.type.d.ts +0 -29
- package/src/Step/StepContext.d.ts +0 -7
- package/src/StepButton/StepButton.type.d.ts +0 -15
- package/src/StepContent/StepContent.d.ts +1 -1
- package/src/StepContent/StepContent.type.d.ts +0 -7
- package/src/StepIcon/StepIcon.type.d.ts +0 -26
- package/src/StepLabel/StepLabel.d.ts +1 -1
- package/src/StepLabel/StepLabel.type.d.ts +0 -23
- package/src/Stepper/Stepper.type.d.ts +0 -27
- package/src/SubMenu/PopperMenu.d.ts +1 -1
- package/src/SubMenu/SubMenu.d.ts +1 -1
- package/src/SwipeableDrawer/SwipeableDrawer.d.ts +1 -27
- package/src/SwipeableDrawer/SwipeableDrawer.types.d.ts +0 -67
- package/src/SwipeableDrawer/hooks/useDrawerGestures.d.ts +0 -110
- package/src/SwipeableDrawer/hooks/useElementSizeObserver.d.ts +0 -5
- package/src/SwipeableDrawer/hooks/useSnapPoints.d.ts +0 -60
- package/src/Switch/Switch.type.d.ts +0 -9
- package/src/Tab/Tab.classes.d.ts +3 -2
- package/src/Tab/Tab.d.ts +1 -1
- package/src/Tab/Tab.type.d.ts +0 -29
- package/src/TabContext/TabContext.d.ts +0 -4
- package/src/TabContext/TabContext.type.d.ts +0 -7
- package/src/TabPanel/TabPanel.d.ts +1 -1
- package/src/TabPanel/TabPanel.type.d.ts +0 -10
- package/src/Table/Table.type.d.ts +0 -19
- package/src/TableBody/TableBody.type.d.ts +0 -3
- package/src/TableCell/TableCell.d.ts +0 -4
- package/src/TableCell/TableCell.type.d.ts +0 -35
- package/src/TableContainer/TableContainer.type.d.ts +0 -7
- package/src/TableFooter/TableFooter.type.d.ts +0 -3
- package/src/TableHead/TableHead.type.d.ts +0 -6
- package/src/TablePagination/TablePagination.type.d.ts +0 -47
- package/src/TableRow/TableRow.type.d.ts +0 -17
- package/src/Tabs/TabMoreMenu.d.ts +0 -16
- package/src/Tabs/TabScrollButton.d.ts +1 -11
- package/src/Tabs/Tabs.classes.d.ts +1 -1
- package/src/Tabs/Tabs.d.ts +1 -1
- package/src/Tabs/Tabs.type.d.ts +2 -36
- package/src/Tabs/TabsContext.d.ts +2 -0
- package/src/Tabs/hooks/useTabsScroller.d.ts +0 -30
- package/src/Tag/Tag.d.ts +1 -1
- package/src/Tag/Tag.type.d.ts +0 -12
- package/src/Text/Text.type.d.ts +0 -13
- package/src/TextField/TextField.type.d.ts +0 -64
- package/src/Textarea/Textarea.d.ts +1 -1
- package/src/Textarea/Textarea.type.d.ts +0 -13
- package/src/TimePicker/NumberPicker.d.ts +1 -1
- package/src/TimePicker/NumberPicker.type.d.ts +0 -12
- package/src/TimePicker/SelectionView.d.ts +0 -6
- package/src/TimePicker/TimeButton.d.ts +1 -4
- package/src/TimePicker/TimePicker.type.d.ts +0 -11
- package/src/TimePicker/ToggleText.d.ts +1 -1
- package/src/TimePicker/ToggleText.type.d.ts +0 -3
- package/src/TimePicker/utils/TimeBoundary.d.ts +0 -3
- package/src/TimePicker/utils/TimePickerHelper.d.ts +0 -19
- package/src/TimePicker/utils/getNumberPickerBoundary.d.ts +0 -3
- package/src/Tooltip/TooltipTrigger.a11y.d.ts +0 -9
- package/src/Tooltip/TooltipTrigger.type.d.ts +0 -44
- package/src/Tooltip/TooltipView.type.d.ts +0 -25
- package/src/Tooltip/useTooltipForceHide.d.ts +0 -4
- package/src/Tray/Tray.d.ts +1 -1
- package/src/Tray/Tray.type.d.ts +0 -13
- package/src/Tray/TrayContext.d.ts +0 -4
- package/src/Tray/hooks/useTray.d.ts +0 -16
- package/src/Tray/hooks/useTrayPanel.d.ts +0 -3
- package/src/TrayMenu/TrayMenu.d.ts +1 -1
- package/src/TrayMenu/TrayMenuItem.d.ts +1 -1
- package/src/VirtualizedList/VirtualizedList.type.d.ts +0 -27
- package/src/VirtualizedMenu/VirtualizedMenu.classes.d.ts +1 -1
- package/src/VirtualizedMenu/VirtualizedMenu.type.d.ts +0 -17
package/SwipeableDrawer.js
CHANGED
|
@@ -19,15 +19,12 @@ import './chunks/Backdrop.js';
|
|
|
19
19
|
|
|
20
20
|
var SwipeableDrawer$1 = {"sui-swipeable-drawer-header-drag":"sui-swipeable-drawer-header-drag"};
|
|
21
21
|
|
|
22
|
-
// Keeps track of whether everything is good to go or not, in the most efficient way possible
|
|
23
22
|
function useReady() {
|
|
24
23
|
const [ready, setReady] = useState(false);
|
|
25
24
|
const [readyMap, updateReadyMap] = useState({});
|
|
26
25
|
const registerReady = useCallback((key) => {
|
|
27
|
-
// Register the check we're gonna wait for until it's ready
|
|
28
26
|
updateReadyMap((ready) => ({ ...ready, [key]: false }));
|
|
29
27
|
return () => {
|
|
30
|
-
// Set it to ready
|
|
31
28
|
updateReadyMap((ready) => ({ ...ready, [key]: true }));
|
|
32
29
|
};
|
|
33
30
|
}, []);
|
|
@@ -47,40 +44,28 @@ function useReady() {
|
|
|
47
44
|
return { ready, registerReady };
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
// Hook for determining the size of an element using the Resize Observer API
|
|
51
47
|
const observerOptions = {
|
|
52
|
-
// Respond to changes to padding, happens often on iOS when using env(safe-area-inset-bottom)
|
|
53
|
-
// And the user hides or shows the Safari browser toolbar
|
|
54
48
|
box: 'border-box',
|
|
55
49
|
};
|
|
56
|
-
/**
|
|
57
|
-
* Hook for determining the size of an element using the Resize Observer API.
|
|
58
|
-
*
|
|
59
|
-
* @param ref - A React ref to an element
|
|
60
|
-
*/
|
|
61
50
|
function useElementSizeObserver(ref, { enabled, resizeSourceRef, }) {
|
|
51
|
+
const { externalWindow, globalThis } = useWindowContext();
|
|
52
|
+
const win = externalWindow ?? globalThis;
|
|
62
53
|
const [size, setSize] = useState(0);
|
|
63
54
|
const handleResize = useCallback((entries) => {
|
|
64
|
-
// we only observe one element, so accessing the first entry here is fine
|
|
65
55
|
const entry = entries?.[0];
|
|
66
56
|
if (!entry) {
|
|
67
|
-
// Early return if no entry - can happen during observer disconnect
|
|
68
57
|
return;
|
|
69
58
|
}
|
|
70
59
|
const el = entry.target;
|
|
71
60
|
if (!el) {
|
|
72
|
-
// Early return if no target element
|
|
73
61
|
return;
|
|
74
62
|
}
|
|
75
|
-
// Prefer intrinsic content size to visible height so drag doesn’t change the measured height
|
|
76
|
-
// @juggle/resize-observer provides consistent borderBoxSize access across browsers
|
|
77
63
|
const roBlock = entry?.borderBoxSize?.[0]?.blockSize ?? 0;
|
|
78
64
|
const contentRectH = entry?.contentRect?.height ?? 0;
|
|
79
65
|
const scrollH = el?.scrollHeight ?? 0;
|
|
80
66
|
const offsetH = el?.offsetHeight ?? 0;
|
|
81
67
|
const newSize = Math.max(scrollH, roBlock, contentRectH, offsetH);
|
|
82
68
|
setSize(newSize);
|
|
83
|
-
// Update resize source if provided
|
|
84
69
|
if (resizeSourceRef) {
|
|
85
70
|
resizeSourceRef.current = 'element';
|
|
86
71
|
}
|
|
@@ -89,6 +74,8 @@ function useElementSizeObserver(ref, { enabled, resizeSourceRef, }) {
|
|
|
89
74
|
if (!enabled) {
|
|
90
75
|
return;
|
|
91
76
|
}
|
|
77
|
+
const rAF = win.requestAnimationFrame.bind(win);
|
|
78
|
+
const cAF = win.cancelAnimationFrame.bind(win);
|
|
92
79
|
let resizeObserver = null;
|
|
93
80
|
let rafId = 0;
|
|
94
81
|
let initialMeasurementRafId = 0;
|
|
@@ -96,93 +83,81 @@ function useElementSizeObserver(ref, { enabled, resizeSourceRef, }) {
|
|
|
96
83
|
const el = ref.current;
|
|
97
84
|
if (!el || !el.isConnected)
|
|
98
85
|
return;
|
|
99
|
-
// @juggle/resize-observer provides cross-browser compatibility and polyfills
|
|
100
86
|
resizeObserver = new ResizeObserver(handleResize);
|
|
101
87
|
resizeObserver.observe(el, observerOptions);
|
|
102
|
-
|
|
103
|
-
initialMeasurementRafId = requestAnimationFrame(() => {
|
|
88
|
+
initialMeasurementRafId = rAF(() => {
|
|
104
89
|
const initial = Math.max(el.scrollHeight, el.offsetHeight, el.getBoundingClientRect().height);
|
|
105
90
|
if (initial > 0) {
|
|
106
91
|
setSize(initial);
|
|
107
92
|
}
|
|
108
|
-
// else keep waiting for RO to update on next ticks
|
|
109
93
|
});
|
|
110
94
|
};
|
|
111
|
-
// If the element is not yet mounted (e.g. Modal shouldRender=false), keep
|
|
112
|
-
// polling via rAF until it's available, then attach the observer.
|
|
113
95
|
const waitForElement = () => {
|
|
114
96
|
if (ref.current) {
|
|
115
97
|
startObserving();
|
|
116
98
|
}
|
|
117
99
|
else {
|
|
118
|
-
rafId =
|
|
100
|
+
rafId = rAF(waitForElement);
|
|
119
101
|
}
|
|
120
102
|
};
|
|
121
103
|
if (ref.current) {
|
|
122
104
|
startObserving();
|
|
123
105
|
}
|
|
124
106
|
else {
|
|
125
|
-
rafId =
|
|
107
|
+
rafId = rAF(waitForElement);
|
|
126
108
|
}
|
|
127
109
|
return () => {
|
|
128
110
|
if (rafId)
|
|
129
|
-
|
|
111
|
+
cAF(rafId);
|
|
130
112
|
if (initialMeasurementRafId)
|
|
131
|
-
|
|
113
|
+
cAF(initialMeasurementRafId);
|
|
132
114
|
if (resizeObserver) {
|
|
133
115
|
resizeObserver.disconnect();
|
|
134
116
|
}
|
|
135
117
|
};
|
|
136
|
-
}, [ref, handleResize, enabled]);
|
|
118
|
+
}, [ref, handleResize, enabled, win]);
|
|
137
119
|
return enabled ? size : 0;
|
|
138
120
|
}
|
|
139
121
|
|
|
140
|
-
// Hook for measuring drawer dimensions
|
|
141
|
-
// Hook for tracking viewport height
|
|
142
122
|
function useMaxHeight(registerReady) {
|
|
143
|
-
const { globalThis } = useWindowContext();
|
|
123
|
+
const { externalWindow, globalThis } = useWindowContext();
|
|
124
|
+
const win = externalWindow ?? globalThis;
|
|
144
125
|
const setReady = useMemo(() => {
|
|
145
126
|
return registerReady ? registerReady('maxHeight') : undefined;
|
|
146
127
|
}, [registerReady]);
|
|
147
|
-
const [maxHeight, setMaxHeight] = useState(() =>
|
|
128
|
+
const [maxHeight, setMaxHeight] = useState(() => win.innerHeight ?? 0);
|
|
148
129
|
const raf = useRef(0);
|
|
149
130
|
const maxReadyCalledRef = useRef(false);
|
|
150
|
-
// Reset the ready flag when setReady changes (drawer reset)
|
|
151
131
|
useLayoutEffect(() => {
|
|
152
132
|
maxReadyCalledRef.current = false;
|
|
153
133
|
}, [setReady]);
|
|
154
134
|
useLayoutEffect(() => {
|
|
135
|
+
const rAF = win.requestAnimationFrame.bind(win);
|
|
136
|
+
const cAF = win.cancelAnimationFrame.bind(win);
|
|
155
137
|
const handleResize = () => {
|
|
156
138
|
if (raf.current) {
|
|
157
|
-
// bail to throttle the amount of resize changes
|
|
158
139
|
return;
|
|
159
140
|
}
|
|
160
|
-
|
|
161
|
-
raf.current = requestAnimationFrame(() => {
|
|
162
|
-
// Check if cleanup already ran (raf.current would be 0)
|
|
141
|
+
raf.current = rAF(() => {
|
|
163
142
|
if (raf.current !== 0) {
|
|
164
|
-
setMaxHeight(
|
|
143
|
+
setMaxHeight(win.innerHeight);
|
|
165
144
|
raf.current = 0;
|
|
166
145
|
}
|
|
167
146
|
});
|
|
168
147
|
};
|
|
169
|
-
|
|
170
|
-
setMaxHeight(
|
|
171
|
-
// Call setReady exactly once for window height readiness
|
|
148
|
+
win.addEventListener('resize', handleResize);
|
|
149
|
+
setMaxHeight(win.innerHeight);
|
|
172
150
|
if (setReady && !maxReadyCalledRef.current) {
|
|
173
151
|
maxReadyCalledRef.current = true;
|
|
174
152
|
setReady();
|
|
175
153
|
}
|
|
176
154
|
return () => {
|
|
177
|
-
|
|
178
|
-
|
|
155
|
+
win.removeEventListener('resize', handleResize);
|
|
156
|
+
cAF(raf.current);
|
|
179
157
|
};
|
|
180
|
-
}, [setReady,
|
|
158
|
+
}, [setReady, win]);
|
|
181
159
|
return maxHeight;
|
|
182
160
|
}
|
|
183
|
-
/**
|
|
184
|
-
* Custom hook to preserve last non-zero height values
|
|
185
|
-
*/
|
|
186
161
|
function usePreservedHeight(currentHeight) {
|
|
187
162
|
const lastHeightRef = useRef(0);
|
|
188
163
|
useLayoutEffect(() => {
|
|
@@ -194,11 +169,7 @@ function usePreservedHeight(currentHeight) {
|
|
|
194
169
|
}
|
|
195
170
|
function useDimensions({ contentRef, footerEnabled, footerRef, headerEnabled, headerRef, registerReady, resizeSourceRef, open, }) {
|
|
196
171
|
const setReady = useMemo(() => registerReady('contentHeight'), [registerReady]);
|
|
197
|
-
// Do not re-register contentHeight readiness on disconnect; register once above and let
|
|
198
|
-
// the ResizeObserver drive readiness when size > 0. This avoids readiness loops.
|
|
199
|
-
// (Intentionally removed disconnection re-register logic)
|
|
200
172
|
const maxHeight = useMaxHeight(registerReady);
|
|
201
|
-
// Measure all elements - only when drawer is open
|
|
202
173
|
const headerHeight = useElementSizeObserver(headerRef, {
|
|
203
174
|
enabled: open && headerEnabled,
|
|
204
175
|
resizeSourceRef,
|
|
@@ -211,12 +182,9 @@ function useDimensions({ contentRef, footerEnabled, footerRef, headerEnabled, he
|
|
|
211
182
|
enabled: open && footerEnabled,
|
|
212
183
|
resizeSourceRef,
|
|
213
184
|
});
|
|
214
|
-
// Preserve last non-zero heights to avoid collapsing to 0 when the
|
|
215
|
-
// modal/portal temporarily unmounts or RO reports 0 during transitions
|
|
216
185
|
const effectiveContentHeight = usePreservedHeight(contentHeight);
|
|
217
186
|
const effectiveHeaderHeight = usePreservedHeight(headerHeight);
|
|
218
187
|
const effectiveFooterHeight = usePreservedHeight(footerHeight);
|
|
219
|
-
// When content is measured (>0), mark ready for contentHeight
|
|
220
188
|
useLayoutEffect(() => {
|
|
221
189
|
if (!setReady)
|
|
222
190
|
return;
|
|
@@ -225,7 +193,6 @@ function useDimensions({ contentRef, footerEnabled, footerRef, headerEnabled, he
|
|
|
225
193
|
setReady();
|
|
226
194
|
}
|
|
227
195
|
}, [contentHeight, contentRef, setReady]);
|
|
228
|
-
// Calculate available space for content, ensuring it's never negative
|
|
229
196
|
const availableContentSpace = Math.max(0, maxHeight - effectiveHeaderHeight - effectiveFooterHeight);
|
|
230
197
|
const minHeight = Math.min(availableContentSpace, effectiveContentHeight) +
|
|
231
198
|
effectiveHeaderHeight +
|
|
@@ -238,7 +205,6 @@ function useDimensions({ contentRef, footerEnabled, footerRef, headerEnabled, he
|
|
|
238
205
|
};
|
|
239
206
|
}
|
|
240
207
|
|
|
241
|
-
// Hook for calculating snap points
|
|
242
208
|
function roundAndCheckForNaN(value) {
|
|
243
209
|
const rounded = Math.round(value);
|
|
244
210
|
if (Number.isNaN(rounded)) {
|
|
@@ -246,15 +212,12 @@ function roundAndCheckForNaN(value) {
|
|
|
246
212
|
}
|
|
247
213
|
return rounded;
|
|
248
214
|
}
|
|
249
|
-
// Clamp function with clear NaN handling
|
|
250
215
|
function clamp(number, lower, upper) {
|
|
251
216
|
number = +number;
|
|
252
217
|
lower = +lower;
|
|
253
218
|
upper = +upper;
|
|
254
|
-
// Handle NaN values with sensible defaults
|
|
255
219
|
const safeLower = Number.isNaN(lower) ? 0 : lower;
|
|
256
220
|
const safeUpper = Number.isNaN(upper) ? Number.POSITIVE_INFINITY : upper;
|
|
257
|
-
// Ensure lower <= upper to avoid invalid ranges
|
|
258
221
|
const finalLower = Math.min(safeLower, safeUpper);
|
|
259
222
|
const finalUpper = Math.max(safeLower, safeUpper);
|
|
260
223
|
if (Number.isNaN(number)) {
|
|
@@ -263,11 +226,9 @@ function clamp(number, lower, upper) {
|
|
|
263
226
|
return Math.min(Math.max(number, finalLower), finalUpper);
|
|
264
227
|
}
|
|
265
228
|
function processSnapPoints(snapPoints, maxHeight) {
|
|
266
|
-
// Validate maxHeight input
|
|
267
229
|
if (!Number.isFinite(maxHeight) || maxHeight <= 0) {
|
|
268
230
|
throw new Error(`Invalid maxHeight: ${maxHeight}. Must be a positive finite number.`);
|
|
269
231
|
}
|
|
270
|
-
// Match React Spring Bottom Sheet implementation exactly
|
|
271
232
|
const safeSnaps = []
|
|
272
233
|
.concat(snapPoints)
|
|
273
234
|
.map(roundAndCheckForNaN);
|
|
@@ -276,7 +237,6 @@ function processSnapPoints(snapPoints, maxHeight) {
|
|
|
276
237
|
return acc;
|
|
277
238
|
}, new Set());
|
|
278
239
|
const processedPoints = Array.from(snapPointsDedupedSet);
|
|
279
|
-
// Handle empty snap points array
|
|
280
240
|
if (processedPoints.length === 0) {
|
|
281
241
|
throw new Error('No valid snap points available. The snapPoints function must return at least one valid number.\n' +
|
|
282
242
|
'Example: snapPoints: ({ minHeight, maxHeight }) => [minHeight, maxHeight]');
|
|
@@ -316,7 +276,6 @@ function useSnapPoints({ contentRef, footerEnabled, footerRef, getSnapPoints, he
|
|
|
316
276
|
})
|
|
317
277
|
: [0], maxHeight);
|
|
318
278
|
function findSnap(numberOrCallback) {
|
|
319
|
-
// Defensive check: should never happen due to processSnapPoints validation
|
|
320
279
|
if (snapPoints.length === 0) {
|
|
321
280
|
throw new Error('Cannot find snap point: no snap points available');
|
|
322
281
|
}
|
|
@@ -334,7 +293,6 @@ function useSnapPoints({ contentRef, footerEnabled, footerRef, getSnapPoints, he
|
|
|
334
293
|
});
|
|
335
294
|
}
|
|
336
295
|
catch (error) {
|
|
337
|
-
// If callback throws, fall back to current position or minSnap
|
|
338
296
|
unsafeSearch = heightRef.current ?? minSnap;
|
|
339
297
|
}
|
|
340
298
|
}
|
|
@@ -346,69 +304,53 @@ function useSnapPoints({ contentRef, footerEnabled, footerRef, getSnapPoints, he
|
|
|
346
304
|
querySnap = roundAndCheckForNaN(unsafeSearch);
|
|
347
305
|
}
|
|
348
306
|
catch (error) {
|
|
349
|
-
// If number is invalid (NaN, etc), fall back to current position or minSnap
|
|
350
307
|
querySnap = heightRef.current ?? minSnap;
|
|
351
308
|
}
|
|
352
|
-
// Support index-based selection: if querySnap is a small integer and within bounds, treat as index
|
|
353
309
|
const isValidIndex = querySnap >= 0 &&
|
|
354
310
|
querySnap < snapPoints.length &&
|
|
355
311
|
Number.isInteger(querySnap);
|
|
356
312
|
if (isValidIndex) {
|
|
357
313
|
return snapPoints[querySnap];
|
|
358
314
|
}
|
|
359
|
-
// Otherwise, find closest snap point by value
|
|
360
315
|
return snapPoints.reduce((prev, curr) => Math.abs(curr - querySnap) < Math.abs(prev - querySnap) ? curr : prev, minSnap);
|
|
361
316
|
}
|
|
362
317
|
return { minSnap, maxSnap, findSnap, maxHeight, snapPoints };
|
|
363
318
|
}
|
|
364
319
|
|
|
365
|
-
//implementation for Drawer gestures
|
|
366
|
-
// Standardized spring configuration
|
|
367
320
|
const SPRING_CONFIG = {
|
|
368
321
|
type: 'spring',
|
|
369
322
|
stiffness: 600,
|
|
370
323
|
damping: 50,
|
|
371
324
|
mass: 1,
|
|
372
325
|
};
|
|
373
|
-
// Rubberband effect constants
|
|
374
326
|
const RUBBERBAND_RESISTANCE = 0.8;
|
|
375
327
|
const SINGLE_SNAP_STRETCH_FACTOR = 1.2;
|
|
376
328
|
const MULTI_SNAP_STRETCH_FACTOR = 1.8;
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
const DISMISS_POSITION_FACTOR = 2; // Divisor for calculating dismiss threshold (minSnap / 2)
|
|
382
|
-
// Default functions
|
|
329
|
+
const DISMISS_THRESHOLD = 50;
|
|
330
|
+
const VELOCITY_THRESHOLD = 0.1;
|
|
331
|
+
const PREDICTION_MULTIPLIER = 2;
|
|
332
|
+
const DISMISS_POSITION_FACTOR = 2;
|
|
383
333
|
function defaultSnapPoints({ minHeight }) {
|
|
384
|
-
// When no snap points are specified, just use content height
|
|
385
|
-
// This means the drawer shows content at natural size and can only dismiss
|
|
386
334
|
return [minHeight];
|
|
387
335
|
}
|
|
388
336
|
function defaultInitialSnap({ snapPoints, lastSnap: _lastSnap, }) {
|
|
389
|
-
// Default behavior: choose the smallest snap point (usually content height)
|
|
390
|
-
// Users can override this in their initialSnap function if they want lastSnap behavior
|
|
391
337
|
return Math.min(...snapPoints);
|
|
392
338
|
}
|
|
393
339
|
function useDrawerGestures(options) {
|
|
394
340
|
const { anchor, open, onClose, snapPoints: getSnapPoints = defaultSnapPoints, initialSnap: getInitialSnap = defaultInitialSnap, contentRef, headerRef, footerRef, headerEnabled, footerEnabled, } = options;
|
|
341
|
+
const { externalWindow } = useWindowContext();
|
|
342
|
+
const gestureWindow = externalWindow;
|
|
395
343
|
const { ready, registerReady } = useReady();
|
|
396
|
-
// Height tracking refs
|
|
397
344
|
const heightRef = useRef(0);
|
|
398
345
|
const lastSnapRef = useRef(null);
|
|
399
346
|
const resizeSourceRef = useRef('window');
|
|
400
|
-
// Animation cleanup ref to prevent memory leaks
|
|
401
347
|
const animationRef = useRef(null);
|
|
402
|
-
// Cleanup animations on unmount to prevent memory leaks
|
|
403
348
|
useLayoutEffect(() => {
|
|
404
349
|
return () => {
|
|
405
350
|
animationRef.current?.stop();
|
|
406
351
|
};
|
|
407
352
|
}, []);
|
|
408
|
-
// Motion values
|
|
409
353
|
const heightMotionValue = useMotionValue(0);
|
|
410
|
-
// We animate with spring only on release; during drag we set the value directly for immediate follow
|
|
411
|
-
// Ensure motion value starts with correct value when drawer opens
|
|
412
354
|
useLayoutEffect(() => {
|
|
413
355
|
if (open &&
|
|
414
356
|
ready &&
|
|
@@ -417,7 +359,6 @@ function useDrawerGestures(options) {
|
|
|
417
359
|
heightMotionValue.set(heightRef.current);
|
|
418
360
|
}
|
|
419
361
|
}, [open, ready, heightMotionValue]);
|
|
420
|
-
// Snap points calculation
|
|
421
362
|
const { minSnap, maxSnap, findSnap, maxHeight } = useSnapPoints({
|
|
422
363
|
contentRef: contentRef,
|
|
423
364
|
footerEnabled,
|
|
@@ -432,14 +373,11 @@ function useDrawerGestures(options) {
|
|
|
432
373
|
resizeSourceRef,
|
|
433
374
|
open,
|
|
434
375
|
});
|
|
435
|
-
// Calculate initial snap
|
|
436
376
|
const defaultSnap = useMemo(() => {
|
|
437
377
|
if (!ready)
|
|
438
378
|
return 0;
|
|
439
|
-
// If initial snap is a function, it receives state via findSnap
|
|
440
379
|
return findSnap(getInitialSnap);
|
|
441
380
|
}, [ready, getInitialSnap, findSnap]);
|
|
442
|
-
// Only set the initial height once per open cycle when content is present
|
|
443
381
|
const didInitRef = useRef(false);
|
|
444
382
|
const isContentPresent = !!contentRef?.current && contentRef.current.isConnected;
|
|
445
383
|
useLayoutEffect(() => {
|
|
@@ -447,16 +385,11 @@ function useDrawerGestures(options) {
|
|
|
447
385
|
return;
|
|
448
386
|
if (didInitRef.current)
|
|
449
387
|
return;
|
|
450
|
-
// Use the calculated defaultSnap (which may or may not include lastSnap based on user's initialSnap function)
|
|
451
388
|
const safeInitial = defaultSnap > 0 ? defaultSnap : minSnap;
|
|
452
|
-
// If we don't have content present and no valid fallback height, wait
|
|
453
389
|
if (!isContentPresent && safeInitial <= 0)
|
|
454
390
|
return;
|
|
455
|
-
// 1. Set to 0 immediately
|
|
456
391
|
heightMotionValue.set(0);
|
|
457
|
-
// 2. Update heightRef
|
|
458
392
|
heightRef.current = safeInitial;
|
|
459
|
-
// 3. Animate to target position
|
|
460
393
|
animationRef.current = animate(heightMotionValue, safeInitial, SPRING_CONFIG);
|
|
461
394
|
didInitRef.current = true;
|
|
462
395
|
}, [
|
|
@@ -468,13 +401,11 @@ function useDrawerGestures(options) {
|
|
|
468
401
|
heightMotionValue,
|
|
469
402
|
lastSnapRef.current,
|
|
470
403
|
]);
|
|
471
|
-
// Content resize:
|
|
472
404
|
useLayoutEffect(() => {
|
|
473
405
|
if (!open || !ready || !isContentPresent)
|
|
474
406
|
return;
|
|
475
407
|
if (!didInitRef.current)
|
|
476
|
-
return;
|
|
477
|
-
// Find closest snap point to current height (preserves user positioning)
|
|
408
|
+
return;
|
|
478
409
|
const currentHeight = heightRef.current ?? 0;
|
|
479
410
|
if (currentHeight > 0) {
|
|
480
411
|
const closestSnap = findSnap(currentHeight);
|
|
@@ -482,37 +413,29 @@ function useDrawerGestures(options) {
|
|
|
482
413
|
heightRef.current = closestSnap;
|
|
483
414
|
lastSnapRef.current = closestSnap;
|
|
484
415
|
}
|
|
485
|
-
}, [minSnap, maxSnap]);
|
|
486
|
-
// Reset init flag when closing so next open can initialize again
|
|
416
|
+
}, [minSnap, maxSnap]);
|
|
487
417
|
useLayoutEffect(() => {
|
|
488
418
|
if (!open) {
|
|
489
419
|
didInitRef.current = false;
|
|
490
|
-
// Preserve the current height as lastSnap for next open
|
|
491
420
|
if (heightRef.current > 0) {
|
|
492
421
|
lastSnapRef.current = heightRef.current;
|
|
493
422
|
}
|
|
494
|
-
// Animate motion value to 0 on close
|
|
495
423
|
animationRef.current = animate(heightMotionValue, 0, SPRING_CONFIG);
|
|
496
424
|
}
|
|
497
425
|
}, [open, heightMotionValue]);
|
|
498
|
-
// Drag handler
|
|
499
426
|
const handleDrag = useEventCallback(({ args: [{ closeOnTap = false } = {}] = [], cancel, down, last, memo = heightMotionValue.get(), movement: [_mx, _my], tap, velocity: [_, velocityY], event, }) => {
|
|
500
427
|
if (!ready) {
|
|
501
428
|
cancel();
|
|
502
429
|
return memo;
|
|
503
430
|
}
|
|
504
|
-
// Handle close on tap (backdrop tap)
|
|
505
431
|
if (closeOnTap && tap) {
|
|
506
432
|
cancel();
|
|
507
|
-
// Use timeout to avoid tap events on backdrop triggering click events underneath
|
|
508
433
|
onClose(event, 'gestureSwipe');
|
|
509
434
|
return memo;
|
|
510
435
|
}
|
|
511
|
-
// Filter out taps
|
|
512
436
|
if (tap) {
|
|
513
437
|
return memo;
|
|
514
438
|
}
|
|
515
|
-
// dismissal logic for all anchors
|
|
516
439
|
const getDismissInfo = () => {
|
|
517
440
|
switch (anchor) {
|
|
518
441
|
case 'bottom':
|
|
@@ -548,10 +471,8 @@ function useDrawerGestures(options) {
|
|
|
548
471
|
}
|
|
549
472
|
};
|
|
550
473
|
const { isDismissDirection, movement, threshold } = getDismissInfo();
|
|
551
|
-
// For horizontal drawers, only handle dismiss (no snap points)
|
|
552
474
|
const isVertical = anchor === 'top' || anchor === 'bottom';
|
|
553
475
|
if (!isVertical) {
|
|
554
|
-
// Check for dismiss condition (horizontal drawers only)
|
|
555
476
|
if (!down && isDismissDirection && movement > threshold) {
|
|
556
477
|
cancel();
|
|
557
478
|
onClose(event, 'gestureSwipe');
|
|
@@ -563,7 +484,6 @@ function useDrawerGestures(options) {
|
|
|
563
484
|
const rawY = memo + my;
|
|
564
485
|
const predictedDistance = my * velocityY;
|
|
565
486
|
const predictedY = Math.max(minSnap, Math.min(maxHeight, rawY + predictedDistance * PREDICTION_MULTIPLIER));
|
|
566
|
-
// Check for vertical dismissal - only when trying to go below minimum snap point
|
|
567
487
|
if (!down && isDismissDirection) {
|
|
568
488
|
const dismissThreshold = minSnap / DISMISS_POSITION_FACTOR;
|
|
569
489
|
const currentPosition = rawY + predictedDistance;
|
|
@@ -576,28 +496,22 @@ function useDrawerGestures(options) {
|
|
|
576
496
|
let newY;
|
|
577
497
|
if (down) {
|
|
578
498
|
if (minSnap === maxSnap) {
|
|
579
|
-
// Special case when min and max snap are the same (only one snap point)
|
|
580
499
|
if (rawY < minSnap) {
|
|
581
|
-
newY = rawY;
|
|
500
|
+
newY = rawY;
|
|
582
501
|
}
|
|
583
502
|
else {
|
|
584
|
-
// Strong resistance when dragging up beyond content
|
|
585
503
|
newY = rubberbandIfOutOfBounds(rawY, minSnap, maxSnap * SINGLE_SNAP_STRETCH_FACTOR, RUBBERBAND_RESISTANCE);
|
|
586
504
|
}
|
|
587
505
|
}
|
|
588
506
|
else {
|
|
589
|
-
// Multiple snap points: allow stretching beyond maxSnap for rubberband effect
|
|
590
507
|
newY = rubberbandIfOutOfBounds(rawY, 0, maxSnap * MULTI_SNAP_STRETCH_FACTOR, RUBBERBAND_RESISTANCE);
|
|
591
508
|
}
|
|
592
509
|
}
|
|
593
510
|
else {
|
|
594
|
-
// On release: use predicted position
|
|
595
511
|
newY = predictedY;
|
|
596
512
|
}
|
|
597
513
|
if (last) {
|
|
598
|
-
// End of gesture: find closest snap point and animate to it
|
|
599
514
|
const targetSnap = findSnap(newY);
|
|
600
|
-
// Animate to target snap point using spring
|
|
601
515
|
animationRef.current = animate(heightMotionValue, targetSnap, {
|
|
602
516
|
...SPRING_CONFIG,
|
|
603
517
|
velocity: Math.abs(velocityY) > VELOCITY_THRESHOLD ? velocityY : 0,
|
|
@@ -606,29 +520,26 @@ function useDrawerGestures(options) {
|
|
|
606
520
|
lastSnapRef.current = targetSnap;
|
|
607
521
|
return memo;
|
|
608
522
|
}
|
|
609
|
-
// During drag: directly set height to follow finger with rubberband
|
|
610
523
|
heightMotionValue.set(newY);
|
|
611
524
|
return memo;
|
|
612
525
|
});
|
|
613
|
-
// Gesture binding
|
|
614
526
|
const isVertical = anchor === 'top' || anchor === 'bottom';
|
|
615
|
-
const
|
|
527
|
+
const gestureConfig = useMemo(() => ({
|
|
616
528
|
filterTaps: true,
|
|
617
|
-
|
|
618
|
-
|
|
529
|
+
...(gestureWindow && {
|
|
530
|
+
window: gestureWindow,
|
|
531
|
+
}),
|
|
532
|
+
}), [gestureWindow]);
|
|
533
|
+
const bind = useDrag(handleDrag, gestureConfig);
|
|
619
534
|
const heightStyle = useTransform(heightMotionValue, (y) => {
|
|
620
|
-
// Ensure drawer never exceeds viewport bounds
|
|
621
535
|
const clamped = Math.max(0, Math.min(y, maxHeight));
|
|
622
536
|
return `${Math.round(clamped)}px`;
|
|
623
537
|
});
|
|
624
|
-
// Imperative snapTo function
|
|
625
538
|
const snapTo = useCallback((numberOrCallback) => {
|
|
626
539
|
if (!ready)
|
|
627
540
|
return;
|
|
628
541
|
const targetSnap = findSnap(numberOrCallback);
|
|
629
|
-
// Animate to target snap point
|
|
630
542
|
animationRef.current = animate(heightMotionValue, targetSnap, SPRING_CONFIG);
|
|
631
|
-
// Update refs
|
|
632
543
|
heightRef.current = targetSnap;
|
|
633
544
|
lastSnapRef.current = targetSnap;
|
|
634
545
|
}, [ready, findSnap, heightMotionValue, heightRef, lastSnapRef]);
|
|
@@ -649,45 +560,16 @@ function useDrawerGestures(options) {
|
|
|
649
560
|
};
|
|
650
561
|
}
|
|
651
562
|
|
|
652
|
-
/**
|
|
653
|
-
* SwipeableDrawer Component - Gesture-enhanced drawer with swipe support
|
|
654
|
-
*
|
|
655
|
-
* Wraps the base Drawer component and adds touch/mouse gesture support for resizing and closing.
|
|
656
|
-
* Perfect for mobile bottom sheets and interactive panels.
|
|
657
|
-
*
|
|
658
|
-
* @example
|
|
659
|
-
* ```tsx
|
|
660
|
-
* bottom sheet with gestures
|
|
661
|
-
* <SwipeableDrawer
|
|
662
|
-
* open={open}
|
|
663
|
-
* onClose={onClose}
|
|
664
|
-
* anchor="bottom"
|
|
665
|
-
* gestureControlsProps={{
|
|
666
|
-
* snapPoints: ({ minHeight, maxHeight }) => [
|
|
667
|
-
* minHeight, // Content height
|
|
668
|
-
* maxHeight * 0.6, // 60% of screen
|
|
669
|
-
* maxHeight // Full screen
|
|
670
|
-
* ],
|
|
671
|
-
* initialSnap: 0 // Start at content height
|
|
672
|
-
* }}
|
|
673
|
-
* >
|
|
674
|
-
* <Content />
|
|
675
|
-
* </SwipeableDrawer>
|
|
676
|
-
* ```
|
|
677
|
-
*/
|
|
678
563
|
const SwipeableDrawer = forwardRef((inProps, ref) => {
|
|
679
564
|
const props = useThemeProps({
|
|
680
565
|
props: inProps,
|
|
681
566
|
name: 'SwipeableDrawer',
|
|
682
567
|
});
|
|
683
568
|
const { anchor = 'bottom', bodyProps, classes, className, children, header, footer, open, onClose, variant = 'temporary', blocking = true, gestureControlsProps, ...rest } = props;
|
|
684
|
-
// Refs for gesture system
|
|
685
569
|
const contentRef = useRef(null);
|
|
686
570
|
const headerRef = useRef(null);
|
|
687
571
|
const footerRef = useRef(null);
|
|
688
572
|
const isVertical = anchor === 'top' || anchor === 'bottom';
|
|
689
|
-
// Stabilize header/footer enabled state to prevent measurement fluctuations
|
|
690
|
-
// Header is enabled if there's a header prop OR if there's a drag handle (for vertical drawers)
|
|
691
573
|
const headerEnabled = useMemo(() => !!header || isVertical, [header, isVertical]);
|
|
692
574
|
const footerEnabled = useMemo(() => !!footer, [footer]);
|
|
693
575
|
const cls = useClasses('swipeable-drawer', classes, className);
|
|
@@ -705,32 +587,25 @@ const SwipeableDrawer = forwardRef((inProps, ref) => {
|
|
|
705
587
|
footerEnabled,
|
|
706
588
|
...gestureProps,
|
|
707
589
|
});
|
|
708
|
-
// Expose snapTo function through action ref
|
|
709
590
|
useImperativeHandle(action, () => ({
|
|
710
591
|
snapTo: gestureControls.snapTo,
|
|
711
592
|
}), [gestureControls.snapTo]);
|
|
712
593
|
const gestureBindProps = gestureControls.bind();
|
|
713
|
-
// Enhanced body props that include gesture motion
|
|
714
594
|
const enhancedBodyProps = {
|
|
715
595
|
...bodyProps,
|
|
716
|
-
// Apply gesture bindings for horizontal drawers (left/right)
|
|
717
|
-
// Vertical drawers (top/bottom) use motion values instead
|
|
718
596
|
...(!isVertical ? gestureBindProps : {}),
|
|
719
597
|
style: {
|
|
720
598
|
...bodyProps?.style,
|
|
721
|
-
// Apply motion styles for vertical drawers (top/bottom)
|
|
722
599
|
...(isVertical && {
|
|
723
600
|
...gestureControls.motionProps.style,
|
|
724
601
|
}),
|
|
725
602
|
},
|
|
726
603
|
};
|
|
727
|
-
// Consolidate measurement refs (refs only)
|
|
728
604
|
const measurementRefs = {
|
|
729
605
|
header: headerRef,
|
|
730
606
|
footer: footerRef,
|
|
731
607
|
content: contentRef,
|
|
732
608
|
};
|
|
733
|
-
// Gesture props for header
|
|
734
609
|
const headerGestureProps = {
|
|
735
610
|
className: clsx(isVertical && cls('header-drag')),
|
|
736
611
|
...(isVertical && gestureBindProps),
|
package/Switch.js
CHANGED
|
@@ -9,9 +9,7 @@ var Switch$1 = {"sui-switch-root":"sui-switch-root","sui-focus-visible":"sui-foc
|
|
|
9
9
|
|
|
10
10
|
const Switch = forwardRef((inProps, ref) => {
|
|
11
11
|
const props = useThemeProps({ props: inProps, name: 'Switch' });
|
|
12
|
-
const { classes, className, inputRef: inputRefProp, inputProps: inputPropsProp,
|
|
13
|
-
/* ⬇️ for input */
|
|
14
|
-
checked: checkedProp, defaultChecked, disabled: disabledProp, autoFocus = false, onBlur, onChange, onFocus, onFocusVisible, required, ...rest } = props;
|
|
12
|
+
const { classes, className, inputRef: inputRefProp, inputProps: inputPropsProp, checked: checkedProp, defaultChecked, disabled: disabledProp, autoFocus = false, onBlur, onChange, onFocus, onFocusVisible, required, ...rest } = props;
|
|
15
13
|
const cls = useClasses('switch', classes, className);
|
|
16
14
|
const { disabled, id } = useFormLabel({
|
|
17
15
|
disabled: disabledProp,
|
|
@@ -34,7 +32,6 @@ const Switch = forwardRef((inProps, ref) => {
|
|
|
34
32
|
if (autoFocus) {
|
|
35
33
|
inputRef.current?.focus();
|
|
36
34
|
}
|
|
37
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
35
|
}, []);
|
|
39
36
|
return (jsxs("span", { className: cls('root', { focusVisible }), ...rest, ref: ref, children: [jsx("input", { ...inputProps, id: id, className: cls('input', { checked }), ref: forkRef }), jsx("span", { className: cls('track') }), jsx("span", { className: cls('dot') })] }));
|
|
40
37
|
});
|