@tamagui/sheet 1.20.6 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Sheet.js +124 -210
- package/dist/cjs/Sheet.js.map +2 -2
- package/dist/cjs/SheetController.js +49 -0
- package/dist/cjs/SheetController.js.map +6 -0
- package/dist/cjs/getNativeSheet.js +39 -0
- package/dist/cjs/getNativeSheet.js.map +6 -0
- package/dist/cjs/index.js +14 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/native-ios.js +5 -0
- package/dist/cjs/native-ios.js.map +6 -0
- package/dist/cjs/nativeSheet.js +58 -0
- package/dist/cjs/nativeSheet.js.map +6 -0
- package/dist/cjs/useSheetChildren.js +68 -0
- package/dist/cjs/useSheetChildren.js.map +6 -0
- package/dist/cjs/useSheetContoller.js +44 -0
- package/dist/cjs/useSheetContoller.js.map +6 -0
- package/dist/cjs/useSheetController.js +44 -0
- package/dist/cjs/useSheetController.js.map +6 -0
- package/dist/cjs/useSheetOpenState.js +51 -0
- package/dist/cjs/useSheetOpenState.js.map +6 -0
- package/dist/cjs/useSheetProviderProps.js +98 -0
- package/dist/cjs/useSheetProviderProps.js.map +6 -0
- package/dist/esm/Sheet.js +123 -200
- package/dist/esm/Sheet.js.map +2 -2
- package/dist/esm/Sheet.mjs +123 -200
- package/dist/esm/Sheet.mjs.map +2 -2
- package/dist/esm/SheetController.js +25 -0
- package/dist/esm/SheetController.js.map +6 -0
- package/dist/esm/SheetController.mjs +25 -0
- package/dist/esm/SheetController.mjs.map +6 -0
- package/dist/esm/getNativeSheet.js +14 -0
- package/dist/esm/getNativeSheet.js.map +6 -0
- package/dist/esm/getNativeSheet.mjs +14 -0
- package/dist/esm/getNativeSheet.mjs.map +6 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +6 -0
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/native-ios.js +4 -0
- package/dist/esm/native-ios.js.map +6 -0
- package/dist/esm/native-ios.mjs +4 -0
- package/dist/esm/native-ios.mjs.map +6 -0
- package/dist/esm/nativeSheet.js +33 -0
- package/dist/esm/nativeSheet.js.map +6 -0
- package/dist/esm/nativeSheet.mjs +33 -0
- package/dist/esm/nativeSheet.mjs.map +6 -0
- package/dist/esm/useSheetChildren.js +34 -0
- package/dist/esm/useSheetChildren.js.map +6 -0
- package/dist/esm/useSheetChildren.mjs +34 -0
- package/dist/esm/useSheetChildren.mjs.map +6 -0
- package/dist/esm/useSheetContoller.js +19 -0
- package/dist/esm/useSheetContoller.js.map +6 -0
- package/dist/esm/useSheetContoller.mjs +19 -0
- package/dist/esm/useSheetContoller.mjs.map +6 -0
- package/dist/esm/useSheetController.js +19 -0
- package/dist/esm/useSheetController.js.map +6 -0
- package/dist/esm/useSheetController.mjs +19 -0
- package/dist/esm/useSheetController.mjs.map +6 -0
- package/dist/esm/useSheetOpenState.js +27 -0
- package/dist/esm/useSheetOpenState.js.map +6 -0
- package/dist/esm/useSheetOpenState.mjs +27 -0
- package/dist/esm/useSheetOpenState.mjs.map +6 -0
- package/dist/esm/useSheetProviderProps.js +64 -0
- package/dist/esm/useSheetProviderProps.js.map +6 -0
- package/dist/esm/useSheetProviderProps.mjs +64 -0
- package/dist/esm/useSheetProviderProps.mjs.map +6 -0
- package/dist/jsx/Sheet.js +88 -159
- package/dist/jsx/Sheet.js.map +2 -2
- package/dist/jsx/Sheet.mjs +88 -159
- package/dist/jsx/Sheet.mjs.map +2 -2
- package/dist/jsx/SheetController.js +24 -0
- package/dist/jsx/SheetController.js.map +6 -0
- package/dist/jsx/SheetController.mjs +24 -0
- package/dist/jsx/SheetController.mjs.map +6 -0
- package/dist/jsx/getNativeSheet.js +14 -0
- package/dist/jsx/getNativeSheet.js.map +6 -0
- package/dist/jsx/getNativeSheet.mjs +14 -0
- package/dist/jsx/getNativeSheet.mjs.map +6 -0
- package/dist/jsx/index.js +6 -0
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +6 -0
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/native-ios.js +4 -0
- package/dist/jsx/native-ios.js.map +6 -0
- package/dist/jsx/native-ios.mjs +4 -0
- package/dist/jsx/native-ios.mjs.map +6 -0
- package/dist/jsx/nativeSheet.js +31 -0
- package/dist/jsx/nativeSheet.js.map +6 -0
- package/dist/jsx/nativeSheet.mjs +31 -0
- package/dist/jsx/nativeSheet.mjs.map +6 -0
- package/dist/jsx/useSheetChildren.js +33 -0
- package/dist/jsx/useSheetChildren.js.map +6 -0
- package/dist/jsx/useSheetChildren.mjs +33 -0
- package/dist/jsx/useSheetChildren.mjs.map +6 -0
- package/dist/jsx/useSheetContoller.js +19 -0
- package/dist/jsx/useSheetContoller.js.map +6 -0
- package/dist/jsx/useSheetContoller.mjs +19 -0
- package/dist/jsx/useSheetContoller.mjs.map +6 -0
- package/dist/jsx/useSheetController.js +19 -0
- package/dist/jsx/useSheetController.js.map +6 -0
- package/dist/jsx/useSheetController.mjs +19 -0
- package/dist/jsx/useSheetController.mjs.map +6 -0
- package/dist/jsx/useSheetOpenState.js +26 -0
- package/dist/jsx/useSheetOpenState.js.map +6 -0
- package/dist/jsx/useSheetOpenState.mjs +26 -0
- package/dist/jsx/useSheetOpenState.mjs.map +6 -0
- package/dist/jsx/useSheetProviderProps.js +64 -0
- package/dist/jsx/useSheetProviderProps.js.map +6 -0
- package/dist/jsx/useSheetProviderProps.mjs +64 -0
- package/dist/jsx/useSheetProviderProps.mjs.map +6 -0
- package/package.json +14 -14
- package/src/Sheet.tsx +97 -183
- package/src/SheetController.tsx +28 -0
- package/src/index.ts +3 -0
- package/src/nativeSheet.tsx +42 -0
- package/src/types.tsx +6 -0
- package/src/useSheetChildren.tsx +33 -0
- package/src/useSheetController.tsx +24 -0
- package/src/useSheetOpenState.tsx +30 -0
- package/src/useSheetProviderProps.tsx +71 -0
- package/types/Sheet.d.ts +31 -42
- package/types/Sheet.d.ts.map +1 -1
- package/types/SheetController.d.ts +6 -0
- package/types/SheetController.d.ts.map +1 -0
- package/types/getNativeSheet.d.ts +3 -0
- package/types/getNativeSheet.d.ts.map +1 -0
- package/types/index.d.ts +3 -0
- package/types/index.d.ts.map +1 -1
- package/types/native-ios.d.ts +2 -0
- package/types/native-ios.d.ts.map +1 -0
- package/types/nativeSheet.d.ts +7 -0
- package/types/nativeSheet.d.ts.map +1 -0
- package/types/types.d.ts +4 -0
- package/types/types.d.ts.map +1 -1
- package/types/useSheetChildren.d.ts +6 -0
- package/types/useSheetChildren.d.ts.map +1 -0
- package/types/useSheetContoller.d.ts +14 -0
- package/types/useSheetContoller.d.ts.map +1 -0
- package/types/useSheetController.d.ts +14 -0
- package/types/useSheetController.d.ts.map +1 -0
- package/types/useSheetOpenState.d.ts +10 -0
- package/types/useSheetOpenState.d.ts.map +1 -0
- package/types/useSheetProviderProps.d.ts +22 -0
- package/types/useSheetProviderProps.d.ts.map +1 -0
package/src/Sheet.tsx
CHANGED
|
@@ -2,8 +2,6 @@ import { AdaptParentContext } from '@tamagui/adapt'
|
|
|
2
2
|
import { useComposedRefs } from '@tamagui/compose-refs'
|
|
3
3
|
import {
|
|
4
4
|
GetProps,
|
|
5
|
-
Slot,
|
|
6
|
-
TamaguiElement,
|
|
7
5
|
Theme,
|
|
8
6
|
isClient,
|
|
9
7
|
isTouchable,
|
|
@@ -21,15 +19,12 @@ import {
|
|
|
21
19
|
import { Portal } from '@tamagui/portal'
|
|
22
20
|
import { RemoveScroll } from '@tamagui/remove-scroll'
|
|
23
21
|
import { ThemeableStack, XStack, XStackProps, YStack, YStackProps } from '@tamagui/stacks'
|
|
24
|
-
import { useConstant } from '@tamagui/use-constant'
|
|
25
|
-
import { useControllableState } from '@tamagui/use-controllable-state'
|
|
26
22
|
import { useKeyboardVisible } from '@tamagui/use-keyboard-visible'
|
|
27
23
|
import React, {
|
|
28
24
|
FunctionComponent,
|
|
29
25
|
RefAttributes,
|
|
30
26
|
createContext,
|
|
31
27
|
forwardRef,
|
|
32
|
-
isValidElement,
|
|
33
28
|
useCallback,
|
|
34
29
|
useContext,
|
|
35
30
|
useEffect,
|
|
@@ -43,15 +38,22 @@ import {
|
|
|
43
38
|
Keyboard,
|
|
44
39
|
PanResponder,
|
|
45
40
|
PanResponderGestureState,
|
|
41
|
+
Platform,
|
|
46
42
|
View,
|
|
47
43
|
} from 'react-native'
|
|
48
44
|
|
|
49
45
|
import { SHEET_HANDLE_NAME, SHEET_NAME } from './constants'
|
|
46
|
+
import { getNativeSheet } from './nativeSheet'
|
|
50
47
|
import { SheetProvider, useSheetContext } from './SheetContext'
|
|
51
48
|
import { SheetScrollView } from './SheetScrollView'
|
|
52
|
-
import {
|
|
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'
|
|
53
54
|
|
|
54
55
|
export { createSheetScope } from './SheetContext'
|
|
56
|
+
export * from './types'
|
|
55
57
|
|
|
56
58
|
/* -------------------------------------------------------------------------------------------------
|
|
57
59
|
* SheetHandle
|
|
@@ -59,17 +61,6 @@ export { createSheetScope } from './SheetContext'
|
|
|
59
61
|
|
|
60
62
|
export const SheetHandleFrame = styled(XStack, {
|
|
61
63
|
name: SHEET_HANDLE_NAME,
|
|
62
|
-
height: 10,
|
|
63
|
-
borderRadius: 100,
|
|
64
|
-
backgroundColor: '$background',
|
|
65
|
-
zIndex: 10,
|
|
66
|
-
marginHorizontal: '35%',
|
|
67
|
-
marginBottom: '$2',
|
|
68
|
-
opacity: 0.5,
|
|
69
|
-
|
|
70
|
-
hoverStyle: {
|
|
71
|
-
opacity: 0.7,
|
|
72
|
-
},
|
|
73
64
|
|
|
74
65
|
variants: {
|
|
75
66
|
open: {
|
|
@@ -81,7 +72,27 @@ export const SheetHandleFrame = styled(XStack, {
|
|
|
81
72
|
pointerEvents: 'none',
|
|
82
73
|
},
|
|
83
74
|
},
|
|
75
|
+
|
|
76
|
+
unstyled: {
|
|
77
|
+
false: {
|
|
78
|
+
height: 10,
|
|
79
|
+
borderRadius: 100,
|
|
80
|
+
backgroundColor: '$background',
|
|
81
|
+
zIndex: 10,
|
|
82
|
+
marginHorizontal: '35%',
|
|
83
|
+
marginBottom: '$2',
|
|
84
|
+
opacity: 0.5,
|
|
85
|
+
|
|
86
|
+
hoverStyle: {
|
|
87
|
+
opacity: 0.7,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
84
91
|
} as const,
|
|
92
|
+
|
|
93
|
+
defaultVariants: {
|
|
94
|
+
unstyled: false,
|
|
95
|
+
},
|
|
85
96
|
})
|
|
86
97
|
|
|
87
98
|
export const SheetHandle = SheetHandleFrame.extractable(
|
|
@@ -110,10 +121,6 @@ const SHEET_OVERLAY_NAME = 'SheetOverlay'
|
|
|
110
121
|
|
|
111
122
|
export const SheetOverlayFrame = styled(ThemeableStack, {
|
|
112
123
|
name: SHEET_OVERLAY_NAME,
|
|
113
|
-
fullscreen: true,
|
|
114
|
-
backgrounded: true,
|
|
115
|
-
opacity: 0.5,
|
|
116
|
-
zIndex: 100_000,
|
|
117
124
|
|
|
118
125
|
variants: {
|
|
119
126
|
closed: {
|
|
@@ -125,7 +132,20 @@ export const SheetOverlayFrame = styled(ThemeableStack, {
|
|
|
125
132
|
pointerEvents: 'auto',
|
|
126
133
|
},
|
|
127
134
|
},
|
|
135
|
+
|
|
136
|
+
unstyled: {
|
|
137
|
+
false: {
|
|
138
|
+
fullscreen: true,
|
|
139
|
+
position: 'absolute',
|
|
140
|
+
backgrounded: true,
|
|
141
|
+
zIndex: 100_000,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
128
144
|
} as const,
|
|
145
|
+
|
|
146
|
+
defaultVariants: {
|
|
147
|
+
unstyled: false,
|
|
148
|
+
},
|
|
129
149
|
})
|
|
130
150
|
|
|
131
151
|
export type SheetOverlayProps = GetProps<typeof SheetOverlayFrame>
|
|
@@ -161,14 +181,25 @@ if (selectionStyleSheet) {
|
|
|
161
181
|
|
|
162
182
|
export const SheetFrameFrame = styled(YStack, {
|
|
163
183
|
name: SHEET_NAME,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
184
|
+
|
|
185
|
+
variants: {
|
|
186
|
+
unstyled: {
|
|
187
|
+
false: {
|
|
188
|
+
flex: 1,
|
|
189
|
+
backgroundColor: '$background',
|
|
190
|
+
borderTopLeftRadius: '$true',
|
|
191
|
+
borderTopRightRadius: '$true',
|
|
192
|
+
width: '100%',
|
|
193
|
+
maxHeight: '100%',
|
|
194
|
+
overflow: 'hidden',
|
|
195
|
+
pointerEvents: 'auto',
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
} as const,
|
|
199
|
+
|
|
200
|
+
defaultVariants: {
|
|
201
|
+
unstyled: false,
|
|
202
|
+
},
|
|
172
203
|
})
|
|
173
204
|
|
|
174
205
|
export const SheetFrame = SheetFrameFrame.extractable(
|
|
@@ -195,21 +226,21 @@ const ParentSheetContext = createContext({
|
|
|
195
226
|
zIndex: 100_000,
|
|
196
227
|
})
|
|
197
228
|
|
|
198
|
-
const useSheetContoller = () => {
|
|
199
|
-
const controller = useContext(SheetControllerContext)
|
|
200
|
-
const isHidden = controller?.hidden
|
|
201
|
-
const isShowingNonSheet = isHidden && controller?.open
|
|
202
|
-
return {
|
|
203
|
-
controller,
|
|
204
|
-
isHidden,
|
|
205
|
-
isShowingNonSheet,
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
229
|
export const Sheet = withStaticProperties(
|
|
210
230
|
forwardRef<View, SheetProps>(function Sheet(props, ref) {
|
|
211
231
|
const hydrated = useDidFinishSSR()
|
|
212
|
-
const { isShowingNonSheet } =
|
|
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
|
+
}
|
|
213
244
|
|
|
214
245
|
/**
|
|
215
246
|
* Performance is sensitive here so avoid all the hooks below with this
|
|
@@ -223,22 +254,11 @@ export const Sheet = withStaticProperties(
|
|
|
223
254
|
sheetComponents
|
|
224
255
|
)
|
|
225
256
|
|
|
226
|
-
const
|
|
227
|
-
forwardRef<View, SheetProps>(function
|
|
257
|
+
const SheetImplementationCustom = themeable(
|
|
258
|
+
forwardRef<View, SheetProps>(function SheetImplementationCustom(props, forwardedRef) {
|
|
228
259
|
const parentSheet = useContext(ParentSheetContext)
|
|
229
|
-
const { isHidden, controller } = useSheetContoller()
|
|
230
260
|
|
|
231
261
|
const {
|
|
232
|
-
__scopeSheet,
|
|
233
|
-
snapPoints: snapPointsProp = [80],
|
|
234
|
-
open: openProp,
|
|
235
|
-
defaultOpen,
|
|
236
|
-
children: childrenProp,
|
|
237
|
-
position: positionProp,
|
|
238
|
-
onPositionChange,
|
|
239
|
-
onOpenChange,
|
|
240
|
-
defaultPosition,
|
|
241
|
-
dismissOnOverlayPress = true,
|
|
242
262
|
animationConfig,
|
|
243
263
|
dismissOnSnapToBottom = false,
|
|
244
264
|
forceRemoveScrollEnabled = null,
|
|
@@ -249,8 +269,28 @@ const SheetImplementation = themeable(
|
|
|
249
269
|
portalProps,
|
|
250
270
|
} = props
|
|
251
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
|
+
|
|
252
292
|
if (process.env.NODE_ENV === 'development') {
|
|
253
|
-
if (
|
|
293
|
+
if (snapPoints.some((p) => p < 0 || p > 100)) {
|
|
254
294
|
console.warn(
|
|
255
295
|
'⚠️ Invalid snapPoint given, snapPoints must be between 0 and 100, equal to percent height of frame'
|
|
256
296
|
)
|
|
@@ -268,66 +308,12 @@ const SheetImplementation = themeable(
|
|
|
268
308
|
const disableDrag = disableDragProp ?? controller?.disableDrag
|
|
269
309
|
const keyboardIsVisible = useKeyboardVisible()
|
|
270
310
|
const themeName = useThemeName()
|
|
271
|
-
const contentRef = React.useRef<TamaguiElement>(null)
|
|
272
|
-
const scrollBridge = useConstant<ScrollBridge>(() => ({
|
|
273
|
-
enabled: false,
|
|
274
|
-
y: 0,
|
|
275
|
-
paneY: 0,
|
|
276
|
-
paneMinY: 0,
|
|
277
|
-
scrollStartY: -1,
|
|
278
|
-
drag: () => {},
|
|
279
|
-
release: () => {},
|
|
280
|
-
scrollLock: false,
|
|
281
|
-
}))
|
|
282
|
-
|
|
283
|
-
const onOpenChangeInternal = (val: boolean) => {
|
|
284
|
-
controller?.onOpenChange?.(val)
|
|
285
|
-
onOpenChange?.(val)
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const [open, setOpen] = useControllableState({
|
|
289
|
-
prop: controller?.open ?? openProp,
|
|
290
|
-
defaultProp: true,
|
|
291
|
-
onChange: onOpenChangeInternal,
|
|
292
|
-
strategy: 'most-recent-wins',
|
|
293
|
-
transition: true,
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
const [frameSize, setFrameSize] = useState<number>(0)
|
|
297
|
-
|
|
298
|
-
const snapPoints = useMemo(
|
|
299
|
-
() => (dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp),
|
|
300
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
301
|
-
[JSON.stringify(snapPointsProp), dismissOnSnapToBottom]
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
// lets set -1 to be always the "open = false" position
|
|
305
|
-
const [position_, setPosition_] = useControllableState({
|
|
306
|
-
prop: positionProp,
|
|
307
|
-
defaultProp: defaultPosition || (open ? 0 : -1),
|
|
308
|
-
onChange: onPositionChange,
|
|
309
|
-
strategy: 'most-recent-wins',
|
|
310
|
-
transition: true,
|
|
311
|
-
})
|
|
312
|
-
const position = open === false ? -1 : position_
|
|
313
311
|
|
|
314
312
|
// reset position to fully open on re-open after dismissOnSnapToBottom
|
|
315
313
|
if (open && dismissOnSnapToBottom && position === snapPoints.length - 1) {
|
|
316
|
-
|
|
314
|
+
setPositionImmediate(0)
|
|
317
315
|
}
|
|
318
316
|
|
|
319
|
-
const setPosition = useCallback(
|
|
320
|
-
(next: number) => {
|
|
321
|
-
// close on dismissOnSnapToBottom (and set position so it animates)
|
|
322
|
-
if (dismissOnSnapToBottom && next === snapPoints.length - 1) {
|
|
323
|
-
setOpen(false)
|
|
324
|
-
} else {
|
|
325
|
-
setPosition_(next)
|
|
326
|
-
}
|
|
327
|
-
},
|
|
328
|
-
[dismissOnSnapToBottom, snapPoints.length, setPosition_, setOpen]
|
|
329
|
-
)
|
|
330
|
-
|
|
331
317
|
const { useAnimatedNumber, useAnimatedNumberReaction, useAnimatedNumberStyle } =
|
|
332
318
|
driver
|
|
333
319
|
|
|
@@ -540,30 +526,6 @@ const SheetImplementation = themeable(
|
|
|
540
526
|
[disableDrag, isShowingInnerSheet, animateTo, frameSize, positions, setPosition]
|
|
541
527
|
)
|
|
542
528
|
|
|
543
|
-
let handleComponent: React.ReactElement | null = null
|
|
544
|
-
let overlayComponent: React.ReactElement | null = null
|
|
545
|
-
let frameComponent: React.ReactElement | null = null
|
|
546
|
-
|
|
547
|
-
// TODO do more radix-like and don't require direct children descendents
|
|
548
|
-
React.Children.forEach(childrenProp, (child) => {
|
|
549
|
-
if (isValidElement(child)) {
|
|
550
|
-
const name = child.type?.['staticConfig']?.componentName
|
|
551
|
-
switch (name) {
|
|
552
|
-
case 'SheetHandle':
|
|
553
|
-
handleComponent = child
|
|
554
|
-
break
|
|
555
|
-
case 'Sheet':
|
|
556
|
-
frameComponent = child
|
|
557
|
-
break
|
|
558
|
-
case 'SheetOverlay':
|
|
559
|
-
overlayComponent = child
|
|
560
|
-
break
|
|
561
|
-
default:
|
|
562
|
-
console.warn('Warning: passed invalid child to Sheet', child)
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
})
|
|
566
|
-
|
|
567
529
|
const animatedStyle = useAnimatedNumberStyle(animatedNumber, (val) => {
|
|
568
530
|
'worklet'
|
|
569
531
|
const translateY = frameSize === 0 ? HIDDEN_SIZE : val
|
|
@@ -629,21 +591,7 @@ const SheetImplementation = themeable(
|
|
|
629
591
|
|
|
630
592
|
const contents = (
|
|
631
593
|
<ParentSheetContext.Provider value={nextParentContext}>
|
|
632
|
-
<SheetProvider
|
|
633
|
-
modal={modal}
|
|
634
|
-
contentRef={contentRef}
|
|
635
|
-
frameSize={frameSize}
|
|
636
|
-
dismissOnOverlayPress={dismissOnOverlayPress}
|
|
637
|
-
dismissOnSnapToBottom={dismissOnSnapToBottom}
|
|
638
|
-
open={open}
|
|
639
|
-
hidden={!!isHidden}
|
|
640
|
-
scope={__scopeSheet}
|
|
641
|
-
position={position}
|
|
642
|
-
snapPoints={snapPoints}
|
|
643
|
-
setPosition={setPosition}
|
|
644
|
-
setOpen={setOpen}
|
|
645
|
-
scrollBridge={scrollBridge}
|
|
646
|
-
>
|
|
594
|
+
<SheetProvider {...providerProps}>
|
|
647
595
|
{shouldHideParentSheet ? null : overlayComponent}
|
|
648
596
|
|
|
649
597
|
<AnimatedView
|
|
@@ -742,37 +690,3 @@ function resisted(y: number, minY: number, maxOverflow = 25) {
|
|
|
742
690
|
}
|
|
743
691
|
return y
|
|
744
692
|
}
|
|
745
|
-
|
|
746
|
-
type SheetControllerContextValue = {
|
|
747
|
-
disableDrag?: boolean
|
|
748
|
-
open?: boolean
|
|
749
|
-
// hide without "closing" to prevent re-animation when shown again
|
|
750
|
-
hidden?: boolean
|
|
751
|
-
onOpenChange?: React.Dispatch<React.SetStateAction<boolean>> | ((val: boolean) => void)
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
const SheetControllerContext = createContext<SheetControllerContextValue | null>(null)
|
|
755
|
-
|
|
756
|
-
export const SheetController = ({
|
|
757
|
-
children,
|
|
758
|
-
onOpenChange: onOpenChangeProp,
|
|
759
|
-
...value
|
|
760
|
-
}: Partial<SheetControllerContextValue> & { children?: React.ReactNode }) => {
|
|
761
|
-
const onOpenChange = useEvent(onOpenChangeProp)
|
|
762
|
-
|
|
763
|
-
const memoValue = useMemo(
|
|
764
|
-
() => ({
|
|
765
|
-
open: value.open,
|
|
766
|
-
hidden: value.hidden,
|
|
767
|
-
disableDrag: value.disableDrag,
|
|
768
|
-
onOpenChange,
|
|
769
|
-
}),
|
|
770
|
-
[onOpenChange, value.open, value.hidden, value.disableDrag]
|
|
771
|
-
)
|
|
772
|
-
|
|
773
|
-
return (
|
|
774
|
-
<SheetControllerContext.Provider value={memoValue}>
|
|
775
|
-
{children}
|
|
776
|
-
</SheetControllerContext.Provider>
|
|
777
|
-
)
|
|
778
|
-
}
|
|
@@ -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
|
@@ -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
|
+
}
|