react-modal-sheet 5.1.1 → 5.2.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 +114 -0
- package/dist/index.d.mts +110 -2
- package/dist/index.d.ts +110 -2
- package/dist/index.js +72 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +71 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/SheetContent.tsx +5 -3
- package/src/hooks/use-scroll-position.ts +69 -12
- package/src/hooks/use-virtual-keyboard.ts +58 -17
- package/src/index.tsx +3 -0
- package/src/sheet.tsx +10 -3
- package/src/snap.ts +17 -1
- package/src/types.tsx +10 -9
- package/src/utils.ts +21 -0
package/README.md
CHANGED
|
@@ -448,6 +448,82 @@ The scroll state provides:
|
|
|
448
448
|
- `scrollPosition`: `'top'`, `'bottom'`, `'middle'`, or `undefined`
|
|
449
449
|
- `currentSnap`: Current snap point index (if using snap points)
|
|
450
450
|
|
|
451
|
+
#### Creating custom scrollers
|
|
452
|
+
|
|
453
|
+
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.
|
|
454
|
+
|
|
455
|
+
> [!NOTE]
|
|
456
|
+
> 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 😊
|
|
457
|
+
|
|
458
|
+
```tsx
|
|
459
|
+
import {
|
|
460
|
+
Sheet,
|
|
461
|
+
useScrollPosition,
|
|
462
|
+
useVirtualKeyboard,
|
|
463
|
+
} from 'react-modal-sheet';
|
|
464
|
+
|
|
465
|
+
function CustomScrollerExample() {
|
|
466
|
+
const [isOpen, setOpen] = useState(false);
|
|
467
|
+
|
|
468
|
+
const { scrollRef, scrollPosition } = useScrollPosition({
|
|
469
|
+
isEnabled: isOpen,
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
const { keyboardHeight } = useVirtualKeyboard({
|
|
473
|
+
isEnabled: isOpen,
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* If you use `var(--keyboard-inset-height)` CSS variable you can just call
|
|
478
|
+
* `useVirtualKeyboard()` without destructuring anything from it:
|
|
479
|
+
*
|
|
480
|
+
* useVirtualKeyboard({ isEnabled: isOpen });
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
return (
|
|
484
|
+
// Disable default keyboard avoidance
|
|
485
|
+
<Sheet avoidKeyboard={false} isOpen={isOpen} onClose={() => setOpen(false)}>
|
|
486
|
+
<Sheet.Container>
|
|
487
|
+
<Sheet.Header />
|
|
488
|
+
<Sheet.Content
|
|
489
|
+
// Disable default scrolling
|
|
490
|
+
disableScroll
|
|
491
|
+
// Dragging is still managed by `Sheet.Content` so we control it here
|
|
492
|
+
disableDrag={scrollPosition !== 'top'}
|
|
493
|
+
>
|
|
494
|
+
<div
|
|
495
|
+
style={{
|
|
496
|
+
// Use CSS variable managed by `useVirtualKeyboard`
|
|
497
|
+
paddingBottom: 'var(--keyboard-inset-height)',
|
|
498
|
+
// Alternatively manually apply keyboard padding
|
|
499
|
+
paddingBottom: keyboardHeight,
|
|
500
|
+
// Some layout styles for custom content
|
|
501
|
+
height: '100%',
|
|
502
|
+
display: 'grid',
|
|
503
|
+
gridTemplateRows: 'auto 1fr auto',
|
|
504
|
+
}}
|
|
505
|
+
>
|
|
506
|
+
<div>Some content here...</div>
|
|
507
|
+
|
|
508
|
+
<div
|
|
509
|
+
// Pass ref to the custom scroller so we can track its scroll position
|
|
510
|
+
ref={scrollRef}
|
|
511
|
+
// Make it scrollable
|
|
512
|
+
style={{ overflowY: 'auto' }}
|
|
513
|
+
>
|
|
514
|
+
<div style={{ height: '400vh' }}>Long content here...</div>
|
|
515
|
+
</div>
|
|
516
|
+
|
|
517
|
+
<div>More content here...</div>
|
|
518
|
+
</div>
|
|
519
|
+
</Sheet.Content>
|
|
520
|
+
</Sheet.Container>
|
|
521
|
+
<Sheet.Backdrop />
|
|
522
|
+
</Sheet>
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
451
527
|
### 🪟 iOS Modal View effect
|
|
452
528
|
|
|
453
529
|
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.
|
|
@@ -778,3 +854,41 @@ If you're experiencing issues after upgrading, check the "What's new in v5" sect
|
|
|
778
854
|
1. **Snap points not working**: Ensure your snap points are in ascending order (`[0, 0.5, 1]` instead of `[1, 0.5, 0]`)
|
|
779
855
|
2. **Scrolling issues**: Remove `Sheet.Scroller` components as scrolling is now handled by `Sheet.Content`
|
|
780
856
|
3. **Detent errors**: Update detent prop values (`"full-height"` → `"default"`, `"content-height"` → `"content"`)
|
|
857
|
+
|
|
858
|
+
## 🤝 Contributing
|
|
859
|
+
|
|
860
|
+
If you find a bug or have a feature request please open an issue. If you want to contribute code please open a pull request.
|
|
861
|
+
|
|
862
|
+
You can build and run the library and the example app locally like this:
|
|
863
|
+
|
|
864
|
+
1. First install [yalc](https://github.com/wclr/yalc) globally for managing local package dependencies.
|
|
865
|
+
|
|
866
|
+
```sh
|
|
867
|
+
npm i yalc -g
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
2. Install deps + configure yalc.
|
|
871
|
+
|
|
872
|
+
```sh
|
|
873
|
+
npm install
|
|
874
|
+
npm run build
|
|
875
|
+
npm run link
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
3. Start a watcher for building the library.
|
|
879
|
+
|
|
880
|
+
```sh
|
|
881
|
+
npm run dev
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
4. Run dev server for the example app (do this in another terminal).
|
|
885
|
+
|
|
886
|
+
```sh
|
|
887
|
+
cd example
|
|
888
|
+
npm run dev
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
5. Open http://localhost:5173/ to see the examples. Now if you make edits to the library code the example app will automatically refresh.
|
|
892
|
+
|
|
893
|
+
> [!TIP]
|
|
894
|
+
> If you want to test the example app on your phone you can run the example app with `npm run dev:host` and then open your computer's local IP address in your phone's browser. Make sure your phone is on the same network as your computer.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { EasingDefinition, motion, MotionValue } from 'motion/react';
|
|
2
|
-
import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject } from 'react';
|
|
2
|
+
import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject, CSSProperties } from 'react';
|
|
3
3
|
|
|
4
4
|
type SheetDetent = 'default' | 'full' | 'content';
|
|
5
5
|
type CommonProps = {
|
|
@@ -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?: CSSProperties;
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import { EasingDefinition, motion, MotionValue } from 'motion/react';
|
|
2
|
-
import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject } from 'react';
|
|
2
|
+
import { ForwardRefExoticComponent, ReactNode, ComponentPropsWithoutRef, RefAttributes, FunctionComponent, HTMLAttributes, RefObject, CSSProperties } from 'react';
|
|
3
3
|
|
|
4
4
|
type SheetDetent = 'default' | 'full' | 'content';
|
|
5
5
|
type CommonProps = {
|
|
@@ -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?: CSSProperties;
|
|
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
|
@@ -188,6 +188,21 @@ var isIPad = cached(function() {
|
|
|
188
188
|
var isIOS = cached(function() {
|
|
189
189
|
return isIPhone() || isIPad();
|
|
190
190
|
});
|
|
191
|
+
function waitForElement(className, interval = 50, maxAttempts = 20) {
|
|
192
|
+
return new Promise((resolve) => {
|
|
193
|
+
let attempts = 0;
|
|
194
|
+
const timer = setInterval(() => {
|
|
195
|
+
const element = document.getElementsByClassName(
|
|
196
|
+
className
|
|
197
|
+
)[0];
|
|
198
|
+
attempts++;
|
|
199
|
+
if (element || attempts >= maxAttempts) {
|
|
200
|
+
clearInterval(timer);
|
|
201
|
+
resolve(element);
|
|
202
|
+
}
|
|
203
|
+
}, interval);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
191
206
|
|
|
192
207
|
// src/SheetBackdrop.tsx
|
|
193
208
|
var isClickable = (props) => !!props.onClick || !!props.onTap;
|
|
@@ -262,12 +277,12 @@ function useDragConstraints() {
|
|
|
262
277
|
const onMeasure = React4.useCallback(() => constraints, []);
|
|
263
278
|
return { ref, onMeasure };
|
|
264
279
|
}
|
|
265
|
-
function useScrollPosition() {
|
|
266
|
-
const
|
|
280
|
+
function useScrollPosition(options = {}) {
|
|
281
|
+
const { debounceDelay = 32, isEnabled = true } = options;
|
|
282
|
+
const [element, setElement] = React4.useState(null);
|
|
267
283
|
const [scrollPosition, setScrollPosition] = React4.useState(void 0);
|
|
268
284
|
React4.useEffect(() => {
|
|
269
|
-
|
|
270
|
-
if (!element) return;
|
|
285
|
+
if (!element || !isEnabled) return;
|
|
271
286
|
let scrollTimeout = null;
|
|
272
287
|
function determineScrollPosition(element2) {
|
|
273
288
|
const { scrollTop, scrollHeight, clientHeight } = element2;
|
|
@@ -290,14 +305,21 @@ function useScrollPosition() {
|
|
|
290
305
|
setScrollPosition(position);
|
|
291
306
|
}
|
|
292
307
|
function onScroll(event) {
|
|
293
|
-
if (event.currentTarget instanceof
|
|
308
|
+
if (event.currentTarget instanceof HTMLElement) {
|
|
294
309
|
const el = event.currentTarget;
|
|
295
310
|
if (scrollTimeout) clearTimeout(scrollTimeout);
|
|
296
|
-
|
|
311
|
+
if (debounceDelay === 0) {
|
|
312
|
+
determineScrollPosition(el);
|
|
313
|
+
} else {
|
|
314
|
+
scrollTimeout = setTimeout(
|
|
315
|
+
() => determineScrollPosition(el),
|
|
316
|
+
debounceDelay
|
|
317
|
+
);
|
|
318
|
+
}
|
|
297
319
|
}
|
|
298
320
|
}
|
|
299
321
|
function onTouchStart(event) {
|
|
300
|
-
if (event.currentTarget instanceof
|
|
322
|
+
if (event.currentTarget instanceof HTMLElement) {
|
|
301
323
|
determineScrollPosition(event.currentTarget);
|
|
302
324
|
}
|
|
303
325
|
}
|
|
@@ -309,8 +331,11 @@ function useScrollPosition() {
|
|
|
309
331
|
element.removeEventListener("scroll", onScroll);
|
|
310
332
|
element.removeEventListener("touchstart", onTouchStart);
|
|
311
333
|
};
|
|
312
|
-
}, []);
|
|
313
|
-
return {
|
|
334
|
+
}, [element, isEnabled]);
|
|
335
|
+
return {
|
|
336
|
+
scrollRef: (element2) => setElement(element2),
|
|
337
|
+
scrollPosition
|
|
338
|
+
};
|
|
314
339
|
}
|
|
315
340
|
|
|
316
341
|
// src/SheetContent.tsx
|
|
@@ -321,6 +346,8 @@ var SheetContent = React4.forwardRef(
|
|
|
321
346
|
children,
|
|
322
347
|
style: styleProp,
|
|
323
348
|
className = "",
|
|
349
|
+
scrollClassName = "",
|
|
350
|
+
scrollStyle: scrollStyleProp,
|
|
324
351
|
scrollRef: scrollRefProp = null,
|
|
325
352
|
unstyled,
|
|
326
353
|
...rest
|
|
@@ -365,9 +392,9 @@ var SheetContent = React4.forwardRef(
|
|
|
365
392
|
/* @__PURE__ */ React4__default.default.createElement(
|
|
366
393
|
react.motion.div,
|
|
367
394
|
{
|
|
368
|
-
ref: mergeRefs([scroll.
|
|
369
|
-
style: scrollStyle,
|
|
370
|
-
className:
|
|
395
|
+
ref: mergeRefs([scroll.scrollRef, scrollRefProp]),
|
|
396
|
+
style: { ...scrollStyle, ...scrollStyleProp },
|
|
397
|
+
className: `react-modal-sheet-content-scroller ${scrollClassName}`
|
|
371
398
|
},
|
|
372
399
|
children
|
|
373
400
|
)
|
|
@@ -865,13 +892,14 @@ function useSheetState({
|
|
|
865
892
|
}, [state]);
|
|
866
893
|
return state;
|
|
867
894
|
}
|
|
868
|
-
function useVirtualKeyboard({
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
895
|
+
function useVirtualKeyboard(options = {}) {
|
|
896
|
+
const {
|
|
897
|
+
containerRef,
|
|
898
|
+
isEnabled = true,
|
|
899
|
+
debounceDelay = 100,
|
|
900
|
+
includeContentEditable = true,
|
|
901
|
+
visualViewportThreshold = 100
|
|
902
|
+
} = options;
|
|
875
903
|
const [state, setState] = React4.useState({
|
|
876
904
|
isVisible: false,
|
|
877
905
|
height: 0
|
|
@@ -886,11 +914,15 @@ function useVirtualKeyboard({
|
|
|
886
914
|
const vv = window.visualViewport;
|
|
887
915
|
const vk = navigator.virtualKeyboard;
|
|
888
916
|
function setKeyboardInsetHeightEnv(height) {
|
|
889
|
-
|
|
890
|
-
(
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
+
}
|
|
894
926
|
}
|
|
895
927
|
function handleFocusIn(e) {
|
|
896
928
|
if (e.target instanceof HTMLElement && isTextInput(e.target)) {
|
|
@@ -968,8 +1000,20 @@ function computeSnapPoints({
|
|
|
968
1000
|
snapPointsProp,
|
|
969
1001
|
sheetHeight
|
|
970
1002
|
}) {
|
|
1003
|
+
if (snapPointsProp[0] !== 0) {
|
|
1004
|
+
console.error(
|
|
1005
|
+
`First snap point should be 0 to ensure the sheet can be fully closed. Got: [${snapPointsProp.join(", ")}]`
|
|
1006
|
+
);
|
|
1007
|
+
snapPointsProp.unshift(0);
|
|
1008
|
+
}
|
|
1009
|
+
if (snapPointsProp[snapPointsProp.length - 1] !== 1) {
|
|
1010
|
+
console.error(
|
|
1011
|
+
`Last snap point should be 1 to ensure the sheet can be fully opened. Got: [${snapPointsProp.join(", ")}]`
|
|
1012
|
+
);
|
|
1013
|
+
snapPointsProp.push(1);
|
|
1014
|
+
}
|
|
971
1015
|
if (sheetHeight <= 0) {
|
|
972
|
-
console.
|
|
1016
|
+
console.error(
|
|
973
1017
|
`Sheet height is ${sheetHeight}, cannot compute snap points. Make sure the sheet is mounted and has a valid height.`
|
|
974
1018
|
);
|
|
975
1019
|
return [];
|
|
@@ -1263,6 +1307,7 @@ var Sheet = React4.forwardRef(
|
|
|
1263
1307
|
isOpen,
|
|
1264
1308
|
onOpen: async () => {
|
|
1265
1309
|
onOpenStart == null ? void 0 : onOpenStart();
|
|
1310
|
+
await waitForElement("react-modal-sheet-container");
|
|
1266
1311
|
const initialSnapPoint = initialSnap !== void 0 ? getSnapPoint(initialSnap) : null;
|
|
1267
1312
|
const yTo = (initialSnapPoint == null ? void 0 : initialSnapPoint.snapValueY) ?? 0;
|
|
1268
1313
|
await react.animate(y, yTo, animationOptions);
|
|
@@ -1330,5 +1375,7 @@ var Sheet2 = Object.assign(Sheet, {
|
|
|
1330
1375
|
});
|
|
1331
1376
|
|
|
1332
1377
|
exports.Sheet = Sheet2;
|
|
1378
|
+
exports.useScrollPosition = useScrollPosition;
|
|
1379
|
+
exports.useVirtualKeyboard = useVirtualKeyboard;
|
|
1333
1380
|
//# sourceMappingURL=index.js.map
|
|
1334
1381
|
//# sourceMappingURL=index.js.map
|