@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.
@@ -66,6 +66,13 @@ they map to our low/base/high pattern.
66
66
  | `--shadow-base` | |
67
67
  | `--shadow-high` | |
68
68
 
69
+ ### Dark mode
70
+
71
+ On web and iOS, the dark theme keeps the same shadow offsets and blur and only
72
+ raises the opacity, so elevated elements stay distinguishable against dark
73
+ surfaces. On Android, the dark theme raises `elevation`, which makes the shadow
74
+ larger and softer, and uses a fully opaque shadow colour.
75
+
69
76
  ## Mobile
70
77
 
71
78
  For mobile designs, the concept of elevation applies to both shadows and
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.115.4",
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.0",
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": "8efe7ed48c2c677ef66802b64d945c259f22a343"
127
+ "gitHead": "9b27100be34c36aa1d4717f298cea4388ab9277d"
127
128
  }
@@ -1,4 +1,4 @@
1
- import { androidTokens, darkTokens, iosTokens } from "@jobber/design";
1
+ import { androidTokens, darkAndroidTokens, darkIosTokens, iosTokens, } from "@jobber/design";
2
2
  import React, { createContext, useCallback, useContext, useState } from "react";
3
3
  import mergeWith from "lodash/mergeWith";
4
4
  import { Platform, useColorScheme } from "react-native";
@@ -7,7 +7,12 @@ const lightTokens = Platform.select({
7
7
  android: () => androidTokens,
8
8
  default: () => androidTokens,
9
9
  })();
10
- const completeDarkTokens = mergeWith({}, lightTokens, darkTokens, (platformValue, darkValue) => {
10
+ const darkPlatformTokens = Platform.select({
11
+ ios: () => darkIosTokens,
12
+ android: () => darkAndroidTokens,
13
+ default: () => darkAndroidTokens,
14
+ })();
15
+ const completeDarkTokens = mergeWith({}, lightTokens, darkPlatformTokens, (platformValue, darkValue) => {
11
16
  const platformValueIsObject = typeof platformValue === "object" && platformValue !== null;
12
17
  const darkValueIsObject = typeof darkValue === "object" && darkValue !== null;
13
18
  if (platformValueIsObject && !darkValueIsObject)
@@ -9,9 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import React from "react";
11
11
  import { act, renderHook } from "@testing-library/react-native";
12
- import { darkTokens, iosTokens } from "@jobber/design";
12
+ import { androidTokens, darkAndroidTokens, darkIosTokens, iosTokens, } from "@jobber/design";
13
13
  import merge from "lodash/merge";
14
- import { useColorScheme } from "react-native";
14
+ import { useColorScheme, } from "react-native";
15
15
  import { AtlantisThemeContextProvider, useAtlantisTheme, } from "./AtlantisThemeContext";
16
16
  jest.mock("react-native", () => {
17
17
  const actual = jest.requireActual("react-native");
@@ -21,7 +21,7 @@ jest.mock("react-native", () => {
21
21
  });
22
22
  return actual;
23
23
  });
24
- const expectedDarkTokens = Object.assign(Object.assign({}, merge({}, iosTokens, darkTokens)), { "shadow-low": iosTokens["shadow-low"], "shadow-base": iosTokens["shadow-base"], "shadow-high": iosTokens["shadow-high"] });
24
+ const expectedDarkTokens = merge({}, iosTokens, darkIosTokens);
25
25
  const expectedLightTokens = iosTokens;
26
26
  const mockUseColorScheme = useColorScheme;
27
27
  function Wrapper({ children, theme, onThemeChange, dangerouslyOverrideTheme, }) {
@@ -56,14 +56,35 @@ describe("ThemeContext", () => {
56
56
  expect(result.current.effectiveTheme).toBe("light");
57
57
  expect(result.current.tokens).toEqual(expectedLightTokens);
58
58
  }));
59
- it.each(["shadow-low", "shadow-base", "shadow-high"])("keeps the platform-native %s token in dark mode", (shadowToken) => __awaiter(void 0, void 0, void 0, function* () {
59
+ it.each(["shadow-low", "shadow-base", "shadow-high"])("uses the dark platform-native %s token in dark mode", (shadowToken) => __awaiter(void 0, void 0, void 0, function* () {
60
60
  const { result } = renderHook(useAtlantisTheme, {
61
61
  wrapper: (props) => (React.createElement(Wrapper, Object.assign({}, props))),
62
62
  });
63
63
  yield act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("dark"); }));
64
- expect(result.current.tokens[shadowToken]).toEqual(iosTokens[shadowToken]);
64
+ expect(result.current.tokens[shadowToken]).toEqual(darkIosTokens[shadowToken]);
65
+ expect(result.current.tokens[shadowToken]).not.toEqual(iosTokens[shadowToken]);
65
66
  expect(typeof result.current.tokens[shadowToken]).toBe("object");
66
67
  }));
68
+ describe("on android", () => {
69
+ let android;
70
+ // The provider picks platform tokens at import time, so it is loaded in an
71
+ // isolated registry after Platform is switched to android. This runs while
72
+ // collecting tests because the testing library registers cleanup hooks.
73
+ jest.isolateModules(() => {
74
+ const { Platform, } = require("react-native");
75
+ jest.replaceProperty(Platform, "OS", "android");
76
+ jest.spyOn(Platform, "select").mockImplementation(spec => spec.android);
77
+ android = Object.assign(Object.assign({}, require("@testing-library/react-native")), require("./AtlantisThemeContext"));
78
+ });
79
+ it.each(["shadow-low", "shadow-base", "shadow-high"])("uses the android %s token in light and dark mode", (shadowToken) => __awaiter(void 0, void 0, void 0, function* () {
80
+ const { result } = android.renderHook(android.useAtlantisTheme, {
81
+ wrapper: ({ children }) => (React.createElement(android.AtlantisThemeContextProvider, null, children)),
82
+ });
83
+ expect(result.current.tokens[shadowToken]).toEqual(androidTokens[shadowToken]);
84
+ yield android.act(() => __awaiter(void 0, void 0, void 0, function* () { return result.current.setTheme("dark"); }));
85
+ expect(result.current.tokens[shadowToken]).toEqual(darkAndroidTokens[shadowToken]);
86
+ }));
87
+ });
67
88
  it("resolves the system theme from the OS color scheme", () => __awaiter(void 0, void 0, void 0, function* () {
68
89
  mockUseColorScheme.mockReturnValue("dark");
69
90
  const { result, rerender } = renderHook(useAtlantisTheme, {