@jobber/components-native 0.113.3 → 0.113.4-implement--94d34f8.2

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.
@@ -11,22 +11,36 @@ import React from "react";
11
11
  import { act, renderHook } from "@testing-library/react-native";
12
12
  import { darkTokens, iosTokens } from "@jobber/design";
13
13
  import merge from "lodash/merge";
14
+ import { useColorScheme } from "react-native";
14
15
  import { AtlantisThemeContextProvider, useAtlantisTheme, } from "./AtlantisThemeContext";
16
+ jest.mock("react-native", () => {
17
+ const actual = jest.requireActual("react-native");
18
+ Object.defineProperty(actual, "useColorScheme", {
19
+ configurable: true,
20
+ value: jest.fn(),
21
+ });
22
+ return actual;
23
+ });
15
24
  const expectedDarkTokens = merge({}, iosTokens, darkTokens);
16
25
  const expectedLightTokens = iosTokens;
17
- function Wrapper({ children, dangerouslyOverrideTheme, }) {
18
- return (React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: dangerouslyOverrideTheme }, children));
26
+ const mockUseColorScheme = useColorScheme;
27
+ function Wrapper({ children, theme, onThemeChange, dangerouslyOverrideTheme, }) {
28
+ return (React.createElement(AtlantisThemeContextProvider, { theme: theme, onThemeChange: onThemeChange, dangerouslyOverrideTheme: dangerouslyOverrideTheme }, children));
19
29
  }
20
30
  function WrapperWithOverride({ children, dangerouslyOverrideTheme, }) {
21
31
  return (React.createElement(Wrapper, null,
22
32
  React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: dangerouslyOverrideTheme }, children)));
23
33
  }
24
34
  describe("ThemeContext", () => {
35
+ beforeEach(() => {
36
+ mockUseColorScheme.mockReturnValue("light");
37
+ });
25
38
  it("defaults to the light theme", () => {
26
39
  const { result } = renderHook(useAtlantisTheme, {
27
40
  wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props))),
28
41
  });
29
42
  expect(result.current.theme).toBe("light");
43
+ expect(result.current.effectiveTheme).toBe("light");
30
44
  expect(result.current.tokens).toEqual(expectedLightTokens);
31
45
  });
32
46
  it("updates the theme and tokens", () => __awaiter(void 0, void 0, void 0, function* () {
@@ -35,9 +49,56 @@ describe("ThemeContext", () => {
35
49
  });
36
50
  yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("dark"); }));
37
51
  expect(result.current.theme).toBe("dark");
52
+ expect(result.current.effectiveTheme).toBe("dark");
38
53
  expect(result.current.tokens).toEqual(expectedDarkTokens);
39
54
  yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("light"); }));
40
55
  expect(result.current.theme).toBe("light");
56
+ expect(result.current.effectiveTheme).toBe("light");
57
+ expect(result.current.tokens).toEqual(expectedLightTokens);
58
+ }));
59
+ it("resolves the system theme from the OS color scheme", () => __awaiter(void 0, void 0, void 0, function* () {
60
+ mockUseColorScheme.mockReturnValue("dark");
61
+ const { result, rerender } = renderHook(useAtlantisTheme, {
62
+ wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props))),
63
+ });
64
+ yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("system"); }));
65
+ expect(result.current.theme).toBe("system");
66
+ expect(result.current.effectiveTheme).toBe("dark");
67
+ expect(result.current.tokens).toEqual(expectedDarkTokens);
68
+ mockUseColorScheme.mockReturnValue("light");
69
+ rerender({});
70
+ expect(result.current.theme).toBe("system");
71
+ expect(result.current.effectiveTheme).toBe("light");
72
+ expect(result.current.tokens).toEqual(expectedLightTokens);
73
+ }));
74
+ it("uses a controlled selected theme", () => {
75
+ mockUseColorScheme.mockReturnValue("dark");
76
+ const { result } = renderHook(useAtlantisTheme, {
77
+ wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props, { theme: "system" }))),
78
+ });
79
+ expect(result.current.theme).toBe("system");
80
+ expect(result.current.effectiveTheme).toBe("dark");
81
+ expect(result.current.tokens).toEqual(expectedDarkTokens);
82
+ });
83
+ it("reports selected theme changes from a controlled provider", () => __awaiter(void 0, void 0, void 0, function* () {
84
+ const onThemeChange = jest.fn();
85
+ const { result } = renderHook(useAtlantisTheme, {
86
+ wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props, { theme: "light", onThemeChange: onThemeChange }))),
87
+ });
88
+ yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("system"); }));
89
+ expect(onThemeChange).toHaveBeenCalledWith("system");
90
+ expect(result.current.theme).toBe("light");
91
+ expect(result.current.effectiveTheme).toBe("light");
92
+ expect(result.current.tokens).toEqual(expectedLightTokens);
93
+ }));
94
+ it("falls back to light when system color scheme is unavailable", () => __awaiter(void 0, void 0, void 0, function* () {
95
+ mockUseColorScheme.mockReturnValue(null);
96
+ const { result } = renderHook(useAtlantisTheme, {
97
+ wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props))),
98
+ });
99
+ yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("system"); }));
100
+ expect(result.current.theme).toBe("system");
101
+ expect(result.current.effectiveTheme).toBe("light");
41
102
  expect(result.current.tokens).toEqual(expectedLightTokens);
42
103
  }));
43
104
  describe("when theme is forced for provider", () => {
@@ -49,16 +110,29 @@ describe("ThemeContext", () => {
49
110
  yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("dark"); }));
50
111
  // This hook shouldn't be affected by it because it's set to the light theme
51
112
  expect(result.current.theme).toBe("light");
113
+ expect(result.current.effectiveTheme).toBe("light");
52
114
  expect(result.current.tokens).toEqual(expectedLightTokens);
53
115
  }));
54
116
  it.each([
55
- { defaultTheme: "light", expectedTokens: expectedLightTokens },
56
- { defaultTheme: "dark", expectedTokens: expectedDarkTokens },
57
- ])("provides the dangerouslyOverrideTheme $defaultTheme tokens", ({ defaultTheme, expectedTokens }) => {
117
+ {
118
+ defaultTheme: "light",
119
+ colorScheme: "dark",
120
+ expectedEffectiveTheme: "light",
121
+ expectedTokens: expectedLightTokens,
122
+ },
123
+ {
124
+ defaultTheme: "dark",
125
+ colorScheme: "light",
126
+ expectedEffectiveTheme: "dark",
127
+ expectedTokens: expectedDarkTokens,
128
+ },
129
+ ])("provides the dangerouslyOverrideTheme $defaultTheme tokens", ({ defaultTheme, colorScheme, expectedEffectiveTheme, expectedTokens, }) => {
130
+ mockUseColorScheme.mockReturnValue(colorScheme);
58
131
  const { result } = renderHook(useAtlantisTheme, {
59
132
  wrapper: (props) => (React.createElement(WrapperWithOverride, Object.assign({}, props, { dangerouslyOverrideTheme: defaultTheme }))),
60
133
  });
61
134
  expect(result.current.theme).toBe(defaultTheme);
135
+ expect(result.current.effectiveTheme).toBe(expectedEffectiveTheme);
62
136
  expect(result.current.tokens).toEqual(expectedTokens);
63
137
  });
64
138
  });
@@ -54,7 +54,7 @@ export function ContentOverlay({ children, title, accessibilityLabel, fullScreen
54
54
  const [currentPosition, setCurrentPosition] = useState(-1);
55
55
  const styles = useStyles();
56
56
  const { t } = useAtlantisI18n();
57
- const { theme, tokens } = useAtlantisTheme();
57
+ const { effectiveTheme, tokens } = useAtlantisTheme();
58
58
  const isScreenReaderEnabled = useIsScreenReaderEnabled();
59
59
  const behavior = computeContentOverlayBehavior({
60
60
  fullScreen,
@@ -179,7 +179,7 @@ export function ContentOverlay({ children, title, accessibilityLabel, fullScreen
179
179
  return (React.createElement(Backdrop, Object.assign({}, props, { pressBehavior: isCloseableOnOverlayTap ? "close" : "none" })));
180
180
  }, [isCloseableOnOverlayTap]);
181
181
  return (React.createElement(BottomSheetModal, { ref: bottomSheetModalRef, containerComponent: Platform.OS === "ios" ? Container : undefined, onChange: handleChange, style: sheetStyle, backgroundStyle: backgroundStyle, handleStyle: styles.handleWrapper, handleIndicatorStyle: handleIndicatorStyles, backdropComponent: backdropComponent, snapPoints: snapPoints, enablePanDownToClose: enablePanDownToClose !== null && enablePanDownToClose !== void 0 ? enablePanDownToClose : effectiveIsDraggable, enableContentPanningGesture: enableContentPanningGesture !== null && enableContentPanningGesture !== void 0 ? enableContentPanningGesture : effectiveIsDraggable, enableHandlePanningGesture: effectiveIsDraggable, enableDynamicSizing: !customSnapPoints && behavior.initialHeight === "contentHeight", keyboardBehavior: "interactive", keyboardBlurBehavior: "restore", topInset: topInset, onDismiss: () => onClose === null || onClose === void 0 ? void 0 : onClose() },
182
- React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: theme },
182
+ React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: effectiveTheme },
183
183
  React.createElement(ContentOverlayKeyboardContext.Provider, { value: scrollEnabled }, scrollEnabled ? (React.createElement(BottomSheetKeyboardAwareScrollView, { ref: scrollViewRef, contentContainerStyle: { paddingBottom: insets.bottom }, keyboardShouldPersistTaps: keyboardShouldPersistTaps ? "handled" : "never", showsVerticalScrollIndicator: false, onScroll: handleOnScroll, stickyHeaderIndices: [0], bottomOffset: KEYBOARD_TOP_PADDING_AUTO_SCROLL },
184
184
  renderHeader(),
185
185
  React.createElement(View, { testID: "ATL-Overlay-Children" }, children))) : (React.createElement(BottomSheetView, null,