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