@tamagui/sheet 1.27.1 → 1.27.2
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/Sheet.js +1 -2
- package/dist/cjs/Sheet.js.map +1 -1
- package/dist/cjs/SheetContext.js.map +1 -1
- package/dist/cjs/SheetImplementationCustom.js +340 -0
- package/dist/cjs/SheetImplementationCustom.js.map +6 -0
- package/dist/cjs/constants.js +10 -0
- package/dist/cjs/constants.js.map +1 -1
- package/dist/cjs/contexts.js +35 -0
- package/dist/cjs/contexts.js.map +6 -0
- package/dist/cjs/createSheet.js +68 -349
- package/dist/cjs/createSheet.js.map +2 -2
- package/dist/cjs/helpers.js +38 -0
- package/dist/cjs/helpers.js.map +6 -0
- package/dist/cjs/nativeSheet.js +3 -5
- package/dist/cjs/nativeSheet.js.map +1 -1
- package/dist/cjs/useSheetController.js +2 -1
- package/dist/cjs/useSheetController.js.map +1 -1
- package/dist/cjs/useSheetProviderProps.js +30 -3
- package/dist/cjs/useSheetProviderProps.js.map +1 -1
- package/dist/esm/Sheet.js +1 -2
- package/dist/esm/Sheet.js.map +1 -1
- package/dist/esm/SheetContext.js.map +1 -1
- package/dist/esm/SheetImplementationCustom.js +336 -0
- package/dist/esm/SheetImplementationCustom.js.map +6 -0
- package/dist/esm/constants.js +8 -0
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/contexts.js +10 -0
- package/dist/esm/contexts.js.map +6 -0
- package/dist/esm/createSheet.js +72 -371
- package/dist/esm/createSheet.js.map +2 -2
- package/dist/esm/helpers.js +14 -0
- package/dist/esm/helpers.js.map +6 -0
- package/dist/esm/nativeSheet.js +3 -5
- package/dist/esm/nativeSheet.js.map +1 -1
- package/dist/esm/useSheetController.js +2 -1
- package/dist/esm/useSheetController.js.map +1 -1
- package/dist/esm/useSheetProviderProps.js +31 -4
- package/dist/esm/useSheetProviderProps.js.map +1 -1
- package/dist/jsx/Sheet.js +1 -2
- package/dist/jsx/Sheet.js.map +1 -1
- package/dist/jsx/Sheet.mjs +1 -2
- package/dist/jsx/Sheet.mjs.map +1 -1
- package/dist/jsx/SheetContext.js.map +1 -1
- package/dist/jsx/SheetContext.mjs.map +1 -1
- package/dist/jsx/SheetImplementationCustom.js +330 -0
- package/dist/jsx/SheetImplementationCustom.js.map +6 -0
- package/dist/jsx/SheetImplementationCustom.mjs +330 -0
- package/dist/jsx/SheetImplementationCustom.mjs.map +6 -0
- package/dist/jsx/constants.js +8 -0
- package/dist/jsx/constants.js.map +1 -1
- package/dist/jsx/constants.mjs +8 -0
- package/dist/jsx/constants.mjs.map +1 -1
- package/dist/jsx/contexts.js +10 -0
- package/dist/jsx/contexts.js.map +6 -0
- package/dist/jsx/contexts.mjs +10 -0
- package/dist/jsx/contexts.mjs.map +6 -0
- package/dist/jsx/createSheet.js +63 -364
- package/dist/jsx/createSheet.js.map +2 -2
- package/dist/jsx/createSheet.mjs +63 -364
- package/dist/jsx/createSheet.mjs.map +2 -2
- package/dist/jsx/helpers.js +14 -0
- package/dist/jsx/helpers.js.map +6 -0
- package/dist/jsx/helpers.mjs +14 -0
- package/dist/jsx/helpers.mjs.map +6 -0
- package/dist/jsx/nativeSheet.js +3 -5
- package/dist/jsx/nativeSheet.js.map +1 -1
- package/dist/jsx/nativeSheet.mjs +3 -5
- package/dist/jsx/nativeSheet.mjs.map +1 -1
- package/dist/jsx/useSheetController.js +2 -1
- package/dist/jsx/useSheetController.js.map +1 -1
- package/dist/jsx/useSheetController.mjs +2 -1
- package/dist/jsx/useSheetController.mjs.map +1 -1
- package/dist/jsx/useSheetProviderProps.js +31 -4
- package/dist/jsx/useSheetProviderProps.js.map +1 -1
- package/dist/jsx/useSheetProviderProps.mjs +31 -4
- package/dist/jsx/useSheetProviderProps.mjs.map +1 -1
- package/package.json +13 -13
- package/src/Sheet.tsx +0 -1
- package/src/SheetContext.tsx +1 -16
- package/src/SheetImplementationCustom.tsx +404 -0
- package/src/constants.tsx +10 -0
- package/src/contexts.ts +9 -0
- package/src/createSheet.tsx +88 -449
- package/src/helpers.tsx +10 -0
- package/src/nativeSheet.tsx +3 -5
- package/src/useSheetController.tsx +1 -0
- package/src/useSheetProviderProps.tsx +48 -7
- package/types/Sheet.d.ts +10 -6
- package/types/Sheet.d.ts.map +1 -1
- package/types/SheetContext.d.ts +100 -27
- package/types/SheetContext.d.ts.map +1 -1
- package/types/SheetImplementationCustom.d.ts +27 -0
- package/types/SheetImplementationCustom.d.ts.map +1 -0
- package/types/constants.d.ts +2 -0
- package/types/constants.d.ts.map +1 -1
- package/types/contexts.d.ts +6 -0
- package/types/contexts.d.ts.map +1 -0
- package/types/createSheet.d.ts +8 -4
- package/types/createSheet.d.ts.map +1 -1
- package/types/helpers.d.ts +2 -0
- package/types/helpers.d.ts.map +1 -0
- package/types/nativeSheet.d.ts.map +1 -1
- package/types/useSheet.d.ts +16 -6
- package/types/useSheet.d.ts.map +1 -1
- package/types/useSheetController.d.ts +1 -0
- package/types/useSheetController.d.ts.map +1 -1
- package/types/useSheetProviderProps.d.ts +8 -3
- package/types/useSheetProviderProps.d.ts.map +1 -1
- package/src/useSheetChildren.tsx +0 -49
- package/src/useSheetSnapPoints.tsx +0 -60
package/src/contexts.ts
ADDED
package/src/createSheet.tsx
CHANGED
|
@@ -1,57 +1,29 @@
|
|
|
1
|
-
import { AdaptParentContext } from '@tamagui/adapt'
|
|
2
1
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
3
2
|
import {
|
|
4
3
|
GetProps,
|
|
5
4
|
StackProps,
|
|
6
5
|
TamaguiComponentExpectingVariants,
|
|
7
|
-
Theme,
|
|
8
|
-
isClient,
|
|
9
|
-
isTouchable,
|
|
10
|
-
isWeb,
|
|
11
6
|
mergeEvent,
|
|
12
|
-
themeable,
|
|
13
|
-
useAnimationDriver,
|
|
14
7
|
useDidFinishSSR,
|
|
15
|
-
useEvent,
|
|
16
|
-
useIsomorphicLayoutEffect,
|
|
17
|
-
useThemeName,
|
|
18
8
|
withStaticProperties,
|
|
19
9
|
} from '@tamagui/core'
|
|
20
|
-
import { Portal } from '@tamagui/portal'
|
|
21
10
|
import { RemoveScroll } from '@tamagui/remove-scroll'
|
|
22
|
-
import { useKeyboardVisible } from '@tamagui/use-keyboard-visible'
|
|
23
11
|
import {
|
|
24
12
|
FunctionComponent,
|
|
25
13
|
RefAttributes,
|
|
26
|
-
createContext,
|
|
27
14
|
forwardRef,
|
|
28
|
-
|
|
29
|
-
useContext,
|
|
30
|
-
useEffect,
|
|
15
|
+
useLayoutEffect,
|
|
31
16
|
useMemo,
|
|
32
|
-
useRef,
|
|
33
|
-
useState,
|
|
34
17
|
} from 'react'
|
|
35
|
-
import {
|
|
36
|
-
Animated,
|
|
37
|
-
GestureResponderEvent,
|
|
38
|
-
Keyboard,
|
|
39
|
-
PanResponder,
|
|
40
|
-
PanResponderGestureState,
|
|
41
|
-
Platform,
|
|
42
|
-
View,
|
|
43
|
-
} from 'react-native'
|
|
18
|
+
import { Platform, View } from 'react-native'
|
|
44
19
|
|
|
45
20
|
import { SHEET_HANDLE_NAME, SHEET_NAME, SHEET_OVERLAY_NAME } from './constants'
|
|
46
21
|
import { getNativeSheet } from './nativeSheet'
|
|
47
|
-
import {
|
|
22
|
+
import { useSheetContext } from './SheetContext'
|
|
23
|
+
import { SheetImplementationCustom } from './SheetImplementationCustom'
|
|
48
24
|
import { SheetScrollView } from './SheetScrollView'
|
|
49
25
|
import { SheetProps, SheetScopedProps } from './types'
|
|
50
|
-
import { useSheetChildren } from './useSheetChildren'
|
|
51
26
|
import { useSheetController } from './useSheetController'
|
|
52
|
-
import { useSheetOpenState } from './useSheetOpenState'
|
|
53
|
-
import { useSheetProviderProps } from './useSheetProviderProps'
|
|
54
|
-
import { useSheetSnapPoints } from './useSheetSnapPoints'
|
|
55
27
|
|
|
56
28
|
type SharedSheetProps = {
|
|
57
29
|
open?: boolean
|
|
@@ -65,15 +37,15 @@ export type CreateSheetProps = {
|
|
|
65
37
|
Overlay: TamaguiComponentExpectingVariants<BaseProps, SharedSheetProps>
|
|
66
38
|
}
|
|
67
39
|
|
|
68
|
-
const selectionStyleSheet = isClient ? document.createElement('style') : null
|
|
69
|
-
if (selectionStyleSheet) {
|
|
70
|
-
document.head.appendChild(selectionStyleSheet)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
40
|
export function createSheet({ Handle, Frame, Overlay }: CreateSheetProps) {
|
|
74
41
|
const SheetHandle = Handle.extractable(
|
|
75
42
|
({ __scopeSheet, ...props }: SheetScopedProps<GetProps<typeof Handle>>) => {
|
|
76
43
|
const context = useSheetContext(SHEET_HANDLE_NAME, __scopeSheet)
|
|
44
|
+
|
|
45
|
+
if (context.onlyShowFrame) {
|
|
46
|
+
return null
|
|
47
|
+
}
|
|
48
|
+
|
|
77
49
|
return (
|
|
78
50
|
<Handle
|
|
79
51
|
onPress={() => {
|
|
@@ -95,22 +67,46 @@ export function createSheet({ Handle, Frame, Overlay }: CreateSheetProps) {
|
|
|
95
67
|
* -----------------------------------------------------------------------------------------------*/
|
|
96
68
|
|
|
97
69
|
const SheetOverlay = Overlay.extractable(
|
|
98
|
-
(
|
|
70
|
+
(propsIn: SheetScopedProps<GetProps<typeof Overlay>>) => {
|
|
71
|
+
const { __scopeSheet, ...props } = propsIn
|
|
99
72
|
const context = useSheetContext(SHEET_OVERLAY_NAME, __scopeSheet)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
73
|
+
|
|
74
|
+
// this ones a bit weird for legacy reasons, we need to hoist it above <Sheet /> AnimatedView
|
|
75
|
+
// so we just pass it up to context
|
|
76
|
+
|
|
77
|
+
const element = useMemo(
|
|
78
|
+
() => (
|
|
79
|
+
<Overlay
|
|
80
|
+
open={context.open && !context.hidden}
|
|
81
|
+
{...props}
|
|
82
|
+
onPress={mergeEvent(
|
|
83
|
+
props.onPress as any,
|
|
84
|
+
context.dismissOnOverlayPress
|
|
85
|
+
? () => {
|
|
86
|
+
context.setOpen(false)
|
|
87
|
+
}
|
|
88
|
+
: undefined
|
|
89
|
+
)}
|
|
90
|
+
/>
|
|
91
|
+
),
|
|
92
|
+
[
|
|
93
|
+
context.open,
|
|
94
|
+
props,
|
|
95
|
+
context.hidden,
|
|
96
|
+
props.onPress,
|
|
97
|
+
context.dismissOnOverlayPress,
|
|
98
|
+
]
|
|
113
99
|
)
|
|
100
|
+
|
|
101
|
+
useLayoutEffect(() => {
|
|
102
|
+
context.onOverlayComponent?.(element)
|
|
103
|
+
}, [element])
|
|
104
|
+
|
|
105
|
+
if (context.onlyShowFrame) {
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null
|
|
114
110
|
}
|
|
115
111
|
)
|
|
116
112
|
|
|
@@ -121,12 +117,51 @@ export function createSheet({ Handle, Frame, Overlay }: CreateSheetProps) {
|
|
|
121
117
|
const SheetFrame = Frame.extractable(
|
|
122
118
|
forwardRef(
|
|
123
119
|
(
|
|
124
|
-
{
|
|
120
|
+
{
|
|
121
|
+
__scopeSheet,
|
|
122
|
+
children,
|
|
123
|
+
...props
|
|
124
|
+
}: SheetScopedProps<
|
|
125
|
+
GetProps<typeof Frame> & {
|
|
126
|
+
disableHideBottomOverflow?: boolean
|
|
127
|
+
}
|
|
128
|
+
>,
|
|
125
129
|
forwardedRef
|
|
126
130
|
) => {
|
|
127
131
|
const context = useSheetContext(SHEET_NAME, __scopeSheet)
|
|
128
132
|
const composedContentRef = useComposedRefs(forwardedRef, context.contentRef)
|
|
129
|
-
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<>
|
|
136
|
+
<RemoveScroll
|
|
137
|
+
forwardProps
|
|
138
|
+
enabled={context.removeScrollEnabled}
|
|
139
|
+
allowPinchZoom
|
|
140
|
+
shards={[context.contentRef]}
|
|
141
|
+
// causes lots of bugs on touch web on site
|
|
142
|
+
removeScrollBar={false}
|
|
143
|
+
>
|
|
144
|
+
<Frame ref={composedContentRef} {...props}>
|
|
145
|
+
{children}
|
|
146
|
+
</Frame>
|
|
147
|
+
</RemoveScroll>
|
|
148
|
+
|
|
149
|
+
{/* below frame hide when bouncing past 100% */}
|
|
150
|
+
{!props.disableHideBottomOverflow && (
|
|
151
|
+
<Frame
|
|
152
|
+
{...props}
|
|
153
|
+
children={null}
|
|
154
|
+
position="absolute"
|
|
155
|
+
bottom={0}
|
|
156
|
+
maxHeight={300}
|
|
157
|
+
left={0}
|
|
158
|
+
right={0}
|
|
159
|
+
borderRadius={0}
|
|
160
|
+
shadowOpacity={0}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
</>
|
|
164
|
+
)
|
|
130
165
|
}
|
|
131
166
|
)
|
|
132
167
|
)
|
|
@@ -174,400 +209,4 @@ export function createSheet({ Handle, Frame, Overlay }: CreateSheetProps) {
|
|
|
174
209
|
})
|
|
175
210
|
}
|
|
176
211
|
|
|
177
|
-
// set all the way off screen
|
|
178
|
-
const HIDDEN_SIZE = 10_000
|
|
179
|
-
|
|
180
|
-
const ParentSheetContext = createContext({
|
|
181
|
-
zIndex: 100_000,
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
const SheetImplementationCustom = themeable(
|
|
185
|
-
forwardRef<View, SheetProps>(function SheetImplementationCustom(props, forwardedRef) {
|
|
186
|
-
const parentSheet = useContext(ParentSheetContext)
|
|
187
|
-
|
|
188
|
-
const {
|
|
189
|
-
animationConfig,
|
|
190
|
-
forceRemoveScrollEnabled = null,
|
|
191
|
-
disableDrag: disableDragProp,
|
|
192
|
-
modal = false,
|
|
193
|
-
zIndex = parentSheet.zIndex + 1,
|
|
194
|
-
moveOnKeyboardChange = false,
|
|
195
|
-
portalProps,
|
|
196
|
-
} = props
|
|
197
|
-
|
|
198
|
-
const state = useSheetOpenState(props)
|
|
199
|
-
const providerProps = useSheetProviderProps(props, state)
|
|
200
|
-
const { positions, maxSnapPoint, screenSize } = useSheetSnapPoints(providerProps)
|
|
201
|
-
|
|
202
|
-
const { position, contentRef, setPosition, scrollBridge, frameSize, setFrameSize } =
|
|
203
|
-
providerProps
|
|
204
|
-
|
|
205
|
-
const { open, isHidden, controller } = state
|
|
206
|
-
|
|
207
|
-
const {
|
|
208
|
-
frameComponent,
|
|
209
|
-
handleComponent,
|
|
210
|
-
bottomCoverComponent,
|
|
211
|
-
overlayComponent,
|
|
212
|
-
rest,
|
|
213
|
-
} = useSheetChildren(props.children)
|
|
214
|
-
|
|
215
|
-
const sheetRef = useRef<View>(null)
|
|
216
|
-
const ref = useComposedRefs(forwardedRef, sheetRef)
|
|
217
|
-
|
|
218
|
-
const driver = useAnimationDriver()
|
|
219
|
-
if (!driver) {
|
|
220
|
-
throw new Error('Must set animations in tamagui.config.ts')
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const disableDrag = disableDragProp ?? controller?.disableDrag
|
|
224
|
-
const keyboardIsVisible = useKeyboardVisible()
|
|
225
|
-
const themeName = useThemeName()
|
|
226
|
-
|
|
227
|
-
const { useAnimatedNumber, useAnimatedNumberReaction, useAnimatedNumberStyle } =
|
|
228
|
-
driver
|
|
229
|
-
|
|
230
|
-
const animatedNumber = useAnimatedNumber(HIDDEN_SIZE)
|
|
231
|
-
|
|
232
|
-
// native only fix
|
|
233
|
-
const at = useRef(0)
|
|
234
|
-
|
|
235
|
-
useAnimatedNumberReaction(
|
|
236
|
-
{
|
|
237
|
-
value: animatedNumber,
|
|
238
|
-
hostRef: sheetRef,
|
|
239
|
-
},
|
|
240
|
-
(value) => {
|
|
241
|
-
if (!driver.isReactNative) return
|
|
242
|
-
at.current = value
|
|
243
|
-
scrollBridge.paneY = value
|
|
244
|
-
}
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
function stopSpring() {
|
|
248
|
-
animatedNumber.stop()
|
|
249
|
-
if (scrollBridge.onFinishAnimate) {
|
|
250
|
-
scrollBridge.onFinishAnimate()
|
|
251
|
-
scrollBridge.onFinishAnimate = undefined
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// we need to set this *after* fully closed to 0, to avoid it overlapping
|
|
256
|
-
// the page when resizing quickly on web for example
|
|
257
|
-
const [opacity, setOpacity] = useState(open ? 1 : 0)
|
|
258
|
-
if (open && opacity === 0) {
|
|
259
|
-
setOpacity(1)
|
|
260
|
-
}
|
|
261
|
-
useEffect(() => {
|
|
262
|
-
if (!open) {
|
|
263
|
-
// need to wait for animation complete, for now lets just do it naively
|
|
264
|
-
const tm = setTimeout(() => {
|
|
265
|
-
setOpacity(0)
|
|
266
|
-
}, 400)
|
|
267
|
-
return () => {
|
|
268
|
-
clearTimeout(tm)
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}, [open])
|
|
272
|
-
|
|
273
|
-
const animateTo = useEvent((position: number) => {
|
|
274
|
-
const current = animatedNumber.getValue()
|
|
275
|
-
if (isHidden && open) return
|
|
276
|
-
if (!current) return
|
|
277
|
-
if (frameSize === 0) return
|
|
278
|
-
const hiddenValue = frameSize === 0 ? HIDDEN_SIZE : screenSize
|
|
279
|
-
const toValue = isHidden || position === -1 ? hiddenValue : positions[position]
|
|
280
|
-
if (at.current === toValue) return
|
|
281
|
-
stopSpring()
|
|
282
|
-
if (isHidden) {
|
|
283
|
-
animatedNumber.setValue(toValue, {
|
|
284
|
-
type: 'timing',
|
|
285
|
-
duration: 0,
|
|
286
|
-
})
|
|
287
|
-
at.current = toValue
|
|
288
|
-
return
|
|
289
|
-
}
|
|
290
|
-
// dont bounce on initial measure to bottom
|
|
291
|
-
const overshootClamping = at.current === HIDDEN_SIZE
|
|
292
|
-
animatedNumber.setValue(toValue, {
|
|
293
|
-
...animationConfig,
|
|
294
|
-
type: 'spring',
|
|
295
|
-
overshootClamping,
|
|
296
|
-
})
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
useIsomorphicLayoutEffect(() => {
|
|
300
|
-
animateTo(position)
|
|
301
|
-
}, [isHidden, frameSize, position, animateTo])
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* This is a hacky workaround for native:
|
|
305
|
-
*/
|
|
306
|
-
const [isShowingInnerSheet, setIsShowingInnerSheet] = useState(false)
|
|
307
|
-
const shouldHideParentSheet = !isWeb && modal && isShowingInnerSheet
|
|
308
|
-
const parentSheetContext = useContext(SheetInsideSheetContext)
|
|
309
|
-
const onInnerSheet = useCallback((hasChild: boolean) => {
|
|
310
|
-
setIsShowingInnerSheet(hasChild)
|
|
311
|
-
}, [])
|
|
312
|
-
|
|
313
|
-
const panResponder = useMemo(
|
|
314
|
-
() => {
|
|
315
|
-
if (disableDrag) return
|
|
316
|
-
if (!frameSize) return
|
|
317
|
-
if (isShowingInnerSheet) return
|
|
318
|
-
|
|
319
|
-
const minY = positions[0]
|
|
320
|
-
scrollBridge.paneMinY = minY
|
|
321
|
-
let startY = at.current
|
|
322
|
-
|
|
323
|
-
function makeUnselectable(val: boolean) {
|
|
324
|
-
if (!selectionStyleSheet) return
|
|
325
|
-
if (!val) {
|
|
326
|
-
selectionStyleSheet.innerText = ''
|
|
327
|
-
} else {
|
|
328
|
-
selectionStyleSheet.innerText =
|
|
329
|
-
':root * { user-select: none !important; -webkit-user-select: none !important; }'
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const release = ({ vy, dragAt }: { dragAt: number; vy: number }) => {
|
|
334
|
-
isExternalDrag = false
|
|
335
|
-
previouslyScrolling = false
|
|
336
|
-
makeUnselectable(false)
|
|
337
|
-
const at = dragAt + startY
|
|
338
|
-
// seems liky vy goes up to about 4 at the very most (+ is down, - is up)
|
|
339
|
-
// lets base our multiplier on the total layout height
|
|
340
|
-
const end = at + frameSize * vy * 0.2
|
|
341
|
-
let closestPoint = 0
|
|
342
|
-
let dist = Infinity
|
|
343
|
-
for (let i = 0; i < positions.length; i++) {
|
|
344
|
-
const position = positions[i]
|
|
345
|
-
const curDist = end > position ? end - position : position - end
|
|
346
|
-
if (curDist < dist) {
|
|
347
|
-
dist = curDist
|
|
348
|
-
closestPoint = i
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
// have to call both because state may not change but need to snap back
|
|
352
|
-
setPosition(closestPoint)
|
|
353
|
-
animateTo(closestPoint)
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
|
|
357
|
-
release({
|
|
358
|
-
vy: state.vy,
|
|
359
|
-
dragAt: state.dy,
|
|
360
|
-
})
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
let previouslyScrolling = false
|
|
364
|
-
|
|
365
|
-
const onMoveShouldSet = (
|
|
366
|
-
_e: GestureResponderEvent,
|
|
367
|
-
{ dy }: PanResponderGestureState
|
|
368
|
-
) => {
|
|
369
|
-
const isScrolled = scrollBridge.y !== 0
|
|
370
|
-
const isDraggingUp = dy < 0
|
|
371
|
-
// we can treat near top instead of exactly to avoid trouble with springs
|
|
372
|
-
const isNearTop = scrollBridge.paneY - 5 <= scrollBridge.paneMinY
|
|
373
|
-
if (isScrolled) {
|
|
374
|
-
previouslyScrolling = true
|
|
375
|
-
return false
|
|
376
|
-
}
|
|
377
|
-
// prevent drag once at top and pulling up
|
|
378
|
-
if (isNearTop) {
|
|
379
|
-
if (!isScrolled && isDraggingUp) {
|
|
380
|
-
return false
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
// we could do some detection of other touchables and cancel here..
|
|
384
|
-
return Math.abs(dy) > 5
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const grant = () => {
|
|
388
|
-
makeUnselectable(true)
|
|
389
|
-
stopSpring()
|
|
390
|
-
startY = at.current
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
let isExternalDrag = false
|
|
394
|
-
|
|
395
|
-
scrollBridge.drag = (dy) => {
|
|
396
|
-
if (!isExternalDrag) {
|
|
397
|
-
isExternalDrag = true
|
|
398
|
-
grant()
|
|
399
|
-
}
|
|
400
|
-
const to = dy + startY
|
|
401
|
-
animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
scrollBridge.release = release
|
|
405
|
-
|
|
406
|
-
return PanResponder.create({
|
|
407
|
-
onMoveShouldSetPanResponder: onMoveShouldSet,
|
|
408
|
-
onPanResponderGrant: grant,
|
|
409
|
-
onPanResponderMove: (_e, { dy }) => {
|
|
410
|
-
const toFull = dy + startY
|
|
411
|
-
const to = resisted(toFull, minY)
|
|
412
|
-
animatedNumber.setValue(to, { type: 'direct' })
|
|
413
|
-
},
|
|
414
|
-
onPanResponderEnd: finish,
|
|
415
|
-
onPanResponderTerminate: finish,
|
|
416
|
-
onPanResponderRelease: finish,
|
|
417
|
-
})
|
|
418
|
-
},
|
|
419
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
420
|
-
[disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition]
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
const animatedStyle = useAnimatedNumberStyle(animatedNumber, (val) => {
|
|
424
|
-
'worklet'
|
|
425
|
-
const translateY = frameSize === 0 ? HIDDEN_SIZE : val
|
|
426
|
-
return {
|
|
427
|
-
transform: [{ translateY }],
|
|
428
|
-
}
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
const sizeBeforeKeyboard = useRef<number | null>(null)
|
|
432
|
-
useEffect(() => {
|
|
433
|
-
if (isWeb || !moveOnKeyboardChange) return
|
|
434
|
-
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', (e) => {
|
|
435
|
-
if (sizeBeforeKeyboard.current !== null) return
|
|
436
|
-
sizeBeforeKeyboard.current = animatedNumber.getValue()
|
|
437
|
-
animatedNumber.setValue(
|
|
438
|
-
Math.max(animatedNumber.getValue() - e.endCoordinates.height, 0)
|
|
439
|
-
)
|
|
440
|
-
})
|
|
441
|
-
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
|
|
442
|
-
if (sizeBeforeKeyboard.current === null) return
|
|
443
|
-
animatedNumber.setValue(sizeBeforeKeyboard.current)
|
|
444
|
-
sizeBeforeKeyboard.current = null
|
|
445
|
-
})
|
|
446
|
-
|
|
447
|
-
return () => {
|
|
448
|
-
keyboardDidHideListener.remove()
|
|
449
|
-
keyboardDidShowListener.remove()
|
|
450
|
-
}
|
|
451
|
-
}, [])
|
|
452
|
-
|
|
453
|
-
// temp until reanimated useAnimatedNumber fix
|
|
454
|
-
const AnimatedView = (driver['NumberView'] ?? driver.View) as typeof Animated.View
|
|
455
|
-
|
|
456
|
-
useIsomorphicLayoutEffect(() => {
|
|
457
|
-
if (!(parentSheetContext && open)) return
|
|
458
|
-
parentSheetContext(true)
|
|
459
|
-
return () => {
|
|
460
|
-
parentSheetContext(false)
|
|
461
|
-
}
|
|
462
|
-
}, [parentSheetContext, open])
|
|
463
|
-
|
|
464
|
-
const nextParentContext = useMemo(
|
|
465
|
-
() => ({
|
|
466
|
-
zIndex,
|
|
467
|
-
}),
|
|
468
|
-
[zIndex]
|
|
469
|
-
)
|
|
470
|
-
|
|
471
|
-
const handleLayout = useCallback(
|
|
472
|
-
(e) => {
|
|
473
|
-
let next = e.nativeEvent?.layout.height
|
|
474
|
-
if (isWeb && isTouchable && !open) {
|
|
475
|
-
// temp fix ios bug where it doesn't go below dynamic bottom...
|
|
476
|
-
next += 100
|
|
477
|
-
}
|
|
478
|
-
if (!next) return
|
|
479
|
-
setFrameSize(() => next)
|
|
480
|
-
},
|
|
481
|
-
[keyboardIsVisible]
|
|
482
|
-
)
|
|
483
|
-
|
|
484
|
-
const removeScrollEnabled = forceRemoveScrollEnabled ?? (open && modal)
|
|
485
|
-
|
|
486
|
-
const contents = (
|
|
487
|
-
<ParentSheetContext.Provider value={nextParentContext}>
|
|
488
|
-
<SheetProvider {...providerProps}>
|
|
489
|
-
{shouldHideParentSheet ? null : overlayComponent}
|
|
490
|
-
|
|
491
|
-
<AnimatedView
|
|
492
|
-
ref={ref}
|
|
493
|
-
{...panResponder?.panHandlers}
|
|
494
|
-
onLayout={handleLayout}
|
|
495
|
-
pointerEvents={open && !shouldHideParentSheet ? 'auto' : 'none'}
|
|
496
|
-
// @ts-ignore
|
|
497
|
-
animation={props.animation}
|
|
498
|
-
style={[
|
|
499
|
-
{
|
|
500
|
-
position: 'absolute',
|
|
501
|
-
zIndex,
|
|
502
|
-
width: '100%',
|
|
503
|
-
height: `${maxSnapPoint}%`,
|
|
504
|
-
opacity,
|
|
505
|
-
},
|
|
506
|
-
animatedStyle,
|
|
507
|
-
]}
|
|
508
|
-
>
|
|
509
|
-
{handleComponent}
|
|
510
|
-
{bottomCoverComponent}
|
|
511
|
-
|
|
512
|
-
{/* somewhat temporary we need to move to properly support children */}
|
|
513
|
-
{rest}
|
|
514
|
-
|
|
515
|
-
{/* @ts-ignore */}
|
|
516
|
-
<RemoveScroll
|
|
517
|
-
forwardProps
|
|
518
|
-
enabled={removeScrollEnabled}
|
|
519
|
-
allowPinchZoom
|
|
520
|
-
shards={[contentRef]}
|
|
521
|
-
// causes lots of bugs on touch web on site
|
|
522
|
-
removeScrollBar={false}
|
|
523
|
-
>
|
|
524
|
-
{frameComponent}
|
|
525
|
-
</RemoveScroll>
|
|
526
|
-
</AnimatedView>
|
|
527
|
-
</SheetProvider>
|
|
528
|
-
</ParentSheetContext.Provider>
|
|
529
|
-
)
|
|
530
|
-
|
|
531
|
-
const adaptContext = useContext(AdaptParentContext)
|
|
532
|
-
|
|
533
|
-
if (modal) {
|
|
534
|
-
const modalContents = (
|
|
535
|
-
<Portal zIndex={zIndex} {...portalProps}>
|
|
536
|
-
<Theme forceClassName name={themeName}>
|
|
537
|
-
<AdaptParentContext.Provider value={adaptContext}>
|
|
538
|
-
{contents}
|
|
539
|
-
</AdaptParentContext.Provider>
|
|
540
|
-
</Theme>
|
|
541
|
-
</Portal>
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
if (isWeb) {
|
|
545
|
-
return modalContents
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// on native we don't support multiple modals yet... fix for now is to hide outer one
|
|
549
|
-
return (
|
|
550
|
-
<SheetInsideSheetContext.Provider value={onInnerSheet}>
|
|
551
|
-
{modalContents}
|
|
552
|
-
</SheetInsideSheetContext.Provider>
|
|
553
|
-
)
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
return contents
|
|
557
|
-
})
|
|
558
|
-
)
|
|
559
|
-
|
|
560
|
-
const SheetInsideSheetContext = createContext<((hasChild: boolean) => void) | null>(null)
|
|
561
|
-
|
|
562
212
|
/* -------------------------------------------------------------------------------------------------*/
|
|
563
|
-
|
|
564
|
-
function resisted(y: number, minY: number, maxOverflow = 25) {
|
|
565
|
-
if (y < minY) {
|
|
566
|
-
const past = minY - y
|
|
567
|
-
const pctPast = Math.min(maxOverflow, past) / maxOverflow
|
|
568
|
-
const diminishBy = 1.1 - Math.pow(0.1, pctPast)
|
|
569
|
-
const extra = -diminishBy * maxOverflow
|
|
570
|
-
return minY + extra
|
|
571
|
-
}
|
|
572
|
-
return y
|
|
573
|
-
}
|
package/src/helpers.tsx
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function resisted(y: number, minY: number, maxOverflow = 25) {
|
|
2
|
+
if (y < minY) {
|
|
3
|
+
const past = minY - y
|
|
4
|
+
const pctPast = Math.min(maxOverflow, past) / maxOverflow
|
|
5
|
+
const diminishBy = 1.1 - Math.pow(0.1, pctPast)
|
|
6
|
+
const extra = -diminishBy * maxOverflow
|
|
7
|
+
return minY + extra
|
|
8
|
+
}
|
|
9
|
+
return y
|
|
10
|
+
}
|
package/src/nativeSheet.tsx
CHANGED
|
@@ -3,7 +3,6 @@ import { FunctionComponent, useEffect, useRef } from 'react'
|
|
|
3
3
|
|
|
4
4
|
import { SheetProvider } from './SheetContext'
|
|
5
5
|
import { SheetProps } from './types'
|
|
6
|
-
import { useSheetChildren } from './useSheetChildren'
|
|
7
6
|
import { useSheetOpenState } from './useSheetOpenState'
|
|
8
7
|
import { useSheetProviderProps } from './useSheetProviderProps'
|
|
9
8
|
|
|
@@ -26,7 +25,6 @@ export function setupNativeSheet(platform: SheetNativePlatforms, Implementation:
|
|
|
26
25
|
const providerProps = useSheetProviderProps(props, state)
|
|
27
26
|
// const { position } = providerProps
|
|
28
27
|
// const { positions } = useSheetSnapPoints(providerProps)
|
|
29
|
-
const { frameComponent } = useSheetChildren(props.children)
|
|
30
28
|
|
|
31
29
|
const { open, setOpen } = state
|
|
32
30
|
const ref = useRef<{
|
|
@@ -45,9 +43,9 @@ export function setupNativeSheet(platform: SheetNativePlatforms, Implementation:
|
|
|
45
43
|
|
|
46
44
|
return (
|
|
47
45
|
<>
|
|
48
|
-
<SheetProvider {...providerProps}>
|
|
46
|
+
<SheetProvider {...providerProps} onlyShowFrame>
|
|
49
47
|
<Implementation ref={ref} onModalDismiss={() => setOpen(false)}>
|
|
50
|
-
{
|
|
48
|
+
{props.children}
|
|
51
49
|
</Implementation>
|
|
52
50
|
|
|
53
51
|
{/* for some reason select triggers wont show on native if this isn't inside the actual tree not inside implementation... */}
|
|
@@ -59,7 +57,7 @@ export function setupNativeSheet(platform: SheetNativePlatforms, Implementation:
|
|
|
59
57
|
width={0}
|
|
60
58
|
height={0}
|
|
61
59
|
>
|
|
62
|
-
{
|
|
60
|
+
{props.children}
|
|
63
61
|
</YStack>
|
|
64
62
|
</SheetProvider>
|
|
65
63
|
</>
|