@jobber/components-native 0.113.4-implement--94d34f8.2 → 0.113.4
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.
- package/dist/docs/AtlantisThemeContext/AtlantisThemeContext.md +1 -3
- package/dist/package.json +2 -2
- package/dist/src/AtlantisThemeContext/AtlantisThemeContext.js +9 -23
- package/dist/src/AtlantisThemeContext/AtlantisThemeContext.test.js +5 -79
- package/dist/src/Button/Button.js +1 -1
- package/dist/src/ContentOverlay/ContentOverlay.js +2 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/src/AtlantisThemeContext/AtlantisThemeContext.d.ts +1 -1
- package/dist/types/src/AtlantisThemeContext/index.d.ts +1 -1
- package/dist/types/src/AtlantisThemeContext/types.d.ts +3 -16
- package/package.json +2 -2
- package/src/AtlantisThemeContext/AtlantisThemeContext.test.tsx +5 -127
- package/src/AtlantisThemeContext/AtlantisThemeContext.tsx +8 -33
- package/src/AtlantisThemeContext/docs/AtlantisThemeContextBasicExample.tsx +2 -4
- package/src/AtlantisThemeContext/docs/AtlantisThemeContextForceThemeForProviderExample.tsx +2 -4
- package/src/AtlantisThemeContext/index.ts +0 -1
- package/src/AtlantisThemeContext/types.ts +3 -20
- package/src/Button/Button.tsx +1 -1
- package/src/ContentOverlay/ContentOverlay.tsx +2 -2
|
@@ -293,6 +293,4 @@ Key features:
|
|
|
293
293
|
| Prop | Type | Required | Default | Description |
|
|
294
294
|
|------|------|----------|---------|-------------|
|
|
295
295
|
| `children` | `ReactNode` | Yes | — | The children to render. |
|
|
296
|
-
| `dangerouslyOverrideTheme` | `
|
|
297
|
-
| `onThemeChange` | `(theme: Theme) => void` | No | — | Called when children request a selected theme change through setTheme. |
|
|
298
|
-
| `theme` | `Theme` | No | — | Control the selected theme for this provider. |
|
|
296
|
+
| `dangerouslyOverrideTheme` | `Theme` | No | — | Force the theme for this provider to always be the same as the provided theme. Useful for sections that should remain... |
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.113.4
|
|
3
|
+
"version": "0.113.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native implementation of Atlantis",
|
|
6
6
|
"repository": {
|
|
@@ -124,5 +124,5 @@
|
|
|
124
124
|
"react-native-screens": ">=4.18.0",
|
|
125
125
|
"react-native-svg": ">=12.0.0"
|
|
126
126
|
},
|
|
127
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "b151fce2d669e8b85cea91becf7d9aacee827c3e"
|
|
128
128
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { androidTokens, darkTokens, iosTokens } from "@jobber/design";
|
|
2
|
-
import React, { createContext,
|
|
2
|
+
import React, { createContext, useContext, useState } from "react";
|
|
3
3
|
import merge from "lodash/merge";
|
|
4
|
-
import { Platform
|
|
4
|
+
import { Platform } from "react-native";
|
|
5
5
|
const lightTokens = Platform.select({
|
|
6
6
|
ios: () => iosTokens,
|
|
7
7
|
android: () => androidTokens,
|
|
@@ -10,37 +10,23 @@ const lightTokens = Platform.select({
|
|
|
10
10
|
const completeDarkTokens = merge({}, lightTokens, darkTokens);
|
|
11
11
|
const AtlantisThemeContext = createContext({
|
|
12
12
|
theme: "light",
|
|
13
|
-
effectiveTheme: "light",
|
|
14
13
|
tokens: lightTokens,
|
|
15
14
|
setTheme: () => {
|
|
16
15
|
console.error("useAtlantisTheme accessed outside of AtlantisThemeContextProvider");
|
|
17
16
|
},
|
|
18
17
|
});
|
|
19
|
-
export function AtlantisThemeContextProvider({ children,
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
if (theme === undefined) {
|
|
26
|
-
setUncontrolledTheme(nextTheme);
|
|
27
|
-
}
|
|
28
|
-
}, [onThemeChange, theme]);
|
|
29
|
-
const currentTheme = (_a = dangerouslyOverrideTheme !== null && dangerouslyOverrideTheme !== void 0 ? dangerouslyOverrideTheme : theme) !== null && _a !== void 0 ? _a : uncontrolledTheme;
|
|
30
|
-
const effectiveTheme = resolveEffectiveTheme(currentTheme, colorScheme);
|
|
31
|
-
const currentTokens = effectiveTheme === "dark" ? completeDarkTokens : lightTokens;
|
|
18
|
+
export function AtlantisThemeContextProvider({ children, dangerouslyOverrideTheme, }) {
|
|
19
|
+
// TODO: check last saved theme from local/device storage
|
|
20
|
+
const initialTheme = "light";
|
|
21
|
+
const [globalTheme, setGlobalTheme] = useState(initialTheme);
|
|
22
|
+
const currentTheme = dangerouslyOverrideTheme !== null && dangerouslyOverrideTheme !== void 0 ? dangerouslyOverrideTheme : globalTheme;
|
|
23
|
+
const currentTokens = currentTheme === "dark" ? completeDarkTokens : lightTokens;
|
|
32
24
|
return (React.createElement(AtlantisThemeContext.Provider, { value: {
|
|
33
25
|
theme: currentTheme,
|
|
34
|
-
effectiveTheme,
|
|
35
26
|
tokens: currentTokens,
|
|
36
|
-
setTheme,
|
|
27
|
+
setTheme: setGlobalTheme,
|
|
37
28
|
} }, children));
|
|
38
29
|
}
|
|
39
30
|
export function useAtlantisTheme() {
|
|
40
31
|
return useContext(AtlantisThemeContext);
|
|
41
32
|
}
|
|
42
|
-
function resolveEffectiveTheme(theme, colorScheme) {
|
|
43
|
-
if (theme !== "system")
|
|
44
|
-
return theme;
|
|
45
|
-
return colorScheme === "dark" ? "dark" : "light";
|
|
46
|
-
}
|
|
@@ -11,36 +11,22 @@ 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";
|
|
15
14
|
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
|
-
});
|
|
24
15
|
const expectedDarkTokens = merge({}, iosTokens, darkTokens);
|
|
25
16
|
const expectedLightTokens = iosTokens;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return (React.createElement(AtlantisThemeContextProvider, { theme: theme, onThemeChange: onThemeChange, dangerouslyOverrideTheme: dangerouslyOverrideTheme }, children));
|
|
17
|
+
function Wrapper({ children, dangerouslyOverrideTheme, }) {
|
|
18
|
+
return (React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: dangerouslyOverrideTheme }, children));
|
|
29
19
|
}
|
|
30
20
|
function WrapperWithOverride({ children, dangerouslyOverrideTheme, }) {
|
|
31
21
|
return (React.createElement(Wrapper, null,
|
|
32
22
|
React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: dangerouslyOverrideTheme }, children)));
|
|
33
23
|
}
|
|
34
24
|
describe("ThemeContext", () => {
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
mockUseColorScheme.mockReturnValue("light");
|
|
37
|
-
});
|
|
38
25
|
it("defaults to the light theme", () => {
|
|
39
26
|
const { result } = renderHook(useAtlantisTheme, {
|
|
40
27
|
wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props))),
|
|
41
28
|
});
|
|
42
29
|
expect(result.current.theme).toBe("light");
|
|
43
|
-
expect(result.current.effectiveTheme).toBe("light");
|
|
44
30
|
expect(result.current.tokens).toEqual(expectedLightTokens);
|
|
45
31
|
});
|
|
46
32
|
it("updates the theme and tokens", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -49,56 +35,9 @@ describe("ThemeContext", () => {
|
|
|
49
35
|
});
|
|
50
36
|
yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("dark"); }));
|
|
51
37
|
expect(result.current.theme).toBe("dark");
|
|
52
|
-
expect(result.current.effectiveTheme).toBe("dark");
|
|
53
38
|
expect(result.current.tokens).toEqual(expectedDarkTokens);
|
|
54
39
|
yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("light"); }));
|
|
55
40
|
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");
|
|
102
41
|
expect(result.current.tokens).toEqual(expectedLightTokens);
|
|
103
42
|
}));
|
|
104
43
|
describe("when theme is forced for provider", () => {
|
|
@@ -110,29 +49,16 @@ describe("ThemeContext", () => {
|
|
|
110
49
|
yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("dark"); }));
|
|
111
50
|
// This hook shouldn't be affected by it because it's set to the light theme
|
|
112
51
|
expect(result.current.theme).toBe("light");
|
|
113
|
-
expect(result.current.effectiveTheme).toBe("light");
|
|
114
52
|
expect(result.current.tokens).toEqual(expectedLightTokens);
|
|
115
53
|
}));
|
|
116
54
|
it.each([
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
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);
|
|
55
|
+
{ defaultTheme: "light", expectedTokens: expectedLightTokens },
|
|
56
|
+
{ defaultTheme: "dark", expectedTokens: expectedDarkTokens },
|
|
57
|
+
])("provides the dangerouslyOverrideTheme $defaultTheme tokens", ({ defaultTheme, expectedTokens }) => {
|
|
131
58
|
const { result } = renderHook(useAtlantisTheme, {
|
|
132
59
|
wrapper: (props) => (React.createElement(WrapperWithOverride, Object.assign({}, props, { dangerouslyOverrideTheme: defaultTheme }))),
|
|
133
60
|
});
|
|
134
61
|
expect(result.current.theme).toBe(defaultTheme);
|
|
135
|
-
expect(result.current.effectiveTheme).toBe(expectedEffectiveTheme);
|
|
136
62
|
expect(result.current.tokens).toEqual(expectedTokens);
|
|
137
63
|
});
|
|
138
64
|
});
|
|
@@ -58,7 +58,7 @@ function getIconColorVariation(variation, type, disabled) {
|
|
|
58
58
|
return "disabled";
|
|
59
59
|
}
|
|
60
60
|
if (type === "primary" && variation !== "cancel") {
|
|
61
|
-
return "
|
|
61
|
+
return "surface"; // This should be a text color token instead, but the action label also uses this
|
|
62
62
|
}
|
|
63
63
|
switch (variation) {
|
|
64
64
|
case "learning":
|
|
@@ -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 {
|
|
57
|
+
const { theme, 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:
|
|
182
|
+
React.createElement(AtlantisThemeContextProvider, { dangerouslyOverrideTheme: theme },
|
|
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,
|