react-modal-sheet 5.1.2 → 5.2.1

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/README.md CHANGED
@@ -37,7 +37,7 @@ npm install motion
37
37
  <details>
38
38
  <summary><strong>📚 Table of contents</strong></summary>
39
39
 
40
- - [What's new in v5](#whats-new-in-v5)
40
+ - [What's new in v5](#-whats-new-in-v5)
41
41
  - [Usage](#-usage)
42
42
  - [Props](#%EF%B8%8F-props)
43
43
  - [Methods and properties](#%EF%B8%8F-methods-and-properties)
@@ -57,6 +57,8 @@ Version 5 introduces several major improvements and breaking changes:
57
57
  ### 🔄 Breaking Changes
58
58
 
59
59
  - **Removed `Sheet.Scroller`**: Scrolling is now handled automatically by `Sheet.Content`
60
+ - See [Scrolling behavior](#-scrolling-behavior) section for details
61
+ - See [Making scrollable sheet content always reachable](#making-scrollable-sheet-content-always-reachable) for guidance on how to implement auto padding behavior
60
62
  - **Snap point order reversed**: Snap points now use ascending order (e.g., `[0, 0.5, 1]` instead of `[1, 0.5, 0]`)
61
63
  - This aligns better with other bottom sheet libraries and makes more intuitive sense
62
64
  - **Detent prop values changed**:
@@ -199,12 +201,18 @@ Below you can see an example of how to use these values:
199
201
 
200
202
  ```tsx
201
203
  import { Sheet, SheetRef } from 'react-modal-sheet';
204
+ import { useTransform } from 'motion/react';
202
205
  import { useState, useRef } from 'react';
203
206
 
204
207
  function RefExample() {
205
208
  const [isOpen, setOpen] = useState(false);
206
209
  const ref = useRef<SheetRef>(null);
207
210
 
211
+ const background = useTransform(() => {
212
+ const y = ref.current?.y.get() ?? 0;
213
+ return y > 100 ? 'lightblue' : 'lightcoral';
214
+ });
215
+
208
216
  function doSomething() {
209
217
  console.log('> Current y value:', ref.current?.y.get());
210
218
  console.log('> Current yInverted value:', ref.current?.yInverted.get());
@@ -218,7 +226,7 @@ function RefExample() {
218
226
  <Sheet ref={ref} isOpen={isOpen} onClose={() => setOpen(false)}>
219
227
  <Sheet.Container>
220
228
  <Sheet.Content>
221
- <motion.div style={{ paddingBottom: ref.current?.y }}>
229
+ <motion.div style={{ background }}>
222
230
  Use animated y value in some way
223
231
  </motion.div>
224
232
  {/* Your content here */}
@@ -230,6 +238,61 @@ function RefExample() {
230
238
  }
231
239
  ```
232
240
 
241
+ #### Making scrollable sheet content always reachable
242
+
243
+ One common use case for the `y` value is to apply padding bottom to the sheet content
244
+ when the sheet is not fully open. This ensures that the content is always reachable even when the sheet is partially open, eg. when using snap points.
245
+
246
+ > [!NOTE]
247
+ > Prior to v5 this was a built-in behavior of `Sheet.Scroller` via `autoPadding` prop but since `Sheet.Scroller` has been removed in v5 in favor of `Sheet.Content` handling scrolling internally, you can now implement this behavior yourself with the help of the `y` motion value.
248
+ >
249
+ > Also take a look at the [Creating custom scrollers](#creating-custom-scrollers) section for more advanced use cases when you need to implement your own scroller and potentially apply this padding behavior to that.
250
+
251
+ ```tsx
252
+ import { Sheet, SheetRef } from 'react-modal-sheet';
253
+ import { useTransform } from 'motion/react';
254
+ import { useState, useRef } from 'react';
255
+
256
+ const snapPoints = [0, 0.5, 1];
257
+
258
+ function PaddingExample() {
259
+ const [isOpen, setOpen] = useState(false);
260
+ const ref = useRef<SheetRef>(null);
261
+
262
+ // Add padding bottom based on how far the sheet is from being fully open
263
+ const paddingBottom = useTransform(() => {
264
+ return ref.current?.y.get() ?? 0;
265
+ });
266
+
267
+ return (
268
+ <>
269
+ <button onClick={() => setOpen(true)}>Open sheet</button>
270
+
271
+ <Sheet
272
+ ref={ref}
273
+ isOpen={isOpen}
274
+ onClose={() => setOpen(false)}
275
+ snapPoints={snapPoints}
276
+ initialSnap={1}
277
+ >
278
+ <Sheet.Container>
279
+ <Sheet.Header />
280
+ <Sheet.Content
281
+ // 👇 Apply styles to the inner scroller element
282
+ scrollStyle={{ paddingBottom }}
283
+ // 💡 Recommendation: disable drag for the content so that it doesn't interfere with scrolling
284
+ disableDrag
285
+ >
286
+ This content will always be reachable even when the sheet is not
287
+ fully open.
288
+ </Sheet.Content>
289
+ </Sheet.Container>
290
+ </Sheet>
291
+ </>
292
+ );
293
+ }
294
+ ```
295
+
233
296
  ### Detents
234
297
 
235
298
  By default the sheet will take the full height of the page minus top padding and safe area inset. The `detent` prop controls the sheet's height behavior:
@@ -369,9 +432,42 @@ The keyboard avoidance feature:
369
432
 
370
433
  If you need to disable keyboard avoidance, set `avoidKeyboard={false}`.
371
434
 
372
- > [!NOTE]
435
+ > [!IMPORTANT]
373
436
  > If your sheet content is very long and some inputs are below the keyboard even after adding the padding, you might need to scroll the content into view manually when an input is focused.
374
437
 
438
+ #### Managing virtual keyboard manually
439
+
440
+ If the built-in keyboard avoidance doesn't work for your use case, you can disable it with `avoidKeyboard={false}` and manage the keyboard state manually with the help of the `useVirtualKeyboard` hook.
441
+
442
+ ```tsx
443
+ import { Sheet, useVirtualKeyboard } from 'react-modal-sheet';
444
+
445
+ function ManualKeyboardExample() {
446
+ const [isOpen, setOpen] = useState(false);
447
+
448
+ // This hook manages the `--keyboard-inset-height` CSS variable for you
449
+ useVirtualKeyboard({ isEnabled: isOpen });
450
+
451
+ return (
452
+ // Disable default keyboard avoidance
453
+ <Sheet avoidKeyboard={false} isOpen={isOpen} onClose={() => setOpen(false)}>
454
+ <Sheet.Container>
455
+ <Sheet.Header />
456
+ <Sheet.Content
457
+ // Apply keyboard height as padding bottom to keep content above the keyboard
458
+ style={{ paddingBottom: 'var(--keyboard-inset-height)' }}
459
+ >
460
+ {/* Your content here */}
461
+ </Sheet.Content>
462
+ </Sheet.Container>
463
+ <Sheet.Backdrop />
464
+ </Sheet>
465
+ );
466
+ }
467
+ ```
468
+
469
+ For a more detailed example of using `useVirtualKeyboard` see the [Creating custom scrollers](#creating-custom-scrollers) section below.
470
+
375
471
  ### 📱 Scrolling behavior
376
472
 
377
473
  The `Sheet.Content` component manages scroll interactions internally and provides several ways to control scrolling:
@@ -448,6 +544,82 @@ The scroll state provides:
448
544
  - `scrollPosition`: `'top'`, `'bottom'`, `'middle'`, or `undefined`
449
545
  - `currentSnap`: Current snap point index (if using snap points)
450
546
 
547
+ #### Creating custom scrollers
548
+
549
+ If you need more control over the scrollable area, eg. when you don't want the whole content area to be scrollable, you can disable the default scrolling behavior of the `Sheet.Content` and implement your own scroller with the help of `useScrollPosition` and `useVirtualKeyboard` utility hooks.
550
+
551
+ > [!NOTE]
552
+ > These hooks are internally used by the `Sheet.Content` component so you shouldn't need to use them unless you are implementing a custom scroller. However they are general purpose hooks so you can use them in other parts of your app as well if you want 😊
553
+
554
+ ```tsx
555
+ import {
556
+ Sheet,
557
+ useScrollPosition,
558
+ useVirtualKeyboard,
559
+ } from 'react-modal-sheet';
560
+
561
+ function CustomScrollerExample() {
562
+ const [isOpen, setOpen] = useState(false);
563
+
564
+ const { scrollRef, scrollPosition } = useScrollPosition({
565
+ isEnabled: isOpen,
566
+ });
567
+
568
+ const { keyboardHeight } = useVirtualKeyboard({
569
+ isEnabled: isOpen,
570
+ });
571
+
572
+ /**
573
+ * If you use `var(--keyboard-inset-height)` CSS variable you can just call
574
+ * `useVirtualKeyboard()` without destructuring anything from it:
575
+ *
576
+ * useVirtualKeyboard({ isEnabled: isOpen });
577
+ */
578
+
579
+ return (
580
+ // Disable default keyboard avoidance
581
+ <Sheet avoidKeyboard={false} isOpen={isOpen} onClose={() => setOpen(false)}>
582
+ <Sheet.Container>
583
+ <Sheet.Header />
584
+ <Sheet.Content
585
+ // Disable default scrolling
586
+ disableScroll
587
+ // Dragging is still managed by `Sheet.Content` so we control it here
588
+ disableDrag={scrollPosition !== 'top'}
589
+ >
590
+ <div
591
+ style={{
592
+ // Use CSS variable managed by `useVirtualKeyboard`
593
+ paddingBottom: 'var(--keyboard-inset-height)',
594
+ // Alternatively apply keyboard padding via pixel value (maybe you want to add some extra padding to it)
595
+ paddingBottom: keyboardHeight,
596
+ // Some layout styles for custom content
597
+ height: '100%',
598
+ display: 'grid',
599
+ gridTemplateRows: 'auto 1fr auto',
600
+ }}
601
+ >
602
+ <div>Some content here...</div>
603
+
604
+ <div
605
+ // Pass ref to the custom scroller so we can track its scroll position
606
+ ref={scrollRef}
607
+ // Make it scrollable
608
+ style={{ overflowY: 'auto' }}
609
+ >
610
+ <div style={{ height: '400vh' }}>Long content here...</div>
611
+ </div>
612
+
613
+ <div>More content here...</div>
614
+ </div>
615
+ </Sheet.Content>
616
+ </Sheet.Container>
617
+ <Sheet.Backdrop />
618
+ </Sheet>
619
+ );
620
+ }
621
+ ```
622
+
451
623
  ### 🪟 iOS Modal View effect
452
624
 
453
625
  In addition to the `Sheet.Backdrop` it's possible to apply a scaling effect to the main app element to highlight the modality of the bottom sheet. This effect mimics the [iOS Modal View](https://developer.apple.com/design/human-interface-guidelines/ios/app-architecture/modality/) presentation style to bring more focus to the sheet and add some delight to the user experience.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { EasingDefinition, motion, MotionValue } from 'motion/react';
1
+ import { EasingDefinition, motion, MotionProps, MotionValue } from 'motion/react';
2
2
  import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject } from 'react';
3
3
 
4
4
  type SheetDetent = 'default' | 'full' | 'content';
@@ -47,6 +47,8 @@ type SheetContentProps = MotionCommonProps & CommonProps & {
47
47
  disableDrag?: boolean | ((args: SheetStateInfo) => boolean);
48
48
  disableScroll?: boolean | ((args: SheetStateInfo) => boolean);
49
49
  scrollRef?: RefObject<HTMLDivElement | null>;
50
+ scrollClassName?: string;
51
+ scrollStyle?: MotionProps['style'];
50
52
  };
51
53
  type SheetBackdropProps = MotionCommonProps & CommonProps;
52
54
  type SheetDragIndicatorProps = HTMLAttributes<HTMLDivElement> & CommonProps;
@@ -73,6 +75,112 @@ interface SheetCompoundComponent {
73
75
  }
74
76
  type SheetCompound = SheetComponent & SheetCompoundComponent;
75
77
 
78
+ type UseScrollPositionOptions = {
79
+ /**
80
+ * Debounce delay in ms for scroll event handling.
81
+ * @default 32
82
+ */
83
+ debounceDelay?: number;
84
+ /**
85
+ * Enable or disable the hook entirely.
86
+ * @default true
87
+ */
88
+ isEnabled?: boolean;
89
+ };
90
+ /**
91
+ * Hook to track the scroll position of an element.
92
+ *
93
+ * The scroll position can be 'top', 'bottom', 'middle', or undefined if the content is not scrollable.
94
+ * The hook provides a `scrollRef` callback to assign to the scrollable element.
95
+ *
96
+ * Note that the scroll position is only updated when the user stops scrolling
97
+ * for a short moment (debounced). You can set `debounceDelay` to `0` to disable debouncing entirely.
98
+ *
99
+ * @param options Configuration options for the hook.
100
+ * @returns An object containing the `scrollRef` callback and the current `scrollPosition`.
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * import { useScrollPosition } from 'react-modal-sheet';
105
+ *
106
+ * function MyComponent() {
107
+ * const { scrollRef, scrollPosition } = useScrollPosition();
108
+ *
109
+ * return (
110
+ * <div>
111
+ * <p>Scroll position: {scrollPosition}</p>
112
+ * <div ref={scrollRef} style={{ overflowY: 'auto', maxHeight: '300px' }}>
113
+ * ...long content...
114
+ * </div>
115
+ * </div>
116
+ * );
117
+ * }
118
+ * ```
119
+ */
120
+ declare function useScrollPosition(options?: UseScrollPositionOptions): {
121
+ scrollRef: (element: HTMLElement | null) => void;
122
+ scrollPosition: "top" | "bottom" | "middle" | undefined;
123
+ };
124
+
125
+ type UseVirtualKeyboardOptions = {
126
+ /**
127
+ * Ref to the container element to apply `keyboard-inset-height` CSS variable updates.
128
+ * @default document.documentElement
129
+ */
130
+ containerRef?: RefObject<HTMLElement | null>;
131
+ /**
132
+ * Enable or disable the hook entirely.
133
+ * @default true
134
+ */
135
+ isEnabled?: boolean;
136
+ /**
137
+ * Minimum pixel height difference to consider the keyboard visible.
138
+ * @default 100
139
+ */
140
+ visualViewportThreshold?: number;
141
+ /**
142
+ * Whether to treat contenteditable elements as text inputs.
143
+ * @default true
144
+ */
145
+ includeContentEditable?: boolean;
146
+ /**
147
+ * Delay in ms for debouncing viewport changes.
148
+ * @default 100
149
+ */
150
+ debounceDelay?: number;
151
+ };
152
+ /**
153
+ * A hook that detects virtual keyboard visibility and height.
154
+ * It listens to focus events and visual viewport changes to determine
155
+ * if a text input is focused and the keyboard is likely visible.
156
+ *
157
+ * It also sets the `--keyboard-inset-height` CSS variable on the specified container
158
+ * (or `:root` by default) to allow for easy styling adjustments when the keyboard is open.
159
+ *
160
+ * @param options Configuration options for the hook.
161
+ * @returns An object containing `isKeyboardOpen` and `keyboardHeight`.
162
+ *
163
+ * @example
164
+ * ```tsx
165
+ * import { useVirtualKeyboard } from 'react-modal-sheet';
166
+ *
167
+ * function MyComponent() {
168
+ * const { isKeyboardOpen, keyboardHeight } = useVirtualKeyboard();
169
+ *
170
+ * return (
171
+ * <div>
172
+ * <p>Keyboard is {isKeyboardOpen ? 'open' : 'closed'}</p>
173
+ * <p>Keyboard height: {keyboardHeight}px</p>
174
+ * </div>
175
+ * );
176
+ * }
177
+ * ```
178
+ */
179
+ declare function useVirtualKeyboard(options?: UseVirtualKeyboardOptions): {
180
+ keyboardHeight: number;
181
+ isKeyboardOpen: boolean;
182
+ };
183
+
76
184
  interface SheetRef {
77
185
  y: MotionValue<number>;
78
186
  yInverted: MotionValue<number>;
@@ -81,4 +189,4 @@ interface SheetRef {
81
189
  }
82
190
  declare const Sheet: SheetCompound;
83
191
 
84
- export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig };
192
+ export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig, useScrollPosition, useVirtualKeyboard };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EasingDefinition, motion, MotionValue } from 'motion/react';
1
+ import { EasingDefinition, motion, MotionProps, MotionValue } from 'motion/react';
2
2
  import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject } from 'react';
3
3
 
4
4
  type SheetDetent = 'default' | 'full' | 'content';
@@ -47,6 +47,8 @@ type SheetContentProps = MotionCommonProps & CommonProps & {
47
47
  disableDrag?: boolean | ((args: SheetStateInfo) => boolean);
48
48
  disableScroll?: boolean | ((args: SheetStateInfo) => boolean);
49
49
  scrollRef?: RefObject<HTMLDivElement | null>;
50
+ scrollClassName?: string;
51
+ scrollStyle?: MotionProps['style'];
50
52
  };
51
53
  type SheetBackdropProps = MotionCommonProps & CommonProps;
52
54
  type SheetDragIndicatorProps = HTMLAttributes<HTMLDivElement> & CommonProps;
@@ -73,6 +75,112 @@ interface SheetCompoundComponent {
73
75
  }
74
76
  type SheetCompound = SheetComponent & SheetCompoundComponent;
75
77
 
78
+ type UseScrollPositionOptions = {
79
+ /**
80
+ * Debounce delay in ms for scroll event handling.
81
+ * @default 32
82
+ */
83
+ debounceDelay?: number;
84
+ /**
85
+ * Enable or disable the hook entirely.
86
+ * @default true
87
+ */
88
+ isEnabled?: boolean;
89
+ };
90
+ /**
91
+ * Hook to track the scroll position of an element.
92
+ *
93
+ * The scroll position can be 'top', 'bottom', 'middle', or undefined if the content is not scrollable.
94
+ * The hook provides a `scrollRef` callback to assign to the scrollable element.
95
+ *
96
+ * Note that the scroll position is only updated when the user stops scrolling
97
+ * for a short moment (debounced). You can set `debounceDelay` to `0` to disable debouncing entirely.
98
+ *
99
+ * @param options Configuration options for the hook.
100
+ * @returns An object containing the `scrollRef` callback and the current `scrollPosition`.
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * import { useScrollPosition } from 'react-modal-sheet';
105
+ *
106
+ * function MyComponent() {
107
+ * const { scrollRef, scrollPosition } = useScrollPosition();
108
+ *
109
+ * return (
110
+ * <div>
111
+ * <p>Scroll position: {scrollPosition}</p>
112
+ * <div ref={scrollRef} style={{ overflowY: 'auto', maxHeight: '300px' }}>
113
+ * ...long content...
114
+ * </div>
115
+ * </div>
116
+ * );
117
+ * }
118
+ * ```
119
+ */
120
+ declare function useScrollPosition(options?: UseScrollPositionOptions): {
121
+ scrollRef: (element: HTMLElement | null) => void;
122
+ scrollPosition: "top" | "bottom" | "middle" | undefined;
123
+ };
124
+
125
+ type UseVirtualKeyboardOptions = {
126
+ /**
127
+ * Ref to the container element to apply `keyboard-inset-height` CSS variable updates.
128
+ * @default document.documentElement
129
+ */
130
+ containerRef?: RefObject<HTMLElement | null>;
131
+ /**
132
+ * Enable or disable the hook entirely.
133
+ * @default true
134
+ */
135
+ isEnabled?: boolean;
136
+ /**
137
+ * Minimum pixel height difference to consider the keyboard visible.
138
+ * @default 100
139
+ */
140
+ visualViewportThreshold?: number;
141
+ /**
142
+ * Whether to treat contenteditable elements as text inputs.
143
+ * @default true
144
+ */
145
+ includeContentEditable?: boolean;
146
+ /**
147
+ * Delay in ms for debouncing viewport changes.
148
+ * @default 100
149
+ */
150
+ debounceDelay?: number;
151
+ };
152
+ /**
153
+ * A hook that detects virtual keyboard visibility and height.
154
+ * It listens to focus events and visual viewport changes to determine
155
+ * if a text input is focused and the keyboard is likely visible.
156
+ *
157
+ * It also sets the `--keyboard-inset-height` CSS variable on the specified container
158
+ * (or `:root` by default) to allow for easy styling adjustments when the keyboard is open.
159
+ *
160
+ * @param options Configuration options for the hook.
161
+ * @returns An object containing `isKeyboardOpen` and `keyboardHeight`.
162
+ *
163
+ * @example
164
+ * ```tsx
165
+ * import { useVirtualKeyboard } from 'react-modal-sheet';
166
+ *
167
+ * function MyComponent() {
168
+ * const { isKeyboardOpen, keyboardHeight } = useVirtualKeyboard();
169
+ *
170
+ * return (
171
+ * <div>
172
+ * <p>Keyboard is {isKeyboardOpen ? 'open' : 'closed'}</p>
173
+ * <p>Keyboard height: {keyboardHeight}px</p>
174
+ * </div>
175
+ * );
176
+ * }
177
+ * ```
178
+ */
179
+ declare function useVirtualKeyboard(options?: UseVirtualKeyboardOptions): {
180
+ keyboardHeight: number;
181
+ isKeyboardOpen: boolean;
182
+ };
183
+
76
184
  interface SheetRef {
77
185
  y: MotionValue<number>;
78
186
  yInverted: MotionValue<number>;
@@ -81,4 +189,4 @@ interface SheetRef {
81
189
  }
82
190
  declare const Sheet: SheetCompound;
83
191
 
84
- export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig };
192
+ export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig, useScrollPosition, useVirtualKeyboard };
package/dist/index.js CHANGED
@@ -277,12 +277,12 @@ function useDragConstraints() {
277
277
  const onMeasure = React4.useCallback(() => constraints, []);
278
278
  return { ref, onMeasure };
279
279
  }
280
- function useScrollPosition() {
281
- const ref = React4.useRef(null);
280
+ function useScrollPosition(options = {}) {
281
+ const { debounceDelay = 32, isEnabled = true } = options;
282
+ const [element, setElement] = React4.useState(null);
282
283
  const [scrollPosition, setScrollPosition] = React4.useState(void 0);
283
284
  React4.useEffect(() => {
284
- const element = ref.current;
285
- if (!element) return;
285
+ if (!element || !isEnabled) return;
286
286
  let scrollTimeout = null;
287
287
  function determineScrollPosition(element2) {
288
288
  const { scrollTop, scrollHeight, clientHeight } = element2;
@@ -305,14 +305,21 @@ function useScrollPosition() {
305
305
  setScrollPosition(position);
306
306
  }
307
307
  function onScroll(event) {
308
- if (event.currentTarget instanceof HTMLDivElement) {
308
+ if (event.currentTarget instanceof HTMLElement) {
309
309
  const el = event.currentTarget;
310
310
  if (scrollTimeout) clearTimeout(scrollTimeout);
311
- scrollTimeout = setTimeout(() => determineScrollPosition(el), 32);
311
+ if (debounceDelay === 0) {
312
+ determineScrollPosition(el);
313
+ } else {
314
+ scrollTimeout = setTimeout(
315
+ () => determineScrollPosition(el),
316
+ debounceDelay
317
+ );
318
+ }
312
319
  }
313
320
  }
314
321
  function onTouchStart(event) {
315
- if (event.currentTarget instanceof HTMLDivElement) {
322
+ if (event.currentTarget instanceof HTMLElement) {
316
323
  determineScrollPosition(event.currentTarget);
317
324
  }
318
325
  }
@@ -324,8 +331,11 @@ function useScrollPosition() {
324
331
  element.removeEventListener("scroll", onScroll);
325
332
  element.removeEventListener("touchstart", onTouchStart);
326
333
  };
327
- }, []);
328
- return { ref, scrollPosition };
334
+ }, [element, isEnabled]);
335
+ return {
336
+ scrollRef: (element2) => setElement(element2),
337
+ scrollPosition
338
+ };
329
339
  }
330
340
 
331
341
  // src/SheetContent.tsx
@@ -336,6 +346,8 @@ var SheetContent = React4.forwardRef(
336
346
  children,
337
347
  style: styleProp,
338
348
  className = "",
349
+ scrollClassName = "",
350
+ scrollStyle: scrollStyleProp,
339
351
  scrollRef: scrollRefProp = null,
340
352
  unstyled,
341
353
  ...rest
@@ -380,9 +392,9 @@ var SheetContent = React4.forwardRef(
380
392
  /* @__PURE__ */ React4__default.default.createElement(
381
393
  react.motion.div,
382
394
  {
383
- ref: mergeRefs([scroll.ref, scrollRefProp]),
384
- style: scrollStyle,
385
- className: "react-modal-sheet-content-scroller"
395
+ ref: mergeRefs([scroll.scrollRef, scrollRefProp]),
396
+ style: { ...scrollStyle, ...scrollStyleProp },
397
+ className: `react-modal-sheet-content-scroller ${scrollClassName}`
386
398
  },
387
399
  children
388
400
  )
@@ -880,13 +892,14 @@ function useSheetState({
880
892
  }, [state]);
881
893
  return state;
882
894
  }
883
- function useVirtualKeyboard({
884
- containerRef,
885
- isEnabled = true,
886
- debounceDelay = 100,
887
- includeContentEditable = true,
888
- visualViewportThreshold = 100
889
- }) {
895
+ function useVirtualKeyboard(options = {}) {
896
+ const {
897
+ containerRef,
898
+ isEnabled = true,
899
+ debounceDelay = 100,
900
+ includeContentEditable = true,
901
+ visualViewportThreshold = 100
902
+ } = options;
890
903
  const [state, setState] = React4.useState({
891
904
  isVisible: false,
892
905
  height: 0
@@ -901,11 +914,15 @@ function useVirtualKeyboard({
901
914
  const vv = window.visualViewport;
902
915
  const vk = navigator.virtualKeyboard;
903
916
  function setKeyboardInsetHeightEnv(height) {
904
- var _a;
905
- (_a = containerRef.current) == null ? void 0 : _a.style.setProperty(
906
- "--keyboard-inset-height",
907
- `${height}px`
908
- );
917
+ const element = (containerRef == null ? void 0 : containerRef.current) || document.documentElement;
918
+ if (window.isSecureContext) {
919
+ element.style.setProperty(
920
+ "--keyboard-inset-height",
921
+ `env(keyboard-inset-height, ${height}px)`
922
+ );
923
+ } else {
924
+ element.style.setProperty("--keyboard-inset-height", `${height}px`);
925
+ }
909
926
  }
910
927
  function handleFocusIn(e) {
911
928
  if (e.target instanceof HTMLElement && isTextInput(e.target)) {
@@ -1358,5 +1375,7 @@ var Sheet2 = Object.assign(Sheet, {
1358
1375
  });
1359
1376
 
1360
1377
  exports.Sheet = Sheet2;
1378
+ exports.useScrollPosition = useScrollPosition;
1379
+ exports.useVirtualKeyboard = useVirtualKeyboard;
1361
1380
  //# sourceMappingURL=index.js.map
1362
1381
  //# sourceMappingURL=index.js.map