@tamagui/sheet 1.20.7 → 1.21.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 (144) hide show
  1. package/dist/cjs/Sheet.js +75 -187
  2. package/dist/cjs/Sheet.js.map +2 -2
  3. package/dist/cjs/SheetController.js +49 -0
  4. package/dist/cjs/SheetController.js.map +6 -0
  5. package/dist/cjs/getNativeSheet.js +39 -0
  6. package/dist/cjs/getNativeSheet.js.map +6 -0
  7. package/dist/cjs/index.js +14 -1
  8. package/dist/cjs/index.js.map +1 -1
  9. package/dist/cjs/native-ios.js +5 -0
  10. package/dist/cjs/native-ios.js.map +6 -0
  11. package/dist/cjs/nativeSheet.js +58 -0
  12. package/dist/cjs/nativeSheet.js.map +6 -0
  13. package/dist/cjs/useSheetChildren.js +68 -0
  14. package/dist/cjs/useSheetChildren.js.map +6 -0
  15. package/dist/cjs/useSheetContoller.js +44 -0
  16. package/dist/cjs/useSheetContoller.js.map +6 -0
  17. package/dist/cjs/useSheetController.js +44 -0
  18. package/dist/cjs/useSheetController.js.map +6 -0
  19. package/dist/cjs/useSheetOpenState.js +51 -0
  20. package/dist/cjs/useSheetOpenState.js.map +6 -0
  21. package/dist/cjs/useSheetProviderProps.js +98 -0
  22. package/dist/cjs/useSheetProviderProps.js.map +6 -0
  23. package/dist/esm/Sheet.js +77 -178
  24. package/dist/esm/Sheet.js.map +2 -2
  25. package/dist/esm/Sheet.mjs +77 -178
  26. package/dist/esm/Sheet.mjs.map +2 -2
  27. package/dist/esm/SheetController.js +25 -0
  28. package/dist/esm/SheetController.js.map +6 -0
  29. package/dist/esm/SheetController.mjs +25 -0
  30. package/dist/esm/SheetController.mjs.map +6 -0
  31. package/dist/esm/getNativeSheet.js +14 -0
  32. package/dist/esm/getNativeSheet.js.map +6 -0
  33. package/dist/esm/getNativeSheet.mjs +14 -0
  34. package/dist/esm/getNativeSheet.mjs.map +6 -0
  35. package/dist/esm/index.js +6 -0
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/index.mjs +6 -0
  38. package/dist/esm/index.mjs.map +1 -1
  39. package/dist/esm/native-ios.js +4 -0
  40. package/dist/esm/native-ios.js.map +6 -0
  41. package/dist/esm/native-ios.mjs +4 -0
  42. package/dist/esm/native-ios.mjs.map +6 -0
  43. package/dist/esm/nativeSheet.js +33 -0
  44. package/dist/esm/nativeSheet.js.map +6 -0
  45. package/dist/esm/nativeSheet.mjs +33 -0
  46. package/dist/esm/nativeSheet.mjs.map +6 -0
  47. package/dist/esm/useSheetChildren.js +34 -0
  48. package/dist/esm/useSheetChildren.js.map +6 -0
  49. package/dist/esm/useSheetChildren.mjs +34 -0
  50. package/dist/esm/useSheetChildren.mjs.map +6 -0
  51. package/dist/esm/useSheetContoller.js +19 -0
  52. package/dist/esm/useSheetContoller.js.map +6 -0
  53. package/dist/esm/useSheetContoller.mjs +19 -0
  54. package/dist/esm/useSheetContoller.mjs.map +6 -0
  55. package/dist/esm/useSheetController.js +19 -0
  56. package/dist/esm/useSheetController.js.map +6 -0
  57. package/dist/esm/useSheetController.mjs +19 -0
  58. package/dist/esm/useSheetController.mjs.map +6 -0
  59. package/dist/esm/useSheetOpenState.js +27 -0
  60. package/dist/esm/useSheetOpenState.js.map +6 -0
  61. package/dist/esm/useSheetOpenState.mjs +27 -0
  62. package/dist/esm/useSheetOpenState.mjs.map +6 -0
  63. package/dist/esm/useSheetProviderProps.js +64 -0
  64. package/dist/esm/useSheetProviderProps.js.map +6 -0
  65. package/dist/esm/useSheetProviderProps.mjs +64 -0
  66. package/dist/esm/useSheetProviderProps.mjs.map +6 -0
  67. package/dist/jsx/Sheet.js +42 -137
  68. package/dist/jsx/Sheet.js.map +2 -2
  69. package/dist/jsx/Sheet.mjs +42 -137
  70. package/dist/jsx/Sheet.mjs.map +2 -2
  71. package/dist/jsx/SheetController.js +24 -0
  72. package/dist/jsx/SheetController.js.map +6 -0
  73. package/dist/jsx/SheetController.mjs +24 -0
  74. package/dist/jsx/SheetController.mjs.map +6 -0
  75. package/dist/jsx/getNativeSheet.js +14 -0
  76. package/dist/jsx/getNativeSheet.js.map +6 -0
  77. package/dist/jsx/getNativeSheet.mjs +14 -0
  78. package/dist/jsx/getNativeSheet.mjs.map +6 -0
  79. package/dist/jsx/index.js +6 -0
  80. package/dist/jsx/index.js.map +1 -1
  81. package/dist/jsx/index.mjs +6 -0
  82. package/dist/jsx/index.mjs.map +1 -1
  83. package/dist/jsx/native-ios.js +4 -0
  84. package/dist/jsx/native-ios.js.map +6 -0
  85. package/dist/jsx/native-ios.mjs +4 -0
  86. package/dist/jsx/native-ios.mjs.map +6 -0
  87. package/dist/jsx/nativeSheet.js +31 -0
  88. package/dist/jsx/nativeSheet.js.map +6 -0
  89. package/dist/jsx/nativeSheet.mjs +31 -0
  90. package/dist/jsx/nativeSheet.mjs.map +6 -0
  91. package/dist/jsx/useSheetChildren.js +33 -0
  92. package/dist/jsx/useSheetChildren.js.map +6 -0
  93. package/dist/jsx/useSheetChildren.mjs +33 -0
  94. package/dist/jsx/useSheetChildren.mjs.map +6 -0
  95. package/dist/jsx/useSheetContoller.js +19 -0
  96. package/dist/jsx/useSheetContoller.js.map +6 -0
  97. package/dist/jsx/useSheetContoller.mjs +19 -0
  98. package/dist/jsx/useSheetContoller.mjs.map +6 -0
  99. package/dist/jsx/useSheetController.js +19 -0
  100. package/dist/jsx/useSheetController.js.map +6 -0
  101. package/dist/jsx/useSheetController.mjs +19 -0
  102. package/dist/jsx/useSheetController.mjs.map +6 -0
  103. package/dist/jsx/useSheetOpenState.js +26 -0
  104. package/dist/jsx/useSheetOpenState.js.map +6 -0
  105. package/dist/jsx/useSheetOpenState.mjs +26 -0
  106. package/dist/jsx/useSheetOpenState.mjs.map +6 -0
  107. package/dist/jsx/useSheetProviderProps.js +64 -0
  108. package/dist/jsx/useSheetProviderProps.js.map +6 -0
  109. package/dist/jsx/useSheetProviderProps.mjs +64 -0
  110. package/dist/jsx/useSheetProviderProps.mjs.map +6 -0
  111. package/package.json +14 -14
  112. package/src/Sheet.tsx +44 -159
  113. package/src/SheetController.tsx +28 -0
  114. package/src/index.ts +3 -0
  115. package/src/nativeSheet.tsx +42 -0
  116. package/src/types.tsx +6 -0
  117. package/src/useSheetChildren.tsx +33 -0
  118. package/src/useSheetController.tsx +24 -0
  119. package/src/useSheetOpenState.tsx +30 -0
  120. package/src/useSheetProviderProps.tsx +71 -0
  121. package/types/Sheet.d.ts +7 -15
  122. package/types/Sheet.d.ts.map +1 -1
  123. package/types/SheetController.d.ts +6 -0
  124. package/types/SheetController.d.ts.map +1 -0
  125. package/types/getNativeSheet.d.ts +3 -0
  126. package/types/getNativeSheet.d.ts.map +1 -0
  127. package/types/index.d.ts +3 -0
  128. package/types/index.d.ts.map +1 -1
  129. package/types/native-ios.d.ts +2 -0
  130. package/types/native-ios.d.ts.map +1 -0
  131. package/types/nativeSheet.d.ts +7 -0
  132. package/types/nativeSheet.d.ts.map +1 -0
  133. package/types/types.d.ts +4 -0
  134. package/types/types.d.ts.map +1 -1
  135. package/types/useSheetChildren.d.ts +6 -0
  136. package/types/useSheetChildren.d.ts.map +1 -0
  137. package/types/useSheetContoller.d.ts +14 -0
  138. package/types/useSheetContoller.d.ts.map +1 -0
  139. package/types/useSheetController.d.ts +14 -0
  140. package/types/useSheetController.d.ts.map +1 -0
  141. package/types/useSheetOpenState.d.ts +10 -0
  142. package/types/useSheetOpenState.d.ts.map +1 -0
  143. package/types/useSheetProviderProps.d.ts +22 -0
  144. package/types/useSheetProviderProps.d.ts.map +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/sheet",
3
- "version": "1.20.7",
3
+ "version": "1.21.1",
4
4
  "sideEffects": [
5
5
  "*.css"
6
6
  ],
@@ -30,26 +30,26 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "@tamagui/animations-react-native": "1.20.7",
34
- "@tamagui/compose-refs": "1.20.7",
35
- "@tamagui/core": "1.20.7",
36
- "@tamagui/create-context": "1.20.7",
37
- "@tamagui/portal": "1.20.7",
38
- "@tamagui/remove-scroll": "1.20.7",
39
- "@tamagui/scroll-view": "1.20.7",
40
- "@tamagui/stacks": "1.20.7",
41
- "@tamagui/use-constant": "1.20.7",
42
- "@tamagui/use-controllable-state": "1.20.7",
43
- "@tamagui/use-keyboard-visible": "1.20.7"
33
+ "@tamagui/animations-react-native": "1.21.1",
34
+ "@tamagui/compose-refs": "1.21.1",
35
+ "@tamagui/core": "1.21.1",
36
+ "@tamagui/create-context": "1.21.1",
37
+ "@tamagui/portal": "1.21.1",
38
+ "@tamagui/remove-scroll": "1.21.1",
39
+ "@tamagui/scroll-view": "1.21.1",
40
+ "@tamagui/stacks": "1.21.1",
41
+ "@tamagui/use-constant": "1.21.1",
42
+ "@tamagui/use-controllable-state": "1.21.1",
43
+ "@tamagui/use-keyboard-visible": "1.21.1"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": "*",
47
47
  "react-native": "*"
48
48
  },
49
49
  "devDependencies": {
50
- "@tamagui/build": "1.20.7",
50
+ "@tamagui/build": "1.21.1",
51
51
  "react": "^18.2.0",
52
- "react-native": "^0.71.4"
52
+ "react-native": "^0.71.7"
53
53
  },
54
54
  "publishConfig": {
55
55
  "access": "public"
package/src/Sheet.tsx CHANGED
@@ -2,7 +2,6 @@ import { AdaptParentContext } from '@tamagui/adapt'
2
2
  import { useComposedRefs } from '@tamagui/compose-refs'
3
3
  import {
4
4
  GetProps,
5
- TamaguiElement,
6
5
  Theme,
7
6
  isClient,
8
7
  isTouchable,
@@ -20,15 +19,12 @@ import {
20
19
  import { Portal } from '@tamagui/portal'
21
20
  import { RemoveScroll } from '@tamagui/remove-scroll'
22
21
  import { ThemeableStack, XStack, XStackProps, YStack, YStackProps } from '@tamagui/stacks'
23
- import { useConstant } from '@tamagui/use-constant'
24
- import { useControllableState } from '@tamagui/use-controllable-state'
25
22
  import { useKeyboardVisible } from '@tamagui/use-keyboard-visible'
26
23
  import React, {
27
24
  FunctionComponent,
28
25
  RefAttributes,
29
26
  createContext,
30
27
  forwardRef,
31
- isValidElement,
32
28
  useCallback,
33
29
  useContext,
34
30
  useEffect,
@@ -42,13 +38,19 @@ import {
42
38
  Keyboard,
43
39
  PanResponder,
44
40
  PanResponderGestureState,
41
+ Platform,
45
42
  View,
46
43
  } from 'react-native'
47
44
 
48
45
  import { SHEET_HANDLE_NAME, SHEET_NAME } from './constants'
46
+ import { getNativeSheet } from './nativeSheet'
49
47
  import { SheetProvider, useSheetContext } from './SheetContext'
50
48
  import { SheetScrollView } from './SheetScrollView'
51
- import { ScrollBridge, SheetProps, SheetScopedProps } from './types'
49
+ import { SheetProps, SheetScopedProps } from './types'
50
+ import { useSheetChildren } from './useSheetChildren'
51
+ import { useSheetController } from './useSheetController'
52
+ import { useSheetOpenState } from './useSheetOpenState'
53
+ import { useSheetProviderProps } from './useSheetProviderProps'
52
54
 
53
55
  export { createSheetScope } from './SheetContext'
54
56
  export * from './types'
@@ -224,21 +226,21 @@ const ParentSheetContext = createContext({
224
226
  zIndex: 100_000,
225
227
  })
226
228
 
227
- const useSheetContoller = () => {
228
- const controller = useContext(SheetControllerContext)
229
- const isHidden = controller?.hidden
230
- const isShowingNonSheet = isHidden && controller?.open
231
- return {
232
- controller,
233
- isHidden,
234
- isShowingNonSheet,
235
- }
236
- }
237
-
238
229
  export const Sheet = withStaticProperties(
239
230
  forwardRef<View, SheetProps>(function Sheet(props, ref) {
240
231
  const hydrated = useDidFinishSSR()
241
- const { isShowingNonSheet } = useSheetContoller()
232
+ const { isShowingNonSheet } = useSheetController()
233
+
234
+ let SheetImplementation = SheetImplementationCustom
235
+
236
+ if (props.native && Platform.OS === 'ios') {
237
+ if (process.env.TAMAGUI_TARGET === 'native') {
238
+ const impl = getNativeSheet('ios')
239
+ if (impl) {
240
+ SheetImplementation = impl
241
+ }
242
+ }
243
+ }
242
244
 
243
245
  /**
244
246
  * Performance is sensitive here so avoid all the hooks below with this
@@ -252,22 +254,11 @@ export const Sheet = withStaticProperties(
252
254
  sheetComponents
253
255
  )
254
256
 
255
- const SheetImplementation = themeable(
256
- forwardRef<View, SheetProps>(function SheetImplementation(props, forwardedRef) {
257
+ const SheetImplementationCustom = themeable(
258
+ forwardRef<View, SheetProps>(function SheetImplementationCustom(props, forwardedRef) {
257
259
  const parentSheet = useContext(ParentSheetContext)
258
- const { isHidden, controller } = useSheetContoller()
259
260
 
260
261
  const {
261
- __scopeSheet,
262
- snapPoints: snapPointsProp = [80],
263
- open: openProp,
264
- defaultOpen,
265
- children: childrenProp,
266
- position: positionProp,
267
- onPositionChange,
268
- onOpenChange,
269
- defaultPosition,
270
- dismissOnOverlayPress = true,
271
262
  animationConfig,
272
263
  dismissOnSnapToBottom = false,
273
264
  forceRemoveScrollEnabled = null,
@@ -278,8 +269,28 @@ const SheetImplementation = themeable(
278
269
  portalProps,
279
270
  } = props
280
271
 
272
+ const state = useSheetOpenState(props)
273
+ const providerProps = useSheetProviderProps(props, state)
274
+
275
+ const {
276
+ snapPoints,
277
+ position,
278
+ contentRef,
279
+ setPosition,
280
+ setPositionImmediate,
281
+ scrollBridge,
282
+ frameSize,
283
+ setFrameSize,
284
+ } = providerProps
285
+
286
+ const { open, isHidden, controller } = state
287
+
288
+ const { frameComponent, handleComponent, overlayComponent } = useSheetChildren(
289
+ props.children
290
+ )
291
+
281
292
  if (process.env.NODE_ENV === 'development') {
282
- if (snapPointsProp.some((p) => p < 0 || p > 100)) {
293
+ if (snapPoints.some((p) => p < 0 || p > 100)) {
283
294
  console.warn(
284
295
  '⚠️ Invalid snapPoint given, snapPoints must be between 0 and 100, equal to percent height of frame'
285
296
  )
@@ -297,66 +308,12 @@ const SheetImplementation = themeable(
297
308
  const disableDrag = disableDragProp ?? controller?.disableDrag
298
309
  const keyboardIsVisible = useKeyboardVisible()
299
310
  const themeName = useThemeName()
300
- const contentRef = React.useRef<TamaguiElement>(null)
301
- const scrollBridge = useConstant<ScrollBridge>(() => ({
302
- enabled: false,
303
- y: 0,
304
- paneY: 0,
305
- paneMinY: 0,
306
- scrollStartY: -1,
307
- drag: () => {},
308
- release: () => {},
309
- scrollLock: false,
310
- }))
311
-
312
- const onOpenChangeInternal = (val: boolean) => {
313
- controller?.onOpenChange?.(val)
314
- onOpenChange?.(val)
315
- }
316
-
317
- const [open, setOpen] = useControllableState({
318
- prop: controller?.open ?? openProp,
319
- defaultProp: true,
320
- onChange: onOpenChangeInternal,
321
- strategy: 'most-recent-wins',
322
- transition: true,
323
- })
324
-
325
- const [frameSize, setFrameSize] = useState<number>(0)
326
-
327
- const snapPoints = useMemo(
328
- () => (dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),
329
- // eslint-disable-next-line react-hooks/exhaustive-deps
330
- [JSON.stringify(snapPointsProp), dismissOnSnapToBottom]
331
- )
332
-
333
- // lets set -1 to be always the "open = false" position
334
- const [position_, setPosition_] = useControllableState({
335
- prop: positionProp,
336
- defaultProp: defaultPosition || (open ? 0 : -1),
337
- onChange: onPositionChange,
338
- strategy: 'most-recent-wins',
339
- transition: true,
340
- })
341
- const position = open === false ? -1 : position_
342
311
 
343
312
  // reset position to fully open on re-open after dismissOnSnapToBottom
344
313
  if (open && dismissOnSnapToBottom && position === snapPoints.length - 1) {
345
- setPosition_(0)
314
+ setPositionImmediate(0)
346
315
  }
347
316
 
348
- const setPosition = useCallback(
349
- (next: number) => {
350
- // close on dismissOnSnapToBottom (and set position so it animates)
351
- if (dismissOnSnapToBottom && next === snapPoints.length - 1) {
352
- setOpen(false)
353
- } else {
354
- setPosition_(next)
355
- }
356
- },
357
- [dismissOnSnapToBottom, snapPoints.length, setPosition_, setOpen]
358
- )
359
-
360
317
  const { useAnimatedNumber, useAnimatedNumberReaction, useAnimatedNumberStyle } =
361
318
  driver
362
319
 
@@ -569,30 +526,6 @@ const SheetImplementation = themeable(
569
526
  [disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition]
570
527
  )
571
528
 
572
- let handleComponent: React.ReactElement | null = null
573
- let overlayComponent: React.ReactElement | null = null
574
- let frameComponent: React.ReactElement | null = null
575
-
576
- // TODO do more radix-like and don't require direct children descendents
577
- React.Children.forEach(childrenProp, (child) => {
578
- if (isValidElement(child)) {
579
- const name = child.type?.['staticConfig']?.componentName
580
- switch (name) {
581
- case 'SheetHandle':
582
- handleComponent = child
583
- break
584
- case 'Sheet':
585
- frameComponent = child
586
- break
587
- case 'SheetOverlay':
588
- overlayComponent = child
589
- break
590
- default:
591
- console.warn('Warning: passed invalid child to Sheet', child)
592
- }
593
- }
594
- })
595
-
596
529
  const animatedStyle = useAnimatedNumberStyle(animatedNumber, (val) => {
597
530
  'worklet'
598
531
  const translateY = frameSize === 0 ? HIDDEN_SIZE : val
@@ -658,21 +591,7 @@ const SheetImplementation = themeable(
658
591
 
659
592
  const contents = (
660
593
  <ParentSheetContext.Provider value={nextParentContext}>
661
- <SheetProvider
662
- modal={modal}
663
- contentRef={contentRef}
664
- frameSize={frameSize}
665
- dismissOnOverlayPress={dismissOnOverlayPress}
666
- dismissOnSnapToBottom={dismissOnSnapToBottom}
667
- open={open}
668
- hidden={!!isHidden}
669
- scope={__scopeSheet}
670
- position={position}
671
- snapPoints={snapPoints}
672
- setPosition={setPosition}
673
- setOpen={setOpen}
674
- scrollBridge={scrollBridge}
675
- >
594
+ <SheetProvider {...providerProps}>
676
595
  {shouldHideParentSheet ? null : overlayComponent}
677
596
 
678
597
  <AnimatedView
@@ -771,37 +690,3 @@ function resisted(y: number, minY: number, maxOverflow = 25) {
771
690
  }
772
691
  return y
773
692
  }
774
-
775
- type SheetControllerContextValue = {
776
- disableDrag?: boolean
777
- open?: boolean
778
- // hide without "closing" to prevent re-animation when shown again
779
- hidden?: boolean
780
- onOpenChange?: React.Dispatch<React.SetStateAction<boolean>> | ((val: boolean) => void)
781
- }
782
-
783
- const SheetControllerContext = createContext<SheetControllerContextValue | null>(null)
784
-
785
- export const SheetController = ({
786
- children,
787
- onOpenChange: onOpenChangeProp,
788
- ...value
789
- }: Partial<SheetControllerContextValue> & { children?: React.ReactNode }) => {
790
- const onOpenChange = useEvent(onOpenChangeProp)
791
-
792
- const memoValue = useMemo(
793
- () => ({
794
- open: value.open,
795
- hidden: value.hidden,
796
- disableDrag: value.disableDrag,
797
- onOpenChange,
798
- }),
799
- [onOpenChange, value.open, value.hidden, value.disableDrag]
800
- )
801
-
802
- return (
803
- <SheetControllerContext.Provider value={memoValue}>
804
- {children}
805
- </SheetControllerContext.Provider>
806
- )
807
- }
@@ -0,0 +1,28 @@
1
+ import { useEvent } from '@tamagui/core'
2
+ import React, { useMemo } from 'react'
3
+
4
+ import { SheetControllerContext, SheetControllerContextValue } from './useSheetController'
5
+
6
+ export const SheetController = ({
7
+ children,
8
+ onOpenChange: onOpenChangeProp,
9
+ ...value
10
+ }: Partial<SheetControllerContextValue> & { children?: React.ReactNode }) => {
11
+ const onOpenChange = useEvent(onOpenChangeProp)
12
+
13
+ const memoValue = useMemo(
14
+ () => ({
15
+ open: value.open,
16
+ hidden: value.hidden,
17
+ disableDrag: value.disableDrag,
18
+ onOpenChange,
19
+ }),
20
+ [onOpenChange, value.open, value.hidden, value.disableDrag]
21
+ )
22
+
23
+ return (
24
+ <SheetControllerContext.Provider value={memoValue}>
25
+ {children}
26
+ </SheetControllerContext.Provider>
27
+ )
28
+ }
package/src/index.ts CHANGED
@@ -1 +1,4 @@
1
1
  export * from './Sheet'
2
+ export * from './SheetController'
3
+ export * from './useSheetController'
4
+ export { setupNativeSheet } from './nativeSheet'
@@ -0,0 +1,42 @@
1
+ import { FunctionComponent, useEffect, useRef } from 'react'
2
+
3
+ import { SheetProvider } from './SheetContext'
4
+ import { SheetProps } from './types'
5
+ import { useSheetChildren } from './useSheetChildren'
6
+ import { useSheetOpenState } from './useSheetOpenState'
7
+ import { useSheetProviderProps } from './useSheetProviderProps'
8
+
9
+ type SheetNativePlatforms = 'ios'
10
+
11
+ const nativeSheets: Record<SheetNativePlatforms, FunctionComponent<SheetProps> | null> = {
12
+ ios: null,
13
+ }
14
+
15
+ export function getNativeSheet(platform: SheetNativePlatforms) {
16
+ return nativeSheets[platform]
17
+ }
18
+
19
+ export function setupNativeSheet(platform: SheetNativePlatforms, Implementation: any) {
20
+ if (platform === 'ios') {
21
+ nativeSheets[platform] = (props: SheetProps) => {
22
+ const state = useSheetOpenState(props)
23
+ const providerProps = useSheetProviderProps(props, state)
24
+ const { frameComponent } = useSheetChildren(props.children)
25
+
26
+ const { open, setOpen } = state
27
+ const ref = useRef<{
28
+ setVisibility: Function
29
+ }>()
30
+
31
+ useEffect(() => {
32
+ ref.current?.setVisibility(open)
33
+ }, [open])
34
+
35
+ return (
36
+ <Implementation ref={ref} onModalDismiss={() => setOpen(false)}>
37
+ <SheetProvider {...providerProps}>{frameComponent}</SheetProvider>
38
+ </Implementation>
39
+ )
40
+ }
41
+ }
42
+ }
package/src/types.tsx CHANGED
@@ -18,6 +18,12 @@ export type SheetProps = ScopedProps<
18
18
  dismissOnSnapToBottom?: boolean
19
19
  forceRemoveScrollEnabled?: boolean
20
20
  animationConfig?: AnimatedNumberStrategy
21
+
22
+ /**
23
+ * Adapts the sheet to use native sheet on the given platform (if available)
24
+ */
25
+ native?: 'ios'[] | boolean
26
+
21
27
  /**
22
28
  * Pass if you're using the CSS animation driver
23
29
  */
@@ -0,0 +1,33 @@
1
+ import React, { isValidElement } from 'react'
2
+
3
+ export function useSheetChildren(childrenProp: any) {
4
+ let handleComponent: React.ReactElement | null = null
5
+ let overlayComponent: React.ReactElement | null = null
6
+ let frameComponent: React.ReactElement | null = null
7
+
8
+ // TODO do more radix-like and don't require direct children descendents
9
+ React.Children.forEach(childrenProp, (child) => {
10
+ if (isValidElement(child)) {
11
+ const name = child.type?.['staticConfig']?.componentName
12
+ switch (name) {
13
+ case 'SheetHandle':
14
+ handleComponent = child
15
+ break
16
+ case 'Sheet':
17
+ frameComponent = child
18
+ break
19
+ case 'SheetOverlay':
20
+ overlayComponent = child
21
+ break
22
+ default:
23
+ console.warn('Warning: passed invalid child to Sheet', child)
24
+ }
25
+ }
26
+ })
27
+
28
+ return {
29
+ handleComponent,
30
+ overlayComponent,
31
+ frameComponent,
32
+ }
33
+ }
@@ -0,0 +1,24 @@
1
+ import { createContext, useContext } from 'react'
2
+
3
+ export const useSheetController = () => {
4
+ const controller = useContext(SheetControllerContext)
5
+ const isHidden = controller?.hidden
6
+ const isShowingNonSheet = isHidden && controller?.open
7
+ return {
8
+ controller,
9
+ isHidden,
10
+ isShowingNonSheet,
11
+ }
12
+ }
13
+
14
+ export const SheetControllerContext = createContext<SheetControllerContextValue | null>(
15
+ null
16
+ )
17
+
18
+ export type SheetControllerContextValue = {
19
+ disableDrag?: boolean
20
+ open?: boolean
21
+ // hide without "closing" to prevent re-animation when shown again
22
+ hidden?: boolean
23
+ onOpenChange?: React.Dispatch<React.SetStateAction<boolean>> | ((val: boolean) => void)
24
+ }
@@ -0,0 +1,30 @@
1
+ import { useControllableState } from '@tamagui/use-controllable-state'
2
+
3
+ import { SheetProps } from './types'
4
+ import { useSheetController } from './useSheetController'
5
+
6
+ export const useSheetOpenState = (props: SheetProps) => {
7
+ const { isHidden, controller } = useSheetController()
8
+
9
+ const onOpenChangeInternal = (val: boolean) => {
10
+ controller?.onOpenChange?.(val)
11
+ props.onOpenChange?.(val)
12
+ }
13
+
14
+ const [open, setOpen] = useControllableState({
15
+ prop: controller?.open ?? props.open,
16
+ defaultProp: props.defaultOpen ?? false,
17
+ onChange: onOpenChangeInternal,
18
+ strategy: 'most-recent-wins',
19
+ transition: true,
20
+ })
21
+
22
+ return {
23
+ open,
24
+ setOpen,
25
+ isHidden,
26
+ controller,
27
+ }
28
+ }
29
+
30
+ export type SheetOpenState = ReturnType<typeof useSheetOpenState>
@@ -0,0 +1,71 @@
1
+ import { TamaguiElement } from '@tamagui/core'
2
+ import { useConstant } from '@tamagui/use-constant'
3
+ import { useControllableState } from '@tamagui/use-controllable-state'
4
+ import React, { useCallback, useMemo, useState } from 'react'
5
+
6
+ import { ScrollBridge, SheetProps } from './types'
7
+ import { SheetOpenState } from './useSheetOpenState'
8
+
9
+ export function useSheetProviderProps(props: SheetProps, state: SheetOpenState) {
10
+ const contentRef = React.useRef<TamaguiElement>(null)
11
+ const [frameSize, setFrameSize] = useState<number>(0)
12
+ const snapPointsProp = props.snapPoints || [80]
13
+
14
+ const snapPoints = useMemo(
15
+ () => (props.dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),
16
+ // eslint-disable-next-line react-hooks/exhaustive-deps
17
+ [JSON.stringify(snapPointsProp), props.dismissOnSnapToBottom]
18
+ )
19
+
20
+ // lets set -1 to be always the "open = false" position
21
+ const [position_, setPositionImmediate] = useControllableState({
22
+ prop: props.position,
23
+ defaultProp: props.defaultPosition || (state.open ? 0 : -1),
24
+ onChange: props.onPositionChange,
25
+ strategy: 'most-recent-wins',
26
+ transition: true,
27
+ })
28
+
29
+ const position = state.open === false ? -1 : position_
30
+
31
+ const setPosition = useCallback(
32
+ (next: number) => {
33
+ // close on dismissOnSnapToBottom (and set position so it animates)
34
+ if (props.dismissOnSnapToBottom && next === snapPoints.length - 1) {
35
+ state.setOpen(false)
36
+ } else {
37
+ setPositionImmediate(next)
38
+ }
39
+ },
40
+ [props.dismissOnSnapToBottom, snapPoints.length, setPositionImmediate, state.setOpen]
41
+ )
42
+
43
+ const scrollBridge = useConstant<ScrollBridge>(() => ({
44
+ enabled: false,
45
+ y: 0,
46
+ paneY: 0,
47
+ paneMinY: 0,
48
+ scrollStartY: -1,
49
+ drag: () => {},
50
+ release: () => {},
51
+ scrollLock: false,
52
+ }))
53
+
54
+ return {
55
+ modal: !!props.modal,
56
+ open: state.open,
57
+ setOpen: state.setOpen,
58
+ hidden: !!state.isHidden,
59
+ contentRef,
60
+ frameSize,
61
+ setFrameSize,
62
+ dismissOnOverlayPress: props.dismissOnOverlayPress ?? true,
63
+ dismissOnSnapToBottom: props.dismissOnSnapToBottom ?? false,
64
+ scope: props.__scopeSheet,
65
+ position,
66
+ snapPoints,
67
+ setPosition,
68
+ setPositionImmediate,
69
+ scrollBridge,
70
+ }
71
+ }
package/types/Sheet.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GetProps, TamaguiElement } from '@tamagui/core';
1
+ import { GetProps } from '@tamagui/core';
2
2
  import { XStackProps } from '@tamagui/stacks';
3
3
  import React from 'react';
4
4
  import { View } from 'react-native';
@@ -23,7 +23,7 @@ export declare const SheetHandleFrame: import("@tamagui/core").TamaguiComponent<
23
23
  }, "open" | "unstyled"> & {
24
24
  readonly open?: boolean | undefined;
25
25
  readonly unstyled?: boolean | undefined;
26
- }>>, TamaguiElement, Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & import("@tamagui/core/types/reactNativeTypes").RNViewProps, {
26
+ }>>, import("@tamagui/core").TamaguiElement, Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & import("@tamagui/core/types/reactNativeTypes").RNViewProps, {
27
27
  readonly fullscreen?: boolean | undefined;
28
28
  readonly elevation?: import("@tamagui/core").SizeTokens | undefined;
29
29
  } & {
@@ -87,7 +87,7 @@ export declare const SheetOverlayFrame: import("@tamagui/core").TamaguiComponent
87
87
  }, "unstyled" | "closed"> & {
88
88
  readonly closed?: boolean | undefined;
89
89
  readonly unstyled?: boolean | undefined;
90
- }>>, TamaguiElement, Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & import("@tamagui/core/types/reactNativeTypes").RNViewProps, {
90
+ }>>, import("@tamagui/core").TamaguiElement, Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & import("@tamagui/core/types/reactNativeTypes").RNViewProps, {
91
91
  readonly fullscreen?: boolean | undefined;
92
92
  readonly elevation?: import("@tamagui/core").SizeTokens | undefined;
93
93
  } & {
@@ -125,7 +125,7 @@ export declare const SheetFrameFrame: import("@tamagui/core").TamaguiComponent<O
125
125
  readonly elevation?: import("@tamagui/core").SizeTokens | undefined;
126
126
  }, "unstyled"> & {
127
127
  readonly unstyled?: boolean | undefined;
128
- }>>, TamaguiElement, Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & import("@tamagui/core/types/reactNativeTypes").RNViewProps, {
128
+ }>>, import("@tamagui/core").TamaguiElement, Omit<import("react-native").ViewProps, "display" | "children" | "onLayout" | keyof import("react-native").GestureResponderHandlers> & import("@tamagui/core").ExtendBaseStackProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & import("@tamagui/core/types/reactNativeTypes").RNViewProps, {
129
129
  readonly fullscreen?: boolean | undefined;
130
130
  readonly elevation?: import("@tamagui/core").SizeTokens | undefined;
131
131
  } & {
@@ -158,6 +158,7 @@ export declare const Sheet: React.ForwardRefExoticComponent<{
158
158
  dismissOnSnapToBottom?: boolean | undefined;
159
159
  forceRemoveScrollEnabled?: boolean | undefined;
160
160
  animationConfig?: import("@tamagui/core").AnimatedNumberStrategy | undefined;
161
+ native?: boolean | "ios"[] | undefined;
161
162
  animation?: import("@tamagui/core").AnimationProp | undefined;
162
163
  handleDisableScroll?: boolean | undefined;
163
164
  disableDrag?: boolean | undefined;
@@ -188,7 +189,7 @@ export declare const Sheet: React.ForwardRefExoticComponent<{
188
189
  readonly fullscreen?: boolean | undefined;
189
190
  }>> & import("@tamagui/core").PseudoProps<Partial<import("react-native").ScrollViewProps & Omit<import("@tamagui/core").StackProps, keyof import("react-native").ScrollViewProps> & Omit<{}, "fullscreen"> & {
190
191
  readonly fullscreen?: boolean | undefined;
191
- }>> & React.RefAttributes<TamaguiElement>>;
192
+ }>> & React.RefAttributes<import("@tamagui/core").TamaguiElement>>;
192
193
  };
193
194
  export declare const ControlledSheet: React.FunctionComponent<Omit<SheetProps, "open" | "onOpenChange"> & React.RefAttributes<View>> & {
194
195
  Handle: ({ __scopeSheet, ...props }: SheetScopedProps<XStackProps>) => JSX.Element;
@@ -211,15 +212,6 @@ export declare const ControlledSheet: React.FunctionComponent<Omit<SheetProps, "
211
212
  readonly fullscreen?: boolean | undefined;
212
213
  }>> & import("@tamagui/core").PseudoProps<Partial<import("react-native").ScrollViewProps & Omit<import("@tamagui/core").StackProps, keyof import("react-native").ScrollViewProps> & Omit<{}, "fullscreen"> & {
213
214
  readonly fullscreen?: boolean | undefined;
214
- }>> & React.RefAttributes<TamaguiElement>>;
215
+ }>> & React.RefAttributes<import("@tamagui/core").TamaguiElement>>;
215
216
  };
216
- type SheetControllerContextValue = {
217
- disableDrag?: boolean;
218
- open?: boolean;
219
- hidden?: boolean;
220
- onOpenChange?: React.Dispatch<React.SetStateAction<boolean>> | ((val: boolean) => void);
221
- };
222
- export declare const SheetController: ({ children, onOpenChange: onOpenChangeProp, ...value }: Partial<SheetControllerContextValue> & {
223
- children?: React.ReactNode;
224
- }) => JSX.Element;
225
217
  //# sourceMappingURL=Sheet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Sheet.d.ts","sourceRoot":"","sources":["../src/Sheet.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,QAAQ,EACR,cAAc,EAcf,MAAM,eAAe,CAAA;AAGtB,OAAO,EAA0B,WAAW,EAAuB,MAAM,iBAAiB,CAAA;AAI1F,OAAO,KAYN,MAAM,OAAO,CAAA;AACd,OAAO,EAML,IAAI,EACL,MAAM,cAAc,CAAA;AAKrB,OAAO,EAAgB,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,cAAc,SAAS,CAAA;AAMvB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC3B,CAAA;AAEF,eAAO,MAAM,WAAW,+BACO,iBAAiB,WAAW,CAAC,gBAe3D,CAAA;AAQD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2B5B,CAAA;AAEF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAElE,eAAO,MAAM,YAAY,+BACM,iBAAiB,iBAAiB,CAAC,gBAiBjE,CAAA;AAWD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;EAqB1B,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;iCAQtB,CAAA;AA2BD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;yCA7Ia,iBAAiB,WAAW,CAAC;;;;;;;;;;;;;0CAuD7B,iBAAiB,iBAAiB,CAAC;;;;;;;;CAqGjE,CAAA;AA4eD,eAAO,MAAM,eAAe;yCAxoBG,iBAAiB,WAAW,CAAC;;;;;;;;;;;;;0CAuD7B,iBAAiB,iBAAiB,CAAC;;;;;;;;CAolB1C,CAAA;AA2BxB,KAAK,2BAA2B,GAAG;IACjC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC,CAAA;CACxF,CAAA;AAID,eAAO,MAAM,eAAe;eAI2B,MAAM,SAAS;iBAkBrE,CAAA"}
1
+ {"version":3,"file":"Sheet.d.ts","sourceRoot":"","sources":["../src/Sheet.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,QAAQ,EAcT,MAAM,eAAe,CAAA;AAGtB,OAAO,EAA0B,WAAW,EAAuB,MAAM,iBAAiB,CAAA;AAE1F,OAAO,KAWN,MAAM,OAAO,CAAA;AACd,OAAO,EAOL,IAAI,EACL,MAAM,cAAc,CAAA;AAMrB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAMtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,cAAc,SAAS,CAAA;AAMvB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;EAkC3B,CAAA;AAEF,eAAO,MAAM,WAAW,+BACO,iBAAiB,WAAW,CAAC,gBAe3D,CAAA;AAQD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2B5B,CAAA;AAEF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAElE,eAAO,MAAM,YAAY,+BACM,iBAAiB,iBAAiB,CAAC,gBAiBjE,CAAA;AAWD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;EAqB1B,CAAA;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;iCAQtB,CAAA;AAgBD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;yCAlIa,iBAAiB,WAAW,CAAC;;;;;;;;;;;;;0CAuD7B,iBAAiB,iBAAiB,CAAC;;;;;;;;CAqGjE,CAAA;AAyZD,eAAO,MAAM,eAAe;yCArjBG,iBAAiB,WAAW,CAAC;;;;;;;;;;;;;0CAuD7B,iBAAiB,iBAAiB,CAAC;;;;;;;;CAigB1C,CAAA"}