@jobber/components-native 0.114.7 → 0.114.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.114.7",
3
+ "version": "0.114.9",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -73,7 +73,7 @@
73
73
  "devDependencies": {
74
74
  "@babel/runtime": "^7.29.2",
75
75
  "@gorhom/bottom-sheet": "^5.2.8",
76
- "@jobber/design": "0.117.0",
76
+ "@jobber/design": "0.117.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",
@@ -123,5 +123,5 @@
123
123
  "react-native-screens": ">=4.18.0",
124
124
  "react-native-svg": ">=12.0.0"
125
125
  },
126
- "gitHead": "96774b47d51dfa7778ca1958ef0fe46cfd5099cf"
126
+ "gitHead": "03a318392b77ae6bb66564ec8bc82416f0cb8da7"
127
127
  }
@@ -32,6 +32,17 @@ Consumers that need to persist or display the user's choice should use `theme`.
32
32
  Consumers that need to style non-Atlantis surfaces should usually use
33
33
  `effectiveTheme`.
34
34
 
35
+ ## Platform token composition
36
+
37
+ Native themes start with the current platform's iOS or Android token set and
38
+ then apply dark theme overrides. An override must preserve the native token's
39
+ runtime shape. If a dark override is a primitive but the platform token is an
40
+ object, the provider keeps the platform value.
41
+
42
+ This matters for shadows: web dark shadow tokens are CSS strings, while native
43
+ shadow tokens are React Native style objects. Keeping the platform object means
44
+ consumers can safely continue to spread `tokens["shadow-base"]` in both themes.
45
+
35
46
  ## Controlled vs uncontrolled usage
36
47
 
37
48
  `AtlantisThemeContextProvider` supports both controlled and uncontrolled usage.
@@ -23,7 +23,12 @@ jest.mock("react-native", () => {
23
23
  return actual;
24
24
  });
25
25
 
26
- const expectedDarkTokens = merge({}, iosTokens, darkTokens);
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
+ };
27
32
  const expectedLightTokens = iosTokens;
28
33
  const mockUseColorScheme = useColorScheme as jest.MockedFunction<
29
34
  typeof useColorScheme
@@ -96,6 +101,24 @@ describe("ThemeContext", () => {
96
101
  expect(result.current.tokens).toEqual(expectedLightTokens);
97
102
  });
98
103
 
104
+ it.each(["shadow-low", "shadow-base", "shadow-high"] as const)(
105
+ "keeps the platform-native %s token in dark mode",
106
+ async shadowToken => {
107
+ const { result } = renderHook(useAtlantisTheme, {
108
+ wrapper: (props: AtlantisThemeContextProviderProps) => (
109
+ <Wrapper {...props} />
110
+ ),
111
+ });
112
+
113
+ await act(async () => result.current.setTheme("dark"));
114
+
115
+ expect(result.current.tokens[shadowToken]).toEqual(
116
+ iosTokens[shadowToken],
117
+ );
118
+ expect(typeof result.current.tokens[shadowToken]).toBe("object");
119
+ },
120
+ );
121
+
99
122
  it("resolves the system theme from the OS color scheme", async () => {
100
123
  mockUseColorScheme.mockReturnValue("dark");
101
124
 
@@ -1,6 +1,6 @@
1
1
  import { androidTokens, darkTokens, iosTokens } from "@jobber/design";
2
2
  import React, { createContext, useCallback, useContext, useState } from "react";
3
- import merge from "lodash/merge";
3
+ import mergeWith from "lodash/mergeWith";
4
4
  import { Platform, useColorScheme } from "react-native";
5
5
  import type {
6
6
  AtlantisThemeContextProviderProps,
@@ -15,7 +15,19 @@ const lightTokens = Platform.select({
15
15
  default: () => androidTokens,
16
16
  })();
17
17
 
18
- const completeDarkTokens = merge({}, lightTokens, darkTokens);
18
+ const completeDarkTokens = mergeWith(
19
+ {},
20
+ lightTokens,
21
+ darkTokens,
22
+ (platformValue, darkValue) => {
23
+ const platformValueIsObject =
24
+ typeof platformValue === "object" && platformValue !== null;
25
+ const darkValueIsObject =
26
+ typeof darkValue === "object" && darkValue !== null;
27
+
28
+ if (platformValueIsObject && !darkValueIsObject) return platformValue;
29
+ },
30
+ );
19
31
 
20
32
  const defaultAtlantisThemeContextValue: AtlantisThemeContextValue = {
21
33
  theme: "light",