@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.
Files changed (115) hide show
  1. package/dist/cjs/SheetController.js +12 -4
  2. package/dist/cjs/SheetController.js.map +2 -2
  3. package/dist/cjs/SheetController.native.js +12 -4
  4. package/dist/cjs/SheetController.native.js.map +2 -2
  5. package/dist/cjs/SheetImplementationCustom.js +248 -238
  6. package/dist/cjs/SheetImplementationCustom.js.map +2 -2
  7. package/dist/cjs/SheetImplementationCustom.native.js +27 -19
  8. package/dist/cjs/SheetImplementationCustom.native.js.map +2 -2
  9. package/dist/cjs/SheetScrollView.js +14 -6
  10. package/dist/cjs/SheetScrollView.js.map +2 -2
  11. package/dist/cjs/SheetScrollView.native.js +14 -6
  12. package/dist/cjs/SheetScrollView.native.js.map +2 -2
  13. package/dist/cjs/contexts.js +13 -5
  14. package/dist/cjs/contexts.js.map +2 -2
  15. package/dist/cjs/contexts.native.js +12 -4
  16. package/dist/cjs/contexts.native.js.map +2 -2
  17. package/dist/cjs/useSheetController.js +13 -7
  18. package/dist/cjs/useSheetController.js.map +2 -2
  19. package/dist/cjs/useSheetController.native.js +13 -5
  20. package/dist/cjs/useSheetController.native.js.map +2 -2
  21. package/dist/cjs/useSheetProviderProps.js +4 -4
  22. package/dist/cjs/useSheetProviderProps.js.map +1 -1
  23. package/dist/cjs/useSheetProviderProps.native.js +5 -5
  24. package/dist/cjs/useSheetProviderProps.native.js.map +1 -1
  25. package/dist/esm/SheetController.js +2 -2
  26. package/dist/esm/SheetController.js.map +1 -1
  27. package/dist/esm/SheetController.mjs +2 -2
  28. package/dist/esm/SheetController.mjs.map +1 -1
  29. package/dist/esm/SheetController.native.js +2 -2
  30. package/dist/esm/SheetController.native.js.map +2 -2
  31. package/dist/esm/SheetImplementationCustom.js +238 -245
  32. package/dist/esm/SheetImplementationCustom.js.map +1 -1
  33. package/dist/esm/SheetImplementationCustom.mjs +22 -22
  34. package/dist/esm/SheetImplementationCustom.mjs.map +1 -1
  35. package/dist/esm/SheetImplementationCustom.native.js +17 -17
  36. package/dist/esm/SheetImplementationCustom.native.js.map +2 -2
  37. package/dist/esm/SheetScrollView.js +4 -4
  38. package/dist/esm/SheetScrollView.js.map +1 -1
  39. package/dist/esm/SheetScrollView.mjs +5 -5
  40. package/dist/esm/SheetScrollView.mjs.map +1 -1
  41. package/dist/esm/SheetScrollView.native.js +4 -4
  42. package/dist/esm/SheetScrollView.native.js.map +2 -2
  43. package/dist/esm/contexts.js +3 -3
  44. package/dist/esm/contexts.js.map +1 -1
  45. package/dist/esm/contexts.mjs +3 -3
  46. package/dist/esm/contexts.mjs.map +1 -1
  47. package/dist/esm/contexts.native.js +3 -3
  48. package/dist/esm/contexts.native.js.map +2 -2
  49. package/dist/esm/useSheetController.js +3 -5
  50. package/dist/esm/useSheetController.js.map +1 -1
  51. package/dist/esm/useSheetController.mjs +3 -3
  52. package/dist/esm/useSheetController.mjs.map +1 -1
  53. package/dist/esm/useSheetController.native.js +3 -3
  54. package/dist/esm/useSheetController.native.js.map +2 -2
  55. package/dist/esm/useSheetProviderProps.js +4 -4
  56. package/dist/esm/useSheetProviderProps.js.map +1 -1
  57. package/dist/esm/useSheetProviderProps.mjs +6 -6
  58. package/dist/esm/useSheetProviderProps.mjs.map +1 -1
  59. package/dist/esm/useSheetProviderProps.native.js +5 -5
  60. package/dist/esm/useSheetProviderProps.native.js.map +2 -2
  61. package/dist/jsx/SheetController.js +2 -2
  62. package/dist/jsx/SheetController.js.map +1 -1
  63. package/dist/jsx/SheetController.mjs +2 -2
  64. package/dist/jsx/SheetController.mjs.map +1 -1
  65. package/dist/jsx/SheetController.native.js +2 -2
  66. package/dist/jsx/SheetController.native.js.map +2 -2
  67. package/dist/jsx/SheetImplementationCustom.js +238 -245
  68. package/dist/jsx/SheetImplementationCustom.js.map +1 -1
  69. package/dist/jsx/SheetImplementationCustom.mjs +22 -22
  70. package/dist/jsx/SheetImplementationCustom.mjs.map +1 -1
  71. package/dist/jsx/SheetImplementationCustom.native.js +17 -17
  72. package/dist/jsx/SheetImplementationCustom.native.js.map +2 -2
  73. package/dist/jsx/SheetScrollView.js +4 -4
  74. package/dist/jsx/SheetScrollView.js.map +1 -1
  75. package/dist/jsx/SheetScrollView.mjs +5 -5
  76. package/dist/jsx/SheetScrollView.mjs.map +1 -1
  77. package/dist/jsx/SheetScrollView.native.js +4 -4
  78. package/dist/jsx/SheetScrollView.native.js.map +2 -2
  79. package/dist/jsx/contexts.js +3 -3
  80. package/dist/jsx/contexts.js.map +1 -1
  81. package/dist/jsx/contexts.mjs +3 -3
  82. package/dist/jsx/contexts.mjs.map +1 -1
  83. package/dist/jsx/contexts.native.js +3 -3
  84. package/dist/jsx/contexts.native.js.map +2 -2
  85. package/dist/jsx/useSheetController.js +3 -5
  86. package/dist/jsx/useSheetController.js.map +1 -1
  87. package/dist/jsx/useSheetController.mjs +3 -3
  88. package/dist/jsx/useSheetController.mjs.map +1 -1
  89. package/dist/jsx/useSheetController.native.js +3 -3
  90. package/dist/jsx/useSheetController.native.js.map +2 -2
  91. package/dist/jsx/useSheetProviderProps.js +4 -4
  92. package/dist/jsx/useSheetProviderProps.js.map +1 -1
  93. package/dist/jsx/useSheetProviderProps.mjs +6 -6
  94. package/dist/jsx/useSheetProviderProps.mjs.map +1 -1
  95. package/dist/jsx/useSheetProviderProps.native.js +5 -5
  96. package/dist/jsx/useSheetProviderProps.native.js.map +2 -2
  97. package/package.json +16 -16
  98. package/src/SheetController.tsx +3 -2
  99. package/src/SheetImplementationCustom.tsx +426 -432
  100. package/src/SheetScrollView.tsx +9 -5
  101. package/src/contexts.ts +3 -3
  102. package/src/useSheetController.tsx +4 -5
  103. package/src/useSheetProviderProps.tsx +6 -6
  104. package/types/SheetController.d.ts +1 -1
  105. package/types/SheetController.d.ts.map +1 -1
  106. package/types/SheetImplementationCustom.d.ts +5 -4
  107. package/types/SheetImplementationCustom.d.ts.map +1 -1
  108. package/types/SheetScrollView.d.ts +3 -2
  109. package/types/SheetScrollView.d.ts.map +1 -1
  110. package/types/contexts.d.ts +3 -2
  111. package/types/contexts.d.ts.map +1 -1
  112. package/types/useSheetController.d.ts +2 -1
  113. package/types/useSheetController.d.ts.map +1 -1
  114. package/types/useSheetProviderProps.d.ts +1 -1
  115. 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
- import {
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>(function SheetImplementationCustom(props, forwardedRef) {
46
- const parentSheet = useContext(ParentSheetContext)
47
-
48
- const {
49
- animation,
50
- animationConfig: animationConfigProp,
51
- modal = false,
52
- zIndex = parentSheet.zIndex + 1,
53
- moveOnKeyboardChange = false,
54
- unmountChildrenWhenHidden = false,
55
- portalProps,
56
- containerComponent: ContainerComponent = Fragment,
57
- } = props
58
-
59
- const keyboardIsVisible = useKeyboardVisible()
60
- const state = useSheetOpenState(props)
61
- const [overlayComponent, setOverlayComponent] = useState<any>(null)
62
-
63
- const providerProps = useSheetProviderProps(props, state, {
64
- onOverlayComponent: setOverlayComponent,
65
- })
66
- const {
67
- frameSize,
68
- setFrameSize,
69
- snapPoints,
70
- snapPointsMode,
71
- hasFit,
72
- position,
73
- setPosition,
74
- scrollBridge,
75
- screenSize,
76
- setMaxContentSize,
77
- maxSnapPoint,
78
- } = providerProps
79
- const { open, controller, isHidden } = state
80
-
81
- const sheetRef = useRef<View>(null)
82
- const ref = useComposedRefs(forwardedRef, sheetRef)
83
-
84
- // TODO this can be extracted into a helper getAnimationConfig(animationProp as array | string)
85
- const animationConfig = (() => {
86
- const [animationProp, animationPropConfig] = !animation
87
- ? []
88
- : Array.isArray(animation)
89
- ? animation
90
- : ([animation] as const)
91
- return (
92
- animationConfigProp ??
93
- (animationProp
94
- ? {
95
- ...(getConfig().animations.animations[animationProp as string] as Object),
96
- ...animationPropConfig,
97
- }
98
- : null)
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
- * This is a hacky workaround for native:
104
- */
105
- const [isShowingInnerSheet, setIsShowingInnerSheet] = useState(false)
106
- const shouldHideParentSheet = !isWeb && modal && isShowingInnerSheet
107
- const parentSheetContext = useContext(SheetInsideSheetContext)
108
- const onInnerSheet = useCallback((hasChild: boolean) => {
109
- setIsShowingInnerSheet(hasChild)
110
- }, [])
111
-
112
- const positions = useMemo(
113
- () =>
114
- snapPoints.map((point) =>
115
- getYPositions(snapPointsMode, point, screenSize, frameSize)
116
- ),
117
- [screenSize, frameSize, snapPoints, snapPointsMode]
118
- )
119
-
120
- const { animationDriver } = useConfiguration()
121
- const { useAnimatedNumber, useAnimatedNumberStyle, useAnimatedNumberReaction } =
122
- animationDriver
123
- const AnimatedView = (animationDriver.View ?? Stack) as typeof Animated.View
124
-
125
- useIsomorphicLayoutEffect(() => {
126
- if (!(parentSheetContext && open)) return
127
- parentSheetContext(true)
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
- [animationDriver]
141
+ React.useCallback(
142
+ (value) => {
143
+ at.current = value
144
+ scrollBridge.paneY = value
145
+ },
146
+ [animationDriver]
147
+ )
154
148
  )
155
- )
156
149
 
157
- function stopSpring() {
158
- animatedNumber.stop()
159
- if (scrollBridge.onFinishAnimate) {
160
- scrollBridge.onFinishAnimate()
161
- scrollBridge.onFinishAnimate = undefined
150
+ function stopSpring() {
151
+ animatedNumber.stop()
152
+ if (scrollBridge.onFinishAnimate) {
153
+ scrollBridge.onFinishAnimate()
154
+ scrollBridge.onFinishAnimate = undefined
155
+ }
162
156
  }
163
- }
164
157
 
165
- const hasntMeasured = at.current === hiddenSize
158
+ const hasntMeasured = at.current === hiddenSize
166
159
 
167
- const animateTo = useEvent((position: number) => {
168
- if (frameSize === 0) return
160
+ const animateTo = useEvent((position: number) => {
161
+ if (frameSize === 0) return
169
162
 
170
- let toValue = isHidden || position === -1 ? screenSize : positions[position]
163
+ let toValue = isHidden || position === -1 ? screenSize : positions[position]
171
164
 
172
- if (at.current === toValue) return
173
- at.current = toValue
165
+ if (at.current === toValue) return
166
+ at.current = toValue
174
167
 
175
- stopSpring()
168
+ stopSpring()
176
169
 
177
- if (hasntMeasured || isHidden) {
178
- // first run, we need to set to screen size before running
179
- animatedNumber.setValue(
180
- screenSize,
181
- {
182
- type: 'timing',
183
- duration: 0,
184
- },
185
- () => {
186
- if (isHidden) {
187
- return
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
- toValue = positions[position]
191
- at.current = toValue
192
-
193
- animatedNumber.setValue(toValue, {
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
- useIsomorphicLayoutEffect(() => {
209
- if (screenSize && hasntMeasured) {
210
- animatedNumber.setValue(screenSize, {
211
- type: 'timing',
212
- duration: 0,
213
- })
214
- }
215
- }, [hasntMeasured, screenSize])
201
+ useIsomorphicLayoutEffect(() => {
202
+ if (screenSize && hasntMeasured) {
203
+ animatedNumber.setValue(screenSize, {
204
+ type: 'timing',
205
+ duration: 0,
206
+ })
207
+ }
208
+ }, [hasntMeasured, screenSize])
216
209
 
217
- useIsomorphicLayoutEffect(() => {
218
- if (!frameSize || !screenSize || isHidden || (hasntMeasured && !open)) {
219
- return
220
- }
221
- animateTo(position)
222
- }, [isHidden, frameSize, screenSize, open, position])
223
-
224
- const disableDrag = props.disableDrag ?? controller?.disableDrag
225
- const themeName = useThemeName()
226
- const [isDragging, setIsDragging] = useState(false)
227
-
228
- const panResponder = useMemo(() => {
229
- if (disableDrag) return
230
- if (!frameSize) return
231
- if (isShowingInnerSheet) return
232
-
233
- const minY = positions[0]
234
- scrollBridge.paneMinY = minY
235
- let startY = at.current
236
-
237
- function setPanning(val: boolean) {
238
- setIsDragging(val)
239
-
240
- // make unselectable:
241
- if (!SHEET_HIDDEN_STYLESHEET) return
242
- if (!val) {
243
- SHEET_HIDDEN_STYLESHEET.innerText = ''
244
- } else {
245
- SHEET_HIDDEN_STYLESHEET.innerText =
246
- ':root * { user-select: none !important; -webkit-user-select: none !important; }'
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
- const release = ({ vy, dragAt }: { dragAt: number; vy: number }) => {
251
- isExternalDrag = false
252
- previouslyScrolling = false
253
- setPanning(false)
254
- const at = dragAt + startY
255
- // seems liky vy goes up to about 4 at the very most (+ is down, - is up)
256
- // lets base our multiplier on the total layout height
257
- const end = at + frameSize * vy * 0.2
258
- let closestPoint = 0
259
- let dist = Number.POSITIVE_INFINITY
260
- for (let i = 0; i < positions.length; i++) {
261
- const position = positions[i]
262
- const curDist = end > position ? end - position : position - end
263
- if (curDist < dist) {
264
- dist = curDist
265
- closestPoint = i
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
- const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
274
- release({
275
- vy: state.vy,
276
- dragAt: state.dy,
277
- })
278
- }
266
+ const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
267
+ release({
268
+ vy: state.vy,
269
+ dragAt: state.dy,
270
+ })
271
+ }
279
272
 
280
- let previouslyScrolling = false
273
+ let previouslyScrolling = false
281
274
 
282
- const onMoveShouldSet = (
283
- e: GestureResponderEvent,
284
- { dy }: PanResponderGestureState
285
- ) => {
286
- // if dragging handle always allow:
287
- if (e.target === providerProps.handleRef.current) {
288
- return true
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
- const isScrolled = scrollBridge.y !== 0
292
- const isDraggingUp = dy < 0
293
- // we can treat near top instead of exactly to avoid trouble with springs
294
- const isNearTop = scrollBridge.paneY - 5 <= scrollBridge.paneMinY
295
- if (isScrolled) {
296
- previouslyScrolling = true
297
- return false
298
- }
299
- // prevent drag once at top and pulling up
300
- if (isNearTop) {
301
- if (!isScrolled && isDraggingUp) {
302
- // TODO: pulling past the limit breaks scroll on native, need to better make ScrollView
303
- if (!isWeb) {
304
- return false
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
- const grant = () => {
313
- setPanning(true)
314
- stopSpring()
315
- startY = at.current
316
- }
305
+ const grant = () => {
306
+ setPanning(true)
307
+ stopSpring()
308
+ startY = at.current
309
+ }
317
310
 
318
- let isExternalDrag = false
311
+ let isExternalDrag = false
319
312
 
320
- scrollBridge.drag = (dy) => {
321
- if (!isExternalDrag) {
322
- isExternalDrag = true
323
- grant()
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
- scrollBridge.release = release
322
+ scrollBridge.release = release
330
323
 
331
- return PanResponder.create({
332
- onMoveShouldSetPanResponder: onMoveShouldSet,
333
- onPanResponderGrant: grant,
334
- onPanResponderMove: (_e, { dy }) => {
335
- const toFull = dy + startY
336
- const to = resisted(toFull, minY)
337
- animatedNumber.setValue(to, { type: 'direct' })
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
- onPanResponderEnd: finish,
340
- onPanResponderTerminate: finish,
341
- onPanResponderRelease: finish,
342
- })
343
- }, [disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition])
344
-
345
- const handleAnimationViewLayout = useCallback(
346
- (e: LayoutChangeEvent) => {
347
- // avoid bugs where it grows forever for whatever reason
348
- const next = Math.min(
349
- e.nativeEvent?.layout.height,
350
- Dimensions.get('window').height
351
- )
352
- if (!next) return
353
- setFrameSize(next)
354
- },
355
- [keyboardIsVisible]
356
- )
357
-
358
- const handleMaxContentViewLayout = useCallback(
359
- (e: LayoutChangeEvent) => {
360
- // avoid bugs where it grows forever for whatever reason
361
- const next = Math.min(
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
- return () => {
397
- keyboardDidHideListener.remove()
398
- keyboardDidShowListener.remove()
399
- }
400
- }, [moveOnKeyboardChange])
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
- clearTimeout(tm)
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
- }, [open])
419
-
420
- const forcedContentHeight = hasFit
421
- ? undefined
422
- : snapPointsMode === 'percent'
423
- ? `${maxSnapPoint}${isWeb ? 'dvh' : '%'}`
424
- : maxSnapPoint
425
-
426
- const contents = (
427
- <ParentSheetContext.Provider value={nextParentContext}>
428
- <SheetProvider {...providerProps}>
429
- <AnimatePresence custom={{ open }}>
430
- {shouldHideParentSheet || !open ? null : overlayComponent}
431
- </AnimatePresence>
432
-
433
- {snapPointsMode !== 'percent' && (
434
- <View
435
- style={{
436
- opacity: 0,
437
- position: 'absolute',
438
- top: 0,
439
- left: 0,
440
- right: 0,
441
- bottom: 0,
442
- pointerEvents: 'none',
443
- }}
444
- onLayout={handleMaxContentViewLayout}
445
- />
446
- )}
447
-
448
- <AnimatedView
449
- ref={ref}
450
- {...panResponder?.panHandlers}
451
- onLayout={handleAnimationViewLayout}
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
- animatedStyle,
471
- ]}
472
- >
473
- {props.children}
474
- </AnimatedView>
475
- </SheetProvider>
476
- </ParentSheetContext.Provider>
477
- )
478
-
479
- const adaptContext = useContext(AdaptParentContext)
480
-
481
- // start mounted so we get an accurate measurement the first time
482
- const shouldMountChildren = Boolean(opacity || !unmountChildrenWhenHidden)
483
-
484
- if (modal) {
485
- const modalContents = (
486
- <Portal zIndex={zIndex} {...portalProps}>
487
- {shouldMountChildren && (
488
- <ContainerComponent>
489
- <Theme forceClassName name={themeName}>
490
- <AdaptParentContext.Provider value={adaptContext}>
491
- {contents}
492
- </AdaptParentContext.Provider>
493
- </Theme>
494
- </ContainerComponent>
495
- )}
496
- </Portal>
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
- if (isWeb) {
500
- return modalContents
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
- // on native we don't support multiple modals yet... fix for now is to hide outer one
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(