@jobber/components-native 0.80.1 → 0.81.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,3 +1,4 @@
1
+ import React from "react";
1
2
  import { AtlantisThemeContextProviderProps, AtlantisThemeContextValue } from "./types";
2
- export declare function AtlantisThemeContextProvider({ children, dangerouslyOverrideTheme, }: AtlantisThemeContextProviderProps): JSX.Element;
3
+ export declare function AtlantisThemeContextProvider({ children, dangerouslyOverrideTheme, }: AtlantisThemeContextProviderProps): React.JSX.Element;
3
4
  export declare function useAtlantisTheme(): AtlantisThemeContextValue;
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import { useSizeStyles } from "./Glimmer.size.style";
2
3
  import { useShapeStyles } from "./Glimmer.shape.style";
3
4
  export type GlimmerShapes = keyof ReturnType<typeof useShapeStyles>;
@@ -26,5 +27,5 @@ interface GlimmerProps {
26
27
  }
27
28
  export declare const GLIMMER_TEST_ID = "ATL-Glimmer";
28
29
  export declare const GLIMMER_SHINE_TEST_ID = "ATL-Glimmer-Shine";
29
- export declare function Glimmer({ width, shape, size, timing, }: GlimmerProps): JSX.Element;
30
+ export declare function Glimmer({ width, shape, size, timing, }: GlimmerProps): React.JSX.Element;
30
31
  export {};
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  interface ProgressBarSteppedProps {
2
3
  readonly total: number;
3
4
  readonly current: number;
@@ -5,5 +6,5 @@ interface ProgressBarSteppedProps {
5
6
  readonly loading?: boolean;
6
7
  readonly inProgress?: number;
7
8
  }
8
- export declare function ProgressBarStepped({ total, current, color, loading, inProgress, }: ProgressBarSteppedProps): JSX.Element;
9
+ export declare function ProgressBarStepped({ total, current, color, loading, inProgress, }: ProgressBarSteppedProps): React.JSX.Element;
9
10
  export {};
package/jestSetup.js CHANGED
@@ -33,5 +33,6 @@ jest.mock("react-native-reanimated", () => {
33
33
  FadeIn: {
34
34
  duration: () => undefined,
35
35
  },
36
+ useEvent: () => ({ listeners: [] }),
36
37
  };
37
38
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.80.1",
3
+ "version": "0.81.0",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -70,7 +70,7 @@
70
70
  "date-fns-tz": "^2.0.0",
71
71
  "react": "^18.2.0",
72
72
  "react-intl": "^6.4.2",
73
- "react-native": ">=0.69.2",
73
+ "react-native": ">=0.76.0",
74
74
  "react-native-gesture-handler": ">=2.10.0",
75
75
  "react-native-keyboard-aware-scroll-view": "^0.9.5",
76
76
  "react-native-modal-datetime-picker": " >=13.0.0",
@@ -80,5 +80,5 @@
80
80
  "react-native-safe-area-context": "^4.5.2",
81
81
  "react-native-svg": ">=12.0.0"
82
82
  },
83
- "gitHead": "04ad3ff367621aa073dcb0bde7ce4aa13197e875"
83
+ "gitHead": "53243a521ce9e1f2a05e29674b2d720dd6ffd49e"
84
84
  }
@@ -35,7 +35,7 @@ it("renders an inactive Chip with a default backgroundColor", () => {
35
35
  backgroundColor: tokens["color-surface--reverse"],
36
36
  });
37
37
  expect(getByTestId("chipTest").props.style).toContainEqual({
38
- backgroundColor: tokens["color-surface--background"],
38
+ backgroundColor: tokens["color-interactive--background"],
39
39
  });
40
40
  });
41
41
 
package/src/Chip/Chip.tsx CHANGED
@@ -82,7 +82,7 @@ export function Chip({
82
82
  backgroundColor:
83
83
  inactiveBackgroundColor === "surface"
84
84
  ? tokens["color-surface"]
85
- : tokens["color-surface--background"],
85
+ : tokens["color-interactive--background"],
86
86
  },
87
87
  isActive && { backgroundColor: accentColor },
88
88
  ];
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { fireEvent, render } from "@testing-library/react-native";
2
+ import { fireEvent, render, screen } from "@testing-library/react-native";
3
3
  import { ReactTestInstance } from "react-test-renderer";
4
4
  import { Disclosure } from ".";
5
5
  import { Text } from "../Text";
@@ -23,49 +23,107 @@ function fireLayoutEvent(disclosureContent: ReactTestInstance) {
23
23
  });
24
24
  }
25
25
 
26
- it("renders a Disclosure with a header and a content when open is true", () => {
27
- const disclosure = render(
28
- <Disclosure
29
- header={<Text>This is the header</Text>}
30
- content={<Text>This is the content</Text>}
31
- open={true}
32
- isEmpty={false}
33
- onToggle={() => {
34
- return;
35
- }}
36
- />,
37
- );
38
- fireLayoutEvent(disclosure.getByTestId("content"));
39
- expect(disclosure).toMatchSnapshot();
40
- });
26
+ describe("Disclosure", () => {
27
+ const defaultProps = {
28
+ header: <Text>This is the header</Text>,
29
+ content: <Text>This is the content</Text>,
30
+ onToggle: jest.fn(),
31
+ };
41
32
 
42
- it("renders a Disclosure with a header and with a content of size 0 when closed is false", () => {
43
- const disclosure = render(
44
- <Disclosure
45
- header={<Text>This is the header</Text>}
46
- content={<Text>This is the content</Text>}
47
- open={false}
48
- isEmpty={false}
49
- onToggle={() => {
50
- return;
51
- }}
52
- />,
53
- );
54
- fireLayoutEvent(disclosure.getByTestId("content"));
55
- expect(disclosure).toMatchSnapshot();
56
- });
33
+ it("renders a Disclosure with a header and a content when open is true", () => {
34
+ render(
35
+ <Disclosure
36
+ header={<Text>This is the header</Text>}
37
+ content={<Text>This is the content</Text>}
38
+ open={true}
39
+ isEmpty={false}
40
+ onToggle={() => {
41
+ return;
42
+ }}
43
+ />,
44
+ );
45
+
46
+ expect(screen.getByText("This is the header")).toBeTruthy();
47
+
48
+ const content = screen.getByTestId("content");
49
+ fireLayoutEvent(content);
50
+
51
+ expect(screen.getByText("This is the content")).toBeTruthy();
52
+ expect(screen.getByTestId("arrowUp")).toBeTruthy();
53
+ });
54
+
55
+ it("renders a Disclosure with a header and with a content of size 0 when open is false", () => {
56
+ render(
57
+ <Disclosure
58
+ header={<Text>This is the header</Text>}
59
+ content={<Text>This is the content</Text>}
60
+ open={false}
61
+ isEmpty={false}
62
+ onToggle={() => {
63
+ return;
64
+ }}
65
+ />,
66
+ );
67
+
68
+ expect(screen.getByText("This is the header")).toBeTruthy();
69
+
70
+ const content = screen.getByTestId("content");
71
+ fireLayoutEvent(content);
72
+
73
+ expect(screen.getByText("This is the content")).toBeTruthy();
74
+ expect(screen.getByTestId("arrowUp")).toBeTruthy();
75
+ });
57
76
 
58
- it("should not render the caret when the Disclosure is empty", () => {
59
- const disclosure = render(
60
- <Disclosure
61
- header={<Text>This is the header</Text>}
62
- content={<Text>This is the content</Text>}
63
- open={false}
64
- isEmpty={true}
65
- onToggle={() => {
66
- return;
67
- }}
68
- />,
69
- );
70
- expect(disclosure).toMatchSnapshot();
77
+ it("should not render the caret when the Disclosure is empty", () => {
78
+ render(
79
+ <Disclosure
80
+ header={<Text>This is the header</Text>}
81
+ content={<Text>This is the content</Text>}
82
+ open={false}
83
+ isEmpty={true}
84
+ onToggle={() => {
85
+ return;
86
+ }}
87
+ />,
88
+ );
89
+
90
+ expect(screen.getByText("This is the header")).toBeTruthy();
91
+ expect(screen.queryByTestId("arrowUp")).toBeNull();
92
+ });
93
+
94
+ it("calls onToggle when header is pressed", () => {
95
+ const onToggleMock = jest.fn();
96
+ const { getByText } = render(
97
+ <Disclosure
98
+ {...defaultProps}
99
+ onToggle={onToggleMock}
100
+ open={false}
101
+ isEmpty={false}
102
+ />,
103
+ );
104
+
105
+ const headerText = getByText("This is the header");
106
+
107
+ fireEvent.press(headerText);
108
+
109
+ expect(onToggleMock).toHaveBeenCalledTimes(1);
110
+ });
111
+
112
+ it("does not call onToggle when header is pressed and isEmpty is true", () => {
113
+ const onToggleMock = jest.fn();
114
+ const { getByText } = render(
115
+ <Disclosure
116
+ {...defaultProps}
117
+ onToggle={onToggleMock}
118
+ open={false}
119
+ isEmpty={true}
120
+ />,
121
+ );
122
+
123
+ const headerText = getByText("This is the header");
124
+
125
+ fireEvent.press(headerText);
126
+
127
+ expect(onToggleMock).not.toHaveBeenCalled();
128
+ });
71
129
  });
@@ -545,7 +545,7 @@ describe("Form", () => {
545
545
  });
546
546
 
547
547
  describe("Safe Area", () => {
548
- it("does render a safe area when there's a saveButtonOffset is provided", () => {
548
+ it("does render a safe area when there's NO saveButtonOffset provided", () => {
549
549
  const { getByTestId } = render(<FormTest onSubmit={onSubmitMock} />);
550
550
 
551
551
  expect(getByTestId("ATL-FormSafeArea")).toBeDefined();
@@ -7,7 +7,7 @@ export const useStyles = buildThemedStyles(tokens => {
7
7
  height: 8,
8
8
  borderRadius: tokens["radius-circle"],
9
9
  overflow: "hidden",
10
- backgroundColor: tokens["color-surface--background"],
10
+ backgroundColor: tokens["color-interactive--background"],
11
11
  },
12
12
  progress: {
13
13
  height: "100%",
@@ -4,8 +4,8 @@ import {
4
4
  fireEvent,
5
5
  render as renderComponent,
6
6
  } from "@testing-library/react-native";
7
+ import { Animated } from "react-native";
7
8
  import { GLIMMER_SHINE_TEST_ID, GLIMMER_TEST_ID, Glimmer } from "./Glimmer";
8
- import { tokens } from "../utils/design";
9
9
 
10
10
  let screen: ReturnType<typeof renderComponent<typeof Glimmer>>;
11
11
 
@@ -48,6 +48,10 @@ describe("Glimmer", () => {
48
48
 
49
49
  it("renders sets the correct width", () => {
50
50
  jest.useFakeTimers();
51
+
52
+ // Spy on Animated.timing to verify the animation configuration
53
+ const timingSpy = jest.spyOn(Animated, "timing");
54
+
51
55
  render(<Glimmer />);
52
56
 
53
57
  act(() => {
@@ -62,12 +66,19 @@ describe("Glimmer", () => {
62
66
  expect.objectContaining({ transform: [{ translateX: -48 }] }),
63
67
  );
64
68
 
65
- jest.advanceTimersByTime(tokens["timing-loading--extended"]);
69
+ expect(timingSpy).toHaveBeenCalled();
66
70
 
67
- expect(element.props.style).toEqual(
68
- expect.objectContaining({ transform: [{ translateX: 348 }] }),
69
- );
71
+ // Get the last call to timing
72
+ const lastCall = timingSpy.mock.calls[timingSpy.mock.calls.length - 1];
73
+
74
+ // The first argument should be the animated value
75
+ // The second argument should be the config
76
+ const config = lastCall[1];
77
+
78
+ // Verify animation targets the right end position (300 + 48 = 348)
79
+ expect(config.toValue).toBe(348);
70
80
 
81
+ timingSpy.mockRestore();
71
82
  jest.useRealTimers();
72
83
  });
73
84
  });
@@ -33,7 +33,9 @@ export function ProgressBar({
33
33
  <ProgressBarStepped
34
34
  total={total}
35
35
  current={current}
36
- color={reverseTheme ? undefined : tokens["color-surface--background"]}
36
+ color={
37
+ reverseTheme ? undefined : tokens["color-interactive--background"]
38
+ }
37
39
  loading={loading}
38
40
  inProgress={inProgress}
39
41
  />
@@ -43,7 +45,7 @@ export function ProgressBar({
43
45
  width={100}
44
46
  animationDuration={0}
45
47
  color={
46
- reverseTheme ? undefined : tokens["color-surface--background"]
48
+ reverseTheme ? undefined : tokens["color-interactive--background"]
47
49
  }
48
50
  />
49
51
  {!loading && (
@@ -34,7 +34,7 @@ exports[`renders blue inProgress bar when 1 or more jobs is in progress 1`] = `
34
34
  "width": "100%",
35
35
  },
36
36
  {
37
- "backgroundColor": "hsl(53, 21%, 93%)",
37
+ "backgroundColor": "hsl(51, 17%, 85%)",
38
38
  "width": "100%",
39
39
  },
40
40
  ]
@@ -116,7 +116,7 @@ exports[`renders green CompletedProgress bar when 1 or more jobs is completed 1`
116
116
  "width": "100%",
117
117
  },
118
118
  {
119
- "backgroundColor": "hsl(53, 21%, 93%)",
119
+ "backgroundColor": "hsl(51, 17%, 85%)",
120
120
  "width": "100%",
121
121
  },
122
122
  ]
@@ -2,61 +2,86 @@ import React from "react";
2
2
  import { fireEvent, render } from "@testing-library/react-native";
3
3
  import { BaseSwitch } from "./BaseSwitch";
4
4
 
5
- it("renders a Switch with value true", () => {
6
- const tree = render(<BaseSwitch value={true} />).toJSON();
7
- expect(tree).toMatchSnapshot();
8
- });
5
+ describe("BaseSwitch", () => {
6
+ describe("rendering", () => {
7
+ it("renders with value true", () => {
8
+ const { getByRole } = render(<BaseSwitch value={true} />);
9
+ const switchElement = getByRole("switch");
10
+ expect(switchElement).toBeDefined();
11
+ expect(switchElement.props.accessibilityState.checked).toBe(true);
12
+ });
9
13
 
10
- it("renders a Switch with defaultValue true", () => {
11
- const tree = render(<BaseSwitch defaultValue={true} />).toJSON();
12
- expect(tree).toMatchSnapshot();
13
- });
14
+ it("renders with defaultValue true", () => {
15
+ const { getByRole } = render(<BaseSwitch defaultValue={true} />);
16
+ const switchElement = getByRole("switch");
17
+ expect(switchElement).toBeDefined();
18
+ expect(switchElement.props.accessibilityState.checked).toBe(true);
19
+ });
14
20
 
15
- it("renders a Switch with value false", () => {
16
- const tree = render(<BaseSwitch value={false} />).toJSON();
17
- expect(tree).toMatchSnapshot();
18
- });
21
+ it("renders with value false", () => {
22
+ const { getByRole } = render(<BaseSwitch value={false} />);
23
+ const switchElement = getByRole("switch");
24
+ expect(switchElement).toBeDefined();
25
+ expect(switchElement.props.accessibilityState.checked).toBe(false);
26
+ });
19
27
 
20
- it("renders a Switch with defaultValue false", () => {
21
- const tree = render(<BaseSwitch defaultValue={false} />).toJSON();
22
- expect(tree).toMatchSnapshot();
23
- });
28
+ it("renders with defaultValue false", () => {
29
+ const { getByRole } = render(<BaseSwitch defaultValue={false} />);
30
+ const switchElement = getByRole("switch");
31
+ expect(switchElement).toBeDefined();
32
+ expect(switchElement.props.accessibilityState.checked).toBe(false);
33
+ });
24
34
 
25
- it("renders a disabled Switch with value true", () => {
26
- const tree = render(<BaseSwitch value={true} disabled={true} />).toJSON();
27
- expect(tree).toMatchSnapshot();
28
- });
35
+ it("renders correctly when disabled with value true", () => {
36
+ const { getByRole } = render(<BaseSwitch value={true} disabled={true} />);
37
+ const switchElement = getByRole("switch");
38
+ expect(switchElement).toBeDefined();
39
+ expect(switchElement.props.accessibilityState.checked).toBe(true);
40
+ expect(switchElement.props.accessibilityState.disabled).toBe(true);
41
+ });
29
42
 
30
- it("renders a disabled Switch with value false", () => {
31
- const tree = render(<BaseSwitch value={false} disabled={true} />).toJSON();
32
- expect(tree).toMatchSnapshot();
33
- });
43
+ it("renders correctly when disabled with value false", () => {
44
+ const { getByRole } = render(
45
+ <BaseSwitch value={false} disabled={true} />,
46
+ );
47
+ const switchElement = getByRole("switch");
48
+ expect(switchElement).toBeDefined();
49
+ expect(switchElement.props.accessibilityState.checked).toBe(false);
50
+ expect(switchElement.props.accessibilityState.disabled).toBe(true);
51
+ });
52
+ });
34
53
 
35
- it("invokes the valueChange callback", () => {
36
- const valueChangedCallback = jest.fn();
37
- const tree = render(
38
- <BaseSwitch
39
- value={false}
40
- onValueChange={valueChangedCallback}
41
- accessibilityLabel={"test switch"}
42
- />,
43
- );
44
- fireEvent(tree.getByLabelText("test switch"), "valueChange", true);
45
- expect(valueChangedCallback).toHaveBeenCalledWith(true);
46
- fireEvent(tree.getByLabelText("test switch"), "valueChange", false);
47
- expect(valueChangedCallback).toHaveBeenCalledWith(false);
48
- });
54
+ describe("behavior", () => {
55
+ it("invokes the valueChange callback", () => {
56
+ const valueChangedCallback = jest.fn();
57
+ const { getByLabelText } = render(
58
+ <BaseSwitch
59
+ value={false}
60
+ onValueChange={valueChangedCallback}
61
+ accessibilityLabel={"test switch"}
62
+ />,
63
+ );
64
+
65
+ fireEvent(getByLabelText("test switch"), "valueChange", true);
66
+ expect(valueChangedCallback).toHaveBeenCalledWith(true);
67
+
68
+ fireEvent(getByLabelText("test switch"), "valueChange", false);
69
+ expect(valueChangedCallback).toHaveBeenCalledWith(false);
70
+ });
71
+
72
+ it("doesn't invoke the valueChange callback if disabled", () => {
73
+ const valueChangedCallback = jest.fn();
74
+ const { getByLabelText } = render(
75
+ <BaseSwitch
76
+ value={false}
77
+ disabled={true}
78
+ onValueChange={valueChangedCallback}
79
+ accessibilityLabel={"test switch"}
80
+ />,
81
+ );
49
82
 
50
- it("doesn't invoke the valueChange callback if disabled", () => {
51
- const valueChangedCallback = jest.fn();
52
- const tree = render(
53
- <BaseSwitch
54
- value={false}
55
- disabled={true}
56
- onValueChange={valueChangedCallback}
57
- accessibilityLabel={"test switch"}
58
- />,
59
- );
60
- fireEvent(tree.getByLabelText("test switch"), "valueChange", true);
61
- expect(valueChangedCallback).not.toHaveBeenCalled();
83
+ fireEvent(getByLabelText("test switch"), "valueChange", true);
84
+ expect(valueChangedCallback).not.toHaveBeenCalled();
85
+ });
86
+ });
62
87
  });
@@ -60,7 +60,7 @@ export function BaseSwitch({
60
60
  } else if (internalValue) {
61
61
  return tokens["color-interactive"];
62
62
  } else {
63
- return tokens["color-surface--background"];
63
+ return tokens["color-interactive--background"];
64
64
  }
65
65
  }
66
66
 
@@ -81,7 +81,7 @@ export function BaseSwitch({
81
81
  //iOS
82
82
  return {
83
83
  true: tokens["color-interactive"],
84
- false: tokens["color-surface--background"],
84
+ false: tokens["color-interactive--background"],
85
85
  };
86
86
  }
87
87
  }
@@ -98,7 +98,7 @@ export function BaseSwitch({
98
98
  disabled={disabled}
99
99
  thumbColor={getThumbColor()}
100
100
  trackColor={getTrackColors()}
101
- ios_backgroundColor={tokens["color-surface--background"]}
101
+ ios_backgroundColor={tokens["color-interactive--background"]}
102
102
  accessibilityLabel={accessibilityLabel}
103
103
  accessibilityRole={"switch"}
104
104
  accessibilityState={{