@tamagui/sheet 1.108.0 → 1.108.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/dist/cjs/SheetController.js +12 -4
- package/dist/cjs/SheetController.js.map +2 -2
- package/dist/cjs/SheetController.native.js +12 -4
- package/dist/cjs/SheetController.native.js.map +2 -2
- package/dist/cjs/SheetImplementationCustom.js +248 -238
- package/dist/cjs/SheetImplementationCustom.js.map +2 -2
- package/dist/cjs/SheetImplementationCustom.native.js +27 -19
- package/dist/cjs/SheetImplementationCustom.native.js.map +2 -2
- package/dist/cjs/SheetScrollView.js +14 -6
- package/dist/cjs/SheetScrollView.js.map +2 -2
- package/dist/cjs/SheetScrollView.native.js +14 -6
- package/dist/cjs/SheetScrollView.native.js.map +2 -2
- package/dist/cjs/contexts.js +13 -5
- package/dist/cjs/contexts.js.map +2 -2
- package/dist/cjs/contexts.native.js +12 -4
- package/dist/cjs/contexts.native.js.map +2 -2
- package/dist/cjs/useSheetController.js +13 -7
- package/dist/cjs/useSheetController.js.map +2 -2
- package/dist/cjs/useSheetController.native.js +13 -5
- package/dist/cjs/useSheetController.native.js.map +2 -2
- package/dist/cjs/useSheetProviderProps.js +4 -4
- package/dist/cjs/useSheetProviderProps.js.map +1 -1
- package/dist/cjs/useSheetProviderProps.native.js +5 -5
- package/dist/cjs/useSheetProviderProps.native.js.map +1 -1
- package/dist/esm/SheetController.js +2 -2
- package/dist/esm/SheetController.js.map +1 -1
- package/dist/esm/SheetController.mjs +2 -2
- package/dist/esm/SheetController.mjs.map +1 -1
- package/dist/esm/SheetController.native.js +2 -2
- package/dist/esm/SheetController.native.js.map +2 -2
- package/dist/esm/SheetImplementationCustom.js +238 -245
- package/dist/esm/SheetImplementationCustom.js.map +1 -1
- package/dist/esm/SheetImplementationCustom.mjs +22 -22
- package/dist/esm/SheetImplementationCustom.mjs.map +1 -1
- package/dist/esm/SheetImplementationCustom.native.js +17 -17
- package/dist/esm/SheetImplementationCustom.native.js.map +2 -2
- package/dist/esm/SheetScrollView.js +4 -4
- package/dist/esm/SheetScrollView.js.map +1 -1
- package/dist/esm/SheetScrollView.mjs +5 -5
- package/dist/esm/SheetScrollView.mjs.map +1 -1
- package/dist/esm/SheetScrollView.native.js +4 -4
- package/dist/esm/SheetScrollView.native.js.map +2 -2
- package/dist/esm/contexts.js +3 -3
- package/dist/esm/contexts.js.map +1 -1
- package/dist/esm/contexts.mjs +3 -3
- package/dist/esm/contexts.mjs.map +1 -1
- package/dist/esm/contexts.native.js +3 -3
- package/dist/esm/contexts.native.js.map +2 -2
- package/dist/esm/useSheetController.js +3 -5
- package/dist/esm/useSheetController.js.map +1 -1
- package/dist/esm/useSheetController.mjs +3 -3
- package/dist/esm/useSheetController.mjs.map +1 -1
- package/dist/esm/useSheetController.native.js +3 -3
- package/dist/esm/useSheetController.native.js.map +2 -2
- package/dist/esm/useSheetProviderProps.js +4 -4
- package/dist/esm/useSheetProviderProps.js.map +1 -1
- package/dist/esm/useSheetProviderProps.mjs +6 -6
- package/dist/esm/useSheetProviderProps.mjs.map +1 -1
- package/dist/esm/useSheetProviderProps.native.js +5 -5
- package/dist/esm/useSheetProviderProps.native.js.map +2 -2
- package/dist/jsx/SheetController.js +2 -2
- package/dist/jsx/SheetController.js.map +1 -1
- package/dist/jsx/SheetController.mjs +2 -2
- package/dist/jsx/SheetController.mjs.map +1 -1
- package/dist/jsx/SheetController.native.js +2 -2
- package/dist/jsx/SheetController.native.js.map +2 -2
- package/dist/jsx/SheetImplementationCustom.js +238 -245
- package/dist/jsx/SheetImplementationCustom.js.map +1 -1
- package/dist/jsx/SheetImplementationCustom.mjs +22 -22
- package/dist/jsx/SheetImplementationCustom.mjs.map +1 -1
- package/dist/jsx/SheetImplementationCustom.native.js +17 -17
- package/dist/jsx/SheetImplementationCustom.native.js.map +2 -2
- package/dist/jsx/SheetScrollView.js +4 -4
- package/dist/jsx/SheetScrollView.js.map +1 -1
- package/dist/jsx/SheetScrollView.mjs +5 -5
- package/dist/jsx/SheetScrollView.mjs.map +1 -1
- package/dist/jsx/SheetScrollView.native.js +4 -4
- package/dist/jsx/SheetScrollView.native.js.map +2 -2
- package/dist/jsx/contexts.js +3 -3
- package/dist/jsx/contexts.js.map +1 -1
- package/dist/jsx/contexts.mjs +3 -3
- package/dist/jsx/contexts.mjs.map +1 -1
- package/dist/jsx/contexts.native.js +3 -3
- package/dist/jsx/contexts.native.js.map +2 -2
- package/dist/jsx/useSheetController.js +3 -5
- package/dist/jsx/useSheetController.js.map +1 -1
- package/dist/jsx/useSheetController.mjs +3 -3
- package/dist/jsx/useSheetController.mjs.map +1 -1
- package/dist/jsx/useSheetController.native.js +3 -3
- package/dist/jsx/useSheetController.native.js.map +2 -2
- package/dist/jsx/useSheetProviderProps.js +4 -4
- package/dist/jsx/useSheetProviderProps.js.map +1 -1
- package/dist/jsx/useSheetProviderProps.mjs +6 -6
- package/dist/jsx/useSheetProviderProps.mjs.map +1 -1
- package/dist/jsx/useSheetProviderProps.native.js +5 -5
- package/dist/jsx/useSheetProviderProps.native.js.map +2 -2
- package/package.json +16 -16
- package/src/SheetController.tsx +3 -2
- package/src/SheetImplementationCustom.tsx +426 -432
- package/src/SheetScrollView.tsx +9 -5
- package/src/contexts.ts +3 -3
- package/src/useSheetController.tsx +4 -5
- package/src/useSheetProviderProps.tsx +6 -6
- package/types/SheetController.d.ts +1 -1
- package/types/SheetController.d.ts.map +1 -1
- package/types/SheetImplementationCustom.d.ts +5 -4
- package/types/SheetImplementationCustom.d.ts.map +1 -1
- package/types/SheetScrollView.d.ts +3 -2
- package/types/SheetScrollView.d.ts.map +1 -1
- package/types/contexts.d.ts +3 -2
- package/types/contexts.d.ts.map +1 -1
- package/types/useSheetController.d.ts +2 -1
- package/types/useSheetController.d.ts.map +1 -1
- package/types/useSheetProviderProps.d.ts +1 -1
- package/types/useSheetProviderProps.d.ts.map +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from 'react'
|
|
1
2
|
import { AdaptParentContext } from '@tamagui/adapt'
|
|
2
3
|
import { AnimatePresence } from '@tamagui/animate-presence'
|
|
3
4
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
@@ -13,16 +14,7 @@ import {
|
|
|
13
14
|
} from '@tamagui/core'
|
|
14
15
|
import { Portal } from '@tamagui/portal'
|
|
15
16
|
import { useKeyboardVisible } from '@tamagui/use-keyboard-visible'
|
|
16
|
-
|
|
17
|
-
forwardRef,
|
|
18
|
-
Fragment,
|
|
19
|
-
useCallback,
|
|
20
|
-
useContext,
|
|
21
|
-
useEffect,
|
|
22
|
-
useMemo,
|
|
23
|
-
useRef,
|
|
24
|
-
useState,
|
|
25
|
-
} from 'react'
|
|
17
|
+
|
|
26
18
|
import type {
|
|
27
19
|
Animated,
|
|
28
20
|
GestureResponderEvent,
|
|
@@ -42,474 +34,476 @@ import { useSheetProviderProps } from './useSheetProviderProps'
|
|
|
42
34
|
let hiddenSize = 10_000.1
|
|
43
35
|
|
|
44
36
|
export const SheetImplementationCustom = themeable(
|
|
45
|
-
forwardRef<View, SheetProps>(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
37
|
+
React.forwardRef<View, SheetProps>(
|
|
38
|
+
function SheetImplementationCustom(props, forwardedRef) {
|
|
39
|
+
const parentSheet = React.useContext(ParentSheetContext)
|
|
40
|
+
|
|
41
|
+
const {
|
|
42
|
+
animation,
|
|
43
|
+
animationConfig: animationConfigProp,
|
|
44
|
+
modal = false,
|
|
45
|
+
zIndex = parentSheet.zIndex + 1,
|
|
46
|
+
moveOnKeyboardChange = false,
|
|
47
|
+
unmountChildrenWhenHidden = false,
|
|
48
|
+
portalProps,
|
|
49
|
+
containerComponent: ContainerComponent = React.Fragment,
|
|
50
|
+
} = props
|
|
51
|
+
|
|
52
|
+
const keyboardIsVisible = useKeyboardVisible()
|
|
53
|
+
const state = useSheetOpenState(props)
|
|
54
|
+
const [overlayComponent, setOverlayComponent] = React.useState<any>(null)
|
|
55
|
+
|
|
56
|
+
const providerProps = useSheetProviderProps(props, state, {
|
|
57
|
+
onOverlayComponent: setOverlayComponent,
|
|
58
|
+
})
|
|
59
|
+
const {
|
|
60
|
+
frameSize,
|
|
61
|
+
setFrameSize,
|
|
62
|
+
snapPoints,
|
|
63
|
+
snapPointsMode,
|
|
64
|
+
hasFit,
|
|
65
|
+
position,
|
|
66
|
+
setPosition,
|
|
67
|
+
scrollBridge,
|
|
68
|
+
screenSize,
|
|
69
|
+
setMaxContentSize,
|
|
70
|
+
maxSnapPoint,
|
|
71
|
+
} = providerProps
|
|
72
|
+
const { open, controller, isHidden } = state
|
|
73
|
+
|
|
74
|
+
const sheetRef = React.useRef<View>(null)
|
|
75
|
+
const ref = useComposedRefs(forwardedRef, sheetRef)
|
|
76
|
+
|
|
77
|
+
// TODO this can be extracted into a helper getAnimationConfig(animationProp as array | string)
|
|
78
|
+
const animationConfig = (() => {
|
|
79
|
+
const [animationProp, animationPropConfig] = !animation
|
|
80
|
+
? []
|
|
81
|
+
: Array.isArray(animation)
|
|
82
|
+
? animation
|
|
83
|
+
: ([animation] as const)
|
|
84
|
+
return (
|
|
85
|
+
animationConfigProp ??
|
|
86
|
+
(animationProp
|
|
87
|
+
? {
|
|
88
|
+
...(getConfig().animations.animations[animationProp as string] as Object),
|
|
89
|
+
...animationPropConfig,
|
|
90
|
+
}
|
|
91
|
+
: null)
|
|
92
|
+
)
|
|
93
|
+
})()
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* This is a hacky workaround for native:
|
|
97
|
+
*/
|
|
98
|
+
const [isShowingInnerSheet, setIsShowingInnerSheet] = React.useState(false)
|
|
99
|
+
const shouldHideParentSheet = !isWeb && modal && isShowingInnerSheet
|
|
100
|
+
const parentSheetContext = React.useContext(SheetInsideSheetContext)
|
|
101
|
+
const onInnerSheet = React.useCallback((hasChild: boolean) => {
|
|
102
|
+
setIsShowingInnerSheet(hasChild)
|
|
103
|
+
}, [])
|
|
104
|
+
|
|
105
|
+
const positions = React.useMemo(
|
|
106
|
+
() =>
|
|
107
|
+
snapPoints.map((point) =>
|
|
108
|
+
getYPositions(snapPointsMode, point, screenSize, frameSize)
|
|
109
|
+
),
|
|
110
|
+
[screenSize, frameSize, snapPoints, snapPointsMode]
|
|
99
111
|
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return () => {
|
|
129
|
-
parentSheetContext(false)
|
|
130
|
-
}
|
|
131
|
-
}, [parentSheetContext, open])
|
|
132
|
-
|
|
133
|
-
const nextParentContext = useMemo(
|
|
134
|
-
() => ({
|
|
135
|
-
zIndex,
|
|
136
|
-
}),
|
|
137
|
-
[zIndex]
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
const animatedNumber = useAnimatedNumber(hiddenSize)
|
|
141
|
-
const at = useRef(hiddenSize)
|
|
142
|
-
|
|
143
|
-
useAnimatedNumberReaction(
|
|
144
|
-
{
|
|
145
|
-
value: animatedNumber,
|
|
146
|
-
hostRef: sheetRef,
|
|
147
|
-
},
|
|
148
|
-
useCallback(
|
|
149
|
-
(value) => {
|
|
150
|
-
at.current = value
|
|
151
|
-
scrollBridge.paneY = value
|
|
112
|
+
|
|
113
|
+
const { animationDriver } = useConfiguration()
|
|
114
|
+
const { useAnimatedNumber, useAnimatedNumberStyle, useAnimatedNumberReaction } =
|
|
115
|
+
animationDriver
|
|
116
|
+
const AnimatedView = (animationDriver.View ?? Stack) as typeof Animated.View
|
|
117
|
+
|
|
118
|
+
useIsomorphicLayoutEffect(() => {
|
|
119
|
+
if (!(parentSheetContext && open)) return
|
|
120
|
+
parentSheetContext(true)
|
|
121
|
+
return () => {
|
|
122
|
+
parentSheetContext(false)
|
|
123
|
+
}
|
|
124
|
+
}, [parentSheetContext, open])
|
|
125
|
+
|
|
126
|
+
const nextParentContext = React.useMemo(
|
|
127
|
+
() => ({
|
|
128
|
+
zIndex,
|
|
129
|
+
}),
|
|
130
|
+
[zIndex]
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
const animatedNumber = useAnimatedNumber(hiddenSize)
|
|
134
|
+
const at = React.useRef(hiddenSize)
|
|
135
|
+
|
|
136
|
+
useAnimatedNumberReaction(
|
|
137
|
+
{
|
|
138
|
+
value: animatedNumber,
|
|
139
|
+
hostRef: sheetRef,
|
|
152
140
|
},
|
|
153
|
-
|
|
141
|
+
React.useCallback(
|
|
142
|
+
(value) => {
|
|
143
|
+
at.current = value
|
|
144
|
+
scrollBridge.paneY = value
|
|
145
|
+
},
|
|
146
|
+
[animationDriver]
|
|
147
|
+
)
|
|
154
148
|
)
|
|
155
|
-
)
|
|
156
149
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
150
|
+
function stopSpring() {
|
|
151
|
+
animatedNumber.stop()
|
|
152
|
+
if (scrollBridge.onFinishAnimate) {
|
|
153
|
+
scrollBridge.onFinishAnimate()
|
|
154
|
+
scrollBridge.onFinishAnimate = undefined
|
|
155
|
+
}
|
|
162
156
|
}
|
|
163
|
-
}
|
|
164
157
|
|
|
165
|
-
|
|
158
|
+
const hasntMeasured = at.current === hiddenSize
|
|
166
159
|
|
|
167
|
-
|
|
168
|
-
|
|
160
|
+
const animateTo = useEvent((position: number) => {
|
|
161
|
+
if (frameSize === 0) return
|
|
169
162
|
|
|
170
|
-
|
|
163
|
+
let toValue = isHidden || position === -1 ? screenSize : positions[position]
|
|
171
164
|
|
|
172
|
-
|
|
173
|
-
|
|
165
|
+
if (at.current === toValue) return
|
|
166
|
+
at.current = toValue
|
|
174
167
|
|
|
175
|
-
|
|
168
|
+
stopSpring()
|
|
176
169
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
170
|
+
if (hasntMeasured || isHidden) {
|
|
171
|
+
// first run, we need to set to screen size before running
|
|
172
|
+
animatedNumber.setValue(
|
|
173
|
+
screenSize,
|
|
174
|
+
{
|
|
175
|
+
type: 'timing',
|
|
176
|
+
duration: 0,
|
|
177
|
+
},
|
|
178
|
+
() => {
|
|
179
|
+
if (isHidden) {
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
toValue = positions[position]
|
|
184
|
+
at.current = toValue
|
|
185
|
+
|
|
186
|
+
animatedNumber.setValue(toValue, {
|
|
187
|
+
type: 'spring',
|
|
188
|
+
...animationConfig,
|
|
189
|
+
})
|
|
188
190
|
}
|
|
191
|
+
)
|
|
192
|
+
return
|
|
193
|
+
}
|
|
189
194
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
type: 'spring',
|
|
195
|
-
...animationConfig,
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
)
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
animatedNumber.setValue(toValue, {
|
|
203
|
-
type: 'spring',
|
|
204
|
-
...animationConfig,
|
|
195
|
+
animatedNumber.setValue(toValue, {
|
|
196
|
+
type: 'spring',
|
|
197
|
+
...animationConfig,
|
|
198
|
+
})
|
|
205
199
|
})
|
|
206
|
-
})
|
|
207
200
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
201
|
+
useIsomorphicLayoutEffect(() => {
|
|
202
|
+
if (screenSize && hasntMeasured) {
|
|
203
|
+
animatedNumber.setValue(screenSize, {
|
|
204
|
+
type: 'timing',
|
|
205
|
+
duration: 0,
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
}, [hasntMeasured, screenSize])
|
|
216
209
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
210
|
+
useIsomorphicLayoutEffect(() => {
|
|
211
|
+
if (!frameSize || !screenSize || isHidden || (hasntMeasured && !open)) {
|
|
212
|
+
return
|
|
213
|
+
}
|
|
214
|
+
animateTo(position)
|
|
215
|
+
}, [isHidden, frameSize, screenSize, open, position])
|
|
216
|
+
|
|
217
|
+
const disableDrag = props.disableDrag ?? controller?.disableDrag
|
|
218
|
+
const themeName = useThemeName()
|
|
219
|
+
const [isDragging, setIsDragging] = React.useState(false)
|
|
220
|
+
|
|
221
|
+
const panResponder = React.useMemo(() => {
|
|
222
|
+
if (disableDrag) return
|
|
223
|
+
if (!frameSize) return
|
|
224
|
+
if (isShowingInnerSheet) return
|
|
225
|
+
|
|
226
|
+
const minY = positions[0]
|
|
227
|
+
scrollBridge.paneMinY = minY
|
|
228
|
+
let startY = at.current
|
|
229
|
+
|
|
230
|
+
function setPanning(val: boolean) {
|
|
231
|
+
setIsDragging(val)
|
|
232
|
+
|
|
233
|
+
// make unselectable:
|
|
234
|
+
if (!SHEET_HIDDEN_STYLESHEET) return
|
|
235
|
+
if (!val) {
|
|
236
|
+
SHEET_HIDDEN_STYLESHEET.innerText = ''
|
|
237
|
+
} else {
|
|
238
|
+
SHEET_HIDDEN_STYLESHEET.innerText =
|
|
239
|
+
':root * { user-select: none !important; -webkit-user-select: none !important; }'
|
|
240
|
+
}
|
|
247
241
|
}
|
|
248
|
-
}
|
|
249
242
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
243
|
+
const release = ({ vy, dragAt }: { dragAt: number; vy: number }) => {
|
|
244
|
+
isExternalDrag = false
|
|
245
|
+
previouslyScrolling = false
|
|
246
|
+
setPanning(false)
|
|
247
|
+
const at = dragAt + startY
|
|
248
|
+
// seems liky vy goes up to about 4 at the very most (+ is down, - is up)
|
|
249
|
+
// lets base our multiplier on the total layout height
|
|
250
|
+
const end = at + frameSize * vy * 0.2
|
|
251
|
+
let closestPoint = 0
|
|
252
|
+
let dist = Number.POSITIVE_INFINITY
|
|
253
|
+
for (let i = 0; i < positions.length; i++) {
|
|
254
|
+
const position = positions[i]
|
|
255
|
+
const curDist = end > position ? end - position : position - end
|
|
256
|
+
if (curDist < dist) {
|
|
257
|
+
dist = curDist
|
|
258
|
+
closestPoint = i
|
|
259
|
+
}
|
|
266
260
|
}
|
|
261
|
+
// have to call both because state may not change but need to snap back
|
|
262
|
+
setPosition(closestPoint)
|
|
263
|
+
animateTo(closestPoint)
|
|
267
264
|
}
|
|
268
|
-
// have to call both because state may not change but need to snap back
|
|
269
|
-
setPosition(closestPoint)
|
|
270
|
-
animateTo(closestPoint)
|
|
271
|
-
}
|
|
272
265
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
266
|
+
const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
|
|
267
|
+
release({
|
|
268
|
+
vy: state.vy,
|
|
269
|
+
dragAt: state.dy,
|
|
270
|
+
})
|
|
271
|
+
}
|
|
279
272
|
|
|
280
|
-
|
|
273
|
+
let previouslyScrolling = false
|
|
281
274
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
275
|
+
const onMoveShouldSet = (
|
|
276
|
+
e: GestureResponderEvent,
|
|
277
|
+
{ dy }: PanResponderGestureState
|
|
278
|
+
) => {
|
|
279
|
+
// if dragging handle always allow:
|
|
280
|
+
if (e.target === providerProps.handleRef.current) {
|
|
281
|
+
return true
|
|
282
|
+
}
|
|
290
283
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
284
|
+
const isScrolled = scrollBridge.y !== 0
|
|
285
|
+
const isDraggingUp = dy < 0
|
|
286
|
+
// we can treat near top instead of exactly to avoid trouble with springs
|
|
287
|
+
const isNearTop = scrollBridge.paneY - 5 <= scrollBridge.paneMinY
|
|
288
|
+
if (isScrolled) {
|
|
289
|
+
previouslyScrolling = true
|
|
290
|
+
return false
|
|
291
|
+
}
|
|
292
|
+
// prevent drag once at top and pulling up
|
|
293
|
+
if (isNearTop) {
|
|
294
|
+
if (!isScrolled && isDraggingUp) {
|
|
295
|
+
// TODO: pulling past the limit breaks scroll on native, need to better make ScrollView
|
|
296
|
+
if (!isWeb) {
|
|
297
|
+
return false
|
|
298
|
+
}
|
|
305
299
|
}
|
|
306
300
|
}
|
|
301
|
+
// we could do some detection of other touchables and cancel here..
|
|
302
|
+
return Math.abs(dy) > 5
|
|
307
303
|
}
|
|
308
|
-
// we could do some detection of other touchables and cancel here..
|
|
309
|
-
return Math.abs(dy) > 5
|
|
310
|
-
}
|
|
311
304
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
305
|
+
const grant = () => {
|
|
306
|
+
setPanning(true)
|
|
307
|
+
stopSpring()
|
|
308
|
+
startY = at.current
|
|
309
|
+
}
|
|
317
310
|
|
|
318
|
-
|
|
311
|
+
let isExternalDrag = false
|
|
319
312
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
313
|
+
scrollBridge.drag = (dy) => {
|
|
314
|
+
if (!isExternalDrag) {
|
|
315
|
+
isExternalDrag = true
|
|
316
|
+
grant()
|
|
317
|
+
}
|
|
318
|
+
const to = dy + startY
|
|
319
|
+
animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
|
|
324
320
|
}
|
|
325
|
-
const to = dy + startY
|
|
326
|
-
animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
|
|
327
|
-
}
|
|
328
321
|
|
|
329
|
-
|
|
322
|
+
scrollBridge.release = release
|
|
330
323
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
324
|
+
return PanResponder.create({
|
|
325
|
+
onMoveShouldSetPanResponder: onMoveShouldSet,
|
|
326
|
+
onPanResponderGrant: grant,
|
|
327
|
+
onPanResponderMove: (_e, { dy }) => {
|
|
328
|
+
const toFull = dy + startY
|
|
329
|
+
const to = resisted(toFull, minY)
|
|
330
|
+
animatedNumber.setValue(to, { type: 'direct' })
|
|
331
|
+
},
|
|
332
|
+
onPanResponderEnd: finish,
|
|
333
|
+
onPanResponderTerminate: finish,
|
|
334
|
+
onPanResponderRelease: finish,
|
|
335
|
+
})
|
|
336
|
+
}, [disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition])
|
|
337
|
+
|
|
338
|
+
const handleAnimationViewLayout = React.useCallback(
|
|
339
|
+
(e: LayoutChangeEvent) => {
|
|
340
|
+
// avoid bugs where it grows forever for whatever reason
|
|
341
|
+
const next = Math.min(
|
|
342
|
+
e.nativeEvent?.layout.height,
|
|
343
|
+
Dimensions.get('window').height
|
|
344
|
+
)
|
|
345
|
+
if (!next) return
|
|
346
|
+
setFrameSize(next)
|
|
338
347
|
},
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
e.nativeEvent?.layout.height,
|
|
363
|
-
Dimensions.get('window').height
|
|
364
|
-
)
|
|
365
|
-
if (!next) return
|
|
366
|
-
setMaxContentSize(next)
|
|
367
|
-
},
|
|
368
|
-
[keyboardIsVisible]
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
const animatedStyle = useAnimatedNumberStyle(animatedNumber, (val) => {
|
|
372
|
-
'worklet'
|
|
373
|
-
const translateY = frameSize === 0 ? hiddenSize : val
|
|
374
|
-
|
|
375
|
-
return {
|
|
376
|
-
transform: [{ translateY }],
|
|
377
|
-
}
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
const sizeBeforeKeyboard = useRef<number | null>(null)
|
|
381
|
-
useEffect(() => {
|
|
382
|
-
if (isWeb || !moveOnKeyboardChange) return
|
|
383
|
-
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (e) => {
|
|
384
|
-
if (sizeBeforeKeyboard.current !== null) return
|
|
385
|
-
sizeBeforeKeyboard.current = animatedNumber.getValue()
|
|
386
|
-
animatedNumber.setValue(
|
|
387
|
-
Math.max(animatedNumber.getValue() - e.endCoordinates.height, 0)
|
|
388
|
-
)
|
|
389
|
-
})
|
|
390
|
-
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
|
391
|
-
if (sizeBeforeKeyboard.current === null) return
|
|
392
|
-
animatedNumber.setValue(sizeBeforeKeyboard.current)
|
|
393
|
-
sizeBeforeKeyboard.current = null
|
|
348
|
+
[keyboardIsVisible]
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
const handleMaxContentViewLayout = React.useCallback(
|
|
352
|
+
(e: LayoutChangeEvent) => {
|
|
353
|
+
// avoid bugs where it grows forever for whatever reason
|
|
354
|
+
const next = Math.min(
|
|
355
|
+
e.nativeEvent?.layout.height,
|
|
356
|
+
Dimensions.get('window').height
|
|
357
|
+
)
|
|
358
|
+
if (!next) return
|
|
359
|
+
setMaxContentSize(next)
|
|
360
|
+
},
|
|
361
|
+
[keyboardIsVisible]
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
const animatedStyle = useAnimatedNumberStyle(animatedNumber, (val) => {
|
|
365
|
+
'worklet'
|
|
366
|
+
const translateY = frameSize === 0 ? hiddenSize : val
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
transform: [{ translateY }],
|
|
370
|
+
}
|
|
394
371
|
})
|
|
395
372
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
373
|
+
const sizeBeforeKeyboard = React.useRef<number | null>(null)
|
|
374
|
+
React.useEffect(() => {
|
|
375
|
+
if (isWeb || !moveOnKeyboardChange) return
|
|
376
|
+
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (e) => {
|
|
377
|
+
if (sizeBeforeKeyboard.current !== null) return
|
|
378
|
+
sizeBeforeKeyboard.current = animatedNumber.getValue()
|
|
379
|
+
animatedNumber.setValue(
|
|
380
|
+
Math.max(animatedNumber.getValue() - e.endCoordinates.height, 0)
|
|
381
|
+
)
|
|
382
|
+
})
|
|
383
|
+
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
|
384
|
+
if (sizeBeforeKeyboard.current === null) return
|
|
385
|
+
animatedNumber.setValue(sizeBeforeKeyboard.current)
|
|
386
|
+
sizeBeforeKeyboard.current = null
|
|
387
|
+
})
|
|
401
388
|
|
|
402
|
-
// we need to set this *after* fully closed to 0, to avoid it overlapping
|
|
403
|
-
// the page when resizing quickly on web for example
|
|
404
|
-
const [opacity, setOpacity] = useState(open ? 1 : 0)
|
|
405
|
-
if (open && opacity === 0) {
|
|
406
|
-
setOpacity(1)
|
|
407
|
-
}
|
|
408
|
-
useEffect(() => {
|
|
409
|
-
if (!open) {
|
|
410
|
-
// need to wait for animation complete, for now lets just do it naively
|
|
411
|
-
const tm = setTimeout(() => {
|
|
412
|
-
setOpacity(0)
|
|
413
|
-
}, 400)
|
|
414
389
|
return () => {
|
|
415
|
-
|
|
390
|
+
keyboardDidHideListener.remove()
|
|
391
|
+
keyboardDidShowListener.remove()
|
|
416
392
|
}
|
|
393
|
+
}, [moveOnKeyboardChange])
|
|
394
|
+
|
|
395
|
+
// we need to set this *after* fully closed to 0, to avoid it overlapping
|
|
396
|
+
// the page when resizing quickly on web for example
|
|
397
|
+
const [opacity, setOpacity] = React.useState(open ? 1 : 0)
|
|
398
|
+
if (open && opacity === 0) {
|
|
399
|
+
setOpacity(1)
|
|
417
400
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
{
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
{...(!isDragging && {
|
|
453
|
-
// @ts-ignore for CSS driver this is necessary to attach the transition
|
|
454
|
-
animation,
|
|
455
|
-
})}
|
|
456
|
-
// @ts-ignore
|
|
457
|
-
disableClassName
|
|
458
|
-
style={[
|
|
459
|
-
{
|
|
460
|
-
position: 'absolute',
|
|
461
|
-
zIndex,
|
|
462
|
-
width: '100%',
|
|
463
|
-
height: forcedContentHeight,
|
|
464
|
-
minHeight: forcedContentHeight,
|
|
465
|
-
opacity,
|
|
466
|
-
...((shouldHideParentSheet || !open) && {
|
|
401
|
+
React.useEffect(() => {
|
|
402
|
+
if (!open) {
|
|
403
|
+
// need to wait for animation complete, for now lets just do it naively
|
|
404
|
+
const tm = setTimeout(() => {
|
|
405
|
+
setOpacity(0)
|
|
406
|
+
}, 400)
|
|
407
|
+
return () => {
|
|
408
|
+
clearTimeout(tm)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}, [open])
|
|
412
|
+
|
|
413
|
+
const forcedContentHeight = hasFit
|
|
414
|
+
? undefined
|
|
415
|
+
: snapPointsMode === 'percent'
|
|
416
|
+
? `${maxSnapPoint}${isWeb ? 'dvh' : '%'}`
|
|
417
|
+
: maxSnapPoint
|
|
418
|
+
|
|
419
|
+
const contents = (
|
|
420
|
+
<ParentSheetContext.Provider value={nextParentContext}>
|
|
421
|
+
<SheetProvider {...providerProps}>
|
|
422
|
+
<AnimatePresence custom={{ open }}>
|
|
423
|
+
{shouldHideParentSheet || !open ? null : overlayComponent}
|
|
424
|
+
</AnimatePresence>
|
|
425
|
+
|
|
426
|
+
{snapPointsMode !== 'percent' && (
|
|
427
|
+
<View
|
|
428
|
+
style={{
|
|
429
|
+
opacity: 0,
|
|
430
|
+
position: 'absolute',
|
|
431
|
+
top: 0,
|
|
432
|
+
left: 0,
|
|
433
|
+
right: 0,
|
|
434
|
+
bottom: 0,
|
|
467
435
|
pointerEvents: 'none',
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
{
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
436
|
+
}}
|
|
437
|
+
onLayout={handleMaxContentViewLayout}
|
|
438
|
+
/>
|
|
439
|
+
)}
|
|
440
|
+
|
|
441
|
+
<AnimatedView
|
|
442
|
+
ref={ref}
|
|
443
|
+
{...panResponder?.panHandlers}
|
|
444
|
+
onLayout={handleAnimationViewLayout}
|
|
445
|
+
{...(!isDragging && {
|
|
446
|
+
// @ts-ignore for CSS driver this is necessary to attach the transition
|
|
447
|
+
animation,
|
|
448
|
+
})}
|
|
449
|
+
// @ts-ignore
|
|
450
|
+
disableClassName
|
|
451
|
+
style={[
|
|
452
|
+
{
|
|
453
|
+
position: 'absolute',
|
|
454
|
+
zIndex,
|
|
455
|
+
width: '100%',
|
|
456
|
+
height: forcedContentHeight,
|
|
457
|
+
minHeight: forcedContentHeight,
|
|
458
|
+
opacity,
|
|
459
|
+
...((shouldHideParentSheet || !open) && {
|
|
460
|
+
pointerEvents: 'none',
|
|
461
|
+
}),
|
|
462
|
+
},
|
|
463
|
+
animatedStyle,
|
|
464
|
+
]}
|
|
465
|
+
>
|
|
466
|
+
{props.children}
|
|
467
|
+
</AnimatedView>
|
|
468
|
+
</SheetProvider>
|
|
469
|
+
</ParentSheetContext.Provider>
|
|
497
470
|
)
|
|
498
471
|
|
|
499
|
-
|
|
500
|
-
|
|
472
|
+
const adaptContext = React.useContext(AdaptParentContext)
|
|
473
|
+
|
|
474
|
+
// start mounted so we get an accurate measurement the first time
|
|
475
|
+
const shouldMountChildren = Boolean(opacity || !unmountChildrenWhenHidden)
|
|
476
|
+
|
|
477
|
+
if (modal) {
|
|
478
|
+
const modalContents = (
|
|
479
|
+
<Portal zIndex={zIndex} {...portalProps}>
|
|
480
|
+
{shouldMountChildren && (
|
|
481
|
+
<ContainerComponent>
|
|
482
|
+
<Theme forceClassName name={themeName}>
|
|
483
|
+
<AdaptParentContext.Provider value={adaptContext}>
|
|
484
|
+
{contents}
|
|
485
|
+
</AdaptParentContext.Provider>
|
|
486
|
+
</Theme>
|
|
487
|
+
</ContainerComponent>
|
|
488
|
+
)}
|
|
489
|
+
</Portal>
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
if (isWeb) {
|
|
493
|
+
return modalContents
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// on native we don't support multiple modals yet... fix for now is to hide outer one
|
|
497
|
+
return (
|
|
498
|
+
<SheetInsideSheetContext.Provider value={onInnerSheet}>
|
|
499
|
+
{modalContents}
|
|
500
|
+
</SheetInsideSheetContext.Provider>
|
|
501
|
+
)
|
|
501
502
|
}
|
|
502
503
|
|
|
503
|
-
|
|
504
|
-
return (
|
|
505
|
-
<SheetInsideSheetContext.Provider value={onInnerSheet}>
|
|
506
|
-
{modalContents}
|
|
507
|
-
</SheetInsideSheetContext.Provider>
|
|
508
|
-
)
|
|
504
|
+
return contents
|
|
509
505
|
}
|
|
510
|
-
|
|
511
|
-
return contents
|
|
512
|
-
})
|
|
506
|
+
)
|
|
513
507
|
)
|
|
514
508
|
|
|
515
509
|
function getYPositions(
|