react-modal-sheet 2.2.1 → 3.1.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/src/sheet.tsx CHANGED
@@ -1,12 +1,21 @@
1
- import * as React from 'react';
2
- import * as ReactDOM from 'react-dom';
1
+ import React, {
2
+ Children,
3
+ cloneElement,
4
+ forwardRef,
5
+ useEffect,
6
+ useImperativeHandle,
7
+ useMemo,
8
+ useRef,
9
+ } from 'react';
10
+
11
+ import { createPortal } from 'react-dom';
3
12
 
4
13
  import {
5
14
  animate,
6
15
  AnimatePresence,
7
16
  motion,
8
- PanInfo,
9
- Transition,
17
+ type PanInfo,
18
+ type Transition,
10
19
  useMotionValue,
11
20
  useReducedMotion,
12
21
  useTransform,
@@ -14,9 +23,9 @@ import {
14
23
 
15
24
  import {
16
25
  useModalEffect,
17
- useWindowHeight,
26
+ useDimensions,
18
27
  useIsomorphicLayoutEffect,
19
- useEvent,
28
+ useEffectEvent,
20
29
  } from './hooks';
21
30
 
22
31
  import {
@@ -27,13 +36,13 @@ import {
27
36
  IS_SSR,
28
37
  } from './constants';
29
38
 
30
- import { SheetContextType, SheetProps } from './types';
39
+ import { type SheetContextType, type SheetProps } from './types';
31
40
  import { SheetScrollerContextProvider, SheetContext } from './context';
32
41
  import { getClosest, inDescendingOrder, validateSnapTo } from './utils';
33
42
  import { usePreventScroll } from './use-prevent-scroll';
34
43
  import styles from './styles';
35
44
 
36
- const Sheet = React.forwardRef<any, SheetProps>(
45
+ const Sheet = forwardRef<any, SheetProps>(
37
46
  (
38
47
  {
39
48
  onOpenStart,
@@ -58,9 +67,9 @@ const Sheet = React.forwardRef<any, SheetProps>(
58
67
  },
59
68
  ref
60
69
  ) => {
61
- const sheetRef = React.useRef<any>(null);
70
+ const sheetRef = useRef<HTMLDivElement>(null);
62
71
  const indicatorRotation = useMotionValue(0);
63
- const windowHeight = useWindowHeight();
72
+ const { height: windowHeight } = useDimensions();
64
73
  const shouldReduceMotion = useReducedMotion();
65
74
  const reduceMotion = Boolean(prefersReducedMotion || shouldReduceMotion);
66
75
  const animationOptions: Transition = {
@@ -73,17 +82,17 @@ const Sheet = React.forwardRef<any, SheetProps>(
73
82
  // and after that it is driven by the gestures and/or snapping
74
83
  const y = useMotionValue(0);
75
84
 
76
- const zIndex = useTransform(y, value =>
77
- value >= windowHeight ? -1 : 9999999
85
+ // +2 for tolerance in case the animated value is slightly off
86
+ const zIndex = useTransform(y, (value) =>
87
+ value + 2 >= windowHeight ? -1 : 9999999
78
88
  );
79
-
80
- const visibility = useTransform(y, value =>
81
- value >= windowHeight ? 'hidden' : 'visible'
89
+ const visibility = useTransform(y, (value) =>
90
+ value + 2 >= windowHeight ? 'hidden' : 'visible'
82
91
  );
83
92
 
84
93
  // Keep the callback fns up-to-date so that they can be accessed inside
85
94
  // the effect without including them to the dependencies array
86
- const callbacks = React.useRef({
95
+ const callbacks = useRef({
87
96
  onOpenStart,
88
97
  onOpenEnd,
89
98
  onCloseStart,
@@ -101,7 +110,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
101
110
 
102
111
  if (snapPoints) {
103
112
  // Convert negative / percentage snap points to absolute values
104
- snapPoints = snapPoints.map(point => {
113
+ snapPoints = snapPoints.map((point) => {
105
114
  // Percentage values e.g. between 0.0 and 1.0
106
115
  if (point > 0 && point <= 1) return Math.round(point * windowHeight);
107
116
  return point < 0 ? windowHeight + point : point; // negative values
@@ -109,11 +118,13 @@ const Sheet = React.forwardRef<any, SheetProps>(
109
118
 
110
119
  console.assert(
111
120
  inDescendingOrder(snapPoints) || windowHeight === 0,
112
- `Snap points need to be in descending order got: [${snapPoints}]`
121
+ `Snap points need to be in descending order got: [${snapPoints.join(
122
+ ', '
123
+ )}]`
113
124
  );
114
125
  }
115
126
 
116
- const onDrag = useEvent((_, { delta }: PanInfo) => {
127
+ const onDrag = useEffectEvent((_, { delta }: PanInfo) => {
117
128
  // Update drag indicator rotation based on drag velocity
118
129
  const velocity = y.getVelocity();
119
130
 
@@ -124,20 +135,36 @@ const Sheet = React.forwardRef<any, SheetProps>(
124
135
  y.set(Math.max(y.get() + delta.y, 0));
125
136
  });
126
137
 
127
- const onDragEnd = useEvent((_, { velocity }: PanInfo) => {
138
+ const onDragStart = useEffectEvent(() => {
139
+ // Find focused input inside the sheet and blur it when dragging starts
140
+ // to prevent a weird ghost caret "bug" on mobile
141
+ const focusedElement = document.activeElement as HTMLElement | null;
142
+ if (!focusedElement || !sheetRef.current) return;
143
+
144
+ const isInput =
145
+ focusedElement.tagName === 'INPUT' ||
146
+ focusedElement.tagName === 'TEXTAREA';
147
+
148
+ // Only blur the focused element if it's inside the sheet
149
+ if (isInput && sheetRef.current.contains(focusedElement)) {
150
+ focusedElement.blur();
151
+ }
152
+ });
153
+
154
+ const onDragEnd = useEffectEvent((_, { velocity }: PanInfo) => {
128
155
  if (velocity.y > DRAG_VELOCITY_THRESHOLD) {
129
156
  // User flicked the sheet down
130
157
  onClose();
131
158
  } else {
132
- const sheetEl = sheetRef.current as HTMLDivElement;
133
- const sheetHeight = sheetEl.getBoundingClientRect().height;
159
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
160
+ const sheetHeight = sheetRef.current!.getBoundingClientRect().height;
134
161
  const currentY = y.get();
135
162
 
136
163
  let snapTo = 0;
137
164
 
138
165
  if (snapPoints) {
139
166
  const snapToValues = snapPoints.map(
140
- p => sheetHeight - Math.min(p, sheetHeight)
167
+ (p) => sheetHeight - Math.min(p, sheetHeight)
141
168
  );
142
169
 
143
170
  // Allow snapping to the top of the sheet if detent is set to `content-height`
@@ -155,7 +182,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
155
182
  snapTo = validateSnapTo({ snapTo, sheetHeight });
156
183
 
157
184
  // Update the spring value so that the sheet is animated to the snap point
158
- animate(y, snapTo, animationOptions);
185
+ void animate(y, snapTo, animationOptions);
159
186
 
160
187
  if (snapPoints && onSnap) {
161
188
  const snapValue = Math.abs(Math.round(snapPoints[0] - snapTo));
@@ -164,7 +191,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
164
191
  }
165
192
 
166
193
  const roundedSheetHeight = Math.round(sheetHeight);
167
- const shouldClose = snapTo >= roundedSheetHeight;
194
+ const shouldClose = snapTo + 2 >= roundedSheetHeight; // 2px tolerance
168
195
 
169
196
  if (shouldClose) onClose();
170
197
  }
@@ -174,22 +201,18 @@ const Sheet = React.forwardRef<any, SheetProps>(
174
201
  });
175
202
 
176
203
  // Trigger onSnap callback when sheet is opened or closed
177
- React.useEffect(() => {
204
+ useEffect(() => {
178
205
  if (!snapPoints || !onSnap) return;
179
206
  const snapIndex = isOpen ? initialSnap : snapPoints.length - 1;
180
207
  onSnap(snapIndex);
181
208
  }, [isOpen]); // eslint-disable-line
182
209
 
183
- React.useImperativeHandle(ref, () => ({
210
+ useImperativeHandle(ref, () => ({
184
211
  y,
185
212
  snapTo: (snapIndex: number) => {
186
- const sheetEl = sheetRef.current as HTMLDivElement | null;
213
+ const sheetEl = sheetRef.current;
187
214
 
188
- if (
189
- snapPoints &&
190
- snapPoints[snapIndex] !== undefined &&
191
- sheetEl !== null
192
- ) {
215
+ if (snapPoints?.[snapIndex] !== undefined && sheetEl) {
193
216
  const sheetHeight = sheetEl.getBoundingClientRect().height;
194
217
  const snapPoint = snapPoints[snapIndex];
195
218
  const snapTo = validateSnapTo({
@@ -197,7 +220,7 @@ const Sheet = React.forwardRef<any, SheetProps>(
197
220
  sheetHeight,
198
221
  });
199
222
 
200
- animate(y, snapTo, animationOptions);
223
+ void animate(y, snapTo, animationOptions);
201
224
  if (onSnap) onSnap(snapIndex);
202
225
  if (snapTo >= sheetHeight) onClose();
203
226
  }
@@ -208,20 +231,21 @@ const Sheet = React.forwardRef<any, SheetProps>(
208
231
 
209
232
  // Framer Motion should handle body scroll locking but it's not working
210
233
  // properly on iOS. Scroll locking from React Aria seems to work much better.
211
- usePreventScroll({ isDisabled: disableScrollLocking === true || !isOpen });
234
+ usePreventScroll({ isDisabled: disableScrollLocking || !isOpen });
212
235
 
213
- const dragProps = React.useMemo(() => {
236
+ const dragProps = useMemo(() => {
214
237
  const dragProps: SheetContextType['dragProps'] = {
215
238
  drag: 'y',
216
239
  dragElastic: 0,
217
240
  dragMomentum: false,
218
241
  dragPropagation: false,
219
242
  onDrag,
243
+ onDragStart,
220
244
  onDragEnd,
221
245
  };
222
246
 
223
247
  return disableDrag ? undefined : dragProps;
224
- }, [disableDrag]); // eslint-disable-line
248
+ }, [disableDrag, windowHeight]); // eslint-disable-line
225
249
 
226
250
  const context: SheetContextType = {
227
251
  y,
@@ -250,8 +274,8 @@ const Sheet = React.forwardRef<any, SheetProps>(
250
274
  {/* NOTE: AnimatePresence requires us to set keys to children */}
251
275
  {isOpen ? (
252
276
  <SheetScrollerContextProvider>
253
- {React.Children.map(children, (child: any, i) =>
254
- React.cloneElement(child, { key: `sheet-child-${i}` })
277
+ {Children.map(children, (child: any, i) =>
278
+ cloneElement(child, { key: `sheet-child-${i}` })
255
279
  )}
256
280
  </SheetScrollerContextProvider>
257
281
  ) : null}
@@ -262,8 +286,10 @@ const Sheet = React.forwardRef<any, SheetProps>(
262
286
 
263
287
  if (IS_SSR) return sheet;
264
288
 
265
- return ReactDOM.createPortal(sheet, mountPoint ?? document.body);
289
+ return createPortal(sheet, mountPoint ?? document.body);
266
290
  }
267
291
  );
268
292
 
293
+ Sheet.displayName = 'Sheet';
294
+
269
295
  export default Sheet;
package/src/styles.ts CHANGED
@@ -1,6 +1,6 @@
1
- import * as CSS from 'csstype';
1
+ import { type Properties } from 'csstype';
2
2
 
3
- const styles: { [key: string]: CSS.Properties } = {
3
+ const styles: Record<string, Properties> = {
4
4
  wrapper: {
5
5
  position: 'fixed',
6
6
  top: 0,
package/src/types.tsx CHANGED
@@ -1,19 +1,28 @@
1
1
  import {
2
- DragHandlers,
3
- MotionValue,
4
- MotionProps,
5
- motion,
6
- EasingDefinition,
7
- Transition,
2
+ type ComponentPropsWithoutRef,
3
+ type ForwardRefExoticComponent,
4
+ type HTMLAttributes,
5
+ type MutableRefObject,
6
+ type ReactNode,
7
+ type RefAttributes,
8
+ } from 'react';
9
+
10
+ import {
11
+ type DragHandlers,
12
+ type MotionValue,
13
+ type MotionProps,
14
+ type motion,
15
+ type EasingDefinition,
16
+ type Transition,
8
17
  } from 'framer-motion';
9
18
 
10
- export type SheetEvents = {
19
+ export interface SheetEvents {
11
20
  onOpenStart?: () => void;
12
21
  onOpenEnd?: () => void;
13
22
  onCloseStart?: () => void;
14
23
  onCloseEnd?: () => void;
15
24
  onSnap?: (index: number) => void;
16
- };
25
+ }
17
26
 
18
27
  export type SheetDetent = 'full-height' | 'content-height';
19
28
 
@@ -21,14 +30,14 @@ type CommonProps = MotionProps & {
21
30
  className?: string;
22
31
  };
23
32
 
24
- export type SheetTweenConfig = {
33
+ export interface SheetTweenConfig {
25
34
  ease: EasingDefinition;
26
35
  duration: number;
27
- };
36
+ }
28
37
 
29
38
  export type SheetProps = {
30
39
  isOpen: boolean;
31
- children: React.ReactNode;
40
+ children: ReactNode;
32
41
  onClose: () => void;
33
42
  rootId?: string;
34
43
  mountPoint?: Element;
@@ -40,13 +49,13 @@ export type SheetProps = {
40
49
  disableScrollLocking?: boolean;
41
50
  prefersReducedMotion?: boolean;
42
51
  } & SheetEvents &
43
- React.ComponentPropsWithoutRef<typeof motion.div>;
52
+ ComponentPropsWithoutRef<typeof motion.div>;
44
53
 
45
54
  export type SheetContainerProps = Omit<
46
55
  CommonProps,
47
56
  'initial' | 'animate' | 'exit' | 'onAnimationComplete'
48
57
  > & {
49
- children: React.ReactNode;
58
+ children: ReactNode;
50
59
  };
51
60
 
52
61
  export type SheetDraggableProps = Omit<
@@ -59,7 +68,7 @@ export type SheetDraggableProps = Omit<
59
68
  | 'onDragStart'
60
69
  | 'onDragEnd'
61
70
  > & {
62
- children?: React.ReactNode;
71
+ children?: ReactNode;
63
72
  disableDrag?: boolean;
64
73
  };
65
74
 
@@ -68,67 +77,68 @@ export type SheetBackdropProps = Omit<
68
77
  'initial' | 'animate' | 'exit'
69
78
  >;
70
79
 
71
- export type SheetScrollerProps = React.HTMLAttributes<HTMLDivElement> & {
80
+ export type SheetScrollerProps = HTMLAttributes<HTMLDivElement> & {
72
81
  draggableAt?: 'top' | 'bottom' | 'both';
73
82
  };
74
83
 
75
- export type SheetDragProps = {
84
+ export interface SheetDragProps {
76
85
  drag: 'y';
77
86
  dragElastic: number;
78
87
  dragMomentum: boolean;
79
88
  dragPropagation: boolean;
80
89
  onDrag: DragHandlers['onDrag'];
90
+ onDragStart: DragHandlers['onDragStart'];
81
91
  onDragEnd: DragHandlers['onDragEnd'];
82
- };
92
+ }
83
93
 
84
- export type SheetContextType = {
94
+ export interface SheetContextType {
85
95
  y: MotionValue<any>;
86
- sheetRef: React.MutableRefObject<any>;
96
+ sheetRef: MutableRefObject<any>;
87
97
  isOpen: boolean;
88
98
  snapPoints: SheetProps['snapPoints'];
89
99
  detent: SheetDetent;
90
100
  initialSnap: SheetProps['initialSnap'];
91
101
  indicatorRotation: MotionValue<number>;
92
- callbacks: React.MutableRefObject<SheetEvents>;
102
+ callbacks: MutableRefObject<SheetEvents>;
93
103
  dragProps?: SheetDragProps;
94
104
  windowHeight: number;
95
105
  animationOptions: Transition;
96
106
  reduceMotion: boolean;
97
107
  disableDrag: boolean;
98
- };
108
+ }
99
109
 
100
- export type SheetScrollerContextType = {
110
+ export interface SheetScrollerContextType {
101
111
  disableDrag: boolean;
102
112
  setDragDisabled: () => void;
103
113
  setDragEnabled: () => void;
104
- };
114
+ }
105
115
 
106
- type ContainerComponent = React.ForwardRefExoticComponent<
107
- SheetContainerProps & React.RefAttributes<any>
116
+ type ContainerComponent = ForwardRefExoticComponent<
117
+ SheetContainerProps & RefAttributes<any>
108
118
  >;
109
119
 
110
- type DraggableComponent = React.ForwardRefExoticComponent<
111
- SheetDraggableProps & React.RefAttributes<any>
120
+ type DraggableComponent = ForwardRefExoticComponent<
121
+ SheetDraggableProps & RefAttributes<any>
112
122
  >;
113
123
 
114
- type BackdropComponent = React.ForwardRefExoticComponent<
115
- SheetBackdropProps & React.RefAttributes<any>
124
+ type BackdropComponent = ForwardRefExoticComponent<
125
+ SheetBackdropProps & RefAttributes<any>
116
126
  >;
117
127
 
118
- type SheetComponent = React.ForwardRefExoticComponent<
119
- SheetProps & React.RefAttributes<any>
128
+ type SheetComponent = ForwardRefExoticComponent<
129
+ SheetProps & RefAttributes<any>
120
130
  >;
121
131
 
122
- type ScrollerComponent = React.ForwardRefExoticComponent<
123
- SheetScrollerProps & React.RefAttributes<any>
132
+ type ScrollerComponent = ForwardRefExoticComponent<
133
+ SheetScrollerProps & RefAttributes<any>
124
134
  >;
125
135
 
126
- type SheetCompoundComponent = {
136
+ interface SheetCompoundComponent {
127
137
  Container: ContainerComponent;
128
138
  Header: DraggableComponent;
129
139
  Content: DraggableComponent;
130
140
  Backdrop: BackdropComponent;
131
141
  Scroller: ScrollerComponent;
132
- };
142
+ }
133
143
 
134
144
  export type SheetCompound = SheetComponent & SheetCompoundComponent;
@@ -11,8 +11,8 @@ interface PreventScrollOptions {
11
11
  isDisabled?: boolean;
12
12
  }
13
13
 
14
- // @ts-ignore
15
- const visualViewport = typeof window !== 'undefined' && window.visualViewport;
14
+ const visualViewport =
15
+ typeof window !== 'undefined' ? (window as any).visualViewport : undefined;
16
16
 
17
17
  // HTML input types that do not cause the software keyboard to appear.
18
18
  const nonTextInputTypes = new Set([
@@ -37,7 +37,7 @@ let restore: any;
37
37
  * shift due to the scrollbars disappearing.
38
38
  */
39
39
  export function usePreventScroll(options: PreventScrollOptions = {}) {
40
- let { isDisabled } = options;
40
+ const { isDisabled } = options;
41
41
 
42
42
  useLayoutEffect(() => {
43
43
  if (isDisabled) {
@@ -104,7 +104,8 @@ function preventScrollStandard() {
104
104
  function preventScrollMobileSafari() {
105
105
  let scrollable: Element | undefined;
106
106
  let lastY = 0;
107
- let onTouchStart = (e: TouchEvent) => {
107
+
108
+ const onTouchStart = (e: TouchEvent) => {
108
109
  // Store the nearest scrollable parent element from the element that the user touched.
109
110
  scrollable = getScrollParent(e.target as Element);
110
111
  if (
@@ -117,7 +118,7 @@ function preventScrollMobileSafari() {
117
118
  lastY = e.changedTouches[0].pageY;
118
119
  };
119
120
 
120
- let onTouchMove = (e: TouchEvent) => {
121
+ const onTouchMove = (e: TouchEvent) => {
121
122
  // In special situations, `onTouchStart` may be called without `onTouchStart` being called.
122
123
  // (e.g. when the user places a finger on the screen before the <Sheet> is mounted and then moves the finger after it is mounted).
123
124
  // If `onTouchStart` is not called, `scrollable` is `undefined`. Therefore, such cases are ignored.
@@ -138,9 +139,9 @@ function preventScrollMobileSafari() {
138
139
  // of a nested scrollable area, otherwise mobile Safari will start scrolling
139
140
  // the window instead. Unfortunately, this disables bounce scrolling when at
140
141
  // the top but it's the best we can do.
141
- let y = e.changedTouches[0].pageY;
142
- let scrollTop = scrollable.scrollTop;
143
- let bottom = scrollable.scrollHeight - scrollable.clientHeight;
142
+ const y = e.changedTouches[0].pageY;
143
+ const scrollTop = scrollable.scrollTop;
144
+ const bottom = scrollable.scrollHeight - scrollable.clientHeight;
144
145
 
145
146
  // Fix for: https://github.com/adobe/react-spectrum/pull/3780/files
146
147
  if (bottom === 0) {
@@ -154,8 +155,8 @@ function preventScrollMobileSafari() {
154
155
  lastY = y;
155
156
  };
156
157
 
157
- let onTouchEnd = (e: TouchEvent) => {
158
- let target = e.target as HTMLElement;
158
+ const onTouchEnd = (e: TouchEvent) => {
159
+ const target = e.target as HTMLElement;
159
160
 
160
161
  // Apply this change if we're not already focused on the target element
161
162
  if (willOpenKeyboard(target) && target !== document.activeElement) {
@@ -172,8 +173,8 @@ function preventScrollMobileSafari() {
172
173
  }
173
174
  };
174
175
 
175
- let onFocus = (e: FocusEvent) => {
176
- let target = e.target as HTMLElement;
176
+ const onFocus = (e: FocusEvent) => {
177
+ const target = e.target as HTMLElement;
177
178
  if (willOpenKeyboard(target)) {
178
179
  // Transform also needs to be applied in the focus event in cases where focus moves
179
180
  // other than tapping on an input directly, e.g. the next/previous buttons in the
@@ -197,7 +198,9 @@ function preventScrollMobileSafari() {
197
198
  // measure the correct position to scroll to.
198
199
  visualViewport.addEventListener(
199
200
  'resize',
200
- () => scrollIntoView(target),
201
+ () => {
202
+ scrollIntoView(target);
203
+ },
201
204
  { once: true }
202
205
  );
203
206
  }
@@ -206,7 +209,7 @@ function preventScrollMobileSafari() {
206
209
  }
207
210
  };
208
211
 
209
- let onWindowScroll = () => {
212
+ const onWindowScroll = () => {
210
213
  // Last resort. If the window scrolled, scroll it back to the top.
211
214
  // It should always be at the top because the body will have a negative margin (see below).
212
215
  window.scrollTo(0, 0);
@@ -215,10 +218,10 @@ function preventScrollMobileSafari() {
215
218
  // Record the original scroll position so we can restore it.
216
219
  // Then apply a negative margin to the body to offset it by the scroll position. This will
217
220
  // enable us to scroll the window to the top, which is required for the rest of this to work.
218
- let scrollX = window.pageXOffset;
219
- let scrollY = window.pageYOffset;
221
+ const scrollX = window.pageXOffset;
222
+ const scrollY = window.pageYOffset;
220
223
 
221
- let restoreStyles = chain(
224
+ const restoreStyles = chain(
222
225
  setStyle(
223
226
  document.documentElement,
224
227
  'paddingRight',
@@ -231,7 +234,7 @@ function preventScrollMobileSafari() {
231
234
  // Scroll to the top. The negative margin on the body will make this appear the same.
232
235
  window.scrollTo(0, 0);
233
236
 
234
- let removeEvents = chain(
237
+ const removeEvents = chain(
235
238
  addEvent(document, 'touchstart', onTouchStart, {
236
239
  passive: false,
237
240
  capture: true,
@@ -258,7 +261,7 @@ function preventScrollMobileSafari() {
258
261
 
259
262
  // Sets a CSS property on an element, and returns a function to revert it to the previous value.
260
263
  function setStyle(element: any, style: string, value: string) {
261
- let cur = element.style[style];
264
+ const cur = element.style[style];
262
265
  element.style[style] = value;
263
266
 
264
267
  return () => {
@@ -280,17 +283,17 @@ function addEvent<K extends keyof GlobalEventHandlersEventMap>(
280
283
  }
281
284
 
282
285
  function scrollIntoView(target: Element) {
283
- let root = document.scrollingElement || document.documentElement;
286
+ const root = document.scrollingElement || document.documentElement;
284
287
  while (target && target !== root) {
285
288
  // Find the parent scrollable element and adjust the scroll position if the target is not already in view.
286
- let scrollable = getScrollParent(target);
289
+ const scrollable = getScrollParent(target);
287
290
  if (
288
291
  scrollable !== document.documentElement &&
289
292
  scrollable !== document.body &&
290
293
  scrollable !== target
291
294
  ) {
292
- let scrollableTop = scrollable.getBoundingClientRect().top;
293
- let targetTop = target.getBoundingClientRect().top;
295
+ const scrollableTop = scrollable.getBoundingClientRect().top;
296
+ const targetTop = target.getBoundingClientRect().top;
294
297
  if (targetTop > scrollableTop + target.clientHeight) {
295
298
  scrollable.scrollTop += targetTop - scrollableTop;
296
299
  }
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import { type ForwardedRef, type RefCallback } from 'react';
2
2
 
3
3
  export function getClosest(nums: number[], goal: number) {
4
4
  let closest = nums[0];
@@ -74,8 +74,9 @@ export function validateSnapTo({
74
74
  }) {
75
75
  if (snapTo < 0) {
76
76
  console.warn(
77
- `Snap point is out of bounds. Sheet height is ${sheetHeight} but snap point is ${sheetHeight +
78
- Math.abs(snapTo)}.`
77
+ `Snap point is out of bounds. Sheet height is ${sheetHeight} but snap point is ${
78
+ sheetHeight + Math.abs(snapTo)
79
+ }.`
79
80
  );
80
81
  }
81
82
 
@@ -83,8 +84,8 @@ export function validateSnapTo({
83
84
  }
84
85
 
85
86
  export function mergeRefs<T = any>(
86
- refs: React.ForwardedRef<T>[]
87
- ): React.RefCallback<T> {
87
+ refs: Array<ForwardedRef<T>>
88
+ ): RefCallback<T> {
88
89
  return (value: any) => {
89
90
  refs.forEach((ref: any) => {
90
91
  if (typeof ref === 'function') {
@@ -1,5 +0,0 @@
1
- import * as React from 'react';
2
- declare const SheetBackdrop: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
3
- className?: string | undefined;
4
- }, "style" | "transformTemplate" | "transformValues" | "children" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "drag" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragConstraints" | "dragElastic" | "dragMomentum" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDragStart" | "onDragEnd" | "onDrag" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & React.RefAttributes<any>>;
5
- export default SheetBackdrop;
@@ -1,7 +0,0 @@
1
- import * as React from 'react';
2
- declare const SheetContainer: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
3
- className?: string | undefined;
4
- }, "style" | "transformTemplate" | "transformValues" | "children" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "drag" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragConstraints" | "dragElastic" | "dragMomentum" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDragStart" | "onDragEnd" | "onDrag" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & {
5
- children: React.ReactNode;
6
- } & React.RefAttributes<any>>;
7
- export default SheetContainer;
@@ -1,8 +0,0 @@
1
- import * as React from 'react';
2
- declare const SheetContent: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
3
- className?: string | undefined;
4
- }, "style" | "transformTemplate" | "transformValues" | "children" | "initial" | "animate" | "exit" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & {
5
- children?: React.ReactNode;
6
- disableDrag?: boolean | undefined;
7
- } & React.RefAttributes<any>>;
8
- export default SheetContent;
@@ -1,8 +0,0 @@
1
- import * as React from 'react';
2
- declare const SheetHeader: React.ForwardRefExoticComponent<Pick<import("framer-motion").MotionProps & {
3
- className?: string | undefined;
4
- }, "style" | "transformTemplate" | "transformValues" | "children" | "initial" | "animate" | "exit" | "variants" | "transition" | "onBeforeLayoutMeasure" | "onLayoutMeasure" | "onUpdate" | "onAnimationStart" | "onAnimationComplete" | "onPan" | "onPanStart" | "onPanSessionStart" | "onPanEnd" | "onTap" | "onTapStart" | "onTapCancel" | "whileTap" | "whileHover" | "onHoverStart" | "onHoverEnd" | "whileFocus" | "whileInView" | "onViewportEnter" | "onViewportLeave" | "viewport" | "whileDrag" | "dragDirectionLock" | "dragPropagation" | "dragTransition" | "dragControls" | "dragSnapToOrigin" | "dragListener" | "onMeasureDragConstraints" | "_dragX" | "_dragY" | "onDirectionLock" | "onDragTransitionEnd" | "layout" | "layoutId" | "onLayoutAnimationStart" | "onLayoutAnimationComplete" | "layoutDependency" | "layoutScroll" | "layoutRoot" | "custom" | "inherit" | "ignoreStrict" | "className"> & {
5
- children?: React.ReactNode;
6
- disableDrag?: boolean | undefined;
7
- } & React.RefAttributes<any>>;
8
- export default SheetHeader;
@@ -1,5 +0,0 @@
1
- import * as React from 'react';
2
- declare const SheetScroller: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
3
- draggableAt?: "top" | "bottom" | "both" | undefined;
4
- } & React.RefAttributes<any>>;
5
- export default SheetScroller;
@@ -1,12 +0,0 @@
1
- export declare const MAX_HEIGHT = "calc(100% - env(safe-area-inset-top) - 34px)";
2
- export declare const IS_SSR: boolean;
3
- export declare const DEFAULT_TWEEN_CONFIG: {
4
- ease: string;
5
- duration: number;
6
- };
7
- export declare const REDUCED_MOTION_TWEEN_CONFIG: {
8
- ease: string;
9
- duration: number;
10
- };
11
- export declare const DRAG_CLOSE_THRESHOLD = 0.6;
12
- export declare const DRAG_VELOCITY_THRESHOLD = 500;