@jobber/components-native 0.88.1-JOB-139048-04134dd.0 → 0.88.1-JOB-136074-020f532.3

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,5 +1,5 @@
1
1
  import React from "react";
2
- import type { Modalize } from "react-native-modalize";
2
+ import { Modalize } from "react-native-modalize";
3
3
  import type { ContentOverlayProps } from "./types";
4
4
  export declare const ContentOverlay: React.ForwardRefExoticComponent<ContentOverlayProps & React.RefAttributes<{
5
5
  open?: Modalize["open"];
@@ -1,3 +1,2 @@
1
1
  export { ContentOverlay } from "./ContentOverlay";
2
- export { UNSAFE_WrappedModalize } from "./UNSAFE_WrappedModalize";
3
2
  export type { ContentOverlayRef, ModalBackgroundColor } from "./types";
@@ -5,6 +5,7 @@ export declare const atlantisFormContextDefaultValues: {
5
5
  setLocalCache: () => undefined;
6
6
  removeLocalCache: () => undefined;
7
7
  };
8
+ edgeToEdgeEnabled: boolean;
8
9
  };
9
10
  export declare const AtlantisFormContext: import("react").Context<AtlantisFormContextProps>;
10
11
  export declare function useAtlantisFormContext(): AtlantisFormContextProps;
@@ -21,5 +21,6 @@ export interface AtlantisFormContextProps {
21
21
  setLocalCache: (data: DeepPartial<TData>) => void;
22
22
  removeLocalCache: () => void;
23
23
  };
24
+ edgeToEdgeEnabled?: boolean;
24
25
  }
25
26
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.88.1-JOB-139048-04134dd.0+04134dd81",
3
+ "version": "0.88.1-JOB-136074-020f532.3+020f532a0",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -94,5 +94,5 @@
94
94
  "react-native-safe-area-context": "^5.4.0",
95
95
  "react-native-svg": ">=12.0.0"
96
96
  },
97
- "gitHead": "04134dd81a80801cb9749c94d92f80b0e1d7c7dc"
97
+ "gitHead": "020f532a06bc1651b24f6c7743a11dbd4e72553b"
98
98
  }
@@ -4,7 +4,7 @@ import { AccessibilityInfo, View } from "react-native";
4
4
  import { Host } from "react-native-portalize";
5
5
  import type { ReactTestInstance } from "react-test-renderer";
6
6
  import { act } from "react-test-renderer";
7
- import type { ContentOverlayRef, ModalBackgroundColor } from "./types";
7
+ import type { ContentOverlayRef, ModalBackgroundColor } from "./ContentOverlay";
8
8
  import { ContentOverlay } from "./ContentOverlay";
9
9
  import { tokens } from "../utils/design";
10
10
  import { Button } from "../Button";
@@ -106,30 +106,23 @@ function renderContentOverlay(
106
106
  return renderResult;
107
107
  }
108
108
 
109
- async function renderAndOpenContentOverlay(
110
- defaultOptions = getDefaultOptions(),
111
- ) {
109
+ function renderAndOpenContentOverlay(defaultOptions = getDefaultOptions()) {
112
110
  const rendered = renderContentOverlay(defaultOptions);
113
111
 
114
112
  act(() => {
115
113
  fireEvent.press(rendered.getByLabelText(defaultOptions.buttonLabel));
116
114
  });
117
115
 
118
- // Wait for the modal to open asynchronously (due to requestAnimationFrame)
119
- await waitFor(() => {
120
- expect(rendered.getByTestId("ATL-Overlay-Header")).toBeDefined();
121
- });
122
-
123
116
  return rendered;
124
117
  }
125
118
 
126
119
  describe("when open is called on the content overlay ref", () => {
127
- it("should open the content overlay, exposing the content to the user", async () => {
120
+ it("should open the content overlay, exposing the content to the user", () => {
128
121
  const options: testRendererOptions = {
129
122
  ...getDefaultOptions(),
130
123
  text: "I am text within the content overlay",
131
124
  };
132
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
125
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
133
126
 
134
127
  expect(contentOverlayScreen.getByText(options.text)).toBeDefined();
135
128
  });
@@ -142,7 +135,7 @@ describe("when the close button is clicked on an open content overlay", () => {
142
135
  text: "I am text within the content overlay",
143
136
  showDismiss: true,
144
137
  };
145
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
138
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
146
139
 
147
140
  act(() => {
148
141
  fireEvent.press(
@@ -163,7 +156,7 @@ describe("when the close button is clicked on an open content overlay with a def
163
156
  onCloseCallback: jest.fn(),
164
157
  showDismiss: true,
165
158
  };
166
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
159
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
167
160
 
168
161
  act(() => {
169
162
  fireEvent.press(
@@ -198,7 +191,7 @@ describe("when the content overlay is created with a defined onOpen prop", () =>
198
191
  ...getDefaultOptions(),
199
192
  onOpenCallback: jest.fn(),
200
193
  };
201
- await renderAndOpenContentOverlay(options);
194
+ renderAndOpenContentOverlay(options);
202
195
 
203
196
  await waitFor(() => {
204
197
  expect(options.onOpenCallback).toHaveBeenCalled();
@@ -208,25 +201,25 @@ describe("when the content overlay is created with a defined onOpen prop", () =>
208
201
  });
209
202
 
210
203
  describe("when title prop passed to content overlay", () => {
211
- it("should set the header title", async () => {
204
+ it("should set the header title", () => {
212
205
  const options: testRendererOptions = {
213
206
  ...getDefaultOptions(),
214
207
  title: "Awesome Title",
215
208
  };
216
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
209
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
217
210
 
218
211
  expect(contentOverlayScreen.getByText(options.title)).toBeDefined();
219
212
  });
220
213
  });
221
214
 
222
215
  describe("when accessibilityLabel prop passed to content overlay", () => {
223
- it("should set the header accessibilityLabel", async () => {
216
+ it("should set the header accessibilityLabel", () => {
224
217
  const options: testRendererOptions = {
225
218
  ...getDefaultOptions(),
226
219
  a11yLabel: "Awesome a11y Label",
227
220
  showDismiss: true,
228
221
  };
229
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
222
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
230
223
 
231
224
  expect(
232
225
  contentOverlayScreen.getByLabelText(options.a11yLabel || "ohno"),
@@ -235,13 +228,13 @@ describe("when accessibilityLabel prop passed to content overlay", () => {
235
228
  });
236
229
 
237
230
  describe("when accessibilityLabel prop NOT passed to content overlay", () => {
238
- it("should use default accessibilityLabel", async () => {
231
+ it("should use default accessibilityLabel", () => {
239
232
  const options: testRendererOptions = {
240
233
  ...getDefaultOptions(),
241
234
  title: "Awesome Title",
242
235
  showDismiss: true,
243
236
  };
244
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
237
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
245
238
 
246
239
  expect(
247
240
  contentOverlayScreen.getAllByLabelText(`Close ${options.title} modal`),
@@ -258,7 +251,7 @@ describe("when there is a screen reader enabled", () => {
258
251
  const options: testRendererOptions = {
259
252
  ...getDefaultOptions(),
260
253
  };
261
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
254
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
262
255
 
263
256
  expect(
264
257
  await contentOverlayScreen.findByTestId("ATL-Overlay-CloseButton"),
@@ -267,12 +260,12 @@ describe("when there is a screen reader enabled", () => {
267
260
  });
268
261
 
269
262
  describe("when fullScreen is set to true", () => {
270
- it("should show the dismiss button", async () => {
263
+ it("should show the dismiss button", () => {
271
264
  const options: testRendererOptions = {
272
265
  ...getDefaultOptions(),
273
266
  fullScreen: true,
274
267
  };
275
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
268
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
276
269
  expect(
277
270
  contentOverlayScreen.getByTestId("ATL-Overlay-CloseButton"),
278
271
  ).toBeDefined();
@@ -280,12 +273,12 @@ describe("when fullScreen is set to true", () => {
280
273
  });
281
274
 
282
275
  describe("when showDismiss is set to true", () => {
283
- it("should show the dismiss button", async () => {
276
+ it("should show the dismiss button", () => {
284
277
  const options: testRendererOptions = {
285
278
  ...getDefaultOptions(),
286
279
  showDismiss: true,
287
280
  };
288
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
281
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
289
282
  expect(
290
283
  contentOverlayScreen.getByTestId("ATL-Overlay-CloseButton"),
291
284
  ).toBeDefined();
@@ -299,7 +292,7 @@ describe("when the close button is clicked on an open content overlay with a def
299
292
  onBeforeExitCallback: jest.fn(),
300
293
  showDismiss: true,
301
294
  };
302
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
295
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
303
296
 
304
297
  act(() => {
305
298
  fireEvent.press(
@@ -315,11 +308,11 @@ describe("when the close button is clicked on an open content overlay with a def
315
308
 
316
309
  describe("modalBackgroundColor prop", () => {
317
310
  describe("when using the default surface value", () => {
318
- it("renders the component with the color-surface color", async () => {
311
+ it("renders the component with the color-surface color", () => {
319
312
  const options: testRendererOptions = {
320
313
  ...getDefaultOptions(),
321
314
  };
322
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
315
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
323
316
  const OverlayHeader = contentOverlayScreen.getByTestId(
324
317
  "ATL-Overlay-Header",
325
318
  ).children[0] as ReactTestInstance;
@@ -344,12 +337,12 @@ describe("modalBackgroundColor prop", () => {
344
337
  });
345
338
 
346
339
  describe("when set to background", () => {
347
- it("changes the backround color of the modal to color-surface--background", async () => {
340
+ it("changes the backround color of the modal to color-surface--background", () => {
348
341
  const options: testRendererOptions = {
349
342
  ...getDefaultOptions(),
350
343
  modalBackgroundColor: "background",
351
344
  };
352
- const contentOverlayScreen = await renderAndOpenContentOverlay(options);
345
+ const contentOverlayScreen = renderAndOpenContentOverlay(options);
353
346
  const OverlayHeader = contentOverlayScreen.getByTestId(
354
347
  "ATL-Overlay-Header",
355
348
  ).children[0] as ReactTestInstance;
@@ -7,7 +7,7 @@ import React, {
7
7
  useRef,
8
8
  useState,
9
9
  } from "react";
10
- import type { Modalize } from "react-native-modalize";
10
+ import { Modalize } from "react-native-modalize";
11
11
  import { useSafeAreaInsets } from "react-native-safe-area-context";
12
12
  import type { NativeScrollEvent, NativeSyntheticEvent } from "react-native";
13
13
  import {
@@ -26,7 +26,6 @@ import type {
26
26
  ContentOverlayRef,
27
27
  ModalBackgroundColor,
28
28
  } from "./types";
29
- import { UNSAFE_WrappedModalize } from "./UNSAFE_WrappedModalize";
30
29
  import { useIsScreenReaderEnabled } from "../hooks";
31
30
  import { IconButton } from "../IconButton";
32
31
  import { Heading } from "../Heading";
@@ -154,7 +153,7 @@ function ContentOverlayInternal(
154
153
  return (
155
154
  <>
156
155
  {headerHeightKnown && childrenHeightKnown && (
157
- <UNSAFE_WrappedModalize
156
+ <Modalize
158
157
  ref={callbackInternalRef}
159
158
  overlayStyle={styles.overlay}
160
159
  handleStyle={styles.handle}
@@ -197,7 +196,7 @@ function ContentOverlayInternal(
197
196
  >
198
197
  {Platform.OS === "android" ? renderedHeader : undefined}
199
198
  {renderedChildren}
200
- </UNSAFE_WrappedModalize>
199
+ </Modalize>
201
200
  )}
202
201
  {!childrenHeightKnown && (
203
202
  <View style={[styles.hiddenContent, modalStyle]}>
@@ -1,3 +1,2 @@
1
1
  export { ContentOverlay } from "./ContentOverlay";
2
- export { UNSAFE_WrappedModalize } from "./UNSAFE_WrappedModalize";
3
2
  export type { ContentOverlayRef, ModalBackgroundColor } from "./types";
package/src/Form/Form.tsx CHANGED
@@ -26,6 +26,7 @@ import { useScrollToError } from "./hooks/useScrollToError";
26
26
  import { FormSaveButton } from "./components/FormSaveButton";
27
27
  import { useSaveButtonPosition } from "./hooks/useSaveButtonPosition";
28
28
  import { FormCache } from "./components/FormCache/FormCache";
29
+ import { useAtlantisFormContext } from "./context/AtlantisFormContext";
29
30
  import { InputAccessoriesProvider } from "../InputText";
30
31
  import { tokens } from "../utils/design";
31
32
  import { ErrorMessageProvider } from "../ErrorMessageWrapper";
@@ -134,6 +135,8 @@ function InternalForm<T extends FieldValues, S>({
134
135
 
135
136
  const styles = useStyles();
136
137
 
138
+ const { edgeToEdgeEnabled } = useAtlantisFormContext();
139
+
137
140
  return (
138
141
  <FormProvider {...formMethods}>
139
142
  <>
@@ -161,6 +164,7 @@ function InternalForm<T extends FieldValues, S>({
161
164
  <KeyboardAwareScrollView
162
165
  enableResetScrollToCoords={false}
163
166
  enableAutomaticScroll={true}
167
+ enableOnAndroid={edgeToEdgeEnabled}
164
168
  keyboardOpeningTime={
165
169
  Platform.OS === "ios" ? tokens["timing-slowest"] : 0
166
170
  }
@@ -168,6 +172,7 @@ function InternalForm<T extends FieldValues, S>({
168
172
  ref={scrollViewRef}
169
173
  {...keyboardProps}
170
174
  extraHeight={headerHeight}
175
+ extraScrollHeight={edgeToEdgeEnabled ? tokens["space-large"] : 0}
171
176
  contentContainerStyle={
172
177
  !keyboardHeight && styles.scrollContentContainer
173
178
  }
@@ -11,6 +11,7 @@ export const atlantisFormContextDefaultValues = {
11
11
  setLocalCache: () => undefined,
12
12
  removeLocalCache: () => undefined,
13
13
  }),
14
+ edgeToEdgeEnabled: false,
14
15
  };
15
16
 
16
17
  export const AtlantisFormContext = createContext<AtlantisFormContextProps>(
@@ -30,4 +30,5 @@ export interface AtlantisFormContextProps {
30
30
  setLocalCache: (data: DeepPartial<TData>) => void;
31
31
  removeLocalCache: () => void;
32
32
  };
33
+ edgeToEdgeEnabled?: boolean;
33
34
  }
@@ -64,7 +64,6 @@
64
64
  "ThumbnailList",
65
65
  "Toast",
66
66
  "Typography",
67
- "TypographyGestureDetector",
68
- "UNSAFE_WrappedModalize"
67
+ "TypographyGestureDetector"
69
68
  ]
70
69
  }
@@ -1,27 +0,0 @@
1
- import React, { forwardRef, useImperativeHandle, useRef, useState, } from "react";
2
- import { Modalize } from "react-native-modalize";
3
- // DON'T USE THIS COMPONENT DIRECTLY.
4
- // It is exposed only so that the deprecated ContentOverlay component can use this along with the
5
- // newer one contained in this lib.
6
- // This is a temporary solution for new architecture. JOB-137549 plans to replace modalize entirely.
7
- export const UNSAFE_WrappedModalize = forwardRef((props, ref) => {
8
- const innerRef = useRef(null);
9
- const [openRenderId, setOpenRenderId] = useState(0);
10
- useImperativeHandle(ref, () => ({
11
- open(dest) {
12
- setOpenRenderId(id => id + 1);
13
- // Open on a fresh tick for additional safety
14
- requestAnimationFrame(() => {
15
- var _a;
16
- (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.open(dest);
17
- });
18
- },
19
- close(dest) {
20
- var _a;
21
- (_a = innerRef.current) === null || _a === void 0 ? void 0 : _a.close(dest);
22
- },
23
- }), []);
24
- // Use a unique key to force a remount, ensuring we get fresh gesture handler nodes within modalize
25
- return (React.createElement(Modalize, Object.assign({ key: `modalize-${openRenderId}`, ref: innerRef }, props)));
26
- });
27
- UNSAFE_WrappedModalize.displayName = "UNSAFE_WrappedModalize";
@@ -1,3 +0,0 @@
1
- import React from "react";
2
- import type { IHandles } from "react-native-modalize/lib/options";
3
- export declare const UNSAFE_WrappedModalize: React.ForwardRefExoticComponent<Omit<import("react-native-modalize/lib/options").IProps<any> & React.RefAttributes<string | number | boolean | {} | React.ReactPortal | React.ReactElement<any, string | ((props: any) => React.ReactElement<any, any> | null) | (new (props: any) => React.Component<any, any, any>)> | React.ReactNodeArray | undefined>, "ref"> & React.RefAttributes<IHandles>>;
@@ -1,45 +0,0 @@
1
- import React, {
2
- forwardRef,
3
- useImperativeHandle,
4
- useRef,
5
- useState,
6
- } from "react";
7
- import { Modalize } from "react-native-modalize";
8
- import type { IHandles } from "react-native-modalize/lib/options";
9
-
10
- type Props = React.ComponentProps<typeof Modalize>;
11
-
12
- // DON'T USE THIS COMPONENT DIRECTLY.
13
- // It is exposed only so that the deprecated ContentOverlay component can use this along with the
14
- // newer one contained in this lib.
15
- // This is a temporary solution for new architecture. JOB-137549 plans to replace modalize entirely.
16
- export const UNSAFE_WrappedModalize = forwardRef<IHandles, Props>(
17
- (props, ref) => {
18
- const innerRef = useRef<IHandles | null>(null);
19
- const [openRenderId, setOpenRenderId] = useState(0);
20
-
21
- useImperativeHandle(
22
- ref,
23
- () => ({
24
- open(dest) {
25
- setOpenRenderId(id => id + 1);
26
- // Open on a fresh tick for additional safety
27
- requestAnimationFrame(() => {
28
- innerRef.current?.open(dest);
29
- });
30
- },
31
- close(dest) {
32
- innerRef.current?.close(dest);
33
- },
34
- }),
35
- [],
36
- );
37
-
38
- // Use a unique key to force a remount, ensuring we get fresh gesture handler nodes within modalize
39
- return (
40
- <Modalize key={`modalize-${openRenderId}`} ref={innerRef} {...props} />
41
- );
42
- },
43
- );
44
-
45
- UNSAFE_WrappedModalize.displayName = "UNSAFE_WrappedModalize";