@tamagui/sheet 1.88.13 → 1.89.0-1706308641099

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.
@@ -0,0 +1,57 @@
1
+ import { composeRefs } from "@tamagui/compose-refs";
2
+ import { ScrollView } from "@tamagui/scroll-view";
3
+ import { forwardRef, useMemo, useRef } from "react";
4
+ import { useSheetContext } from "./SheetContext.mjs";
5
+ import { jsx } from "react/jsx-runtime";
6
+ const SHEET_SCROLL_VIEW_NAME = "SheetScrollView",
7
+ SheetScrollView = forwardRef(({
8
+ __scopeSheet,
9
+ children,
10
+ onScroll,
11
+ ...props
12
+ }, ref) => {
13
+ const context = useSheetContext(SHEET_SCROLL_VIEW_NAME, __scopeSheet),
14
+ {
15
+ scrollBridge
16
+ } = context,
17
+ scrollRef = useRef(null),
18
+ state = useRef({
19
+ lastPageY: 0,
20
+ dragAt: 0,
21
+ dys: [],
22
+ // store a few recent dys to get velocity on release
23
+ isScrolling: !1,
24
+ isDragging: !1
25
+ }),
26
+ release = () => {
27
+ if (!state.current.isDragging) return;
28
+ state.current.isDragging = !1, scrollBridge.scrollStartY = -1, state.current.isScrolling = !1;
29
+ let vy = 0;
30
+ if (state.current.dys.length) {
31
+ const recentDys = state.current.dys.slice(-10);
32
+ vy = (recentDys.length ? recentDys.reduce((a, b) => a + b, 0) : 0) / recentDys.length * 0.04;
33
+ }
34
+ state.current.dys = [], scrollBridge.release({
35
+ dragAt: state.current.dragAt,
36
+ vy
37
+ });
38
+ };
39
+ return /* @__PURE__ */jsx(ScrollView, {
40
+ ref: composeRefs(scrollRef, ref),
41
+ flex: 1,
42
+ scrollEventThrottle: 8,
43
+ onScroll: e => {
44
+ const {
45
+ y
46
+ } = e.nativeEvent.contentOffset;
47
+ scrollBridge.y = y, y > 0 && (scrollBridge.scrollStartY = -1), onScroll?.(e);
48
+ },
49
+ onStartShouldSetResponder: () => (scrollBridge.scrollStartY = -1, state.current.isDragging = !0, !0),
50
+ onMoveShouldSetResponder: () => !1,
51
+ onResponderRelease: release,
52
+ className: "_ovs-contain",
53
+ ...props,
54
+ children: useMemo(() => children, [children])
55
+ });
56
+ });
57
+ export { SheetScrollView };
@@ -0,0 +1,8 @@
1
+ import { isClient } from "@tamagui/core";
2
+ const constants = {},
3
+ SHEET_NAME = "Sheet",
4
+ SHEET_HANDLE_NAME = "SheetHandle",
5
+ SHEET_OVERLAY_NAME = "SheetOverlay",
6
+ SHEET_HIDDEN_STYLESHEET = isClient ? document.createElement("style") : null;
7
+ SHEET_HIDDEN_STYLESHEET && document.head.appendChild(SHEET_HIDDEN_STYLESHEET);
8
+ export { SHEET_HANDLE_NAME, SHEET_HIDDEN_STYLESHEET, SHEET_NAME, SHEET_OVERLAY_NAME, constants };
@@ -0,0 +1,6 @@
1
+ import { createContext } from "react";
2
+ const ParentSheetContext = createContext({
3
+ zIndex: 1e5
4
+ }),
5
+ SheetInsideSheetContext = createContext(null);
6
+ export { ParentSheetContext, SheetInsideSheetContext };
@@ -0,0 +1,138 @@
1
+ import { useComposedRefs } from "@tamagui/compose-refs";
2
+ import { useIsomorphicLayoutEffect } from "@tamagui/constants";
3
+ import { Stack } from "@tamagui/core";
4
+ import { composeEventHandlers, withStaticProperties } from "@tamagui/helpers";
5
+ import { RemoveScroll } from "@tamagui/remove-scroll";
6
+ import { useDidFinishSSR } from "@tamagui/use-did-finish-ssr";
7
+ import { forwardRef, memo, useMemo } from "react";
8
+ import { Platform } from "react-native-web";
9
+ import { SHEET_HANDLE_NAME, SHEET_NAME, SHEET_OVERLAY_NAME } from "./constants.mjs";
10
+ import { useSheetContext } from "./SheetContext.mjs";
11
+ import { SheetImplementationCustom } from "./SheetImplementationCustom.mjs";
12
+ import { SheetScrollView } from "./SheetScrollView.mjs";
13
+ import { useSheetController } from "./useSheetController.mjs";
14
+ import { useSheetOffscreenSize } from "./useSheetOffscreenSize.mjs";
15
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
16
+ function createSheet({
17
+ Handle,
18
+ Frame,
19
+ Overlay
20
+ }) {
21
+ const SheetHandle = Handle.extractable(({
22
+ __scopeSheet,
23
+ ...props
24
+ }) => {
25
+ const context = useSheetContext(SHEET_HANDLE_NAME, __scopeSheet);
26
+ return context.onlyShowFrame ? null :
27
+ // @ts-ignore
28
+ /* @__PURE__ */
29
+ jsx(Handle, {
30
+ onPress: () => {
31
+ const max = context.snapPoints.length + (context.dismissOnSnapToBottom ? -1 : 0),
32
+ nextPos = (context.position + 1) % max;
33
+ context.setPosition(nextPos);
34
+ },
35
+ open: context.open,
36
+ ...props
37
+ });
38
+ }),
39
+ SheetOverlay = Overlay.extractable(memo(propsIn => {
40
+ const {
41
+ __scopeSheet,
42
+ ...props
43
+ } = propsIn,
44
+ context = useSheetContext(SHEET_OVERLAY_NAME, __scopeSheet),
45
+ element = useMemo(() =>
46
+ // @ts-ignore
47
+ /* @__PURE__ */
48
+ jsx(Overlay, {
49
+ ...props,
50
+ onPress: composeEventHandlers(props.onPress, context.dismissOnOverlayPress ? () => {
51
+ context.setOpen(!1);
52
+ } : void 0)
53
+ }), [props.onPress, context.dismissOnOverlayPress]);
54
+ return useIsomorphicLayoutEffect(() => {
55
+ context.onOverlayComponent?.(element);
56
+ }, [element]), context.onlyShowFrame, null;
57
+ })),
58
+ SheetFrame = Frame.extractable(forwardRef(({
59
+ __scopeSheet,
60
+ adjustPaddingForOffscreenContent,
61
+ disableHideBottomOverflow,
62
+ children,
63
+ ...props
64
+ }, forwardedRef) => {
65
+ const context = useSheetContext(SHEET_NAME, __scopeSheet),
66
+ {
67
+ hasFit,
68
+ removeScrollEnabled,
69
+ frameSize,
70
+ contentRef
71
+ } = context,
72
+ composedContentRef = useComposedRefs(forwardedRef, contentRef),
73
+ offscreenSize = useSheetOffscreenSize(context),
74
+ sheetContents = useMemo(() =>
75
+ // @ts-ignore
76
+ /* @__PURE__ */
77
+ jsxs(Frame, {
78
+ ref: composedContentRef,
79
+ flex: hasFit ? 0 : 1,
80
+ height: hasFit ? void 0 : frameSize,
81
+ ...props,
82
+ children: [children, adjustPaddingForOffscreenContent && /* @__PURE__ */jsx(Stack, {
83
+ "data-sheet-offscreen-pad": !0,
84
+ height: offscreenSize,
85
+ width: "100%"
86
+ })]
87
+ }), [props, frameSize, offscreenSize, adjustPaddingForOffscreenContent, hasFit]);
88
+ return /* @__PURE__ */jsxs(Fragment, {
89
+ children: [/* @__PURE__ */jsx(RemoveScroll, {
90
+ forwardProps: !0,
91
+ enabled: removeScrollEnabled,
92
+ allowPinchZoom: !0,
93
+ shards: [contentRef],
94
+ removeScrollBar: !1,
95
+ children: sheetContents
96
+ }), !disableHideBottomOverflow &&
97
+ // @ts-ignore
98
+ /* @__PURE__ */
99
+ jsx(Frame, {
100
+ ...props,
101
+ componentName: "SheetCover",
102
+ children: null,
103
+ position: "absolute",
104
+ bottom: "-50%",
105
+ zIndex: -1,
106
+ height: context.frameSize,
107
+ left: 0,
108
+ right: 0,
109
+ borderWidth: 0,
110
+ borderRadius: 0,
111
+ shadowOpacity: 0
112
+ })]
113
+ });
114
+ })),
115
+ Sheet = forwardRef(function (props, ref) {
116
+ const hydrated = useDidFinishSSR(),
117
+ {
118
+ isShowingNonSheet
119
+ } = useSheetController();
120
+ let SheetImplementation = SheetImplementationCustom;
121
+ return props.native && Platform.OS, isShowingNonSheet || !hydrated ? null : /* @__PURE__ */jsx(SheetImplementation, {
122
+ ref,
123
+ ...props
124
+ });
125
+ }),
126
+ components = {
127
+ Frame: SheetFrame,
128
+ Overlay: SheetOverlay,
129
+ Handle: SheetHandle,
130
+ ScrollView: SheetScrollView
131
+ },
132
+ Controlled = withStaticProperties(Sheet, components);
133
+ return withStaticProperties(Sheet, {
134
+ ...components,
135
+ Controlled
136
+ });
137
+ }
138
+ export { createSheet };
@@ -0,0 +1,9 @@
1
+ function resisted(y, minY, maxOverflow = 25) {
2
+ if (y < minY) {
3
+ const past = minY - y,
4
+ extra = -(1.1 - 0.1 ** (Math.min(maxOverflow, past) / maxOverflow)) * maxOverflow;
5
+ return minY + extra;
6
+ }
7
+ return y;
8
+ }
9
+ export { resisted };
@@ -0,0 +1,7 @@
1
+ export * from "./Sheet.mjs";
2
+ export * from "./useSheet.mjs";
3
+ export * from "./createSheet.mjs";
4
+ export * from "./SheetController.mjs";
5
+ export * from "./useSheetController.mjs";
6
+ import { setupNativeSheet } from "./nativeSheet.mjs";
7
+ export { setupNativeSheet };
@@ -0,0 +1,50 @@
1
+ import { YStack } from "@tamagui/stacks";
2
+ import { useEffect, useRef } from "react";
3
+ import { View } from "react-native-web";
4
+ import { SheetProvider } from "./SheetContext.mjs";
5
+ import { useSheetOpenState } from "./useSheetOpenState.mjs";
6
+ import { useSheetProviderProps } from "./useSheetProviderProps.mjs";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ const nativeSheets = {
9
+ ios: null
10
+ };
11
+ function getNativeSheet(platform) {
12
+ return nativeSheets[platform];
13
+ }
14
+ function setupNativeSheet(platform, Implementation) {
15
+ platform === "ios" && (nativeSheets[platform] = props => {
16
+ const state = useSheetOpenState(props),
17
+ providerProps = useSheetProviderProps(props, state),
18
+ {
19
+ open,
20
+ setOpen
21
+ } = state,
22
+ ref = useRef();
23
+ return useEffect(() => {
24
+ ref.current?.setVisibility(open);
25
+ }, [open]), /* @__PURE__ */jsx(Fragment, {
26
+ children: /* @__PURE__ */jsxs(SheetProvider, {
27
+ ...providerProps,
28
+ onlyShowFrame: !0,
29
+ children: [/* @__PURE__ */jsx(Implementation, {
30
+ ref,
31
+ onModalDismiss: () => setOpen(!1),
32
+ children: /* @__PURE__ */jsx(View, {
33
+ style: {
34
+ flex: 1
35
+ },
36
+ children: props.children
37
+ })
38
+ }), /* @__PURE__ */jsx(YStack, {
39
+ position: "absolute",
40
+ opacity: 0,
41
+ pointerEvents: "none",
42
+ width: 0,
43
+ height: 0,
44
+ children: props.children
45
+ })]
46
+ })
47
+ });
48
+ });
49
+ }
50
+ export { getNativeSheet, setupNativeSheet };
File without changes
@@ -0,0 +1,3 @@
1
+ import { useSheetContext } from "./SheetContext.mjs";
2
+ const useSheet = () => useSheetContext("", void 0);
3
+ export { useSheet };
@@ -0,0 +1,14 @@
1
+ import { createContext, useContext } from "react";
2
+ const useSheetController = () => {
3
+ const controller = useContext(SheetControllerContext),
4
+ isHidden = controller?.hidden,
5
+ isShowingNonSheet = isHidden && controller?.open;
6
+ return {
7
+ controller,
8
+ isHidden,
9
+ isShowingNonSheet,
10
+ disableDrag: controller?.disableDrag
11
+ };
12
+ },
13
+ SheetControllerContext = createContext(null);
14
+ export { SheetControllerContext, useSheetController };
@@ -0,0 +1,27 @@
1
+ const useSheetOffscreenSize = ({
2
+ snapPoints,
3
+ position,
4
+ screenSize,
5
+ frameSize,
6
+ snapPointsMode
7
+ }) => {
8
+ if (snapPointsMode === "fit") return 0;
9
+ if (snapPointsMode === "constant") {
10
+ const maxSize2 = Number(snapPoints[0]),
11
+ currentSize2 = Number(snapPoints[position] ?? 0);
12
+ return maxSize2 - currentSize2;
13
+ }
14
+ if (snapPointsMode === "percent") {
15
+ const maxPercentOpened = Number(snapPoints[0]) / 100,
16
+ percentOpened = Number(snapPoints[position] ?? 0) / 100;
17
+ return (maxPercentOpened - percentOpened) * screenSize;
18
+ }
19
+ const maxSnapPoint = snapPoints[0];
20
+ if (maxSnapPoint === "fit") return 0;
21
+ const maxSize = typeof maxSnapPoint == "string" ? Number(maxSnapPoint.slice(0, -1)) / 100 * screenSize : maxSnapPoint,
22
+ currentSnapPoint = snapPoints[position] ?? 0,
23
+ currentSize = typeof currentSnapPoint == "string" ? Number(currentSnapPoint.slice(0, -1)) / 100 * screenSize : currentSnapPoint,
24
+ offscreenSize = maxSize - currentSize;
25
+ return Number.isNaN(offscreenSize) ? 0 : offscreenSize;
26
+ };
27
+ export { useSheetOffscreenSize };
@@ -0,0 +1,25 @@
1
+ import { useControllableState } from "@tamagui/use-controllable-state";
2
+ import { useSheetController } from "./useSheetController.mjs";
3
+ const useSheetOpenState = props => {
4
+ const {
5
+ isHidden,
6
+ controller
7
+ } = useSheetController(),
8
+ onOpenChangeInternal = val => {
9
+ controller?.onOpenChange?.(val), props.onOpenChange?.(val);
10
+ },
11
+ [open, setOpen] = useControllableState({
12
+ prop: controller?.open ?? props.open,
13
+ defaultProp: props.defaultOpen ?? !1,
14
+ onChange: onOpenChangeInternal,
15
+ strategy: "most-recent-wins",
16
+ transition: !0
17
+ });
18
+ return {
19
+ open,
20
+ setOpen,
21
+ isHidden,
22
+ controller
23
+ };
24
+ };
25
+ export { useSheetOpenState };
@@ -0,0 +1,86 @@
1
+ import { useConfiguration } from "@tamagui/core";
2
+ import { useConstant } from "@tamagui/use-constant";
3
+ import { useControllableState } from "@tamagui/use-controllable-state";
4
+ import React, { useCallback, useEffect, useMemo, useState } from "react";
5
+ function useSheetProviderProps(props, state, options = {}) {
6
+ const contentRef = React.useRef(null),
7
+ [frameSize, setFrameSize] = useState(0),
8
+ [maxContentSize, setMaxContentSize] = useState(0),
9
+ snapPointsMode = props.snapPointsMode ?? "percent",
10
+ snapPointsProp = props.snapPoints ?? (snapPointsMode === "percent" ? [80] : snapPointsMode === "constant" ? [256] : ["fit"]),
11
+ hasFit = snapPointsProp[0] === "fit",
12
+ snapPoints = useMemo(() => props.dismissOnSnapToBottom ? [...snapPointsProp, 0] : snapPointsProp,
13
+ // eslint-disable-next-line react-hooks/exhaustive-deps
14
+ [JSON.stringify(snapPointsProp), props.dismissOnSnapToBottom]),
15
+ [position_, setPositionImmediate] = useControllableState({
16
+ prop: props.position,
17
+ defaultProp: props.defaultPosition || (state.open ? 0 : -1),
18
+ onChange: props.onPositionChange,
19
+ strategy: "most-recent-wins",
20
+ transition: !0
21
+ }),
22
+ position = state.open === !1 ? -1 : position_,
23
+ {
24
+ open
25
+ } = state,
26
+ setPosition = useCallback(next => {
27
+ props.dismissOnSnapToBottom && next === snapPoints.length - 1 ? state.setOpen(!1) : setPositionImmediate(next);
28
+ }, [props.dismissOnSnapToBottom, snapPoints.length, setPositionImmediate, state.setOpen]);
29
+ process.env.NODE_ENV === "development" && (snapPointsMode === "mixed" && snapPoints.some(p => {
30
+ if (typeof p == "string") {
31
+ if (p === "fit") return !1;
32
+ if (p.endsWith("%")) {
33
+ const n = Number(p.slice(0, -1));
34
+ return n < 0 || n > 100;
35
+ }
36
+ return !0;
37
+ }
38
+ return typeof p != "number" || p < 0;
39
+ }) && console.warn('\u26A0\uFE0F Invalid snapPoint given, snapPoints must be positive numeric values, string percentages between 0-100%, or "fit" when snapPointsMode is mixed'), snapPointsMode === "mixed" && snapPoints.indexOf("fit") > 0 && console.warn('\u26A0\uFE0F Invalid snapPoint given, "fit" must be the first/largest snap point when snapPointsMode is mixed'), snapPointsMode === "fit" && (snapPoints.length !== (props.dismissOnSnapToBottom ? 2 : 1) || snapPoints[0] !== "fit") && console.warn("\u26A0\uFE0F Invalid snapPoint given, there are no snap points when snapPointsMode is fit"), snapPointsMode === "constant" && snapPoints.some(p => typeof p != "number" || p < 0) && console.warn("\u26A0\uFE0F Invalid snapPoint given, snapPoints must be positive numeric values when snapPointsMode is constant"), snapPointsMode === "percent" && snapPoints.some(p => typeof p != "number" || p < 0 || p > 100) && console.warn("\u26A0\uFE0F Invalid snapPoint given, snapPoints must be numeric values between 0 and 100 when snapPointsMode is percent")), open && props.dismissOnSnapToBottom && position === snapPoints.length - 1 && setPositionImmediate(0);
40
+ const shouldSetPositionOpen = open && position < 0;
41
+ useEffect(() => {
42
+ shouldSetPositionOpen && setPosition(0);
43
+ }, [setPosition, shouldSetPositionOpen]);
44
+ const {
45
+ animationDriver
46
+ } = useConfiguration();
47
+ if (!animationDriver) throw new Error("Must set animations in tamagui.config.ts");
48
+ const scrollBridge = useConstant(() => ({
49
+ enabled: !1,
50
+ y: 0,
51
+ paneY: 0,
52
+ paneMinY: 0,
53
+ scrollStartY: -1,
54
+ drag: () => {},
55
+ release: () => {},
56
+ scrollLock: !1
57
+ })),
58
+ removeScrollEnabled = props.forceRemoveScrollEnabled ?? (open && props.modal),
59
+ maxSnapPoint = snapPoints[0];
60
+ return {
61
+ screenSize: snapPointsMode === "percent" ? frameSize / ((typeof maxSnapPoint == "number" ? maxSnapPoint : 100) / 100) : maxContentSize,
62
+ maxSnapPoint,
63
+ removeScrollEnabled,
64
+ scrollBridge,
65
+ modal: !!props.modal,
66
+ open: state.open,
67
+ setOpen: state.setOpen,
68
+ hidden: !!state.isHidden,
69
+ contentRef,
70
+ frameSize,
71
+ setFrameSize,
72
+ dismissOnOverlayPress: props.dismissOnOverlayPress ?? !0,
73
+ dismissOnSnapToBottom: props.dismissOnSnapToBottom ?? !1,
74
+ onOverlayComponent: options.onOverlayComponent,
75
+ scope: props.__scopeSheet,
76
+ hasFit,
77
+ position,
78
+ snapPoints,
79
+ snapPointsMode,
80
+ setMaxContentSize,
81
+ setPosition,
82
+ setPositionImmediate,
83
+ onlyShowFrame: !1
84
+ };
85
+ }
86
+ export { useSheetProviderProps };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/sheet",
3
- "version": "1.88.13",
3
+ "version": "1.89.0-1706308641099",
4
4
  "sideEffects": [
5
5
  "*.css"
6
6
  ],
@@ -33,27 +33,27 @@
33
33
  }
34
34
  },
35
35
  "dependencies": {
36
- "@tamagui/animate-presence": "1.88.13",
37
- "@tamagui/animations-react-native": "1.88.13",
38
- "@tamagui/compose-refs": "1.88.13",
39
- "@tamagui/constants": "1.88.13",
40
- "@tamagui/core": "1.88.13",
41
- "@tamagui/create-context": "1.88.13",
42
- "@tamagui/helpers": "1.88.13",
43
- "@tamagui/portal": "1.88.13",
44
- "@tamagui/remove-scroll": "1.88.13",
45
- "@tamagui/scroll-view": "1.88.13",
46
- "@tamagui/stacks": "1.88.13",
47
- "@tamagui/use-constant": "1.88.13",
48
- "@tamagui/use-controllable-state": "1.88.13",
49
- "@tamagui/use-keyboard-visible": "1.88.13"
36
+ "@tamagui/animate-presence": "1.89.0-1706308641099",
37
+ "@tamagui/animations-react-native": "1.89.0-1706308641099",
38
+ "@tamagui/compose-refs": "1.89.0-1706308641099",
39
+ "@tamagui/constants": "1.89.0-1706308641099",
40
+ "@tamagui/core": "1.89.0-1706308641099",
41
+ "@tamagui/create-context": "1.89.0-1706308641099",
42
+ "@tamagui/helpers": "1.89.0-1706308641099",
43
+ "@tamagui/portal": "1.89.0-1706308641099",
44
+ "@tamagui/remove-scroll": "1.89.0-1706308641099",
45
+ "@tamagui/scroll-view": "1.89.0-1706308641099",
46
+ "@tamagui/stacks": "1.89.0-1706308641099",
47
+ "@tamagui/use-constant": "1.89.0-1706308641099",
48
+ "@tamagui/use-controllable-state": "1.89.0-1706308641099",
49
+ "@tamagui/use-keyboard-visible": "1.89.0-1706308641099"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "react": "*",
53
53
  "react-native": "*"
54
54
  },
55
55
  "devDependencies": {
56
- "@tamagui/build": "1.88.13",
56
+ "@tamagui/build": "1.89.0-1706308641099",
57
57
  "react": "^18.2.0",
58
58
  "react-native": "^0.72.6"
59
59
  },