@gryt/ui-native 0.9.0 → 0.11.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.
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAQtB,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAClF,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AASjE,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,CAAC;IAC7E,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAWD,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,IAAgB,EAChB,IAAe,EACf,SAAS,EACT,OAAO,EACP,KAAK,EACL,QAAgB,EAChB,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,WAAW,+BAuEb"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAQtB,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAClF,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AASjE,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,CAAC;IAC7E,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAWD,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,IAAgB,EAChB,IAAe,EACf,SAAS,EACT,OAAO,EACP,KAAK,EACL,QAAgB,EAChB,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,WAAW,+BA8Fb"}
@@ -25,7 +25,7 @@ export function Button({ children, tone = "primary", size = "medium", startIcon,
25
25
  const metrics = SIZES[size];
26
26
  const animate = !reducedMotion && !hasPopup && !disabled;
27
27
  const press = usePressScale(PRESSED_SCALE, !animate);
28
- const background = tone === "primary"
28
+ const fill = tone === "primary"
29
29
  ? theme.color.accent
30
30
  : tone === "secondary"
31
31
  ? theme.color.secondary
@@ -34,7 +34,7 @@ export function Button({ children, tone = "primary", size = "medium", startIcon,
34
34
  : tone === "danger"
35
35
  ? theme.color.danger
36
36
  : "transparent";
37
- const foreground = tone === "primary"
37
+ const label = tone === "primary"
38
38
  ? theme.color.onAccent
39
39
  : tone === "secondary"
40
40
  ? theme.color.onSecondary
@@ -43,6 +43,23 @@ export function Button({ children, tone = "primary", size = "medium", startIcon,
43
43
  : tone === "ghost"
44
44
  ? theme.color.muted
45
45
  : theme.color.text;
46
+ /**
47
+ * Disabled drops the fill rather than fading it.
48
+ *
49
+ * Every tone used to share one `opacity: 0.5`, and on the quiet tones that
50
+ * reads. On a filled one it does not: the accent at half opacity over a dark
51
+ * screen is still a saturated purple button, and nothing in it says it will
52
+ * not respond. That cost two taps on a Save button before I believed it was
53
+ * inert, having written the disabled condition myself half an hour earlier.
54
+ * GRYT-511, and the web's Button makes the same change in the same commit.
55
+ *
56
+ * So a disabled filled button becomes the surface it sits on, with a muted
57
+ * label — same size, same word, no longer claiming to be the action. Ghost
58
+ * has no fill to lose and its label is already muted, so the opacity below is
59
+ * what carries it.
60
+ */
61
+ const background = disabled && tone !== "ghost" ? theme.color.surfaceRaised : fill;
62
+ const foreground = disabled ? theme.color.muted : label;
46
63
  return (_jsx(Animated.View, { style: [press.style, style], children: _jsxs(Pressable, { accessibilityRole: "button", accessibilityState: { disabled: !!disabled }, disabled: disabled, onPressIn: press.onPressIn, onPressOut: press.onPressOut, style: {
47
64
  minHeight: metrics.minHeight,
48
65
  paddingHorizontal: metrics.paddingH,
@@ -52,7 +69,12 @@ export function Button({ children, tone = "primary", size = "medium", startIcon,
52
69
  gap: theme.space(2),
53
70
  borderRadius: theme.radius.full,
54
71
  backgroundColor: background,
55
- opacity: disabled ? 0.5 : 1,
72
+ /* Lighter than it was, because the fill swap is doing the work now.
73
+ It is kept because `startIcon` and `endIcon` are the caller's
74
+ elements with the caller's colours — nothing here can mute those,
75
+ and an icon at full strength on a dead button is the same lie in
76
+ miniature. */
77
+ opacity: disabled ? 0.6 : 1,
56
78
  }, ...rest, children: [startIcon, typeof children === "string" ? (_jsx(Text, { numberOfLines: 1, style: {
57
79
  color: foreground,
58
80
  fontSize: metrics.fontSize,
@@ -1,5 +1,6 @@
1
- import { type ReactNode } from "react";
1
+ import { type ComponentProps, type ReactNode } from "react";
2
2
  import { type StyleProp, type ViewStyle } from "react-native";
3
+ import { BottomSheetScrollView } from "@gorhom/bottom-sheet";
3
4
  import { type OpenStateProps } from "../../overlay/useOpenState.js";
4
5
  /**
5
6
  * A bottom sheet, which is the phone's modal.
@@ -78,7 +79,59 @@ export interface SheetContentProps {
78
79
  children?: ReactNode;
79
80
  style?: StyleProp<ViewStyle>;
80
81
  }
82
+ /**
83
+ * The sheet's body, for content that fits.
84
+ *
85
+ * Use `Sheet.ScrollView` instead when it might not — this is a
86
+ * `BottomSheetView`, which sizes itself to its children, so a scrollable inside
87
+ * it has no bounded height to scroll within and simply grows until the sheet
88
+ * clips it.
89
+ *
90
+ * ## Why it is `height: "100%"`
91
+ *
92
+ * `flex: 1` is not enough on its own: `BottomSheetView` measures its children,
93
+ * so there is no bounded height for a flex child to be all of. Anything inside
94
+ * that wants to be the whole sheet — a column with a row pinned to the bottom,
95
+ * a list — collapses to the height of its own content instead.
96
+ *
97
+ * Every caller in the mobile app passed `height: "100%"` to get around that,
98
+ * all three for the same reason, which is a default being wrong rather than
99
+ * three callers being unusual. It is in the style array before `style`, so a
100
+ * caller can still override it exactly as it can the padding. GRYT-516.
101
+ *
102
+ * A sheet whose content is genuinely shorter than the snap point is unchanged
103
+ * by this: the view has no background of its own, so a full-height one draws
104
+ * the same as a short one.
105
+ */
81
106
  declare function Content({ children, style }: SheetContentProps): import("react").JSX.Element;
107
+ export type SheetScrollViewProps = ComponentProps<typeof BottomSheetScrollView>;
108
+ /**
109
+ * The sheet's body, for content that might not fit.
110
+ *
111
+ * **In place of `Sheet.Content`, not inside it.** React Native's own
112
+ * `ScrollView` does not scroll inside a sheet at all — the sheet's pan gesture
113
+ * and the scroll view's native recogniser both want the touch, and
114
+ * gesture-handler settles that by reference, so the two have to know about each
115
+ * other. `BottomSheetScrollView` is that introduction, which is the same answer
116
+ * `Drawer.ScrollView` reaches by the same route.
117
+ *
118
+ * Being the sheet's body rather than a child of one is what makes it a single
119
+ * component to reach for. Three callers in the app had assembled this by hand
120
+ * and all three had to get four things right together: `padding: 0` and
121
+ * `height: "100%"` on `Sheet.Content`, so the scrollable has a bounded height
122
+ * to scroll within rather than a box that grows with it; the keyboard inset;
123
+ * and `keyboardShouldPersistTaps`, without which the first tap on a button only
124
+ * dismisses the keyboard. GRYT-492.
125
+ *
126
+ * What it does not decide is the snap point. A sheet that takes a keyboard
127
+ * wants a tall one — at 46% the field and the button underneath it are both
128
+ * behind the keyboard — and how tall depends on what is in it.
129
+ *
130
+ * The padding is the same as `Sheet.Content`'s, moved to the content container
131
+ * where it belongs: on the scrollable itself it would clip the scrolling
132
+ * content instead of spacing it.
133
+ */
134
+ declare function ScrollView({ children, style, contentContainerStyle, ...props }: SheetScrollViewProps): import("react").JSX.Element;
82
135
  export interface SheetCloseProps {
83
136
  children?: ReactNode;
84
137
  style?: StyleProp<ViewStyle>;
@@ -92,6 +145,7 @@ declare function Title({ children, style }: SheetTitleProps): import("react").JS
92
145
  export declare const Sheet: typeof Root & {
93
146
  Trigger: typeof Trigger;
94
147
  Content: typeof Content;
148
+ ScrollView: typeof ScrollView;
95
149
  Close: typeof Close;
96
150
  Title: typeof Title;
97
151
  };
@@ -1 +1 @@
1
- {"version":3,"file":"Sheet.d.ts","sourceRoot":"","sources":["../../../src/components/Sheet/Sheet.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAerF,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAE7D;AAeD,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,iBAAS,IAAI,CAAC,EACZ,UAAoB,EACpB,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,UAAU,+BAqBZ;AAWD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAOtD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAuNtD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAOlD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAiBlD;AAED,eAAO,MAAM,KAAK;;;;;CAA0D,CAAC"}
1
+ {"version":3,"file":"Sheet.d.ts","sourceRoot":"","sources":["../../../src/components/Sheet/Sheet.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAyB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAIL,qBAAqB,EAKtB,MAAM,sBAAsB,CAAC;AAM9B,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,kBAAkB,+BAE7D;AAeD,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,iBAAS,IAAI,CAAC,EACZ,UAAoB,EACpB,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,UAAU,+BAqBZ;AAWD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;;;;GAKG;AACH,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAOtD;AAuMD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,iBAAS,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,iBAAiB,+BAuCtD;AAED,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,iBAAS,UAAU,CAAC,EAClB,QAAQ,EACR,KAAK,EACL,qBAAqB,EACrB,GAAG,KAAK,EACT,EAAE,oBAAoB,+BA4BtB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAOlD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,iBAAS,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,eAAe,+BAiBlD;AAED,eAAO,MAAM,KAAK;;;;;;CAMhB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, } from "react";
3
3
  import { Pressable, Text, View } from "react-native";
4
- import { BottomSheetBackdrop, BottomSheetModal, BottomSheetModalProvider, BottomSheetView, useBottomSheetTimingConfigs, } from "@gorhom/bottom-sheet";
4
+ import { BottomSheetBackdrop, BottomSheetModal, BottomSheetModalProvider, BottomSheetScrollView, BottomSheetView, useBottomSheetTimingConfigs, } from "@gorhom/bottom-sheet";
5
5
  import { useSafeAreaInsets } from "react-native-safe-area-context";
6
6
  import { grytDrawerBleed } from "@gryt/theme";
7
7
  import { durations, easeSpringTight } from "../../motion/index.js";
@@ -54,7 +54,14 @@ function Trigger({ children, style }) {
54
54
  const sheet = useSheet("Trigger");
55
55
  return (_jsx(Pressable, { onPress: sheet.open, style: style, children: children }));
56
56
  }
57
- function Content({ children, style }) {
57
+ /**
58
+ * Everything about presenting the modal, shared by `Content` and `ScrollView`.
59
+ *
60
+ * The two are alternatives rather than one inside the other, so both need the
61
+ * whole `BottomSheetModal` — the effect that presents it, the backdrop, the
62
+ * background and the animation curve. This is that, once.
63
+ */
64
+ function useSheetModal() {
58
65
  const theme = useTheme();
59
66
  /**
60
67
  * The phone's own furniture, which the sheet has to stay clear of at both
@@ -71,7 +78,7 @@ function Content({ children, style }) {
71
78
  // on the provider inside the modal.
72
79
  const sheet = useContext(SheetContext);
73
80
  if (!state || !sheet) {
74
- throw new Error("Sheet.Content must be rendered inside Sheet.");
81
+ throw new Error("Sheet.Content and Sheet.ScrollView must be rendered inside Sheet.");
75
82
  }
76
83
  const { ref, isOpen, setOpen, snapPoints } = state;
77
84
  /**
@@ -175,36 +182,80 @@ function Content({ children, style }) {
175
182
  // Tracks the drag, so dragging the sheet down lightens the scrim
176
183
  // rather than holding full opacity until it snaps shut.
177
184
  opacity: 0.6, pressBehavior: "close" })), []);
178
- return (_jsx(BottomSheetModal, { ref: ref, snapPoints: snapPoints,
179
- // So a sheet at 100% stops below the Dynamic Island rather than running
180
- // its content under it.
181
- topInset: insets.top,
182
- // Off, because `snapPoints` is the whole point of this component.
183
- //
184
- // gorhom v5 defaults dynamic sizing on, which measures the content and
185
- // sizes the sheet to it — overriding the snap points entirely. A sheet
186
- // asked for 70% whose content had no intrinsic height collapsed to the
187
- // height of its own footer, which looks like the snap points being
188
- // ignored because they were.
189
- enableDynamicSizing: false, enablePanDownToClose: true,
190
- // A flick down or a tap on the backdrop closes it without anything in
191
- // React asking, so the state has to be told. Uncontrolled, this is what
192
- // makes the next `present` work; controlled, it is how the parent finds
193
- // out its sheet is gone.
194
- //
195
- // `presented` first, and not as a tidy-up: the modal has already
196
- // dismissed itself by the time this runs, and leaving the ref true lets
197
- // the effect below dismiss it a second time. See the note on the ref.
198
- onDismiss: () => {
199
- presented.current = false;
200
- setOpen(false);
201
- }, animationConfigs: animationConfigs, backdropComponent: renderBackdrop, backgroundComponent: renderBackground, handleIndicatorStyle: {
202
- backgroundColor: theme.color.border,
203
- width: 36,
204
- height: 4,
205
- }, children: _jsx(BottomSheetView, { style: [
185
+ return {
186
+ theme,
187
+ insets,
188
+ /* Re-provided inside the modal by whichever part renders the children. See
189
+ * the note at the call sites `@gorhom/portal` does not carry context. */
190
+ sheet,
191
+ modalProps: {
192
+ ref,
193
+ snapPoints,
194
+ // So a sheet at 100% stops below the Dynamic Island rather than running
195
+ // its content under it.
196
+ topInset: insets.top,
197
+ // Off, because `snapPoints` is the whole point of this component.
198
+ //
199
+ // gorhom v5 defaults dynamic sizing on, which measures the content and
200
+ // sizes the sheet to it — overriding the snap points entirely. A sheet
201
+ // asked for 70% whose content had no intrinsic height collapsed to the
202
+ // height of its own footer, which looks like the snap points being
203
+ // ignored because they were.
204
+ enableDynamicSizing: false,
205
+ enablePanDownToClose: true,
206
+ // A flick down or a tap on the backdrop closes it without anything in
207
+ // React asking, so the state has to be told. Uncontrolled, this is what
208
+ // makes the next `present` work; controlled, it is how the parent finds
209
+ // out its sheet is gone.
210
+ //
211
+ // `presented` first, and not as a tidy-up: the modal has already
212
+ // dismissed itself by the time this runs, and leaving the ref true lets
213
+ // the effect below dismiss it a second time. See the note on the ref.
214
+ onDismiss: () => {
215
+ presented.current = false;
216
+ setOpen(false);
217
+ },
218
+ animationConfigs,
219
+ backdropComponent: renderBackdrop,
220
+ backgroundComponent: renderBackground,
221
+ handleIndicatorStyle: {
222
+ backgroundColor: theme.color.border,
223
+ width: 36,
224
+ height: 4,
225
+ },
226
+ },
227
+ };
228
+ }
229
+ /**
230
+ * The sheet's body, for content that fits.
231
+ *
232
+ * Use `Sheet.ScrollView` instead when it might not — this is a
233
+ * `BottomSheetView`, which sizes itself to its children, so a scrollable inside
234
+ * it has no bounded height to scroll within and simply grows until the sheet
235
+ * clips it.
236
+ *
237
+ * ## Why it is `height: "100%"`
238
+ *
239
+ * `flex: 1` is not enough on its own: `BottomSheetView` measures its children,
240
+ * so there is no bounded height for a flex child to be all of. Anything inside
241
+ * that wants to be the whole sheet — a column with a row pinned to the bottom,
242
+ * a list — collapses to the height of its own content instead.
243
+ *
244
+ * Every caller in the mobile app passed `height: "100%"` to get around that,
245
+ * all three for the same reason, which is a default being wrong rather than
246
+ * three callers being unusual. It is in the style array before `style`, so a
247
+ * caller can still override it exactly as it can the padding. GRYT-516.
248
+ *
249
+ * A sheet whose content is genuinely shorter than the snap point is unchanged
250
+ * by this: the view has no background of its own, so a full-height one draws
251
+ * the same as a short one.
252
+ */
253
+ function Content({ children, style }) {
254
+ const { theme, insets, sheet, modalProps } = useSheetModal();
255
+ return (_jsx(BottomSheetModal, { ...modalProps, children: _jsx(BottomSheetView, { style: [
206
256
  {
207
257
  flex: 1,
258
+ height: "100%",
208
259
  padding: theme.space(4),
209
260
  // The home indicator's strip, on top of whatever padding the caller
210
261
  // asked for. Without it the last row of content is clipped by it —
@@ -214,6 +265,52 @@ function Content({ children, style }) {
214
265
  style,
215
266
  ], children: _jsx(SheetContext.Provider, { value: sheet, children: children }) }) }));
216
267
  }
268
+ /**
269
+ * The sheet's body, for content that might not fit.
270
+ *
271
+ * **In place of `Sheet.Content`, not inside it.** React Native's own
272
+ * `ScrollView` does not scroll inside a sheet at all — the sheet's pan gesture
273
+ * and the scroll view's native recogniser both want the touch, and
274
+ * gesture-handler settles that by reference, so the two have to know about each
275
+ * other. `BottomSheetScrollView` is that introduction, which is the same answer
276
+ * `Drawer.ScrollView` reaches by the same route.
277
+ *
278
+ * Being the sheet's body rather than a child of one is what makes it a single
279
+ * component to reach for. Three callers in the app had assembled this by hand
280
+ * and all three had to get four things right together: `padding: 0` and
281
+ * `height: "100%"` on `Sheet.Content`, so the scrollable has a bounded height
282
+ * to scroll within rather than a box that grows with it; the keyboard inset;
283
+ * and `keyboardShouldPersistTaps`, without which the first tap on a button only
284
+ * dismisses the keyboard. GRYT-492.
285
+ *
286
+ * What it does not decide is the snap point. A sheet that takes a keyboard
287
+ * wants a tall one — at 46% the field and the button underneath it are both
288
+ * behind the keyboard — and how tall depends on what is in it.
289
+ *
290
+ * The padding is the same as `Sheet.Content`'s, moved to the content container
291
+ * where it belongs: on the scrollable itself it would clip the scrolling
292
+ * content instead of spacing it.
293
+ */
294
+ function ScrollView({ children, style, contentContainerStyle, ...props }) {
295
+ const { theme, insets, sheet, modalProps } = useSheetModal();
296
+ return (_jsx(BottomSheetModal, { ...modalProps, children: _jsx(BottomSheetScrollView
297
+ // The keyboard's height as a bottom inset, so what it covers can still
298
+ // be scrolled into what is left of the sheet.
299
+ , {
300
+ // The keyboard's height as a bottom inset, so what it covers can still
301
+ // be scrolled into what is left of the sheet.
302
+ automaticallyAdjustKeyboardInsets: true,
303
+ // Or the first tap on anything only dismisses the keyboard, and the
304
+ // button has to be pressed twice.
305
+ keyboardShouldPersistTaps: "handled", ...props, style: [{ flex: 1 }, style], contentContainerStyle: [
306
+ {
307
+ padding: theme.space(4),
308
+ // The home indicator's strip, as in `Content`.
309
+ paddingBottom: theme.space(4) + insets.bottom,
310
+ },
311
+ contentContainerStyle,
312
+ ], children: _jsx(SheetContext.Provider, { value: sheet, children: children }) }) }));
313
+ }
217
314
  function Close({ children, style }) {
218
315
  const sheet = useSheet("Close");
219
316
  return (_jsx(Pressable, { onPress: sheet.close, style: style, children: children }));
@@ -227,4 +324,10 @@ function Title({ children, style }) {
227
324
  marginBottom: theme.space(2),
228
325
  }, children: children }) }));
229
326
  }
230
- export const Sheet = Object.assign(Root, { Trigger, Content, Close, Title });
327
+ export const Sheet = Object.assign(Root, {
328
+ Trigger,
329
+ Content,
330
+ ScrollView,
331
+ Close,
332
+ Title,
333
+ });
package/dist/index.d.ts CHANGED
@@ -30,7 +30,7 @@ export { Drawer, type DrawerPopupProps, type DrawerRootProps, type DrawerSide, }
30
30
  export { NumberField, type NumberFieldProps } from "./components/NumberField/NumberField.js";
31
31
  export { OtpField, type OtpFieldProps } from "./components/OtpField/OtpField.js";
32
32
  export { ScrollArea, type ScrollAreaProps } from "./components/ScrollArea/ScrollArea.js";
33
- export { Sheet, type SheetCloseProps, type SheetContentProps, type SheetProps, SheetProvider, type SheetProviderProps, type SheetTitleProps, type SheetTriggerProps, } from "./components/Sheet/Sheet.js";
33
+ export { Sheet, type SheetCloseProps, type SheetContentProps, type SheetProps, SheetProvider, type SheetProviderProps, type SheetScrollViewProps, type SheetTitleProps, type SheetTriggerProps, } from "./components/Sheet/Sheet.js";
34
34
  export { ToastProvider, useToast, type ToastOptions, type ToastSeverity, } from "./components/Toast/Toast.js";
35
35
  export { Toolbar, ToolbarSeparator, type ToolbarProps, type ToolbarSeparatorProps, } from "./components/Toolbar/Toolbar.js";
36
36
  export { AnchoredPopup, type AnchoredPopupProps } from "./overlay/AnchoredPopup.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gryt/ui-native",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Gryt's design system on React Native. Same tokens as @gryt/ui, a different renderer.",