@jobber/components-native 0.115.4 → 0.115.5
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/Elevations/Elevations.md +7 -0
- package/dist/package.json +4 -3
- package/dist/src/AtlantisThemeContext/AtlantisThemeContext.js +7 -2
- package/dist/src/AtlantisThemeContext/AtlantisThemeContext.test.js +26 -5
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/src/AtlantisThemeContext/AtlantisThemeContext.guide.md +13 -5
- package/src/AtlantisThemeContext/AtlantisThemeContext.test.tsx +61 -9
- package/src/AtlantisThemeContext/AtlantisThemeContext.tsx +13 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.115.
|
|
3
|
+
"version": "0.115.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React Native implementation of Atlantis",
|
|
6
6
|
"repository": {
|
|
@@ -73,11 +73,12 @@
|
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@babel/runtime": "^7.29.2",
|
|
75
75
|
"@gorhom/bottom-sheet": "^5.2.8",
|
|
76
|
-
"@jobber/design": "0.121.
|
|
76
|
+
"@jobber/design": "0.121.1",
|
|
77
77
|
"@jobber/hooks": "2.21.1",
|
|
78
78
|
"@react-native-community/datetimepicker": "^8.4.5",
|
|
79
79
|
"@react-native/babel-preset": "^0.82.1",
|
|
80
80
|
"@storybook/addon-a11y": "10.3.5",
|
|
81
|
+
"@storybook/addon-docs": "10.3.5",
|
|
81
82
|
"@storybook/addon-mcp": "^0.4.2",
|
|
82
83
|
"@storybook/react-native-web-vite": "10.3.5",
|
|
83
84
|
"@testing-library/react-native": "^13.3.3",
|
|
@@ -123,5 +124,5 @@
|
|
|
123
124
|
"react-native-screens": ">=4.18.0",
|
|
124
125
|
"react-native-svg": ">=12.0.0"
|
|
125
126
|
},
|
|
126
|
-
"gitHead": "
|
|
127
|
+
"gitHead": "9b27100be34c36aa1d4717f298cea4388ab9277d"
|
|
127
128
|
}
|
|
@@ -35,13 +35,21 @@ Consumers that need to style non-Atlantis surfaces should usually use
|
|
|
35
35
|
## Platform token composition
|
|
36
36
|
|
|
37
37
|
Native themes start with the current platform's iOS or Android token set and
|
|
38
|
-
then apply
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
then apply that platform's dark token set (`darkIosTokens` or
|
|
39
|
+
`darkAndroidTokens` from `@jobber/design`). Each dark platform set is the web
|
|
40
|
+
dark token set with dark platform overrides layered on top, defined in
|
|
41
|
+
`packages/design/src/tokens/darkPlatformOverride.tokens.json`.
|
|
41
42
|
|
|
42
43
|
This matters for shadows: web dark shadow tokens are CSS strings, while native
|
|
43
|
-
shadow tokens are React Native style objects.
|
|
44
|
-
|
|
44
|
+
shadow tokens are React Native style objects. The dark platform overrides
|
|
45
|
+
replace the dark shadow strings with native shadow objects tuned for dark
|
|
46
|
+
surfaces, so consumers can safely continue to spread `tokens["shadow-base"]` in
|
|
47
|
+
both themes.
|
|
48
|
+
|
|
49
|
+
An override must preserve the native token's runtime shape. If a dark token is a
|
|
50
|
+
primitive but the platform token is an object, the provider keeps the platform
|
|
51
|
+
value. Add a dark platform override when a token needs a different native value
|
|
52
|
+
in dark mode.
|
|
45
53
|
|
|
46
54
|
## Controlled vs uncontrolled usage
|
|
47
55
|
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { act, renderHook } from "@testing-library/react-native";
|
|
3
|
-
import
|
|
3
|
+
import type * as TestingLibrary from "@testing-library/react-native";
|
|
4
|
+
import {
|
|
5
|
+
androidTokens,
|
|
6
|
+
darkAndroidTokens,
|
|
7
|
+
darkIosTokens,
|
|
8
|
+
iosTokens,
|
|
9
|
+
} from "@jobber/design";
|
|
4
10
|
import merge from "lodash/merge";
|
|
5
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type ColorSchemeName,
|
|
13
|
+
type Platform as PlatformModule,
|
|
14
|
+
useColorScheme,
|
|
15
|
+
} from "react-native";
|
|
6
16
|
import {
|
|
7
17
|
AtlantisThemeContextProvider,
|
|
8
18
|
useAtlantisTheme,
|
|
9
19
|
} from "./AtlantisThemeContext";
|
|
20
|
+
import type * as ThemeContextModule from "./AtlantisThemeContext";
|
|
10
21
|
import type {
|
|
11
22
|
AtlantisThemeContextProviderProps,
|
|
12
23
|
EffectiveTheme,
|
|
@@ -23,12 +34,7 @@ jest.mock("react-native", () => {
|
|
|
23
34
|
return actual;
|
|
24
35
|
});
|
|
25
36
|
|
|
26
|
-
const expectedDarkTokens = {
|
|
27
|
-
...merge({}, iosTokens, darkTokens),
|
|
28
|
-
"shadow-low": iosTokens["shadow-low"],
|
|
29
|
-
"shadow-base": iosTokens["shadow-base"],
|
|
30
|
-
"shadow-high": iosTokens["shadow-high"],
|
|
31
|
-
};
|
|
37
|
+
const expectedDarkTokens = merge({}, iosTokens, darkIosTokens);
|
|
32
38
|
const expectedLightTokens = iosTokens;
|
|
33
39
|
const mockUseColorScheme = useColorScheme as jest.MockedFunction<
|
|
34
40
|
typeof useColorScheme
|
|
@@ -102,7 +108,7 @@ describe("ThemeContext", () => {
|
|
|
102
108
|
});
|
|
103
109
|
|
|
104
110
|
it.each(["shadow-low", "shadow-base", "shadow-high"] as const)(
|
|
105
|
-
"
|
|
111
|
+
"uses the dark platform-native %s token in dark mode",
|
|
106
112
|
async shadowToken => {
|
|
107
113
|
const { result } = renderHook(useAtlantisTheme, {
|
|
108
114
|
wrapper: (props: AtlantisThemeContextProviderProps) => (
|
|
@@ -113,12 +119,58 @@ describe("ThemeContext", () => {
|
|
|
113
119
|
await act(async () => result.current.setTheme("dark"));
|
|
114
120
|
|
|
115
121
|
expect(result.current.tokens[shadowToken]).toEqual(
|
|
122
|
+
darkIosTokens[shadowToken],
|
|
123
|
+
);
|
|
124
|
+
expect(result.current.tokens[shadowToken]).not.toEqual(
|
|
116
125
|
iosTokens[shadowToken],
|
|
117
126
|
);
|
|
118
127
|
expect(typeof result.current.tokens[shadowToken]).toBe("object");
|
|
119
128
|
},
|
|
120
129
|
);
|
|
121
130
|
|
|
131
|
+
describe("on android", () => {
|
|
132
|
+
let android!: typeof TestingLibrary & typeof ThemeContextModule;
|
|
133
|
+
|
|
134
|
+
// The provider picks platform tokens at import time, so it is loaded in an
|
|
135
|
+
// isolated registry after Platform is switched to android. This runs while
|
|
136
|
+
// collecting tests because the testing library registers cleanup hooks.
|
|
137
|
+
jest.isolateModules(() => {
|
|
138
|
+
const {
|
|
139
|
+
Platform,
|
|
140
|
+
}: { Platform: typeof PlatformModule } = require("react-native");
|
|
141
|
+
jest.replaceProperty(Platform, "OS", "android");
|
|
142
|
+
jest.spyOn(Platform, "select").mockImplementation(spec => spec.android);
|
|
143
|
+
|
|
144
|
+
android = {
|
|
145
|
+
...require("@testing-library/react-native"),
|
|
146
|
+
...require("./AtlantisThemeContext"),
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it.each(["shadow-low", "shadow-base", "shadow-high"] as const)(
|
|
151
|
+
"uses the android %s token in light and dark mode",
|
|
152
|
+
async shadowToken => {
|
|
153
|
+
const { result } = android.renderHook(android.useAtlantisTheme, {
|
|
154
|
+
wrapper: ({ children }: AtlantisThemeContextProviderProps) => (
|
|
155
|
+
<android.AtlantisThemeContextProvider>
|
|
156
|
+
{children}
|
|
157
|
+
</android.AtlantisThemeContextProvider>
|
|
158
|
+
),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
expect(result.current.tokens[shadowToken]).toEqual(
|
|
162
|
+
androidTokens[shadowToken],
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
await android.act(async () => result.current.setTheme("dark"));
|
|
166
|
+
|
|
167
|
+
expect(result.current.tokens[shadowToken]).toEqual(
|
|
168
|
+
darkAndroidTokens[shadowToken],
|
|
169
|
+
);
|
|
170
|
+
},
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
122
174
|
it("resolves the system theme from the OS color scheme", async () => {
|
|
123
175
|
mockUseColorScheme.mockReturnValue("dark");
|
|
124
176
|
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
androidTokens,
|
|
3
|
+
darkAndroidTokens,
|
|
4
|
+
darkIosTokens,
|
|
5
|
+
iosTokens,
|
|
6
|
+
} from "@jobber/design";
|
|
2
7
|
import React, { createContext, useCallback, useContext, useState } from "react";
|
|
3
8
|
import mergeWith from "lodash/mergeWith";
|
|
4
9
|
import { Platform, useColorScheme } from "react-native";
|
|
@@ -15,10 +20,16 @@ const lightTokens = Platform.select({
|
|
|
15
20
|
default: () => androidTokens,
|
|
16
21
|
})();
|
|
17
22
|
|
|
23
|
+
const darkPlatformTokens = Platform.select({
|
|
24
|
+
ios: () => darkIosTokens,
|
|
25
|
+
android: () => darkAndroidTokens,
|
|
26
|
+
default: () => darkAndroidTokens,
|
|
27
|
+
})();
|
|
28
|
+
|
|
18
29
|
const completeDarkTokens = mergeWith(
|
|
19
30
|
{},
|
|
20
31
|
lightTokens,
|
|
21
|
-
|
|
32
|
+
darkPlatformTokens,
|
|
22
33
|
(platformValue, darkValue) => {
|
|
23
34
|
const platformValueIsObject =
|
|
24
35
|
typeof platformValue === "object" && platformValue !== null;
|