react-native-terra-ui 0.7.2 → 0.8.1
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/CHANGELOG.md +34 -0
- package/README.md +1 -1
- package/lib/module/components/avatar/Avatar.js +20 -20
- package/lib/module/components/avatar/Avatar.js.map +1 -1
- package/lib/module/components/button/Button.js +11 -11
- package/lib/module/components/button/Button.js.map +1 -1
- package/lib/module/components/chip/Chip.js +32 -32
- package/lib/module/components/chip/Chip.js.map +1 -1
- package/lib/module/components/empty-state/EmptyState.js +3 -3
- package/lib/module/components/empty-state/EmptyState.js.map +1 -1
- package/lib/module/components/header/variants/LargeTitleHeader/index.js +30 -32
- package/lib/module/components/header/variants/LargeTitleHeader/index.js.map +1 -1
- package/lib/module/components/header/variants/TitleHeader/index.js +26 -18
- package/lib/module/components/header/variants/TitleHeader/index.js.map +1 -1
- package/lib/module/components/icon/Icon.js +3 -3
- package/lib/module/components/page-indicator/hooks/use-page-indicator-colors.js +2 -2
- package/lib/module/components/screen/Screen.js +63 -34
- package/lib/module/components/screen/Screen.js.map +1 -1
- package/lib/module/components/screen/ScreenContext.js +28 -9
- package/lib/module/components/screen/ScreenContext.js.map +1 -1
- package/lib/module/components/screen/ScreenFlatList.js +4 -162
- package/lib/module/components/screen/ScreenFlatList.js.map +1 -1
- package/lib/module/components/screen/ScreenList.js +81 -97
- package/lib/module/components/screen/ScreenList.js.map +1 -1
- package/lib/module/components/screen/ScreenScrollView.js +64 -115
- package/lib/module/components/screen/ScreenScrollView.js.map +1 -1
- package/lib/module/components/screen/hooks/use-screen-ref.js +18 -0
- package/lib/module/components/screen/hooks/use-screen-ref.js.map +1 -0
- package/lib/module/components/screen/hooks/use-screen-scroll-handler.js +19 -0
- package/lib/module/components/screen/hooks/use-screen-scroll-handler.js.map +1 -0
- package/lib/module/components/screen/index.js.map +1 -1
- package/lib/module/components/screen/parts/ScreenFrame.js +47 -0
- package/lib/module/components/screen/parts/ScreenFrame.js.map +1 -0
- package/lib/module/components/screen/parts/ScreenHeaderAppearance.js +43 -0
- package/lib/module/components/screen/parts/ScreenHeaderAppearance.js.map +1 -0
- package/lib/module/components/screen/parts/ScreenPlaceholder.js +11 -13
- package/lib/module/components/screen/parts/ScreenPlaceholder.js.map +1 -1
- package/lib/module/components/screen/parts/ScreenSafeArea.android.js +27 -0
- package/lib/module/components/screen/parts/ScreenSafeArea.android.js.map +1 -0
- package/lib/module/components/screen/parts/ScreenSafeArea.js +26 -0
- package/lib/module/components/screen/parts/ScreenSafeArea.js.map +1 -0
- package/lib/module/components/screen/utils.js +18 -9
- package/lib/module/components/screen/utils.js.map +1 -1
- package/lib/module/components/spinner/Spinner.js +2 -2
- package/lib/module/components/text/Text.js +1 -1
- package/lib/module/components/toast/Toast.js +13 -13
- package/lib/module/components/toast/Toast.js.map +1 -1
- package/lib/module/components/toolbar/Toolbar.js +2 -2
- package/lib/module/context/ThemeProvider.js +22 -39
- package/lib/module/context/ThemeProvider.js.map +1 -1
- package/lib/module/context/index.js +1 -1
- package/lib/module/context/index.js.map +1 -1
- package/lib/module/theme/breakpoints.js +1 -1
- package/lib/module/theme/define-config.js +21 -0
- package/lib/module/theme/define-config.js.map +1 -0
- package/lib/module/theme/diagnostics.js +13 -0
- package/lib/module/theme/diagnostics.js.map +1 -0
- package/lib/module/theme/errors.js +15 -0
- package/lib/module/theme/errors.js.map +1 -0
- package/lib/module/theme/index.js +7 -1
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/legacy-tokens.js +119 -0
- package/lib/module/theme/legacy-tokens.js.map +1 -0
- package/lib/module/theme/registry.js +122 -130
- package/lib/module/theme/registry.js.map +1 -1
- package/lib/module/theme/resolve-config.js +346 -0
- package/lib/module/theme/resolve-config.js.map +1 -0
- package/lib/module/theme/runtime.js +57 -12
- package/lib/module/theme/runtime.js.map +1 -1
- package/lib/module/theme/screen-margin.js +6 -14
- package/lib/module/theme/screen-margin.js.map +1 -1
- package/lib/module/theme/screen-padding.js +17 -0
- package/lib/module/theme/screen-padding.js.map +1 -0
- package/lib/module/theme/selection-store.js +75 -0
- package/lib/module/theme/selection-store.js.map +1 -0
- package/lib/module/theme/theme.js +81 -36
- package/lib/module/theme/theme.js.map +1 -1
- package/lib/module/theme/tokens/canonical-color-keys.js +102 -0
- package/lib/module/theme/tokens/canonical-color-keys.js.map +1 -0
- package/lib/module/theme/tokens/dark.js +72 -88
- package/lib/module/theme/tokens/dark.js.map +1 -1
- package/lib/module/theme/tokens/light.js +69 -83
- package/lib/module/theme/tokens/light.js.map +1 -1
- package/lib/module/theme/tokens/primitives.js +14 -14
- package/lib/module/theme/tokens/primitives.js.map +1 -1
- package/lib/module/theme/tokens/validate.js +238 -0
- package/lib/module/theme/tokens/validate.js.map +1 -0
- package/lib/module/theme/unistyles-adapter.js +77 -0
- package/lib/module/theme/unistyles-adapter.js.map +1 -0
- package/lib/module/utils/accent-generator.js +476 -0
- package/lib/module/utils/accent-generator.js.map +1 -0
- package/lib/module/utils/accent-utils.js +52 -35
- package/lib/module/utils/accent-utils.js.map +1 -1
- package/lib/module/utils/color-utils.js +224 -7
- package/lib/module/utils/color-utils.js.map +1 -1
- package/lib/module/utils/deep-merge.js +1 -1
- package/lib/module/utils/deep-merge.js.map +1 -1
- package/lib/module/utils/resolve-theme-color.js +2 -2
- package/lib/typescript/src/components/chip/types.d.ts +1 -1
- package/lib/typescript/src/components/empty-state/EmptyState.d.ts +1 -1
- package/lib/typescript/src/components/empty-state/EmptyState.d.ts.map +1 -1
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts +6 -5
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts.map +1 -1
- package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts +11 -5
- package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts.map +1 -1
- package/lib/typescript/src/components/icon/Icon.d.ts +2 -2
- package/lib/typescript/src/components/screen/Screen.d.ts +45 -16
- package/lib/typescript/src/components/screen/Screen.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenContext.d.ts +42 -26
- package/lib/typescript/src/components/screen/ScreenContext.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenFlatList.d.ts +5 -46
- package/lib/typescript/src/components/screen/ScreenFlatList.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenList.d.ts +62 -50
- package/lib/typescript/src/components/screen/ScreenList.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/ScreenScrollView.d.ts +18 -58
- package/lib/typescript/src/components/screen/ScreenScrollView.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/hooks/use-screen-ref.d.ts +5 -0
- package/lib/typescript/src/components/screen/hooks/use-screen-ref.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/hooks/use-screen-scroll-handler.d.ts +53 -0
- package/lib/typescript/src/components/screen/hooks/use-screen-scroll-handler.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/index.d.ts +2 -2
- package/lib/typescript/src/components/screen/index.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/parts/ScreenFrame.d.ts +6 -0
- package/lib/typescript/src/components/screen/parts/ScreenFrame.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/parts/ScreenHeaderAppearance.d.ts +21 -0
- package/lib/typescript/src/components/screen/parts/ScreenHeaderAppearance.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/parts/ScreenPlaceholder.d.ts +6 -8
- package/lib/typescript/src/components/screen/parts/ScreenPlaceholder.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.android.d.ts +7 -0
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.android.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.d.ts +6 -0
- package/lib/typescript/src/components/screen/parts/ScreenSafeArea.d.ts.map +1 -0
- package/lib/typescript/src/components/screen/types.d.ts +27 -32
- package/lib/typescript/src/components/screen/types.d.ts.map +1 -1
- package/lib/typescript/src/components/screen/utils.d.ts +9 -8
- package/lib/typescript/src/components/screen/utils.d.ts.map +1 -1
- package/lib/typescript/src/components/text/Text.d.ts +1 -1
- package/lib/typescript/src/components/text/Text.d.ts.map +1 -1
- package/lib/typescript/src/components/toolbar/Toolbar.d.ts +2 -2
- package/lib/typescript/src/context/ThemeProvider.d.ts +29 -12
- package/lib/typescript/src/context/ThemeProvider.d.ts.map +1 -1
- package/lib/typescript/src/context/index.d.ts +1 -1
- package/lib/typescript/src/context/index.d.ts.map +1 -1
- package/lib/typescript/src/theme/breakpoints.d.ts +1 -1
- package/lib/typescript/src/theme/define-config.d.ts +23 -0
- package/lib/typescript/src/theme/define-config.d.ts.map +1 -0
- package/lib/typescript/src/theme/diagnostics.d.ts +4 -0
- package/lib/typescript/src/theme/diagnostics.d.ts.map +1 -0
- package/lib/typescript/src/theme/errors.d.ts +10 -0
- package/lib/typescript/src/theme/errors.d.ts.map +1 -0
- package/lib/typescript/src/theme/index.d.ts +10 -2
- package/lib/typescript/src/theme/index.d.ts.map +1 -1
- package/lib/typescript/src/theme/legacy-tokens.d.ts +187 -0
- package/lib/typescript/src/theme/legacy-tokens.d.ts.map +1 -0
- package/lib/typescript/src/theme/registry.d.ts +12 -17
- package/lib/typescript/src/theme/registry.d.ts.map +1 -1
- package/lib/typescript/src/theme/resolve-config.d.ts +99 -0
- package/lib/typescript/src/theme/resolve-config.d.ts.map +1 -0
- package/lib/typescript/src/theme/runtime.d.ts +25 -4
- package/lib/typescript/src/theme/runtime.d.ts.map +1 -1
- package/lib/typescript/src/theme/screen-margin.d.ts +6 -14
- package/lib/typescript/src/theme/screen-margin.d.ts.map +1 -1
- package/lib/typescript/src/theme/screen-padding.d.ts +15 -0
- package/lib/typescript/src/theme/screen-padding.d.ts.map +1 -0
- package/lib/typescript/src/theme/selection-store.d.ts +41 -0
- package/lib/typescript/src/theme/selection-store.d.ts.map +1 -0
- package/lib/typescript/src/theme/theme.d.ts +54 -1
- package/lib/typescript/src/theme/theme.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/canonical-color-keys.d.ts +95 -0
- package/lib/typescript/src/theme/tokens/canonical-color-keys.d.ts.map +1 -0
- package/lib/typescript/src/theme/tokens/dark.d.ts +56 -63
- package/lib/typescript/src/theme/tokens/dark.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/light.d.ts +56 -71
- package/lib/typescript/src/theme/tokens/light.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/primitives.d.ts +11 -10
- package/lib/typescript/src/theme/tokens/primitives.d.ts.map +1 -1
- package/lib/typescript/src/theme/tokens/validate.d.ts +34 -0
- package/lib/typescript/src/theme/tokens/validate.d.ts.map +1 -0
- package/lib/typescript/src/theme/types.d.ts +166 -86
- package/lib/typescript/src/theme/types.d.ts.map +1 -1
- package/lib/typescript/src/theme/unistyles-adapter.d.ts +33 -0
- package/lib/typescript/src/theme/unistyles-adapter.d.ts.map +1 -0
- package/lib/typescript/src/utils/accent-generator.d.ts +103 -0
- package/lib/typescript/src/utils/accent-generator.d.ts.map +1 -0
- package/lib/typescript/src/utils/accent-utils.d.ts +15 -2
- package/lib/typescript/src/utils/accent-utils.d.ts.map +1 -1
- package/lib/typescript/src/utils/color-utils.d.ts +59 -2
- package/lib/typescript/src/utils/color-utils.d.ts.map +1 -1
- package/lib/typescript/src/utils/deep-merge.d.ts +1 -0
- package/lib/typescript/src/utils/deep-merge.d.ts.map +1 -1
- package/lib/typescript/src/utils/resolve-theme-color.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/avatar/Avatar.tsx +20 -20
- package/src/components/button/Button.tsx +11 -11
- package/src/components/chip/Chip.tsx +32 -32
- package/src/components/chip/types.ts +1 -1
- package/src/components/empty-state/EmptyState.tsx +4 -4
- package/src/components/header/variants/LargeTitleHeader/index.tsx +31 -30
- package/src/components/header/variants/TitleHeader/index.tsx +33 -22
- package/src/components/icon/Icon.tsx +4 -4
- package/src/components/page-indicator/hooks/use-page-indicator-colors.ts +2 -2
- package/src/components/screen/Screen.tsx +89 -43
- package/src/components/screen/ScreenContext.tsx +48 -28
- package/src/components/screen/ScreenFlatList.tsx +5 -191
- package/src/components/screen/ScreenList.tsx +197 -175
- package/src/components/screen/ScreenScrollView.tsx +92 -167
- package/src/components/screen/hooks/use-screen-ref.ts +24 -0
- package/src/components/screen/hooks/use-screen-scroll-handler.ts +31 -0
- package/src/components/screen/index.ts +8 -2
- package/src/components/screen/parts/ScreenFrame.tsx +49 -0
- package/src/components/screen/parts/ScreenHeaderAppearance.tsx +52 -0
- package/src/components/screen/parts/ScreenPlaceholder.tsx +16 -16
- package/src/components/screen/parts/ScreenSafeArea.android.tsx +22 -0
- package/src/components/screen/parts/ScreenSafeArea.tsx +20 -0
- package/src/components/screen/types.ts +29 -32
- package/src/components/screen/utils.ts +24 -11
- package/src/components/spinner/Spinner.tsx +2 -2
- package/src/components/text/Text.tsx +2 -2
- package/src/components/toast/Toast.tsx +13 -13
- package/src/components/toolbar/Toolbar.tsx +4 -4
- package/src/context/ThemeProvider.tsx +47 -51
- package/src/context/index.ts +1 -1
- package/src/theme/breakpoints.ts +1 -1
- package/src/theme/define-config.ts +27 -0
- package/src/theme/diagnostics.ts +11 -0
- package/src/theme/errors.ts +14 -0
- package/src/theme/index.ts +40 -1
- package/src/theme/legacy-tokens.ts +227 -0
- package/src/theme/registry.ts +119 -137
- package/src/theme/resolve-config.ts +406 -0
- package/src/theme/runtime.ts +52 -14
- package/src/theme/screen-margin.ts +6 -25
- package/src/theme/screen-padding.ts +26 -0
- package/src/theme/selection-store.ts +76 -0
- package/src/theme/theme.ts +104 -39
- package/src/theme/tokens/canonical-color-keys.ts +107 -0
- package/src/theme/tokens/dark.ts +91 -98
- package/src/theme/tokens/light.ts +88 -93
- package/src/theme/tokens/primitives.ts +14 -14
- package/src/theme/tokens/validate.ts +271 -0
- package/src/theme/types.ts +184 -95
- package/src/theme/unistyles-adapter.ts +75 -0
- package/src/utils/accent-generator.ts +530 -0
- package/src/utils/accent-utils.ts +66 -39
- package/src/utils/color-utils.ts +225 -8
- package/src/utils/deep-merge.ts +1 -1
- package/src/utils/resolve-theme-color.ts +2 -2
- package/lib/module/components/screen/parts/BottomSafeArea.js +0 -62
- package/lib/module/components/screen/parts/BottomSafeArea.js.map +0 -1
- package/lib/typescript/src/components/screen/parts/BottomSafeArea.d.ts +0 -30
- package/lib/typescript/src/components/screen/parts/BottomSafeArea.d.ts.map +0 -1
- package/src/components/screen/parts/BottomSafeArea.tsx +0 -59
|
@@ -1,18 +1,31 @@
|
|
|
1
1
|
import { type ComponentType, createElement, isValidElement, type ReactElement } from "react";
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { ScreenContentPadding, ScreenSafeArea, ScreenSafeAreaEdges } from "./types";
|
|
4
4
|
|
|
5
|
-
export type
|
|
5
|
+
export type ListComponent = ComponentType | ReactElement | null | undefined;
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
export function
|
|
9
|
-
if (!
|
|
10
|
-
if (isValidElement(
|
|
11
|
-
return createElement(
|
|
7
|
+
/** Resolves a list header, footer, or empty component to an element. */
|
|
8
|
+
export function renderListComponent(ListComponent: ListComponent): ReactElement | null {
|
|
9
|
+
if (!ListComponent) return null;
|
|
10
|
+
if (isValidElement(ListComponent)) return ListComponent;
|
|
11
|
+
return createElement(ListComponent);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/** Whether `
|
|
15
|
-
export const
|
|
14
|
+
/** Whether `padding` pads the horizontal axis. */
|
|
15
|
+
export const hasHorizontalPadding = (padding: ScreenContentPadding): boolean =>
|
|
16
|
+
padding === "all" || padding === "x";
|
|
16
17
|
|
|
17
|
-
/** Whether `
|
|
18
|
-
export const
|
|
18
|
+
/** Whether `padding` pads the vertical axis (top and bottom). */
|
|
19
|
+
export const hasVerticalPadding = (padding: ScreenContentPadding): boolean =>
|
|
20
|
+
padding === "all" || padding === "y";
|
|
21
|
+
|
|
22
|
+
export function resolveSafeAreaEdges(safeArea: ScreenSafeArea): ScreenSafeAreaEdges {
|
|
23
|
+
const includes = (edge: keyof ScreenSafeAreaEdges) =>
|
|
24
|
+
safeArea === "auto" || (safeArea !== "none" && safeArea.includes(edge));
|
|
25
|
+
return {
|
|
26
|
+
top: includes("top"),
|
|
27
|
+
bottom: includes("bottom"),
|
|
28
|
+
left: includes("left"),
|
|
29
|
+
right: includes("right"),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -70,14 +70,14 @@ const SpinnerIcon = memo(function SpinnerIcon({ size, color, gradientId1, gradie
|
|
|
70
70
|
* <Spinner size="md" color="content.accent" />
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
|
-
export function Spinner({ size = "md", color = "text
|
|
73
|
+
export function Spinner({ size = "md", color = "accent.text" }: SpinnerProps) {
|
|
74
74
|
const { theme } = useUnistyles();
|
|
75
75
|
const id = useId();
|
|
76
76
|
const gradientId1 = `spinner-def-1-${id}`;
|
|
77
77
|
const gradientId2 = `spinner-def-2-${id}`;
|
|
78
78
|
const resolvedColor =
|
|
79
79
|
resolveThemeColor(color, theme) ??
|
|
80
|
-
(theme.color as unknown as Record<string, string | undefined>)["text
|
|
80
|
+
(theme.color as unknown as Record<string, string | undefined>)["accent.text"] ??
|
|
81
81
|
"";
|
|
82
82
|
|
|
83
83
|
const dim = DIMENSION[size];
|
|
@@ -34,7 +34,7 @@ function resolveTextVariant(variant: TextVariant): RoleTextVariant {
|
|
|
34
34
|
export interface TextProps extends RNTextProps {
|
|
35
35
|
/** Typographic role. Defaults to `body-md`. */
|
|
36
36
|
variant?: TextVariant;
|
|
37
|
-
/** Semantic color token (e.g. `
|
|
37
|
+
/** Semantic color token (e.g. `text.secondary`, `danger.soft.fg`). */
|
|
38
38
|
color?: ColorToken;
|
|
39
39
|
/** Override the variant's default weight. */
|
|
40
40
|
weight?: FontWeightToken;
|
|
@@ -85,7 +85,7 @@ export const Text = forwardRef<ComponentRef<typeof RNText>, TextProps>(function
|
|
|
85
85
|
letterSpacing: v.letterSpacing,
|
|
86
86
|
color:
|
|
87
87
|
resolveThemeColor(color, theme) ??
|
|
88
|
-
(theme.color as unknown as Record<string, string | undefined>)["text.
|
|
88
|
+
(theme.color as unknown as Record<string, string | undefined>)["text.primary"] ??
|
|
89
89
|
"",
|
|
90
90
|
};
|
|
91
91
|
// System font: apply numeric weight. Custom font: family encodes the weight.
|
|
@@ -62,17 +62,17 @@ function getToastColors(variant: ToastVariant, theme: TerraTheme): ToastColors {
|
|
|
62
62
|
const base = {
|
|
63
63
|
bg: get("surface.default"),
|
|
64
64
|
border: get("border.subtle"),
|
|
65
|
-
description: get("text.
|
|
65
|
+
description: get("text.secondary"),
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
switch (variant) {
|
|
69
69
|
case "accent":
|
|
70
70
|
return {
|
|
71
71
|
...base,
|
|
72
|
-
title: get("
|
|
73
|
-
icon: get("text
|
|
74
|
-
actionBg: get("
|
|
75
|
-
actionFg: get("
|
|
72
|
+
title: get("accent.text"),
|
|
73
|
+
icon: get("accent.text"),
|
|
74
|
+
actionBg: get("accent.solid.bg"),
|
|
75
|
+
actionFg: get("accent.solid.fg"),
|
|
76
76
|
};
|
|
77
77
|
case "info":
|
|
78
78
|
case "success":
|
|
@@ -80,18 +80,18 @@ function getToastColors(variant: ToastVariant, theme: TerraTheme): ToastColors {
|
|
|
80
80
|
case "danger":
|
|
81
81
|
return {
|
|
82
82
|
...base,
|
|
83
|
-
title: get(
|
|
84
|
-
icon: get(
|
|
85
|
-
actionBg: get(
|
|
86
|
-
actionFg: get(
|
|
83
|
+
title: get(`${variant}.text`),
|
|
84
|
+
icon: get(`${variant}.text`),
|
|
85
|
+
actionBg: get(`${variant}.solid.bg`),
|
|
86
|
+
actionFg: get(`${variant}.solid.fg`),
|
|
87
87
|
};
|
|
88
88
|
case "default":
|
|
89
89
|
return {
|
|
90
90
|
...base,
|
|
91
|
-
title: get("text.
|
|
92
|
-
icon: get("text.
|
|
93
|
-
actionBg: get("
|
|
94
|
-
actionFg: get("
|
|
91
|
+
title: get("text.primary"),
|
|
92
|
+
icon: get("text.tertiary"),
|
|
93
|
+
actionBg: get("neutral.solid.bg"),
|
|
94
|
+
actionFg: get("neutral.solid.fg"),
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
97
|
}
|
|
@@ -39,7 +39,7 @@ interface ToolbarGroupContextValue {
|
|
|
39
39
|
/** Non-null default, so a bare `Toolbar.Button` still paints its own circle. */
|
|
40
40
|
const ToolbarGroupContext = createContext<ToolbarGroupContextValue>({
|
|
41
41
|
background: "surface.default",
|
|
42
|
-
tint: "text.
|
|
42
|
+
tint: "text.primary",
|
|
43
43
|
isGrouped: false,
|
|
44
44
|
});
|
|
45
45
|
|
|
@@ -94,7 +94,7 @@ interface ToolbarButtonBaseProps extends Omit<PressableProps, "children" | "styl
|
|
|
94
94
|
iconSize?: number;
|
|
95
95
|
/**
|
|
96
96
|
* Foreground token for the icon and label. Defaults to the group's `tint`,
|
|
97
|
-
* or `text.
|
|
97
|
+
* or `text.primary` outside a group.
|
|
98
98
|
*/
|
|
99
99
|
tint?: ColorToken;
|
|
100
100
|
/**
|
|
@@ -220,7 +220,7 @@ export interface ToolbarGroupProps extends ViewProps {
|
|
|
220
220
|
background?: ColorToken;
|
|
221
221
|
/**
|
|
222
222
|
* Foreground token inherited by every item's icon and label. Defaults to
|
|
223
|
-
* `text.
|
|
223
|
+
* `text.primary`; a per-item `tint` still wins.
|
|
224
224
|
*/
|
|
225
225
|
tint?: ColorToken;
|
|
226
226
|
|
|
@@ -244,7 +244,7 @@ export interface ToolbarGroupProps extends ViewProps {
|
|
|
244
244
|
* ```
|
|
245
245
|
*/
|
|
246
246
|
export const ToolbarGroup = forwardRef<ComponentRef<typeof View>, ToolbarGroupProps>(function ToolbarGroup(
|
|
247
|
-
{ background = "surface.default", tint = "text.
|
|
247
|
+
{ background = "surface.default", tint = "text.primary", children, style, ...rest },
|
|
248
248
|
ref
|
|
249
249
|
) {
|
|
250
250
|
const context = useMemo<ToolbarGroupContextValue>(
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type PropsWithChildren, useSyncExternalStore } from "react";
|
|
2
2
|
|
|
3
3
|
import { SafeAreaProvider } from "react-native-safe-area-context";
|
|
4
4
|
import { useUnistyles } from "react-native-unistyles";
|
|
5
5
|
|
|
6
6
|
import { bootstrapTerraUI } from "../theme/registry";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
import {
|
|
8
|
+
applyAccent,
|
|
9
|
+
applyScheme,
|
|
10
|
+
getThemeSelection,
|
|
11
|
+
setThemeMode,
|
|
12
|
+
subscribeThemeSelection,
|
|
13
|
+
} from "../theme/runtime";
|
|
14
|
+
import { type ResolvedScreenPadding, resolveScreenPadding } from "../theme/screen-padding";
|
|
15
|
+
import type { Scheme, TerraTheme, ThemeMode } from "../theme/types";
|
|
10
16
|
|
|
11
17
|
// Ensure the default theme is registered on first import. An app that calls
|
|
12
18
|
// `configureTerraUI` itself still wins, whichever module the bundler evaluates
|
|
13
19
|
// first — see the note on `bootstrapTerraUI`.
|
|
14
20
|
bootstrapTerraUI();
|
|
15
21
|
|
|
16
|
-
interface ThemeContextValue {
|
|
17
|
-
accent: string | undefined;
|
|
18
|
-
setAccent: (name: string) => void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const ThemeContext = createContext<ThemeContextValue | null>(null);
|
|
22
|
-
|
|
23
22
|
/**
|
|
24
23
|
* Root provider for Terra UI. Wrap your app once near the root.
|
|
25
24
|
*
|
|
@@ -28,70 +27,67 @@ const ThemeContext = createContext<ThemeContextValue | null>(null);
|
|
|
28
27
|
* <RootNavigator />
|
|
29
28
|
* </TerraUIProvider>
|
|
30
29
|
*/
|
|
31
|
-
export const TerraUIProvider = ({ children }: PropsWithChildren) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const setAccent = useCallback((name: string) => {
|
|
35
|
-
applyAccent(name);
|
|
36
|
-
setAccentState(name);
|
|
37
|
-
}, []);
|
|
38
|
-
|
|
39
|
-
const value = useMemo<ThemeContextValue>(() => ({ accent, setAccent }), [accent, setAccent]);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<ThemeContext.Provider value={value}>
|
|
43
|
-
<SafeAreaProvider>{children}</SafeAreaProvider>
|
|
44
|
-
</ThemeContext.Provider>
|
|
45
|
-
);
|
|
46
|
-
};
|
|
30
|
+
export const TerraUIProvider = ({ children }: PropsWithChildren) => (
|
|
31
|
+
<SafeAreaProvider>{children}</SafeAreaProvider>
|
|
32
|
+
);
|
|
47
33
|
|
|
48
34
|
export interface UseThemeResult {
|
|
49
35
|
/** The active resolved theme. */
|
|
50
36
|
theme: TerraTheme;
|
|
51
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* The currently resolved color scheme — what Unistyles is rendering right
|
|
39
|
+
* now. Under `mode: "system"` this follows the OS appearance.
|
|
40
|
+
*/
|
|
52
41
|
scheme: Scheme;
|
|
53
|
-
/**
|
|
42
|
+
/** Pin a scheme (stops following the system). Same as `setMode(scheme)`. */
|
|
54
43
|
setScheme: (scheme: Scheme) => void;
|
|
55
|
-
/**
|
|
44
|
+
/** Applied accent name, or `undefined` for the base themes. */
|
|
56
45
|
accent: string | undefined;
|
|
57
|
-
/**
|
|
58
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Apply a registered accent; `null` restores the base themes. An unknown
|
|
48
|
+
* name warns in development and leaves the accent unchanged.
|
|
49
|
+
*/
|
|
50
|
+
setAccent: (name: string | null) => void;
|
|
51
|
+
/**
|
|
52
|
+
* How the active scheme is chosen: `system` follows the OS appearance,
|
|
53
|
+
* `light` / `dark` pin a scheme. A system appearance change updates
|
|
54
|
+
* `scheme`, never `mode`.
|
|
55
|
+
*/
|
|
56
|
+
mode: ThemeMode;
|
|
57
|
+
/** Change the theme mode; `setMode("system")` returns to the OS preference. */
|
|
58
|
+
setMode: (mode: ThemeMode) => void;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Access the active theme and switch scheme /
|
|
63
|
-
*
|
|
62
|
+
* Access the active theme and switch scheme / mode / accent. Selection state
|
|
63
|
+
* comes from the runtime store, so changes made imperatively (`applyAccent`,
|
|
64
|
+
* `setThemeMode`) and through this hook are observed by every consumer.
|
|
64
65
|
*/
|
|
65
66
|
export function useTheme(): UseThemeResult {
|
|
66
67
|
const { theme, rt } = useUnistyles();
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const setScheme = useCallback((scheme: Scheme) => {
|
|
70
|
-
applyScheme(scheme);
|
|
71
|
-
}, []);
|
|
68
|
+
const selection = useSyncExternalStore(subscribeThemeSelection, getThemeSelection, getThemeSelection);
|
|
72
69
|
|
|
73
70
|
return {
|
|
74
71
|
theme,
|
|
75
72
|
scheme: (rt.themeName ?? "light") as Scheme,
|
|
76
|
-
setScheme,
|
|
77
|
-
accent:
|
|
78
|
-
setAccent:
|
|
73
|
+
setScheme: applyScheme,
|
|
74
|
+
accent: selection.accent,
|
|
75
|
+
setAccent: applyAccent,
|
|
76
|
+
mode: selection.mode,
|
|
77
|
+
setMode: setThemeMode,
|
|
79
78
|
};
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
/**
|
|
83
|
-
* Resolves `theme.layout.screen.
|
|
82
|
+
* Resolves `theme.layout.screen.padding` for the current runtime breakpoint.
|
|
84
83
|
* For use outside a `StyleSheet.create` factory (e.g. plain-JS layout maths);
|
|
85
|
-
* inside one, call `
|
|
84
|
+
* inside one, call `resolveScreenPadding(theme, rt.breakpoint)` directly so
|
|
86
85
|
* the value stays reactive without a React re-render.
|
|
87
86
|
*/
|
|
88
|
-
export function
|
|
87
|
+
export function useScreenPadding(): ResolvedScreenPadding {
|
|
89
88
|
const { theme, rt } = useUnistyles();
|
|
90
|
-
return
|
|
89
|
+
return resolveScreenPadding(theme, rt.breakpoint);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
console.warn("[react-native-terra-ui] setAccent called outside <TerraUIProvider>.");
|
|
96
|
-
}
|
|
97
|
-
};
|
|
92
|
+
/** @deprecated Use useScreenPadding. */
|
|
93
|
+
export const useScreenMargin = useScreenPadding;
|
package/src/context/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { UseThemeResult } from "./ThemeProvider";
|
|
2
|
-
export { TerraUIProvider, useScreenMargin, useTheme } from "./ThemeProvider";
|
|
2
|
+
export { TerraUIProvider, useScreenMargin, useScreenPadding, useTheme } from "./ThemeProvider";
|
package/src/theme/breakpoints.ts
CHANGED
|
@@ -21,7 +21,7 @@ declare module "react-native-unistyles" {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Resolves a per-breakpoint record (e.g. `theme.layout.screen.
|
|
24
|
+
* Resolves a per-breakpoint record (e.g. `theme.layout.screen.padding.x`) to
|
|
25
25
|
* the value for the current runtime breakpoint (`rt.breakpoint`). A
|
|
26
26
|
* `StyleSheet.create` factory re-runs on breakpoint change, so calling this
|
|
27
27
|
* inside one keeps the resolved value reactive.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TerraConfig } from "./types";
|
|
2
|
+
|
|
3
|
+
/** The literal accent names declared in `T.accents`, or `never` when none are declared. */
|
|
4
|
+
type DeclaredAccentNames<T> = T extends { accents: infer A }
|
|
5
|
+
? A extends Record<string, unknown>
|
|
6
|
+
? keyof A & string
|
|
7
|
+
: never
|
|
8
|
+
: never;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Identity helper for authoring a {@link TerraConfig} with contextual typing.
|
|
12
|
+
* Has no side effects. With literal `accents`, `defaultAccent` must name one of
|
|
13
|
+
* them; a dynamic `Record<string, Accent>` keeps `defaultAccent` as `string`
|
|
14
|
+
* and defers to runtime validation.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const config = defineTerraConfig({
|
|
18
|
+
* accents: { indigo: { light: "#4f46e5", dark: "#818cf8" } },
|
|
19
|
+
* defaultAccent: "indigo",
|
|
20
|
+
* });
|
|
21
|
+
* configureTerraUI(config);
|
|
22
|
+
*/
|
|
23
|
+
export function defineTerraConfig<const T extends TerraConfig>(
|
|
24
|
+
config: T & { defaultAccent?: DeclaredAccentNames<T> }
|
|
25
|
+
): T {
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ContrastDiagnostic } from "#utils/accent-generator";
|
|
2
|
+
|
|
3
|
+
/** Reports each distinct contrast diagnostic once per resolution. */
|
|
4
|
+
export function warnContrastDiagnostics(diagnostics: readonly ContrastDiagnostic[]): void {
|
|
5
|
+
if (typeof __DEV__ === "undefined" || !__DEV__ || diagnostics.length === 0) return;
|
|
6
|
+
|
|
7
|
+
const messages = new Set(diagnostics.map(({ message }) => message));
|
|
8
|
+
for (const message of messages) {
|
|
9
|
+
console.warn(`[react-native-terra-ui] ${message}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown for invalid pure configuration input — before any registry, selection,
|
|
3
|
+
* or native state is touched. `path` points at the offending config entry, e.g.
|
|
4
|
+
* `accents.indigo.dark.seed` or `defaultAccent`.
|
|
5
|
+
*/
|
|
6
|
+
export class TerraConfigError extends Error {
|
|
7
|
+
readonly path: string;
|
|
8
|
+
|
|
9
|
+
constructor(path: string, message: string) {
|
|
10
|
+
super(`[react-native-terra-ui] Invalid config at "${path}": ${message}`);
|
|
11
|
+
this.name = "TerraConfigError";
|
|
12
|
+
this.path = path;
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/theme/index.ts
CHANGED
|
@@ -6,6 +6,19 @@
|
|
|
6
6
|
// resolved `defaultLightTheme` / `defaultDarkTheme` are the public surface.
|
|
7
7
|
|
|
8
8
|
// ─── Utilities (color resolution + accent/merge/typography helpers) ──────────
|
|
9
|
+
export type {
|
|
10
|
+
AccentGenerationContext,
|
|
11
|
+
AccentGenerationResult,
|
|
12
|
+
AccentSurfaceRole,
|
|
13
|
+
ContrastDiagnostic,
|
|
14
|
+
ContrastDiagnosticKind,
|
|
15
|
+
GeneratedAccentRole,
|
|
16
|
+
} from "#utils/accent-generator";
|
|
17
|
+
export {
|
|
18
|
+
checkAccentContrast,
|
|
19
|
+
generateAccentColors,
|
|
20
|
+
isSupportedAccentSeed,
|
|
21
|
+
} from "#utils/accent-generator";
|
|
9
22
|
export { normalizeAccent } from "#utils/accent-utils";
|
|
10
23
|
export { readableOn, shade, withAlpha } from "#utils/color-utils";
|
|
11
24
|
export type { DeepPartial } from "#utils/deep-merge";
|
|
@@ -16,6 +29,8 @@ export { FONT_WEIGHT_VALUE, SYSTEM_FONT } from "#utils/typography";
|
|
|
16
29
|
export type { AppBreakpoints, BreakpointName } from "./breakpoints";
|
|
17
30
|
export { breakpoints, resolveBreakpointValue } from "./breakpoints";
|
|
18
31
|
// ─── Config + runtime ───────────────────────────────────────────────────────
|
|
32
|
+
export { defineTerraConfig } from "./define-config";
|
|
33
|
+
export { TerraConfigError } from "./errors";
|
|
19
34
|
export {
|
|
20
35
|
configureTerraUI,
|
|
21
36
|
getAccentNames,
|
|
@@ -27,38 +42,59 @@ export {
|
|
|
27
42
|
getSurfaceElevation,
|
|
28
43
|
resolveTheme,
|
|
29
44
|
} from "./registry";
|
|
30
|
-
export {
|
|
45
|
+
export { createTerraThemes } from "./resolve-config";
|
|
46
|
+
export type { ThemeSelection } from "./runtime";
|
|
47
|
+
export {
|
|
48
|
+
applyAccent,
|
|
49
|
+
applyScheme,
|
|
50
|
+
getCurrentAccent,
|
|
51
|
+
getThemeMode,
|
|
52
|
+
getThemeSelection,
|
|
53
|
+
setThemeMode,
|
|
54
|
+
} from "./runtime";
|
|
31
55
|
export type { ResolvedScreenMargin } from "./screen-margin";
|
|
32
56
|
export { resolveScreenMargin } from "./screen-margin";
|
|
57
|
+
export type { ResolvedScreenPadding } from "./screen-padding";
|
|
58
|
+
export { resolveScreenPadding } from "./screen-padding";
|
|
33
59
|
// ─── Default themes ───────────────────────────────────────────────────────────
|
|
34
60
|
export { defaultDarkTheme, defaultLightTheme } from "./theme";
|
|
35
61
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
36
62
|
export type {
|
|
37
63
|
Accent,
|
|
64
|
+
AccentColorToken,
|
|
38
65
|
AccentOverride,
|
|
66
|
+
AccentSchemeInput,
|
|
67
|
+
AccentSeed,
|
|
39
68
|
AccentShorthand,
|
|
40
69
|
ActionColorToken,
|
|
41
70
|
BackgroundColorToken,
|
|
42
71
|
BorderColorToken,
|
|
43
72
|
ButtonDefaults,
|
|
73
|
+
CanonicalThemeColor,
|
|
44
74
|
ColorToken,
|
|
45
75
|
ComponentDefaults,
|
|
46
76
|
ContentColorToken,
|
|
77
|
+
CreateTerraThemesOptions,
|
|
47
78
|
DefaultRadiusToken,
|
|
48
79
|
ElevationKey,
|
|
49
80
|
ElevationScale,
|
|
50
81
|
ElevationStyle,
|
|
51
82
|
FontWeightToken,
|
|
52
83
|
LayoutTokens,
|
|
84
|
+
NeutralColorToken,
|
|
53
85
|
OpacityTokens,
|
|
54
86
|
RadiusComponent,
|
|
55
87
|
RadiusKey,
|
|
56
88
|
Scheme,
|
|
89
|
+
ScreenPaddingTokens,
|
|
57
90
|
SpacingKey,
|
|
58
91
|
StatusColorToken,
|
|
59
92
|
SurfaceColorToken,
|
|
60
93
|
SurfaceDefaults,
|
|
94
|
+
TerraColorRegistry,
|
|
95
|
+
TerraColorRegistryCollision,
|
|
61
96
|
TerraConfig,
|
|
97
|
+
TerraCustomColorName,
|
|
62
98
|
TerraIconComponent,
|
|
63
99
|
TerraIconName,
|
|
64
100
|
TerraIconProps,
|
|
@@ -67,11 +103,14 @@ export type {
|
|
|
67
103
|
TerraImageProps,
|
|
68
104
|
TerraSemanticIconName,
|
|
69
105
|
TerraTheme,
|
|
106
|
+
TerraThemeInput,
|
|
70
107
|
TerraThemeOverride,
|
|
71
108
|
TextColorToken,
|
|
72
109
|
TextVariant,
|
|
73
110
|
ThemeColor,
|
|
111
|
+
ThemeMode,
|
|
74
112
|
ThemeRadiusOverride,
|
|
113
|
+
ThemeSpacingOverride,
|
|
75
114
|
TypeStyle,
|
|
76
115
|
Typography,
|
|
77
116
|
} from "./types";
|