@jobber/components-native 0.107.2 → 0.108.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,4 +1,4 @@
1
1
  import React from "react";
2
2
  import type { ContentOverlayProps } from "./types";
3
3
  export declare function useIsKeyboardHandledByScrollView(): boolean;
4
- export declare function ContentOverlay({ children, title, accessibilityLabel, fullScreen, showDismiss, isDraggable, adjustToContentHeight, keyboardShouldPersistTaps, scrollEnabled, modalBackgroundColor, onClose, onOpen, onBeforeExit, loading, ref, }: ContentOverlayProps): React.JSX.Element;
4
+ export declare function ContentOverlay({ children, title, accessibilityLabel, fullScreen, showDismiss, isDraggable, adjustToContentHeight, keyboardShouldPersistTaps, scrollEnabled, modalBackgroundColor, onClose, onOpen, onBeforeExit, allowDragWithBeforeExit, enablePanDownToClose, enableContentPanningGesture, snapPoints: customSnapPoints, loading, ref, }: ContentOverlayProps): React.JSX.Element;
@@ -3,6 +3,7 @@ export interface ContentOverlayConfig {
3
3
  adjustToContentHeight: boolean;
4
4
  isDraggable: boolean;
5
5
  hasOnBeforeExit: boolean;
6
+ allowDragWithBeforeExit: boolean;
6
7
  showDismiss: boolean;
7
8
  }
8
9
  export interface ContentOverlayState {
@@ -63,6 +63,29 @@ export interface ContentOverlayProps {
63
63
  * Callback that is called between overlay is closed and when the "x" button is pressed
64
64
  */
65
65
  readonly onBeforeExit?: () => void;
66
+ /**
67
+ * Whether panning down on the content area closes the sheet. Set false to prevent the sheet from being closed by panning down.
68
+ * Defaults to the resolved draggable state.
69
+ */
70
+ readonly enablePanDownToClose?: boolean;
71
+ /**
72
+ * When `true`, `onBeforeExit` intercepts the dismiss button and back press
73
+ * but does not disable drag. Drag-to-dismiss bypasses `onBeforeExit`.
74
+ * @default false
75
+ */
76
+ readonly allowDragWithBeforeExit?: boolean;
77
+ /**
78
+ * Whether pan on the content area drags the sheet. Set `false` to let
79
+ * nested scrollables own the gesture. Defaults to the resolved draggable
80
+ * state.
81
+ */
82
+ readonly enableContentPanningGesture?: boolean;
83
+ /**
84
+ * Explicit snap points for the overlay (percentages or pixel values).
85
+ * When provided, `adjustToContentHeight` is ignored and the sheet snaps
86
+ * to these positions instead of the measured content height.
87
+ */
88
+ readonly snapPoints?: (string | number)[];
66
89
  /**
67
90
  * Boolean to show a disabled state
68
91
  * @default false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.107.2",
3
+ "version": "0.108.0",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -73,7 +73,7 @@
73
73
  "devDependencies": {
74
74
  "@babel/runtime": "^7.29.2",
75
75
  "@gorhom/bottom-sheet": "^5.2.8",
76
- "@jobber/design": "0.106.1",
76
+ "@jobber/design": "0.107.0",
77
77
  "@jobber/hooks": "2.21.0",
78
78
  "@react-native-community/datetimepicker": "^8.4.5",
79
79
  "@react-native/babel-preset": "^0.82.1",
@@ -124,5 +124,5 @@
124
124
  "react-native-screens": ">=4.18.0",
125
125
  "react-native-svg": ">=12.0.0"
126
126
  },
127
- "gitHead": "3f6678b1792101e43e544ec51cfa17d883362460"
127
+ "gitHead": "d5470a957047c13206da81b769b223f08e670d92"
128
128
  }
@@ -81,6 +81,10 @@ export function ContentOverlay({
81
81
  onClose,
82
82
  onOpen,
83
83
  onBeforeExit,
84
+ allowDragWithBeforeExit = false,
85
+ enablePanDownToClose,
86
+ enableContentPanningGesture,
87
+ snapPoints: customSnapPoints,
84
88
  loading = false,
85
89
  ref,
86
90
  }: ContentOverlayProps) {
@@ -101,6 +105,7 @@ export function ContentOverlay({
101
105
  adjustToContentHeight,
102
106
  isDraggable,
103
107
  hasOnBeforeExit: onBeforeExit !== undefined,
108
+ allowDragWithBeforeExit,
104
109
  showDismiss,
105
110
  },
106
111
  {
@@ -124,12 +129,16 @@ export function ContentOverlay({
124
129
 
125
130
  // enableDynamicSizing will add another snap point of the content height
126
131
  const snapPoints = useMemo(() => {
132
+ if (customSnapPoints && customSnapPoints.length > 0) {
133
+ return customSnapPoints;
134
+ }
135
+
127
136
  // There is a bug with "restore" behavior after keyboard is dismissed.
128
137
  // https://github.com/gorhom/react-native-bottom-sheet/issues/2465
129
138
  // providing a 100% snap point "fixes" it for now, but there is an approved PR to fix it
130
139
  // that just needs to be merged and released: https://github.com/gorhom/react-native-bottom-sheet/pull/2511
131
140
  return ["100%"];
132
- }, []);
141
+ }, [customSnapPoints]);
133
142
 
134
143
  const onCloseController = () => {
135
144
  if (!onBeforeExit) {
@@ -296,10 +305,14 @@ export function ContentOverlay({
296
305
  handleIndicatorStyle={handleIndicatorStyles}
297
306
  backdropComponent={backdropComponent}
298
307
  snapPoints={snapPoints}
299
- enablePanDownToClose={effectiveIsDraggable}
300
- enableContentPanningGesture={effectiveIsDraggable}
308
+ enablePanDownToClose={enablePanDownToClose ?? effectiveIsDraggable}
309
+ enableContentPanningGesture={
310
+ enableContentPanningGesture ?? effectiveIsDraggable
311
+ }
301
312
  enableHandlePanningGesture={effectiveIsDraggable}
302
- enableDynamicSizing={behavior.initialHeight === "contentHeight"}
313
+ enableDynamicSizing={
314
+ !customSnapPoints && behavior.initialHeight === "contentHeight"
315
+ }
303
316
  keyboardBehavior="interactive"
304
317
  keyboardBlurBehavior="restore"
305
318
  topInset={topInset}
@@ -11,6 +11,7 @@ const defaultConfig: ContentOverlayConfig = {
11
11
  adjustToContentHeight: false,
12
12
  isDraggable: true,
13
13
  hasOnBeforeExit: false,
14
+ allowDragWithBeforeExit: false,
14
15
  showDismiss: false,
15
16
  };
16
17
 
@@ -112,6 +113,45 @@ describe("computeContentOverlayBehavior", () => {
112
113
 
113
114
  expect(result.isDraggable).toBe(false);
114
115
  });
116
+
117
+ it("respects isDraggable=true when onBeforeExit is present and allowDragWithBeforeExit=true", () => {
118
+ const config = aConfig({
119
+ isDraggable: true,
120
+ hasOnBeforeExit: true,
121
+ allowDragWithBeforeExit: true,
122
+ });
123
+ const state = aState();
124
+
125
+ const result = computeContentOverlayBehavior(config, state);
126
+
127
+ expect(result.isDraggable).toBe(true);
128
+ });
129
+
130
+ it("respects isDraggable=false when onBeforeExit is present and allowDragWithBeforeExit=true", () => {
131
+ const config = aConfig({
132
+ isDraggable: false,
133
+ hasOnBeforeExit: true,
134
+ allowDragWithBeforeExit: true,
135
+ });
136
+ const state = aState();
137
+
138
+ const result = computeContentOverlayBehavior(config, state);
139
+
140
+ expect(result.isDraggable).toBe(false);
141
+ });
142
+
143
+ it("still overrides to false when onBeforeExit is present and allowDragWithBeforeExit=false (default)", () => {
144
+ const config = aConfig({
145
+ isDraggable: true,
146
+ hasOnBeforeExit: true,
147
+ allowDragWithBeforeExit: false,
148
+ });
149
+ const state = aState();
150
+
151
+ const result = computeContentOverlayBehavior(config, state);
152
+
153
+ expect(result.isDraggable).toBe(false);
154
+ });
115
155
  });
116
156
 
117
157
  describe("showDismiss", () => {
@@ -3,6 +3,7 @@ export interface ContentOverlayConfig {
3
3
  adjustToContentHeight: boolean;
4
4
  isDraggable: boolean;
5
5
  hasOnBeforeExit: boolean;
6
+ allowDragWithBeforeExit: boolean;
6
7
  showDismiss: boolean;
7
8
  }
8
9
 
@@ -76,14 +77,17 @@ function computeInitialHeight(
76
77
 
77
78
  /**
78
79
  * Draggability determination:
79
- * - hasOnBeforeExit: true → false (silent override, regardless of isDraggable prop)
80
+ * - hasOnBeforeExit: true && !allowDragWithBeforeExit → false (legacy override)
81
+ * - hasOnBeforeExit: true && allowDragWithBeforeExit → use isDraggable prop value
80
82
  * - Otherwise → use isDraggable prop value
81
83
  *
82
- * This silent override exists because onBeforeExit needs to intercept close attempts,
83
- * and dragging would bypass that interception.
84
+ * The legacy override exists because onBeforeExit needs to intercept close
85
+ * attempts, and dragging would bypass that interception. Consumers that
86
+ * explicitly accept the asymmetry (e.g. button-press confirmation,
87
+ * drag-dismiss silent) can opt out via `allowDragWithBeforeExit`.
84
88
  */
85
89
  function computeIsDraggable(config: ContentOverlayConfig): boolean {
86
- if (config.hasOnBeforeExit) {
90
+ if (config.hasOnBeforeExit && !config.allowDragWithBeforeExit) {
87
91
  return false;
88
92
  }
89
93
 
@@ -66,6 +66,34 @@ export interface ContentOverlayProps {
66
66
  */
67
67
  readonly onBeforeExit?: () => void;
68
68
 
69
+ /**
70
+ * Whether panning down on the content area closes the sheet. Set false to prevent the sheet from being closed by panning down.
71
+ * Defaults to the resolved draggable state.
72
+ */
73
+
74
+ readonly enablePanDownToClose?: boolean;
75
+
76
+ /**
77
+ * When `true`, `onBeforeExit` intercepts the dismiss button and back press
78
+ * but does not disable drag. Drag-to-dismiss bypasses `onBeforeExit`.
79
+ * @default false
80
+ */
81
+ readonly allowDragWithBeforeExit?: boolean;
82
+
83
+ /**
84
+ * Whether pan on the content area drags the sheet. Set `false` to let
85
+ * nested scrollables own the gesture. Defaults to the resolved draggable
86
+ * state.
87
+ */
88
+ readonly enableContentPanningGesture?: boolean;
89
+
90
+ /**
91
+ * Explicit snap points for the overlay (percentages or pixel values).
92
+ * When provided, `adjustToContentHeight` is ignored and the sheet snaps
93
+ * to these positions instead of the measured content height.
94
+ */
95
+ readonly snapPoints?: (string | number)[];
96
+
69
97
  /**
70
98
  * Boolean to show a disabled state
71
99
  * @default false