@tamagui/sheet 1.0.1-beta.200 → 1.0.1-beta.201

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/src/Sheet.tsx CHANGED
@@ -183,432 +183,447 @@ const ParentSheetContext = createContext({
183
183
  zIndex: 40,
184
184
  })
185
185
 
186
+ const useSheetContoller = () => {
187
+ const controller = useContext(SheetControllerContext)
188
+ const isHidden = controller?.hidden || false
189
+ const isShowingNonSheet = isHidden && controller?.open
190
+ return {
191
+ controller,
192
+ isHidden,
193
+ isShowingNonSheet,
194
+ }
195
+ }
196
+
186
197
  export const Sheet = withStaticProperties(
187
- themeable(
188
- forwardRef<View, SheetProps>(function Sheet(props, ref) {
189
- const parentSheet = useContext(ParentSheetContext)
190
-
191
- const {
192
- __scopeSheet,
193
- snapPoints: snapPointsProp = [80],
194
- open: openProp,
195
- defaultOpen,
196
- children: childrenProp,
197
- position: positionProp,
198
- onPositionChange,
199
- onOpenChange,
200
- defaultPosition,
201
- dismissOnOverlayPress = true,
202
- animationConfig,
203
- dismissOnSnapToBottom = false,
204
- disableDrag: disableDragProp,
205
- modal = false,
206
- handleDisableScroll = true,
207
- zIndex = parentSheet.zIndex + 1,
208
- } = props
209
-
210
- if (process.env.NODE_ENV === 'development') {
211
- if (snapPointsProp.some((p) => p < 0 || p > 100)) {
212
- // eslint-disable-next-line no-console
213
- console.warn(
214
- `⚠️ Invalid snapPoint given, snapPoints must be between 0 and 100, equal to percent height of frame`
215
- )
216
- }
217
- }
198
+ forwardRef<View, SheetProps>(function Sheet(props, ref) {
199
+ const { isShowingNonSheet } = useSheetContoller()
200
+
201
+ /**
202
+ * Performance is sensitive here so avoid all the hooks below with this
203
+ */
204
+ if (isShowingNonSheet) {
205
+ return null
206
+ }
207
+ return <SheetImplementation ref={ref} {...props} />
208
+ }),
209
+ sheetComponents
210
+ )
218
211
 
219
- const driver = getAnimationDriver()
220
- if (!driver) {
221
- throw new Error(`Must set animations in tamagui.config.ts`)
212
+ const SheetImplementation = themeable(
213
+ forwardRef<View, SheetProps>(function SheetImplementation(props, ref) {
214
+ const parentSheet = useContext(ParentSheetContext)
215
+ const { isHidden, controller } = useSheetContoller()
216
+
217
+ const {
218
+ __scopeSheet,
219
+ snapPoints: snapPointsProp = [80],
220
+ open: openProp,
221
+ defaultOpen,
222
+ children: childrenProp,
223
+ position: positionProp,
224
+ onPositionChange,
225
+ onOpenChange,
226
+ defaultPosition,
227
+ dismissOnOverlayPress = true,
228
+ animationConfig,
229
+ dismissOnSnapToBottom = false,
230
+ disableDrag: disableDragProp,
231
+ modal = false,
232
+ handleDisableScroll = true,
233
+ zIndex = parentSheet.zIndex + 1,
234
+ } = props
235
+
236
+ if (process.env.NODE_ENV === 'development') {
237
+ if (snapPointsProp.some((p) => p < 0 || p > 100)) {
238
+ // eslint-disable-next-line no-console
239
+ console.warn(
240
+ `⚠️ Invalid snapPoint given, snapPoints must be between 0 and 100, equal to percent height of frame`
241
+ )
222
242
  }
243
+ }
244
+
245
+ const driver = getAnimationDriver()
246
+ if (!driver) {
247
+ throw new Error(`Must set animations in tamagui.config.ts`)
248
+ }
249
+
250
+ const disableDrag = disableDragProp ?? controller?.disableDrag
251
+ const themeName = useThemeName()
252
+ const contentRef = React.useRef<TamaguiElement>(null)
253
+ const scrollBridge = useConstant<ScrollBridge>(() => ({
254
+ enabled: false,
255
+ y: 0,
256
+ paneY: 0,
257
+ paneMinY: 0,
258
+ scrollStartY: -1,
259
+ drag: () => {},
260
+ release: () => {},
261
+ scrollLock: false,
262
+ }))
263
+
264
+ const onOpenChangeInternal = (val: boolean) => {
265
+ controller?.onOpenChange?.(val)
266
+ onOpenChange?.(val)
267
+ }
268
+
269
+ const [open, setOpen] = useControllableState({
270
+ prop: controller?.open ?? openProp,
271
+ defaultProp: defaultOpen || true,
272
+ onChange: onOpenChangeInternal,
273
+ strategy: 'most-recent-wins',
274
+ })
223
275
 
224
- // allows for sheets to be controlled by other components
225
- const controller = useContext(SheetControllerContext)
226
- const isHidden = controller?.hidden || false
227
- const disableDrag = disableDragProp ?? controller?.disableDrag
228
- const themeName = useThemeName()
229
- const contentRef = React.useRef<TamaguiElement>(null)
230
- const scrollBridge = useConstant<ScrollBridge>(() => ({
231
- enabled: false,
232
- y: 0,
233
- paneY: 0,
234
- paneMinY: 0,
235
- scrollStartY: -1,
236
- drag: () => {},
237
- release: () => {},
238
- scrollLock: false,
239
- }))
240
-
241
- const onOpenChangeInternal = (val: boolean) => {
242
- controller?.onOpenChange?.(val)
243
- onOpenChange?.(val)
244
- }
276
+ const [frameSize, setFrameSize] = useState<number>(0)
245
277
 
246
- const [open, setOpen] = useControllableState({
247
- prop: controller?.open ?? openProp,
248
- defaultProp: defaultOpen || true,
249
- onChange: onOpenChangeInternal,
250
- strategy: 'most-recent-wins',
251
- })
278
+ const snapPoints = useMemo(
279
+ () => (dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),
280
+ // eslint-disable-next-line react-hooks/exhaustive-deps
281
+ [JSON.stringify(snapPointsProp), dismissOnSnapToBottom]
282
+ )
252
283
 
253
- const [frameSize, setFrameSize] = useState<number>(0)
284
+ // lets set -1 to be always the "open = false" position
285
+ const [position_, setPosition_] = useControllableState({
286
+ prop: positionProp,
287
+ defaultProp: defaultPosition || (open ? 0 : -1),
288
+ onChange: onPositionChange,
289
+ strategy: 'most-recent-wins',
290
+ })
291
+ const position = open === false ? -1 : position_
292
+
293
+ // reset position to fully open on re-open after dismissOnSnapToBottom
294
+ if (open && dismissOnSnapToBottom && position === snapPoints.length - 1) {
295
+ setPosition_(0)
296
+ }
297
+
298
+ const setPosition = useCallback(
299
+ (next: number) => {
300
+ // close on dismissOnSnapToBottom (and set position so it animates)
301
+ if (dismissOnSnapToBottom && next === snapPoints.length - 1) {
302
+ setOpen(false)
303
+ } else {
304
+ setPosition_(next)
305
+ }
306
+ },
307
+ [dismissOnSnapToBottom, snapPoints.length, setPosition_, setOpen]
308
+ )
254
309
 
255
- const snapPoints = useMemo(
256
- () => (dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),
257
- // eslint-disable-next-line react-hooks/exhaustive-deps
258
- [JSON.stringify(snapPointsProp), dismissOnSnapToBottom]
259
- )
310
+ const animatedNumber = driver.useAnimatedNumber(HIDDEN_SIZE)
260
311
 
261
- // lets set -1 to be always the "open = false" position
262
- const [position_, setPosition_] = useControllableState({
263
- prop: positionProp,
264
- defaultProp: defaultPosition || (open ? 0 : -1),
265
- onChange: onPositionChange,
266
- strategy: 'most-recent-wins',
267
- })
268
- const position = open === false ? -1 : position_
312
+ // native only fix
313
+ const at = useRef(0)
314
+ driver.useAnimatedNumberReaction(animatedNumber, (value) => {
315
+ at.current = value
316
+ scrollBridge.paneY = value
317
+ })
269
318
 
270
- // reset position to fully open on re-open after dismissOnSnapToBottom
271
- if (open && dismissOnSnapToBottom && position === snapPoints.length - 1) {
272
- setPosition_(0)
319
+ const [isResizing, setIsResizing] = useState(true)
320
+ useIsomorphicLayoutEffect(() => {
321
+ if (!isResizing) {
322
+ setIsResizing(true)
273
323
  }
274
-
275
- const setPosition = useCallback(
276
- (next: number) => {
277
- // close on dismissOnSnapToBottom (and set position so it animates)
278
- if (dismissOnSnapToBottom && next === snapPoints.length - 1) {
279
- setOpen(false)
280
- } else {
281
- setPosition_(next)
282
- }
283
- },
284
- [dismissOnSnapToBottom, snapPoints.length, setPosition_, setOpen]
285
- )
286
-
287
- const animatedNumber = driver.useAnimatedNumber(HIDDEN_SIZE)
288
-
289
- // native only fix
290
- const at = useRef(0)
291
- driver.useAnimatedNumberReaction(animatedNumber, (value) => {
292
- at.current = value
293
- scrollBridge.paneY = value
294
- })
295
-
296
- const [isResizing, setIsResizing] = useState(true)
297
- useIsomorphicLayoutEffect(() => {
298
- if (!isResizing) {
299
- setIsResizing(true)
300
- }
301
- // eslint-disable-next-line react-hooks/exhaustive-deps
302
- }, [modal])
303
-
304
- function stopSpring() {
305
- animatedNumber.stop()
306
- if (scrollBridge.onFinishAnimate) {
307
- scrollBridge.onFinishAnimate()
308
- scrollBridge.onFinishAnimate = undefined
309
- }
324
+ // eslint-disable-next-line react-hooks/exhaustive-deps
325
+ }, [modal])
326
+
327
+ function stopSpring() {
328
+ animatedNumber.stop()
329
+ if (scrollBridge.onFinishAnimate) {
330
+ scrollBridge.onFinishAnimate()
331
+ scrollBridge.onFinishAnimate = undefined
310
332
  }
333
+ }
311
334
 
312
- // open must set position
313
- const shouldSetPositionOpen = open && position < 0
314
- useEffect(() => {
315
- if (shouldSetPositionOpen) {
316
- setPosition(0)
317
- }
318
- }, [setPosition, shouldSetPositionOpen])
335
+ // open must set position
336
+ const shouldSetPositionOpen = open && position < 0
337
+ useEffect(() => {
338
+ if (shouldSetPositionOpen) {
339
+ setPosition(0)
340
+ }
341
+ }, [setPosition, shouldSetPositionOpen])
319
342
 
320
- const positions = useMemo(
321
- () => snapPoints.map((point) => getPercentSize(point, frameSize)),
322
- [frameSize, snapPoints]
323
- )
343
+ const positions = useMemo(
344
+ () => snapPoints.map((point) => getPercentSize(point, frameSize)),
345
+ [frameSize, snapPoints]
346
+ )
324
347
 
325
- const animateTo = useEvent((position: number) => {
326
- const current = animatedNumber.getValue()
327
- if (isHidden && open) return
328
- if (!current) return
329
- if (frameSize === 0) return
330
- const hiddenValue = frameSize === 0 ? HIDDEN_SIZE : frameSize
331
- const toValue = isHidden || position === -1 ? hiddenValue : positions[position]
332
- if (at.current === toValue) return
333
- stopSpring()
334
- if (isHidden || isResizing) {
335
- if (isResizing) {
336
- setIsResizing(false)
337
- }
338
- animatedNumber.setValue(toValue, {
339
- type: 'timing',
340
- duration: 0,
341
- })
342
- at.current = toValue
343
- return
348
+ const animateTo = useEvent((position: number) => {
349
+ const current = animatedNumber.getValue()
350
+ if (isHidden && open) return
351
+ if (!current) return
352
+ if (frameSize === 0) return
353
+ const hiddenValue = frameSize === 0 ? HIDDEN_SIZE : frameSize
354
+ const toValue = isHidden || position === -1 ? hiddenValue : positions[position]
355
+ if (at.current === toValue) return
356
+ stopSpring()
357
+ if (isHidden || isResizing) {
358
+ if (isResizing) {
359
+ setIsResizing(false)
344
360
  }
345
- // dont bounce on initial measure to bottom
346
- const overshootClamping = at.current === HIDDEN_SIZE
347
361
  animatedNumber.setValue(toValue, {
348
- ...animationConfig,
349
- type: 'spring',
350
- overshootClamping,
362
+ type: 'timing',
363
+ duration: 0,
351
364
  })
365
+ at.current = toValue
366
+ return
367
+ }
368
+ // dont bounce on initial measure to bottom
369
+ const overshootClamping = at.current === HIDDEN_SIZE
370
+ animatedNumber.setValue(toValue, {
371
+ ...animationConfig,
372
+ type: 'spring',
373
+ overshootClamping,
352
374
  })
375
+ })
353
376
 
354
- useIsomorphicLayoutEffect(() => {
355
- animateTo(position)
356
- }, [isHidden, frameSize, position, animateTo])
357
-
358
- const panResponder = useMemo(
359
- () => {
360
- if (disableDrag) return
361
- if (!frameSize) return
362
-
363
- const minY = positions[0]
364
- scrollBridge.paneMinY = minY
365
- let startY = at.current
366
-
367
- function makeUnselectable(val: boolean) {
368
- if (!selectionStyleSheet) return
369
- if (!val) {
370
- selectionStyleSheet.innerText = ``
371
- } else {
372
- selectionStyleSheet.innerText = `:root * { user-select: none !important; -webkit-user-select: none !important; }`
373
- }
374
- }
377
+ useIsomorphicLayoutEffect(() => {
378
+ animateTo(position)
379
+ }, [isHidden, frameSize, position, animateTo])
375
380
 
376
- const release = ({ vy, dragAt }: { dragAt: number; vy: number }) => {
377
- isExternalDrag = false
378
- previouslyScrolling = false
379
- makeUnselectable(false)
380
- const at = dragAt + startY
381
- // seems liky vy goes up to about 4 at the very most (+ is down, - is up)
382
- // lets base our multiplier on the total layout height
383
- const end = at + frameSize * vy * 0.2
384
- let closestPoint = 0
385
- let dist = Infinity
386
- for (let i = 0; i < positions.length; i++) {
387
- const position = positions[i]
388
- const curDist = end > position ? end - position : position - end
389
- if (curDist < dist) {
390
- dist = curDist
391
- closestPoint = i
392
- }
393
- }
394
- // have to call both because state may not change but need to snap back
395
- setPosition(closestPoint)
396
- animateTo(closestPoint)
397
- }
381
+ const panResponder = useMemo(
382
+ () => {
383
+ if (disableDrag) return
384
+ if (!frameSize) return
398
385
 
399
- const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
400
- release({
401
- vy: state.vy,
402
- dragAt: state.dy,
403
- })
404
- }
386
+ const minY = positions[0]
387
+ scrollBridge.paneMinY = minY
388
+ let startY = at.current
405
389
 
406
- let previouslyScrolling = false
390
+ function makeUnselectable(val: boolean) {
391
+ if (!selectionStyleSheet) return
392
+ if (!val) {
393
+ selectionStyleSheet.innerText = ``
394
+ } else {
395
+ selectionStyleSheet.innerText = `:root * { user-select: none !important; -webkit-user-select: none !important; }`
396
+ }
397
+ }
407
398
 
408
- const onMoveShouldSet = (_e: GestureResponderEvent, { dy }: PanResponderGestureState) => {
409
- const isScrolled = scrollBridge.y !== 0
410
- const isDraggingUp = dy < 0
411
- const isAtTop = scrollBridge.paneY <= scrollBridge.paneMinY
412
- if (isScrolled) {
413
- previouslyScrolling = true
414
- return false
415
- }
416
- if (previouslyScrolling) {
417
- previouslyScrolling = false
418
- return true
419
- }
420
- // prevent drag once at top and pulling up
421
- if (isAtTop) {
422
- if (!isScrolled && isDraggingUp) {
423
- return false
424
- }
399
+ const release = ({ vy, dragAt }: { dragAt: number; vy: number }) => {
400
+ isExternalDrag = false
401
+ previouslyScrolling = false
402
+ makeUnselectable(false)
403
+ const at = dragAt + startY
404
+ // seems liky vy goes up to about 4 at the very most (+ is down, - is up)
405
+ // lets base our multiplier on the total layout height
406
+ const end = at + frameSize * vy * 0.2
407
+ let closestPoint = 0
408
+ let dist = Infinity
409
+ for (let i = 0; i < positions.length; i++) {
410
+ const position = positions[i]
411
+ const curDist = end > position ? end - position : position - end
412
+ if (curDist < dist) {
413
+ dist = curDist
414
+ closestPoint = i
425
415
  }
426
- // we could do some detection of other touchables and cancel here..
427
- return Math.abs(dy) > 5
428
416
  }
417
+ // have to call both because state may not change but need to snap back
418
+ setPosition(closestPoint)
419
+ animateTo(closestPoint)
420
+ }
429
421
 
430
- const grant = () => {
431
- makeUnselectable(true)
432
- stopSpring()
433
- startY = at.current
434
- }
422
+ const finish = (_e: GestureResponderEvent, state: PanResponderGestureState) => {
423
+ release({
424
+ vy: state.vy,
425
+ dragAt: state.dy,
426
+ })
427
+ }
435
428
 
436
- let isExternalDrag = false
429
+ let previouslyScrolling = false
437
430
 
438
- scrollBridge.drag = (dy) => {
439
- if (!isExternalDrag) {
440
- isExternalDrag = true
441
- grant()
431
+ const onMoveShouldSet = (_e: GestureResponderEvent, { dy }: PanResponderGestureState) => {
432
+ const isScrolled = scrollBridge.y !== 0
433
+ const isDraggingUp = dy < 0
434
+ const isAtTop = scrollBridge.paneY <= scrollBridge.paneMinY
435
+ if (isScrolled) {
436
+ previouslyScrolling = true
437
+ return false
438
+ }
439
+ if (previouslyScrolling) {
440
+ previouslyScrolling = false
441
+ return true
442
+ }
443
+ // prevent drag once at top and pulling up
444
+ if (isAtTop) {
445
+ if (!isScrolled && isDraggingUp) {
446
+ return false
442
447
  }
443
- const to = dy + startY
444
- animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
445
448
  }
449
+ // we could do some detection of other touchables and cancel here..
450
+ return Math.abs(dy) > 5
451
+ }
446
452
 
447
- scrollBridge.release = release
448
-
449
- return PanResponder.create({
450
- onMoveShouldSetPanResponder: onMoveShouldSet,
451
- onPanResponderGrant: grant,
452
- onPanResponderMove: (_e, { dy }) => {
453
- const toFull = dy + startY
454
- const to = resisted(toFull, minY)
455
- animatedNumber.setValue(to, { type: 'direct' })
456
- },
457
- onPanResponderEnd: finish,
458
- onPanResponderTerminate: finish,
459
- onPanResponderRelease: finish,
460
- })
461
- },
462
- // eslint-disable-next-line react-hooks/exhaustive-deps
463
- [disableDrag, animateTo, frameSize, positions, setPosition]
464
- )
453
+ const grant = () => {
454
+ makeUnselectable(true)
455
+ stopSpring()
456
+ startY = at.current
457
+ }
465
458
 
466
- let handleComponent: React.ReactElement | null = null
467
- let overlayComponent: React.ReactElement | null = null
468
- let frameComponent: React.ReactElement | null = null
469
-
470
- // TODO do more radix-like and don't require direct children descendents
471
- React.Children.forEach(childrenProp, (child) => {
472
- if (isValidElement(child)) {
473
- const name = child.type?.['staticConfig']?.componentName
474
- switch (name) {
475
- case 'SheetHandle':
476
- handleComponent = child
477
- break
478
- case 'Sheet':
479
- frameComponent = child
480
- break
481
- case 'SheetOverlay':
482
- overlayComponent = child
483
- break
484
- default:
485
- // eslint-disable-next-line no-console
486
- console.warn('Warning: passed invalid child to Sheet', child)
459
+ let isExternalDrag = false
460
+
461
+ scrollBridge.drag = (dy) => {
462
+ if (!isExternalDrag) {
463
+ isExternalDrag = true
464
+ grant()
487
465
  }
466
+ const to = dy + startY
467
+ animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
488
468
  }
489
- })
490
469
 
491
- const preventShown = controller?.hidden && controller?.open
470
+ scrollBridge.release = release
471
+
472
+ return PanResponder.create({
473
+ onMoveShouldSetPanResponder: onMoveShouldSet,
474
+ onPanResponderGrant: grant,
475
+ onPanResponderMove: (_e, { dy }) => {
476
+ const toFull = dy + startY
477
+ const to = resisted(toFull, minY)
478
+ animatedNumber.setValue(to, { type: 'direct' })
479
+ },
480
+ onPanResponderEnd: finish,
481
+ onPanResponderTerminate: finish,
482
+ onPanResponderRelease: finish,
483
+ })
484
+ },
485
+ // eslint-disable-next-line react-hooks/exhaustive-deps
486
+ [disableDrag, animateTo, frameSize, positions, setPosition]
487
+ )
492
488
 
493
- const animatedStyle = driver.useAnimatedNumberStyle(animatedNumber, (val) => {
494
- return {
495
- transform: [{ translateY: frameSize === 0 ? HIDDEN_SIZE : val }],
489
+ let handleComponent: React.ReactElement | null = null
490
+ let overlayComponent: React.ReactElement | null = null
491
+ let frameComponent: React.ReactElement | null = null
492
+
493
+ // TODO do more radix-like and don't require direct children descendents
494
+ React.Children.forEach(childrenProp, (child) => {
495
+ if (isValidElement(child)) {
496
+ const name = child.type?.['staticConfig']?.componentName
497
+ switch (name) {
498
+ case 'SheetHandle':
499
+ handleComponent = child
500
+ break
501
+ case 'Sheet':
502
+ frameComponent = child
503
+ break
504
+ case 'SheetOverlay':
505
+ overlayComponent = child
506
+ break
507
+ default:
508
+ // eslint-disable-next-line no-console
509
+ console.warn('Warning: passed invalid child to Sheet', child)
496
510
  }
497
- })
511
+ }
512
+ })
498
513
 
499
- // temp until reanimated useAnimatedNumber fix
500
- const AnimatedView = driver['NumberView'] ?? driver.View
501
-
502
- /**
503
- * This is a hacky workaround for native:
504
- */
505
- const [isShowingInnerSheet, setIsShowingInnerSheet] = useState(false)
506
- const shouldHideParentSheet = !isWeb && modal && isShowingInnerSheet
507
- const parentSheetContext = useContext(SheetInsideSheetContext)
508
- const onInnerSheet = useCallback((hasChild: boolean) => {
509
- setIsShowingInnerSheet(hasChild)
510
- }, [])
511
-
512
- useIsomorphicLayoutEffect(() => {
513
- if (!parentSheetContext || !open) return
514
- parentSheetContext(true)
515
- return () => {
516
- parentSheetContext(false)
517
- }
518
- }, [parentSheetContext, open])
514
+ const animatedStyle = driver.useAnimatedNumberStyle(animatedNumber, (val) => {
515
+ return {
516
+ transform: [{ translateY: frameSize === 0 ? HIDDEN_SIZE : val }],
517
+ }
518
+ })
519
519
 
520
- const nextParentContext = useMemo(
521
- () => ({
522
- zIndex,
523
- }),
524
- [zIndex]
525
- )
520
+ // temp until reanimated useAnimatedNumber fix
521
+ const AnimatedView = driver['NumberView'] ?? driver.View
522
+
523
+ /**
524
+ * This is a hacky workaround for native:
525
+ */
526
+ const [isShowingInnerSheet, setIsShowingInnerSheet] = useState(false)
527
+ const shouldHideParentSheet = !isWeb && modal && isShowingInnerSheet
528
+ const parentSheetContext = useContext(SheetInsideSheetContext)
529
+ const onInnerSheet = useCallback((hasChild: boolean) => {
530
+ setIsShowingInnerSheet(hasChild)
531
+ }, [])
532
+
533
+ useIsomorphicLayoutEffect(() => {
534
+ if (!parentSheetContext || !open) return
535
+ parentSheetContext(true)
536
+ return () => {
537
+ parentSheetContext(false)
538
+ }
539
+ }, [parentSheetContext, open])
526
540
 
527
- const contents = (
528
- <ParentSheetContext.Provider value={nextParentContext}>
529
- <SheetProvider
530
- modal={modal}
531
- contentRef={contentRef}
532
- dismissOnOverlayPress={dismissOnOverlayPress}
533
- dismissOnSnapToBottom={dismissOnSnapToBottom}
534
- open={open}
535
- hidden={isHidden}
536
- scope={__scopeSheet}
537
- position={position}
538
- snapPoints={snapPoints}
539
- setPosition={setPosition}
540
- setOpen={setOpen}
541
- scrollBridge={scrollBridge}
541
+ const nextParentContext = useMemo(
542
+ () => ({
543
+ zIndex,
544
+ }),
545
+ [zIndex]
546
+ )
547
+
548
+ const contents = (
549
+ <ParentSheetContext.Provider value={nextParentContext}>
550
+ <SheetProvider
551
+ modal={modal}
552
+ contentRef={contentRef}
553
+ dismissOnOverlayPress={dismissOnOverlayPress}
554
+ dismissOnSnapToBottom={dismissOnSnapToBottom}
555
+ open={open}
556
+ hidden={isHidden}
557
+ scope={__scopeSheet}
558
+ position={position}
559
+ snapPoints={snapPoints}
560
+ setPosition={setPosition}
561
+ setOpen={setOpen}
562
+ scrollBridge={scrollBridge}
563
+ >
564
+ {isResizing || shouldHideParentSheet ? null : overlayComponent}
565
+
566
+ <AnimatedView
567
+ ref={ref}
568
+ {...panResponder?.panHandlers}
569
+ onLayout={(e) => {
570
+ const next = e.nativeEvent.layout.height
571
+ setFrameSize((prev) => {
572
+ const isBigChange = Math.abs(prev - next) > 50
573
+ setIsResizing(isBigChange)
574
+ return next
575
+ })
576
+ }}
577
+ pointerEvents={open && !shouldHideParentSheet ? 'auto' : 'none'}
578
+ style={[
579
+ {
580
+ position: 'absolute',
581
+ zIndex,
582
+ width: '100%',
583
+ height: '100%',
584
+ opacity: shouldHideParentSheet ? 0 : 1,
585
+ },
586
+ animatedStyle,
587
+ ]}
542
588
  >
543
- {isResizing || shouldHideParentSheet ? null : overlayComponent}
544
-
545
- <AnimatedView
546
- ref={ref}
547
- {...panResponder?.panHandlers}
548
- onLayout={(e) => {
549
- const next = e.nativeEvent.layout.height
550
- setFrameSize((prev) => {
551
- const isBigChange = Math.abs(prev - next) > 50
552
- setIsResizing(isBigChange)
553
- return next
554
- })
555
- }}
556
- pointerEvents={open && !shouldHideParentSheet ? 'auto' : 'none'}
557
- style={[
558
- {
559
- position: 'absolute',
560
- zIndex,
561
- width: '100%',
562
- height: '100%',
563
- opacity: shouldHideParentSheet ? 0 : 1,
564
- },
565
- animatedStyle,
566
- ]}
589
+ {handleComponent}
590
+
591
+ <RemoveScroll
592
+ enabled={open && modal && handleDisableScroll}
593
+ as={Slot}
594
+ allowPinchZoom
595
+ shards={[contentRef]}
596
+ // causes lots of bugs on touch web on site
597
+ removeScrollBar={false}
567
598
  >
568
- {handleComponent}
569
-
570
- <RemoveScroll
571
- enabled={open && modal && handleDisableScroll}
572
- as={Slot}
573
- allowPinchZoom
574
- shards={[contentRef]}
575
- // causes lots of bugs on touch web on site
576
- removeScrollBar={false}
577
- >
578
- {isResizing ? null : frameComponent}
579
- </RemoveScroll>
580
- </AnimatedView>
581
- </SheetProvider>
582
- </ParentSheetContext.Provider>
599
+ {isResizing ? null : frameComponent}
600
+ </RemoveScroll>
601
+ </AnimatedView>
602
+ </SheetProvider>
603
+ </ParentSheetContext.Provider>
604
+ )
605
+
606
+ if (modal) {
607
+ const modalContents = (
608
+ <Portal zIndex={zIndex}>
609
+ <Theme name={themeName}>{contents}</Theme>
610
+ </Portal>
583
611
  )
584
612
 
585
- if (preventShown) {
586
- return null
613
+ if (isWeb) {
614
+ return modalContents
587
615
  }
588
616
 
589
- if (modal) {
590
- const modalContents = (
591
- <Portal zIndex={zIndex}>
592
- <Theme name={themeName}>{contents}</Theme>
593
- </Portal>
594
- )
595
-
596
- if (isWeb) {
597
- return modalContents
598
- }
599
-
600
- // on native we don't support multiple modals yet... fix for now is to hide outer one
601
- return (
602
- <SheetInsideSheetContext.Provider value={onInnerSheet}>
603
- {modalContents}
604
- </SheetInsideSheetContext.Provider>
605
- )
606
- }
617
+ // on native we don't support multiple modals yet... fix for now is to hide outer one
618
+ return (
619
+ <SheetInsideSheetContext.Provider value={onInnerSheet}>
620
+ {modalContents}
621
+ </SheetInsideSheetContext.Provider>
622
+ )
623
+ }
607
624
 
608
- return contents
609
- })
610
- ),
611
- sheetComponents
625
+ return contents
626
+ })
612
627
  )
613
628
 
614
629
  const SheetInsideSheetContext = createContext<((hasChild: boolean) => void) | null>(null)