react-modal-sheet 5.4.1 → 5.6.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/README.md +263 -88
- package/dist/index.d.mts +16 -7
- package/dist/index.d.ts +16 -7
- package/dist/index.js +668 -610
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +664 -606
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/context.tsx +16 -6
- package/src/hooks/use-modal-effect.ts +87 -82
- package/src/index.tsx +11 -16
- package/src/{SheetBackdrop.tsx → sheet-backdrop.tsx} +3 -12
- package/src/{SheetContainer.tsx → sheet-container.tsx} +2 -2
- package/src/{SheetContent.tsx → sheet-content.tsx} +9 -3
- package/src/{SheetDragIndicator.tsx → sheet-drag-indicator.tsx} +2 -2
- package/src/{SheetHeader.tsx → sheet-header.tsx} +3 -3
- package/src/sheet.tsx +58 -85
- package/src/snap.ts +202 -103
- package/src/types.tsx +13 -1
- package/src/utils.ts +4 -0
package/README.md
CHANGED
|
@@ -37,12 +37,12 @@ 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)
|
|
41
40
|
- [Usage](#-usage)
|
|
42
41
|
- [Props](#%EF%B8%8F-props)
|
|
43
42
|
- [Methods and properties](#%EF%B8%8F-methods-and-properties)
|
|
43
|
+
- [Detents](#-detents)
|
|
44
44
|
- [Compound Components](#-compound-components)
|
|
45
|
-
- [Advanced
|
|
45
|
+
- [Advanced behavior](#-advanced-behavior)
|
|
46
46
|
- [Customization](#-customization)
|
|
47
47
|
- [Accessibility](#%EF%B8%8F-accessibility)
|
|
48
48
|
- [Troubleshooting](#-troubleshooting)
|
|
@@ -50,39 +50,6 @@ npm install motion
|
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
53
|
-
## 🎉 What's new in v5
|
|
54
|
-
|
|
55
|
-
Version 5 introduces several major improvements and breaking changes:
|
|
56
|
-
|
|
57
|
-
### 🔄 Breaking Changes
|
|
58
|
-
|
|
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
|
|
62
|
-
- **Snap point order reversed**: Snap points now use ascending order (e.g., `[0, 0.5, 1]` instead of `[1, 0.5, 0]`)
|
|
63
|
-
- This aligns better with other bottom sheet libraries and makes more intuitive sense
|
|
64
|
-
- **Detent prop values changed**:
|
|
65
|
-
- `"full-height"` → `"default"`
|
|
66
|
-
- `"content-height"` → `"content"`
|
|
67
|
-
- New `"full"` detent for viewport-filling sheets
|
|
68
|
-
|
|
69
|
-
### ✨ New Features
|
|
70
|
-
|
|
71
|
-
- **Built-in keyboard avoidance**: Best-effort automatic virtual keyboard handling with the `avoidKeyboard` prop
|
|
72
|
-
- **Enhanced scroll control**: Dynamic `disableScroll` and `disableDrag` functions with scroll state
|
|
73
|
-
- **Improved snap point handling**: Better snap point calculation and more natural snapping between points
|
|
74
|
-
- **New sheet properties**: Access `height` and `yInverted` motion values via ref
|
|
75
|
-
- **Prevent dismissal**: New `disableDismiss` prop to prevent sheet from being closed by user gestures
|
|
76
|
-
|
|
77
|
-
### 🔧 Migration from v4
|
|
78
|
-
|
|
79
|
-
1. Remove all `Sheet.Scroller` components - content is now scrollable by default
|
|
80
|
-
2. Reverse your snap point arrays: `[1, 0.5, 0]` → `[0, 0.5, 1]`
|
|
81
|
-
3. Update detent props: `detent="full-height"` → `detent="default"`
|
|
82
|
-
4. Review virtual keyboard handling - it's now automatic with `avoidKeyboard={true}`
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
53
|
## 💻 Usage
|
|
87
54
|
|
|
88
55
|
```tsx
|
|
@@ -144,20 +111,134 @@ Also, by constructing the sheet from smaller pieces makes it easier to apply any
|
|
|
144
111
|
|
|
145
112
|
## ⚙️ Methods and properties
|
|
146
113
|
|
|
114
|
+
React Modal Sheet exposes several methods and properties that can be accessed via a ref or the sheet context.
|
|
115
|
+
|
|
116
|
+
These allow you to imperatively control the sheet's behavior and access its internal state.
|
|
117
|
+
|
|
118
|
+
| Name | Type | Description |
|
|
119
|
+
| --------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
120
|
+
| `y` | `MotionValue<number>` | Current sheet Y position where `0` means fully open at the top. |
|
|
121
|
+
| `yInverted` | `MotionValue<number>` | Inverse of `y`, representing distance from the bottom of the sheet. |
|
|
122
|
+
| `yProgress` | `MotionValue<number>` | Normalized open progress from `0` (closed) to `1` (fully open). |
|
|
123
|
+
| `height` | `number` | Current measured sheet height in pixels. |
|
|
124
|
+
| `currentSnap` | `number \| undefined` | Current active snap point index. `undefined` when snap points are not used. |
|
|
125
|
+
| `snapPoints` | `SheetSnapPoint[]` | Computed snap points with: `snapIndex` index of the snap point, `snapValue` computed pixel value (maps to given `snapPoints` prop values - eg. `0.5` becomes an actual pixel value), `snapValueY` inverted snap pixel value. |
|
|
126
|
+
| `snapTo(index)` | `(index: number) => void` | Imperatively snaps the sheet to a snap point index. Requires `snapPoints` prop. Index `0` closes the sheet. |
|
|
127
|
+
|
|
128
|
+
There are two ways to access sheet methods and properties:
|
|
129
|
+
|
|
130
|
+
1. Via a ref using `useRef`
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { Sheet, type SheetRef } from 'react-modal-sheet';
|
|
134
|
+
import { useRef } from 'react';
|
|
135
|
+
|
|
136
|
+
function RefExample() {
|
|
137
|
+
const sheetRef = useRef<SheetRef>(null);
|
|
138
|
+
|
|
139
|
+
// Then use eg. `sheetRef.current.snapTo()` or `sheetRef.current.y`, etc.
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<Sheet ref={sheetRef}>
|
|
143
|
+
<Sheet.Container>
|
|
144
|
+
<Sheet.Header />
|
|
145
|
+
<Sheet.Content>{/* Your content here */}</Sheet.Content>
|
|
146
|
+
</Sheet.Container>
|
|
147
|
+
<Sheet.Backdrop />
|
|
148
|
+
</Sheet>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
> [!IMPORTANT]
|
|
154
|
+
> [React's rules about refs](https://react.dev/reference/react/useRef#caveats) apply here so don't read the sheet ref during render. If you need to access sheet methods or properties during render, use the `Sheet.useContext` hook instead.
|
|
155
|
+
|
|
156
|
+
2. Via the `Sheet.useContext` hook from any child component of the sheet
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
import { Sheet } from 'react-modal-sheet';
|
|
160
|
+
|
|
161
|
+
function ContextExample() {
|
|
162
|
+
return (
|
|
163
|
+
<Sheet>
|
|
164
|
+
<SheetContainer />
|
|
165
|
+
<Sheet.Backdrop />
|
|
166
|
+
</Sheet>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* NOTE: you need to define a separate component for using the `Sheet.useContext`
|
|
172
|
+
* hook since it can only be used within the sheet component tree.
|
|
173
|
+
*/
|
|
174
|
+
function SheetContainer() {
|
|
175
|
+
const context = Sheet.useContext();
|
|
176
|
+
|
|
177
|
+
// Then use eg. `context.snapTo()` or `context.y`, etc.
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<Sheet.Container>
|
|
181
|
+
<Sheet.Header />
|
|
182
|
+
<Sheet.Content>{/* Your content here */}</Sheet.Content>
|
|
183
|
+
</Sheet.Container>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
> [!TIP]
|
|
189
|
+
> You generally want to prefer the `Sheet.useContext` hook when possible since it doesn't require you to manage refs and works seamlessly with React's declarative nature. However, there are some cases where using a ref might be more convenient, eg. when you need to access sheet methods from outside the sheet component tree.
|
|
190
|
+
>
|
|
191
|
+
> If you want to avoid creating a separate component just for using the `Sheet.useContext` hook, you can also create a reusable component that uses render-props pattern to expose the sheet context:
|
|
192
|
+
>
|
|
193
|
+
> ```tsx
|
|
194
|
+
> import { ReactNode } from 'react';
|
|
195
|
+
> import { Sheet, type SheetContext } from 'react-modal-sheet';
|
|
196
|
+
>
|
|
197
|
+
> // Generic render-prop helper component
|
|
198
|
+
> function WithSheetContext({
|
|
199
|
+
> children,
|
|
200
|
+
> }: {
|
|
201
|
+
> children: (context: SheetContext) => ReactNode;
|
|
202
|
+
> }) {
|
|
203
|
+
> const context = Sheet.useContext();
|
|
204
|
+
> return <>{children(context)}</>;
|
|
205
|
+
> }
|
|
206
|
+
>
|
|
207
|
+
> // Usage
|
|
208
|
+
> function ContextExample() {
|
|
209
|
+
> return (
|
|
210
|
+
> <Sheet snapPoints={[0, 0.5, 1]} initialSnap={1}>
|
|
211
|
+
> <WithSheetContext>
|
|
212
|
+
> {(context) => (
|
|
213
|
+
> <Sheet.Container>
|
|
214
|
+
> <Sheet.Header />
|
|
215
|
+
> <Sheet.Content>
|
|
216
|
+
> <button onClick={() => context.snapTo(2)}>
|
|
217
|
+
> Snap to index 2
|
|
218
|
+
> </button>
|
|
219
|
+
> </Sheet.Content>
|
|
220
|
+
> </Sheet.Container>
|
|
221
|
+
> )}
|
|
222
|
+
> </WithSheetContext>
|
|
223
|
+
> </Sheet>
|
|
224
|
+
> );
|
|
225
|
+
> }
|
|
226
|
+
> ```
|
|
227
|
+
|
|
147
228
|
### `snapTo(index)`
|
|
148
229
|
|
|
149
|
-
Imperative method
|
|
230
|
+
Imperative method for snapping to a snap point in given index.
|
|
150
231
|
|
|
151
232
|
```tsx
|
|
152
|
-
import { Sheet, SheetRef } from 'react-modal-sheet';
|
|
233
|
+
import { Sheet, type SheetRef } from 'react-modal-sheet';
|
|
153
234
|
import { useState, useRef } from 'react';
|
|
154
235
|
|
|
155
236
|
const snapPoints = [0, 0.5, 1];
|
|
156
237
|
|
|
157
238
|
function SnapExample() {
|
|
158
239
|
const [isOpen, setOpen] = useState(false);
|
|
159
|
-
const
|
|
160
|
-
const snapTo = (i: number) =>
|
|
240
|
+
const sheetRef = useRef<SheetRef>(null);
|
|
241
|
+
const snapTo = (i: number) => sheetRef.current?.snapTo(i);
|
|
161
242
|
|
|
162
243
|
return (
|
|
163
244
|
<>
|
|
@@ -165,13 +246,13 @@ function SnapExample() {
|
|
|
165
246
|
|
|
166
247
|
{/* Opens to 50% since initial index is 1 */}
|
|
167
248
|
<Sheet
|
|
168
|
-
ref={
|
|
249
|
+
ref={sheetRef}
|
|
169
250
|
isOpen={isOpen}
|
|
170
251
|
onClose={() => setOpen(false)}
|
|
171
252
|
initialSnap={1}
|
|
172
253
|
snapPoints={snapPoints}
|
|
173
254
|
onSnap={(snapIndex) =>
|
|
174
|
-
console.log('
|
|
255
|
+
console.log('Current snap point index:', snapIndex)
|
|
175
256
|
}
|
|
176
257
|
>
|
|
177
258
|
<Sheet.Container>
|
|
@@ -187,69 +268,163 @@ function SnapExample() {
|
|
|
187
268
|
}
|
|
188
269
|
```
|
|
189
270
|
|
|
190
|
-
### Motion values
|
|
191
|
-
|
|
192
|
-
The `y` value is an internal [MotionValue](https://motion.dev/docs/react-motion-value) that represents the distance to the top most position of the sheet when it is fully open. So for example the `y` value is zero when the sheet is completely open.
|
|
271
|
+
### Internal Motion values
|
|
193
272
|
|
|
194
|
-
The `yInverted
|
|
273
|
+
The `y`, `yInverted`, and `yProgress` values are [MotionValues](https://motion.dev/docs/react-motion-value). The `y` value is the core animated value that drives the sheet's position while dragging and snapping whereas `yInverted` and `yProgress` are derived from `y` and can be used for various animation effects or calculations based on the sheet's position.
|
|
195
274
|
|
|
196
|
-
The `
|
|
197
|
-
|
|
198
|
-
|
|
275
|
+
- The `y` value represents the distance to the top most position of the sheet when it is fully open. So for example the `y` value is zero when the sheet is completely open.
|
|
276
|
+
- The `yInverted` value is the inverse of the `y` value and represents the distance from the bottom of the sheet. This can be useful for certain animations or calculations.
|
|
277
|
+
- The `yProgress` value is a normalized value between 0 and 1 that represents how open the sheet is, where 0 means fully closed and 1 means fully open. This can be useful for triggering animations or effects based on how open the sheet is.
|
|
199
278
|
|
|
200
279
|
Below you can see an example of how to use these values:
|
|
201
280
|
|
|
202
281
|
```tsx
|
|
203
|
-
import { Sheet, SheetRef } from 'react-modal-sheet';
|
|
204
|
-
import { useTransform } from 'motion/react';
|
|
205
|
-
import {
|
|
282
|
+
import { Sheet, type SheetRef } from 'react-modal-sheet';
|
|
283
|
+
import { useTransform, interpolate } from 'motion/react';
|
|
284
|
+
import { useRef } from 'react';
|
|
206
285
|
|
|
207
286
|
function RefExample() {
|
|
208
|
-
const
|
|
209
|
-
const ref = useRef<SheetRef>(null);
|
|
287
|
+
const sheetRef = useRef<SheetRef>(null);
|
|
210
288
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
289
|
+
/**
|
|
290
|
+
* Example 1: Fade out an element as the sheet gets close to being fully open:
|
|
291
|
+
* - y: 0% - 50% → opacity 1
|
|
292
|
+
* - y: 50% - 60% → opacity fades from 1 to 0
|
|
293
|
+
* - y: 60% - 100% → opacity stays at 0
|
|
294
|
+
*/
|
|
295
|
+
const opacity = useTransform(() => {
|
|
296
|
+
const progress = sheetRef?.yProgress.get() ?? 0;
|
|
297
|
+
const mix = interpolate([0, 0.5, 0.6], [1, 1, 0]);
|
|
298
|
+
return mix(progress);
|
|
214
299
|
});
|
|
215
300
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
console.log('> Current yInverted value:', ref.current?.yInverted.get());
|
|
219
|
-
console.log('> Current height value:', ref.current?.height);
|
|
220
|
-
}
|
|
301
|
+
return <Sheet ref={sheetRef}>{/* ... */}</Sheet>;
|
|
302
|
+
}
|
|
221
303
|
|
|
304
|
+
function ContextExample() {
|
|
222
305
|
return (
|
|
223
|
-
|
|
224
|
-
<
|
|
306
|
+
<Sheet>
|
|
307
|
+
<InnerComponent />
|
|
308
|
+
</Sheet>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
225
311
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
312
|
+
function InnerComponent() {
|
|
313
|
+
const context = Sheet.useContext();
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Example 2: Add padding to some content based on how far the sheet is dragged:
|
|
317
|
+
* - y: 0px - 100px → padding 16px to 8px
|
|
318
|
+
* - y: 100px - 200px → padding 8px to 0px
|
|
319
|
+
* - y: > 200px → padding 0px
|
|
320
|
+
*/
|
|
321
|
+
const padding = useTransform(context.yInverted, (value) => {
|
|
322
|
+
const mix = interpolate([0, 100, 200], [16, 8, 0]);
|
|
323
|
+
return mix(value);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Animating based on snap points
|
|
329
|
+
|
|
330
|
+
One cool technique you can use is to animate properties based on the snap point thresholds.
|
|
331
|
+
|
|
332
|
+
For example, you can easily create a custom hook that takes an array of output values corresponding to the snap points and returns a `MotionValue` that updates as the sheet is dragged and snaps to different points:
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
import { interpolate, useTransform } from 'motion/react';
|
|
336
|
+
import { Sheet } from 'react-modal-sheet';
|
|
337
|
+
|
|
338
|
+
export function useSnapPointTransform(
|
|
339
|
+
/** The output values corresponding to the snap points. Must have the same length as snap points array */
|
|
340
|
+
output: number[],
|
|
341
|
+
/** The default value to return during the first render when snap points are not yet calculated */
|
|
342
|
+
defaultValue?: number
|
|
343
|
+
) {
|
|
344
|
+
const { snapPoints, y } = Sheet.useContext();
|
|
345
|
+
|
|
346
|
+
return useTransform(y, (val) => {
|
|
347
|
+
const firstValue = output[0];
|
|
348
|
+
|
|
349
|
+
if (firstValue === undefined) {
|
|
350
|
+
throw new Error('Output array must have at least one value');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (snapPoints.length === 0) {
|
|
354
|
+
return defaultValue ?? firstValue;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (output.length !== snapPoints.length) {
|
|
358
|
+
throw new Error('Output array must have the same length as snap points');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const mix = interpolate(
|
|
362
|
+
snapPoints.map((point) => point.snapValueY),
|
|
363
|
+
output
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
return mix(val);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function SnapPointAnimationExample() {
|
|
371
|
+
return (
|
|
372
|
+
// Provide snap points that `useSnapPointTransform` can use for interpolation
|
|
373
|
+
<Sheet snapPoints={[0, 0.5, 0.7, 1]}>
|
|
374
|
+
<SheetContainer>
|
|
375
|
+
<Sheet.Header />
|
|
376
|
+
<Sheet.Content> {/* Some content here */}</Sheet.Content>
|
|
377
|
+
</SheetContainer>
|
|
378
|
+
<SheetBackdrop />
|
|
379
|
+
</Sheet>
|
|
237
380
|
);
|
|
238
381
|
}
|
|
382
|
+
|
|
383
|
+
function SheetContainer({ children }: { children: ReactNode }) {
|
|
384
|
+
/**
|
|
385
|
+
* Example: Animate border radius based on snap points:
|
|
386
|
+
* - snap point 0 - 1: border radius 32px
|
|
387
|
+
* - snap point 1 - 2: border radius 32px to 8px
|
|
388
|
+
* - snap point 2 - 3: border radius 8px to 0px
|
|
389
|
+
* - snap point 3: border radius 0px
|
|
390
|
+
*/
|
|
391
|
+
const borderRadius = useSnapPointTransform([32, 32, 8, 0]);
|
|
392
|
+
|
|
393
|
+
return (
|
|
394
|
+
<Sheet.Container
|
|
395
|
+
style={{
|
|
396
|
+
borderTopRightRadius: borderRadius,
|
|
397
|
+
borderTopLeftRadius: borderRadius,
|
|
398
|
+
}}
|
|
399
|
+
>
|
|
400
|
+
{children}
|
|
401
|
+
</Sheet.Container>
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function SheetBackdrop() {
|
|
406
|
+
// Fade in the backdrop between last two snap points
|
|
407
|
+
const opacity = useSnapPointTransform([0, 0, 0, 1]);
|
|
408
|
+
|
|
409
|
+
const backgroundColor = useMotionTemplate`
|
|
410
|
+
background-color: rgba(0, 0, 0, ${opacity});
|
|
411
|
+
`;
|
|
412
|
+
|
|
413
|
+
return <Sheet.Backdrop style={{ backgroundColor }} />;
|
|
414
|
+
}
|
|
239
415
|
```
|
|
240
416
|
|
|
417
|
+
See the [Apple Maps example](https://temzasse.github.io/react-modal-sheet/#/apple-maps) for a real-world example of this technique for animating elements based on snap point thresholds.
|
|
418
|
+
|
|
241
419
|
#### Making scrollable sheet content always reachable
|
|
242
420
|
|
|
243
|
-
One
|
|
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.
|
|
421
|
+
One potential use case for the `y` value is to apply padding bottom to the sheet content 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
422
|
|
|
246
|
-
> [!
|
|
247
|
-
>
|
|
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.
|
|
423
|
+
> [!TIP]
|
|
424
|
+
> 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
425
|
|
|
251
426
|
```tsx
|
|
252
|
-
import { Sheet, SheetRef } from 'react-modal-sheet';
|
|
427
|
+
import { Sheet, type SheetRef } from 'react-modal-sheet';
|
|
253
428
|
import { useTransform } from 'motion/react';
|
|
254
429
|
import { useState, useRef } from 'react';
|
|
255
430
|
|
|
@@ -257,11 +432,11 @@ const snapPoints = [0, 0.5, 1];
|
|
|
257
432
|
|
|
258
433
|
function PaddingExample() {
|
|
259
434
|
const [isOpen, setOpen] = useState(false);
|
|
260
|
-
const
|
|
435
|
+
const sheetRef = useRef<SheetRef>(null);
|
|
261
436
|
|
|
262
437
|
// Add padding bottom based on how far the sheet is from being fully open
|
|
263
438
|
const paddingBottom = useTransform(() => {
|
|
264
|
-
return
|
|
439
|
+
return sheetRef.current?.y.get() ?? 0;
|
|
265
440
|
});
|
|
266
441
|
|
|
267
442
|
return (
|
|
@@ -269,7 +444,7 @@ function PaddingExample() {
|
|
|
269
444
|
<button onClick={() => setOpen(true)}>Open sheet</button>
|
|
270
445
|
|
|
271
446
|
<Sheet
|
|
272
|
-
ref={
|
|
447
|
+
ref={sheetRef}
|
|
273
448
|
isOpen={isOpen}
|
|
274
449
|
onClose={() => setOpen(false)}
|
|
275
450
|
snapPoints={snapPoints}
|
|
@@ -293,7 +468,7 @@ function PaddingExample() {
|
|
|
293
468
|
}
|
|
294
469
|
```
|
|
295
470
|
|
|
296
|
-
|
|
471
|
+
## 🪜 Detents
|
|
297
472
|
|
|
298
473
|
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:
|
|
299
474
|
|
|
@@ -398,11 +573,11 @@ Sheet backdrop is a translucent overlay that helps to separate the sheet from it
|
|
|
398
573
|
|
|
399
574
|
> 🖥 Rendered element: `motion.div` or `motion.button`.
|
|
400
575
|
|
|
401
|
-
## ✨ Advanced
|
|
576
|
+
## ✨ Advanced behavior
|
|
402
577
|
|
|
403
578
|
### ⌨️ Virtual keyboard avoidance
|
|
404
579
|
|
|
405
|
-
React Modal Sheet
|
|
580
|
+
React Modal Sheet includes built-in virtual keyboard avoidance that works automatically on mobile devices.
|
|
406
581
|
When the `avoidKeyboard` prop is enabled (which is the default), the sheet will automatically add bottom padding to avoid the virtual keyboard covering input elements.
|
|
407
582
|
|
|
408
583
|
```tsx
|
|
@@ -949,7 +1124,7 @@ If you are using React `StrictMode` the sheet animations might not work as expec
|
|
|
949
1124
|
|
|
950
1125
|
### Upgrading from v4 to v5
|
|
951
1126
|
|
|
952
|
-
|
|
1127
|
+
The most common migration issues are:
|
|
953
1128
|
|
|
954
1129
|
1. **Snap points not working**: Ensure your snap points are in ascending order (`[0, 0.5, 1]` instead of `[1, 0.5, 0]`)
|
|
955
1130
|
2. **Scrolling issues**: Remove `Sheet.Scroller` components as scrolling is now handled by `Sheet.Content`
|
package/dist/index.d.mts
CHANGED
|
@@ -62,6 +62,15 @@ type SheetSnapPoint = {
|
|
|
62
62
|
snapValue: number;
|
|
63
63
|
snapValueY: number;
|
|
64
64
|
};
|
|
65
|
+
interface ExposedContextType {
|
|
66
|
+
currentSnap?: number;
|
|
67
|
+
height: number;
|
|
68
|
+
snapPoints: SheetSnapPoint[];
|
|
69
|
+
snapTo: (index: number) => void;
|
|
70
|
+
y: MotionValue<number>;
|
|
71
|
+
yInverted: MotionValue<number>;
|
|
72
|
+
yProgress: MotionValue<number>;
|
|
73
|
+
}
|
|
65
74
|
type SheetComponent = ForwardRefExoticComponent<SheetProps & RefAttributes<any>>;
|
|
66
75
|
type ContainerComponent = ForwardRefExoticComponent<SheetContainerProps & RefAttributes<any>>;
|
|
67
76
|
type HeaderComponent = ForwardRefExoticComponent<SheetHeaderProps & RefAttributes<any>>;
|
|
@@ -73,6 +82,7 @@ interface SheetCompoundComponent {
|
|
|
73
82
|
DragIndicator: FunctionComponent<SheetDragIndicatorProps>;
|
|
74
83
|
Content: ContentComponent;
|
|
75
84
|
Backdrop: BackdropComponent;
|
|
85
|
+
useContext: () => ExposedContextType;
|
|
76
86
|
}
|
|
77
87
|
type SheetCompound = SheetComponent & SheetCompoundComponent;
|
|
78
88
|
|
|
@@ -177,12 +187,11 @@ declare function useVirtualKeyboard(options?: UseVirtualKeyboardOptions): {
|
|
|
177
187
|
isKeyboardOpen: boolean;
|
|
178
188
|
};
|
|
179
189
|
|
|
180
|
-
interface SheetRef {
|
|
181
|
-
y: MotionValue<number>;
|
|
182
|
-
yInverted: MotionValue<number>;
|
|
183
|
-
height: number;
|
|
184
|
-
snapTo: (index: number) => Promise<void>;
|
|
185
|
-
}
|
|
186
190
|
declare const Sheet: SheetCompound;
|
|
187
191
|
|
|
188
|
-
|
|
192
|
+
interface SheetContext extends ExposedContextType {
|
|
193
|
+
}
|
|
194
|
+
interface SheetRef extends ExposedContextType {
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetContext, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig, useScrollPosition, useVirtualKeyboard };
|
package/dist/index.d.ts
CHANGED
|
@@ -62,6 +62,15 @@ type SheetSnapPoint = {
|
|
|
62
62
|
snapValue: number;
|
|
63
63
|
snapValueY: number;
|
|
64
64
|
};
|
|
65
|
+
interface ExposedContextType {
|
|
66
|
+
currentSnap?: number;
|
|
67
|
+
height: number;
|
|
68
|
+
snapPoints: SheetSnapPoint[];
|
|
69
|
+
snapTo: (index: number) => void;
|
|
70
|
+
y: MotionValue<number>;
|
|
71
|
+
yInverted: MotionValue<number>;
|
|
72
|
+
yProgress: MotionValue<number>;
|
|
73
|
+
}
|
|
65
74
|
type SheetComponent = ForwardRefExoticComponent<SheetProps & RefAttributes<any>>;
|
|
66
75
|
type ContainerComponent = ForwardRefExoticComponent<SheetContainerProps & RefAttributes<any>>;
|
|
67
76
|
type HeaderComponent = ForwardRefExoticComponent<SheetHeaderProps & RefAttributes<any>>;
|
|
@@ -73,6 +82,7 @@ interface SheetCompoundComponent {
|
|
|
73
82
|
DragIndicator: FunctionComponent<SheetDragIndicatorProps>;
|
|
74
83
|
Content: ContentComponent;
|
|
75
84
|
Backdrop: BackdropComponent;
|
|
85
|
+
useContext: () => ExposedContextType;
|
|
76
86
|
}
|
|
77
87
|
type SheetCompound = SheetComponent & SheetCompoundComponent;
|
|
78
88
|
|
|
@@ -177,12 +187,11 @@ declare function useVirtualKeyboard(options?: UseVirtualKeyboardOptions): {
|
|
|
177
187
|
isKeyboardOpen: boolean;
|
|
178
188
|
};
|
|
179
189
|
|
|
180
|
-
interface SheetRef {
|
|
181
|
-
y: MotionValue<number>;
|
|
182
|
-
yInverted: MotionValue<number>;
|
|
183
|
-
height: number;
|
|
184
|
-
snapTo: (index: number) => Promise<void>;
|
|
185
|
-
}
|
|
186
190
|
declare const Sheet: SheetCompound;
|
|
187
191
|
|
|
188
|
-
|
|
192
|
+
interface SheetContext extends ExposedContextType {
|
|
193
|
+
}
|
|
194
|
+
interface SheetRef extends ExposedContextType {
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { Sheet, type SheetBackdropProps, type SheetContainerProps, type SheetContentProps, type SheetContext, type SheetDetent, type SheetDragIndicatorProps, type SheetHeaderProps, type SheetProps, type SheetRef, type SheetSnapPoint, type SheetStateInfo, type SheetTweenConfig, useScrollPosition, useVirtualKeyboard };
|