@tamagui/sheet 1.0.1-beta.140 → 1.0.1-beta.143

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
@@ -4,8 +4,8 @@ import {
4
4
  Slot,
5
5
  TamaguiElement,
6
6
  Theme,
7
+ getAnimationDriver,
7
8
  isClient,
8
- isWeb,
9
9
  mergeEvent,
10
10
  styled,
11
11
  themeable,
@@ -30,13 +30,7 @@ import React, {
30
30
  useRef,
31
31
  useState,
32
32
  } from 'react'
33
- import {
34
- Animated,
35
- GestureResponderEvent,
36
- PanResponder,
37
- PanResponderGestureState,
38
- View,
39
- } from 'react-native'
33
+ import { GestureResponderEvent, PanResponder, PanResponderGestureState, View } from 'react-native'
40
34
 
41
35
  import { SHEET_HANDLE_NAME, SHEET_NAME } from './SHEET_HANDLE_NAME'
42
36
  import { SheetProvider, useSheetContext } from './SheetContext'
@@ -199,12 +193,18 @@ export const Sheet = withStaticProperties(
199
193
 
200
194
  if (process.env.NODE_ENV === 'development') {
201
195
  if (snapPointsProp.some((p) => p < 0 || p > 100)) {
196
+ // eslint-disable-next-line no-console
202
197
  console.warn(
203
198
  `⚠️ Invalid snapPoint given, snapPoints must be between 0 and 100, equal to percent height of frame`
204
199
  )
205
200
  }
206
201
  }
207
202
 
203
+ const driver = getAnimationDriver()
204
+ if (!driver) {
205
+ throw new Error(`Must set animations in tamagui.config.ts`)
206
+ }
207
+
208
208
  // allows for sheets to be controlled by other components
209
209
  const controller = useContext(SheetControllerContext)
210
210
  const isHidden = controller?.hidden || false
@@ -268,10 +268,14 @@ export const Sheet = withStaticProperties(
268
268
  [dismissOnSnapToBottom, snapPoints.length, setPosition_, setOpen]
269
269
  )
270
270
 
271
- const positionValue = useRef<Animated.Value>()
272
- if (!positionValue.current) {
273
- positionValue.current = new Animated.Value(HIDDEN_SIZE)
274
- }
271
+ const animatedNumber = driver.useAnimatedNumber(HIDDEN_SIZE)
272
+
273
+ // native only fix
274
+ const at = useRef(0)
275
+ driver.useAnimatedNumberReaction(animatedNumber, (value) => {
276
+ at.current = value
277
+ scrollBridge.paneY = value
278
+ })
275
279
 
276
280
  const [isResizing, setIsResizing] = useState(true)
277
281
  useIsomorphicLayoutEffect(() => {
@@ -281,10 +285,8 @@ export const Sheet = withStaticProperties(
281
285
  // eslint-disable-next-line react-hooks/exhaustive-deps
282
286
  }, [modal])
283
287
 
284
- const spring = useRef<Animated.CompositeAnimation | null>(null)
285
288
  function stopSpring() {
286
- spring.current?.stop()
287
- spring.current = null
289
+ animatedNumber.stop()
288
290
  if (scrollBridge.onFinishAnimate) {
289
291
  scrollBridge.onFinishAnimate()
290
292
  scrollBridge.onFinishAnimate = undefined
@@ -305,7 +307,7 @@ export const Sheet = withStaticProperties(
305
307
  )
306
308
 
307
309
  const animateTo = useEvent((position: number) => {
308
- const current = positionValue.current
310
+ const current = animatedNumber.getValue()
309
311
  if (isHidden && open) return
310
312
  if (!current) return
311
313
  if (frameSize === 0) return
@@ -317,26 +319,19 @@ export const Sheet = withStaticProperties(
317
319
  if (isResizing) {
318
320
  setIsResizing(false)
319
321
  }
320
- Animated.timing(current, {
321
- useNativeDriver: !isWeb,
322
- toValue,
322
+ animatedNumber.setValue(toValue, {
323
+ type: 'timing',
323
324
  duration: 0,
324
- }).start()
325
+ })
325
326
  at.current = toValue
326
327
  return
327
328
  }
328
329
  // dont bounce on initial measure to bottom
329
330
  const overshootClamping = at.current === HIDDEN_SIZE
330
- spring.current = Animated.spring(current, {
331
- useNativeDriver: !isWeb,
332
- toValue,
333
- overshootClamping,
331
+ animatedNumber.setValue(toValue, {
334
332
  ...animationConfig,
335
- })
336
- spring.current.start(({ finished }) => {
337
- if (finished) {
338
- stopSpring()
339
- }
333
+ type: 'spring',
334
+ overshootClamping,
340
335
  })
341
336
  })
342
337
 
@@ -344,25 +339,11 @@ export const Sheet = withStaticProperties(
344
339
  animateTo(position)
345
340
  }, [isHidden, frameSize, position, animateTo])
346
341
 
347
- // native only fix
348
- const at = useRef(0)
349
- useEffect(() => {
350
- positionValue.current!.addListener(({ value }) => {
351
- at.current = value
352
- scrollBridge.paneY = value
353
- })
354
- return () => {
355
- positionValue.current!.removeAllListeners()
356
- }
357
- }, [])
358
-
359
342
  const panResponder = useMemo(
360
343
  () => {
361
344
  if (disableDrag) return
362
345
  if (!frameSize) return
363
346
 
364
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
365
- const pos = positionValue.current!
366
347
  const minY = positions[0]
367
348
  scrollBridge.paneMinY = minY
368
349
  let startY = at.current
@@ -419,8 +400,12 @@ export const Sheet = withStaticProperties(
419
400
  return true
420
401
  }
421
402
  const isDraggingUp = dy < 0
422
- if (!isScrolled && isDraggingUp) {
423
- return false
403
+ const isAtTop = scrollBridge.paneY <= scrollBridge.paneMinY
404
+ // prevent drag once at top and pulling up
405
+ if (isAtTop) {
406
+ if (!isScrolled && isDraggingUp) {
407
+ return false
408
+ }
424
409
  }
425
410
  // we could do some detection of other touchables and cancel here..
426
411
  return Math.abs(dy) > 8
@@ -434,25 +419,13 @@ export const Sheet = withStaticProperties(
434
419
 
435
420
  let isExternalDrag = false
436
421
 
437
- function setPositionValue(next: number) {
438
- // useful to debug any "jumping"
439
- // if (process.env.NODE_ENV === 'development') {
440
- // const moveAmt = Math.abs(pos['_value'] - next)
441
- // if (moveAmt > 50) {
442
- // console.warn('!!!!!!!!!!!!jump!', moveAmt)
443
- // // debugger
444
- // }
445
- // }
446
- pos.setValue(next)
447
- }
448
-
449
422
  scrollBridge.drag = (dy) => {
450
423
  if (!isExternalDrag) {
451
424
  isExternalDrag = true
452
425
  grant()
453
426
  }
454
427
  const to = dy + startY
455
- setPositionValue(resisted(to, minY))
428
+ animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
456
429
  }
457
430
 
458
431
  scrollBridge.release = release
@@ -462,7 +435,7 @@ export const Sheet = withStaticProperties(
462
435
  onPanResponderGrant: grant,
463
436
  onPanResponderMove: (_e, { dy }) => {
464
437
  const to = dy + startY
465
- setPositionValue(resisted(to, minY))
438
+ animatedNumber.setValue(resisted(to, minY), { type: 'direct' })
466
439
  },
467
440
  onPanResponderEnd: finish,
468
441
  onPanResponderTerminate: finish,
@@ -492,6 +465,7 @@ export const Sheet = withStaticProperties(
492
465
  overlayComponent = child
493
466
  break
494
467
  default:
468
+ // eslint-disable-next-line no-console
495
469
  console.warn('Warning: passed invalid child to Sheet', child)
496
470
  }
497
471
  }
@@ -499,11 +473,18 @@ export const Sheet = withStaticProperties(
499
473
 
500
474
  const preventShown = controller?.hidden && controller?.open
501
475
 
476
+ const animatedStyle = driver.useAnimatedNumberStyle(animatedNumber, (val) => {
477
+ return {
478
+ transform: [{ translateY: frameSize === 0 ? HIDDEN_SIZE : val }],
479
+ }
480
+ })
481
+
502
482
  if (preventShown) {
503
483
  return null
504
484
  }
505
485
 
506
- const translateY = frameSize === 0 ? HIDDEN_SIZE : positionValue.current
486
+ // temp until reanimated useAnimatedNumber fix
487
+ const AnimatedView = driver['NumberView'] ?? driver.View
507
488
 
508
489
  const contents = (
509
490
  <SheetProvider
@@ -522,7 +503,7 @@ export const Sheet = withStaticProperties(
522
503
  >
523
504
  {isResizing ? null : overlayComponent}
524
505
 
525
- <Animated.View
506
+ <AnimatedView
526
507
  ref={ref}
527
508
  {...panResponder?.panHandlers}
528
509
  onLayout={(e) => {
@@ -534,13 +515,15 @@ export const Sheet = withStaticProperties(
534
515
  })
535
516
  }}
536
517
  pointerEvents={open ? 'auto' : 'none'}
537
- style={{
538
- position: 'absolute',
539
- zIndex: 10,
540
- width: '100%',
541
- height: '100%',
542
- transform: [{ translateY }],
543
- }}
518
+ style={[
519
+ {
520
+ position: 'absolute',
521
+ zIndex: 10,
522
+ width: '100%',
523
+ height: '100%',
524
+ },
525
+ animatedStyle,
526
+ ]}
544
527
  >
545
528
  {handleComponent}
546
529
 
@@ -554,7 +537,7 @@ export const Sheet = withStaticProperties(
554
537
  >
555
538
  {isResizing ? null : frameComponent}
556
539
  </RemoveScroll>
557
- </Animated.View>
540
+ </AnimatedView>
558
541
  </SheetProvider>
559
542
  )
560
543
 
@@ -582,11 +565,12 @@ export const Sheet = withStaticProperties(
582
565
  function getPercentSize(point?: number, frameSize?: number) {
583
566
  if (!frameSize) return 0
584
567
  if (point === undefined) {
568
+ // eslint-disable-next-line no-console
585
569
  console.warn(`No snapPoint`)
586
570
  return 0
587
571
  }
588
572
  const pct = point / 100
589
- const next = frameSize - pct * frameSize
573
+ const next = Math.round(frameSize - pct * frameSize)
590
574
  return next
591
575
  }
592
576
 
package/src/types.tsx CHANGED
@@ -1,7 +1,7 @@
1
+ import { AnimatedNumberStrategy } from '@tamagui/core'
1
2
  import { ScopedProps } from '@tamagui/create-context'
2
3
  import { RemoveScroll } from '@tamagui/remove-scroll'
3
4
  import React, { ReactNode } from 'react'
4
- import { Animated } from 'react-native'
5
5
 
6
6
  export type SheetProps = ScopedProps<
7
7
  {
@@ -15,7 +15,7 @@ export type SheetProps = ScopedProps<
15
15
  children?: ReactNode
16
16
  dismissOnOverlayPress?: boolean
17
17
  dismissOnSnapToBottom?: boolean
18
- animationConfig?: Animated.SpringAnimationConfig
18
+ animationConfig?: AnimatedNumberStrategy
19
19
  handleDisableScroll?: boolean
20
20
  disableDrag?: boolean
21
21
  modal?: boolean
package/types/Sheet.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { GetProps } from '@tamagui/core';
2
2
  import { XStackProps } from '@tamagui/stacks';
3
3
  import React from 'react';
4
- import { Animated, View } from 'react-native';
4
+ import { View } from 'react-native';
5
5
  import { SheetScopedProps } from './types';
6
6
  export { createSheetScope } from './SheetContext';
7
7
  export declare const SheetHandleFrame: import("@tamagui/core").TamaguiComponent<Omit<import("react-native").ViewProps, "children" | "display"> & import("@tamagui/core").RNWViewProps & import("@tamagui/core").TamaguiComponentPropsBase & import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase> & import("@tamagui/core").WithShorthands<import("@tamagui/core").WithThemeValues<import("@tamagui/core").StackStylePropsBase>> & Omit<{
@@ -97,7 +97,7 @@ export declare const SheetFrame: React.ForwardRefExoticComponent<Omit<import("re
97
97
  export declare const Sheet: ((props: Omit<{
98
98
  open?: boolean | undefined;
99
99
  defaultOpen?: boolean | undefined;
100
- onChangeOpen?: (React.Dispatch<React.SetStateAction<boolean>> | ((open: boolean) => void)) | undefined;
100
+ onChangeOpen?: (((open: boolean) => void) | React.Dispatch<React.SetStateAction<boolean>>) | undefined;
101
101
  position?: number | undefined;
102
102
  defaultPosition?: number | undefined;
103
103
  snapPoints?: number[] | undefined;
@@ -105,7 +105,7 @@ export declare const Sheet: ((props: Omit<{
105
105
  children?: React.ReactNode;
106
106
  dismissOnOverlayPress?: boolean | undefined;
107
107
  dismissOnSnapToBottom?: boolean | undefined;
108
- animationConfig?: Animated.SpringAnimationConfig | undefined;
108
+ animationConfig?: import("@tamagui/core").AnimatedNumberStrategy | undefined;
109
109
  handleDisableScroll?: boolean | undefined;
110
110
  disableDrag?: boolean | undefined;
111
111
  modal?: boolean | undefined;
package/types/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
+ import { AnimatedNumberStrategy } from '@tamagui/core';
1
2
  import { ScopedProps } from '@tamagui/create-context';
2
3
  import { RemoveScroll } from '@tamagui/remove-scroll';
3
4
  import React, { ReactNode } from 'react';
4
- import { Animated } from 'react-native';
5
5
  export declare type SheetProps = ScopedProps<{
6
6
  open?: boolean;
7
7
  defaultOpen?: boolean;
@@ -13,7 +13,7 @@ export declare type SheetProps = ScopedProps<{
13
13
  children?: ReactNode;
14
14
  dismissOnOverlayPress?: boolean;
15
15
  dismissOnSnapToBottom?: boolean;
16
- animationConfig?: Animated.SpringAnimationConfig;
16
+ animationConfig?: AnimatedNumberStrategy;
17
17
  handleDisableScroll?: boolean;
18
18
  disableDrag?: boolean;
19
19
  modal?: boolean;
@@ -0,0 +1,19 @@
1
+ import { Animated, TextStyle, ViewStyle } from 'react-native';
2
+ import { SharedValue } from 'react-native-reanimated';
3
+ export declare function useAnimated(): {
4
+ View: any;
5
+ Text: any;
6
+ };
7
+ declare type UniversalAnimatedNumber<A> = {
8
+ getInstance(): A;
9
+ getValue(): number;
10
+ setValue(next: number): void;
11
+ };
12
+ export declare function useAnimatedNumberReanimated(initial: number): UniversalAnimatedNumber<SharedValue<number>>;
13
+ export declare function useAnimatedNumberReactionReanimated(value: UniversalAnimatedNumber<SharedValue<number>>, cb: (current: number) => void): void;
14
+ export declare function useAnimatedNumberStyleReanimated<V extends UniversalAnimatedNumber<Animated.Value>>(value: V, getStyle: (value: V) => ViewStyle | TextStyle): ViewStyle | TextStyle;
15
+ export declare function useAnimatedNumber(initial: number): UniversalAnimatedNumber<Animated.Value>;
16
+ export declare function useAnimatedNumberReaction(value: UniversalAnimatedNumber<Animated.Value>, cb: (current: number) => void): void;
17
+ export declare function useAnimatedNumberStyle<V extends UniversalAnimatedNumber<Animated.Value>>(value: V, getStyle: (value: V) => ViewStyle | TextStyle): ViewStyle | TextStyle;
18
+ export {};
19
+ //# sourceMappingURL=useAnimated.d.ts.map
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=useAnimation.d.ts.map
@@ -1,284 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __defProps = Object.defineProperties;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
- var __getProtoOf = Object.getPrototypeOf;
9
- var __hasOwnProp = Object.prototype.hasOwnProperty;
10
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
11
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
- var __spreadValues = (a, b) => {
13
- for (var prop in b || (b = {}))
14
- if (__hasOwnProp.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- if (__getOwnPropSymbols)
17
- for (var prop of __getOwnPropSymbols(b)) {
18
- if (__propIsEnum.call(b, prop))
19
- __defNormalProp(a, prop, b[prop]);
20
- }
21
- return a;
22
- };
23
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
- var __objRest = (source, exclude) => {
25
- var target = {};
26
- for (var prop in source)
27
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
28
- target[prop] = source[prop];
29
- if (source != null && __getOwnPropSymbols)
30
- for (var prop of __getOwnPropSymbols(source)) {
31
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
32
- target[prop] = source[prop];
33
- }
34
- return target;
35
- };
36
- var __export = (target, all) => {
37
- for (var name in all)
38
- __defProp(target, name, { get: all[name], enumerable: true });
39
- };
40
- var __copyProps = (to, from, except, desc) => {
41
- if (from && typeof from === "object" || typeof from === "function") {
42
- for (let key of __getOwnPropNames(from))
43
- if (!__hasOwnProp.call(to, key) && key !== except)
44
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
45
- }
46
- return to;
47
- };
48
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
49
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
50
- var Drawer_exports = {};
51
- __export(Drawer_exports, {
52
- Drawer: () => Drawer,
53
- DrawerBackdrop: () => DrawerBackdrop,
54
- DrawerFrame: () => DrawerFrame,
55
- DrawerHandle: () => DrawerHandle,
56
- DrawerHandleFrame: () => DrawerHandleFrame,
57
- createDrawerScope: () => createDrawerScope
58
- });
59
- module.exports = __toCommonJS(Drawer_exports);
60
- var import_core = require("@tamagui/core");
61
- var import_create_context = require("@tamagui/create-context");
62
- var import_stacks = require("@tamagui/stacks");
63
- var import_use_controllable_state = require("@tamagui/use-controllable-state");
64
- var import_react = __toESM(require("react"));
65
- var import_react_native = require("react-native");
66
- const DRAWER_NAME = "Drawer";
67
- const DRAWER_HANDLE_NAME = "DrawerHandle";
68
- const DrawerHandleFrame = (0, import_core.styled)(import_stacks.XStack, {
69
- name: DRAWER_HANDLE_NAME,
70
- height: 10,
71
- borderRadius: 100,
72
- backgroundColor: "$background",
73
- position: "absolute",
74
- pointerEvents: "auto",
75
- zIndex: 10,
76
- y: -18,
77
- top: 0,
78
- left: "35%",
79
- right: "35%",
80
- opacity: 0.5,
81
- hoverStyle: {
82
- opacity: 0.7
83
- }
84
- });
85
- const DrawerHandle = DrawerHandleFrame.extractable((_a) => {
86
- var _b = _a, { __scopeDrawer } = _b, props = __objRest(_b, ["__scopeDrawer"]);
87
- const context = useDrawerContext(DRAWER_HANDLE_NAME, __scopeDrawer);
88
- return /* @__PURE__ */ import_react.default.createElement(DrawerHandleFrame, __spreadValues({
89
- onPress: () => {
90
- const nextPos = (context.position + 1) % context.snapPoints.length;
91
- context.setPosition(nextPos);
92
- }
93
- }, props));
94
- });
95
- const [createDrawerContext, createDrawerScope] = (0, import_create_context.createContextScope)(DRAWER_NAME);
96
- const [DrawerProvider, useDrawerContext] = createDrawerContext(DRAWER_NAME, {});
97
- const DrawerBackdrop = (0, import_core.styled)(import_stacks.YStack, {
98
- name: "DrawerBackdrop",
99
- backgroundColor: "$color",
100
- fullscreen: true,
101
- opacity: 0.2
102
- });
103
- const DrawerFrame = (0, import_core.styled)(import_stacks.YStack, {
104
- name: "DrawerFrame",
105
- flex: 1,
106
- backgroundColor: "$background",
107
- borderTopLeftRadius: "$4",
108
- borderTopRightRadius: "$4",
109
- padding: "$4",
110
- width: "100%"
111
- });
112
- const useIsSSR = () => {
113
- const [val, setVal] = (0, import_react.useState)(import_core.isWeb ? import_core.isSSR : false);
114
- (0, import_react.useEffect)(() => {
115
- if (import_core.isWeb && !import_core.isSSR) {
116
- setVal(false);
117
- }
118
- }, []);
119
- return val;
120
- };
121
- const Drawer = (0, import_core.withStaticProperties)((0, import_core.themeable)((0, import_react.forwardRef)((props, ref) => {
122
- const _a = props, {
123
- __scopeDrawer,
124
- snapPoints: snapPointsProp = [80, 10],
125
- children: childrenProp,
126
- position: positionProp,
127
- onChangePosition,
128
- defaultPosition
129
- } = _a, rest = __objRest(_a, [
130
- "__scopeDrawer",
131
- "snapPoints",
132
- "children",
133
- "position",
134
- "onChangePosition",
135
- "defaultPosition"
136
- ]);
137
- const isServerSide = useIsSSR();
138
- const [position, setPosition] = (0, import_use_controllable_state.useControllableState)({
139
- prop: positionProp,
140
- defaultProp: defaultPosition || 0,
141
- onChange: onChangePosition,
142
- strategy: "most-recent-wins"
143
- });
144
- const [layout, setLayout] = (0, import_react.useState)();
145
- const positionValue = (0, import_react.useRef)();
146
- if (!positionValue.current) {
147
- positionValue.current = new import_react_native.Animated.Value(position);
148
- }
149
- const snapPoints = (0, import_react.useMemo)(() => snapPointsProp, [JSON.stringify(snapPointsProp)]);
150
- if (isServerSide) {
151
- return null;
152
- }
153
- const spring = (0, import_react.useRef)(null);
154
- function stopSpring() {
155
- var _a2;
156
- (_a2 = spring.current) == null ? void 0 : _a2.stop();
157
- spring.current = null;
158
- }
159
- const positions = (0, import_react.useMemo)(() => snapPoints.map((point) => getYForPosition(point, layout)), [layout, snapPoints]);
160
- const animateTo = (0, import_react.useCallback)((position2) => {
161
- if (!positionValue.current)
162
- return;
163
- const toValue = positions[position2];
164
- stopSpring();
165
- spring.current = import_react_native.Animated.spring(positionValue.current, {
166
- useNativeDriver: !import_core.isWeb,
167
- toValue
168
- });
169
- spring.current.start(({ finished }) => finished && stopSpring());
170
- }, [positions]);
171
- (0, import_react.useLayoutEffect)(() => {
172
- animateTo(position);
173
- }, [position, animateTo]);
174
- const panResponder = (0, import_react.useMemo)(() => {
175
- if (!layout)
176
- return;
177
- console.log("setup pan");
178
- const pos = positionValue.current;
179
- const minY = positions[0];
180
- let startY = pos["_value"];
181
- return import_react_native.PanResponder.create({
182
- onMoveShouldSetPanResponder: (_e, { dy }) => {
183
- return Math.abs(dy) > 6;
184
- },
185
- onPanResponderGrant: () => {
186
- stopSpring();
187
- startY = pos["_value"];
188
- },
189
- onPanResponderMove: (_e, { dy }) => {
190
- const to = dy + startY;
191
- pos.setValue(resisted(to, minY));
192
- },
193
- onPanResponderRelease: (_e, { vy, dy }) => {
194
- const at = dy + startY;
195
- const end = at + layout.height * vy * 0.33;
196
- let closestPoint = 0;
197
- let dist = Infinity;
198
- for (let i = 0; i < positions.length; i++) {
199
- const position2 = positions[i];
200
- const curDist = end > position2 ? end - position2 : position2 - end;
201
- if (curDist < dist) {
202
- dist = curDist;
203
- closestPoint = i;
204
- }
205
- }
206
- setPosition(closestPoint);
207
- animateTo(closestPoint);
208
- }
209
- });
210
- }, [layout, positions, setPosition]);
211
- let handleComponent = null;
212
- let backdropComponent = null;
213
- let frameComponent = null;
214
- import_react.default.Children.forEach(childrenProp, (child) => {
215
- var _a2;
216
- if ((0, import_react.isValidElement)(child)) {
217
- switch ((_a2 = child.type) == null ? void 0 : _a2["staticConfig"].componentName) {
218
- case "DrawerHandle":
219
- handleComponent = child;
220
- break;
221
- case "DrawerFrame":
222
- frameComponent = child;
223
- break;
224
- case "DrawerBackdrop":
225
- backdropComponent = child;
226
- break;
227
- default:
228
- console.warn("Warning: passed invalid child to Drawer", child);
229
- }
230
- }
231
- });
232
- return /* @__PURE__ */ import_react.default.createElement(DrawerProvider, {
233
- scope: __scopeDrawer,
234
- position,
235
- snapPoints,
236
- setPosition
237
- }, backdropComponent, handleComponent, /* @__PURE__ */ import_react.default.createElement(import_react_native.Animated.View, __spreadProps(__spreadValues({}, panResponder == null ? void 0 : panResponder.panHandlers), {
238
- onLayout: (e) => {
239
- setLayout(e.nativeEvent.layout);
240
- },
241
- style: {
242
- width: "100%",
243
- height: "100%",
244
- transform: [{ translateY: positionValue.current }]
245
- }
246
- }), frameComponent));
247
- }), {
248
- componentName: "Drawer"
249
- }), {
250
- Handle: DrawerHandle,
251
- Frame: DrawerFrame,
252
- Backdrop: DrawerBackdrop
253
- });
254
- function getYForPosition(point, layout) {
255
- if (!layout)
256
- return 0;
257
- if (point === void 0) {
258
- console.warn(`No snapPoint`);
259
- return 0;
260
- }
261
- const pct = point / 100;
262
- const next = layout.height - pct * layout.height;
263
- return next;
264
- }
265
- function resisted(y, minY, maxOverflow = 25) {
266
- if (y < minY) {
267
- const past = minY - y;
268
- const pctPast = Math.min(maxOverflow, past) / maxOverflow;
269
- const diminishBy = 1.1 - Math.pow(0.1, pctPast);
270
- const extra = -diminishBy * maxOverflow;
271
- return minY + extra;
272
- }
273
- return y;
274
- }
275
- // Annotate the CommonJS export names for ESM import in node:
276
- 0 && (module.exports = {
277
- Drawer,
278
- DrawerBackdrop,
279
- DrawerFrame,
280
- DrawerHandle,
281
- DrawerHandleFrame,
282
- createDrawerScope
283
- });
284
- //# sourceMappingURL=Drawer.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/Drawer.tsx"],
4
- "sourcesContent": ["import { isSSR, isWeb, styled, themeable, withStaticProperties } from '@tamagui/core'\nimport { ScopedProps, createContextScope } from '@tamagui/create-context'\nimport { XStack, XStackProps, YStack } from '@tamagui/stacks'\nimport { useControllableState } from '@tamagui/use-controllable-state'\nimport React, {\n ReactNode,\n forwardRef,\n isValidElement,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react'\nimport { Animated, LayoutRectangle, PanResponder, View } from 'react-native'\n\ntype PositionChangeHandler =\n | ((position: number) => void)\n | React.Dispatch<React.SetStateAction<number>>\n\nconst DRAWER_NAME = 'Drawer'\nconst DRAWER_HANDLE_NAME = 'DrawerHandle'\n\nexport const DrawerHandleFrame = styled(XStack, {\n name: DRAWER_HANDLE_NAME,\n height: 10,\n borderRadius: 100,\n backgroundColor: '$background',\n position: 'absolute',\n pointerEvents: 'auto',\n zIndex: 10,\n y: -18,\n top: 0,\n left: '35%',\n right: '35%',\n opacity: 0.5,\n\n hoverStyle: {\n opacity: 0.7,\n },\n})\n\nexport const DrawerHandle = DrawerHandleFrame.extractable(\n ({ __scopeDrawer, ...props }: ScopedProps<XStackProps, 'Drawer'>) => {\n const context = useDrawerContext(DRAWER_HANDLE_NAME, __scopeDrawer)\n\n return (\n <DrawerHandleFrame\n onPress={() => {\n const nextPos = (context.position + 1) % context.snapPoints.length\n context.setPosition(nextPos)\n }}\n {...props}\n />\n )\n }\n)\n\ntype DrawerContextValue = {\n position: number\n snapPoints: number[]\n setPosition: React.Dispatch<React.SetStateAction<number>>\n}\n\nconst [createDrawerContext, createDrawerScope] = createContextScope(DRAWER_NAME)\nconst [DrawerProvider, useDrawerContext] = createDrawerContext<DrawerContextValue>(\n DRAWER_NAME,\n {} as any\n)\n\nexport const DrawerBackdrop = styled(YStack, {\n name: 'DrawerBackdrop',\n backgroundColor: '$color',\n fullscreen: true,\n opacity: 0.2,\n})\n\nexport const DrawerFrame = styled(YStack, {\n name: 'DrawerFrame',\n flex: 1,\n backgroundColor: '$background',\n borderTopLeftRadius: '$4',\n borderTopRightRadius: '$4',\n padding: '$4',\n width: '100%',\n})\n\nexport type DrawerProps = ScopedProps<\n {\n open?: boolean\n defaultOpen?: boolean\n defaultPosition?: number\n snapPoints?: number[]\n position?: number\n onChangePosition?: PositionChangeHandler\n children?: ReactNode\n },\n 'Drawer'\n>\n\nconst useIsSSR = () => {\n const [val, setVal] = useState(isWeb ? isSSR : false)\n useEffect(() => {\n if (isWeb && !isSSR) {\n setVal(false)\n }\n }, [])\n return val\n}\n\nexport const Drawer = withStaticProperties(\n themeable(\n forwardRef<View, DrawerProps>((props, ref) => {\n const {\n __scopeDrawer,\n snapPoints: snapPointsProp = [80, 10],\n children: childrenProp,\n position: positionProp,\n onChangePosition,\n defaultPosition,\n ...rest\n } = props\n const isServerSide = useIsSSR()\n\n const [position, setPosition] = useControllableState({\n prop: positionProp,\n defaultProp: defaultPosition || 0,\n onChange: onChangePosition,\n strategy: 'most-recent-wins',\n })\n\n const [layout, setLayout] = useState<LayoutRectangle>()\n\n const positionValue = useRef<Animated.Value>()\n if (!positionValue.current) {\n positionValue.current = new Animated.Value(position)\n }\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const snapPoints = useMemo(() => snapPointsProp, [JSON.stringify(snapPointsProp)])\n\n // we can put non-server side hooks after conditional because based on env\n if (isServerSide) {\n return null\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const spring = useRef<Animated.CompositeAnimation | null>(null)\n\n function stopSpring() {\n spring.current?.stop()\n spring.current = null\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const positions = useMemo(\n () => snapPoints.map((point) => getYForPosition(point, layout)),\n [layout, snapPoints]\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const animateTo = useCallback(\n (position: number) => {\n if (!positionValue.current) return\n const toValue = positions[position]\n stopSpring()\n spring.current = Animated.spring(positionValue.current, {\n useNativeDriver: !isWeb,\n toValue,\n })\n spring.current.start(({ finished }) => finished && stopSpring())\n },\n [positions]\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => {\n animateTo(position)\n }, [position, animateTo])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const panResponder = useMemo(() => {\n if (!layout) return\n console.log('setup pan')\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const pos = positionValue.current!\n const minY = positions[0]\n let startY = pos['_value']\n\n return PanResponder.create({\n onMoveShouldSetPanResponder: (_e, { dy }) => {\n // we could do some detection of other touchables and cancel here..\n // console.log('wut is', _e)\n return Math.abs(dy) > 6\n },\n onPanResponderGrant: () => {\n stopSpring()\n startY = pos['_value']\n },\n onPanResponderMove: (_e, { dy }) => {\n const to = dy + startY\n pos.setValue(resisted(to, minY))\n },\n onPanResponderRelease: (_e, { vy, dy }) => {\n const at = dy + startY\n // seems liky vy goes up to about 4 at the very most (+ is down, - is up)\n // lets base our multiplier on the total layout height\n const end = at + layout.height * vy * 0.33\n let closestPoint = 0\n let dist = Infinity\n for (let i = 0; i < positions.length; i++) {\n const position = positions[i]\n const curDist = end > position ? end - position : position - end\n if (curDist < dist) {\n dist = curDist\n closestPoint = i\n }\n }\n // have to call both because state may not change but need to snap back\n setPosition(closestPoint)\n animateTo(closestPoint)\n },\n })\n }, [layout, positions, setPosition])\n\n let handleComponent: React.ReactElement | null = null\n let backdropComponent: React.ReactElement | null = null\n let frameComponent: React.ReactElement | null = null\n\n React.Children.forEach(childrenProp, (child) => {\n if (isValidElement(child)) {\n switch (child.type?.['staticConfig'].componentName) {\n case 'DrawerHandle':\n handleComponent = child\n break\n case 'DrawerFrame':\n frameComponent = child\n break\n case 'DrawerBackdrop':\n backdropComponent = child\n break\n default:\n console.warn('Warning: passed invalid child to Drawer', child)\n }\n }\n })\n\n return (\n <DrawerProvider\n scope={__scopeDrawer}\n position={position}\n snapPoints={snapPoints}\n setPosition={setPosition}\n >\n {backdropComponent}\n {handleComponent}\n <Animated.View\n {...panResponder?.panHandlers}\n onLayout={(e) => {\n setLayout(e.nativeEvent.layout)\n }}\n style={{\n width: '100%',\n height: '100%',\n transform: [{ translateY: positionValue.current }],\n }}\n >\n {frameComponent}\n </Animated.View>\n </DrawerProvider>\n )\n }),\n {\n componentName: 'Drawer',\n }\n ),\n {\n Handle: DrawerHandle,\n Frame: DrawerFrame,\n Backdrop: DrawerBackdrop,\n }\n)\n\nfunction getYForPosition(point?: number, layout?: LayoutRectangle) {\n if (!layout) return 0\n if (point === undefined) {\n console.warn(`No snapPoint`)\n return 0\n }\n const pct = point / 100\n const next = layout.height - pct * layout.height\n return next\n}\n\nfunction resisted(y: number, minY: number, maxOverflow = 25) {\n if (y < minY) {\n const past = minY - y\n const pctPast = Math.min(maxOverflow, past) / maxOverflow\n const diminishBy = 1.1 - Math.pow(0.1, pctPast)\n const extra = -diminishBy * maxOverflow\n return minY + extra\n }\n return y\n}\n\nexport { createDrawerScope }\n"],
5
- "mappings": "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",
6
- "names": []
7
- }