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
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { deepMerge } from "#utils/deep-merge";
|
|
2
|
+
import type { CanonicalThemeColor, TerraTheme, TerraThemeOverride } from "./types";
|
|
3
|
+
|
|
4
|
+
/** Legacy color names. Explicit action/status-property aliases come first to resolve synonyms. */
|
|
5
|
+
export const legacyColorAliases = {
|
|
6
|
+
"action.bg.primary": "accent.solid.bg",
|
|
7
|
+
"action.bg.primary.active": "accent.solid.bg.pressed",
|
|
8
|
+
"action.bg.primary.disabled": "accent.solid.bg.disabled",
|
|
9
|
+
"action.bg.primary.hover": "accent.solid.bg.hover",
|
|
10
|
+
"action.bg.primary.subtle": "accent.soft.bg",
|
|
11
|
+
"action.bg.primary.subtle.active": "accent.soft.bg.pressed",
|
|
12
|
+
"action.bg.primary.subtle.disabled": "accent.soft.bg.disabled",
|
|
13
|
+
"action.bg.primary.subtle.hover": "accent.soft.bg.hover",
|
|
14
|
+
"action.bg.secondary": "neutral.solid.bg",
|
|
15
|
+
"action.bg.secondary.subtle": "neutral.soft.bg",
|
|
16
|
+
"action.bg.secondary.subtle.active": "neutral.soft.bg.pressed",
|
|
17
|
+
"action.bg.secondary.subtle.disabled": "neutral.soft.bg.disabled",
|
|
18
|
+
"action.bg.secondary.subtle.hover": "neutral.soft.bg.hover",
|
|
19
|
+
"action.fg.primary": "accent.solid.fg",
|
|
20
|
+
"action.fg.primary.subtle": "accent.soft.fg",
|
|
21
|
+
"action.fg.secondary": "neutral.solid.fg",
|
|
22
|
+
"action.fg.secondary.subtle": "neutral.soft.fg",
|
|
23
|
+
"status.danger.bg": "danger.solid.bg",
|
|
24
|
+
"status.danger.bg.subtle": "danger.soft.bg",
|
|
25
|
+
"status.danger.border": "danger.solid.border",
|
|
26
|
+
"status.danger.border.subtle": "danger.soft.border",
|
|
27
|
+
"status.danger.fg": "danger.solid.fg",
|
|
28
|
+
"status.danger.fg.subtle": "danger.soft.fg",
|
|
29
|
+
"status.info.bg": "info.solid.bg",
|
|
30
|
+
"status.info.bg.subtle": "info.soft.bg",
|
|
31
|
+
"status.info.border": "info.solid.border",
|
|
32
|
+
"status.info.border.subtle": "info.soft.border",
|
|
33
|
+
"status.info.fg": "info.solid.fg",
|
|
34
|
+
"status.info.fg.subtle": "info.soft.fg",
|
|
35
|
+
"status.success.bg": "success.solid.bg",
|
|
36
|
+
"status.success.bg.subtle": "success.soft.bg",
|
|
37
|
+
"status.success.border": "success.solid.border",
|
|
38
|
+
"status.success.border.subtle": "success.soft.border",
|
|
39
|
+
"status.success.fg": "success.solid.fg",
|
|
40
|
+
"status.success.fg.subtle": "success.soft.fg",
|
|
41
|
+
"status.warning.bg": "warning.solid.bg",
|
|
42
|
+
"status.warning.bg.subtle": "warning.soft.bg",
|
|
43
|
+
"status.warning.border": "warning.solid.border",
|
|
44
|
+
"status.warning.border.subtle": "warning.soft.border",
|
|
45
|
+
"status.warning.fg": "warning.solid.fg",
|
|
46
|
+
"status.warning.fg.subtle": "warning.soft.fg",
|
|
47
|
+
"background": "surface.canvas",
|
|
48
|
+
"border.accent": "accent.border",
|
|
49
|
+
"border.focus": "focus.ring",
|
|
50
|
+
"status.danger": "danger.solid.bg",
|
|
51
|
+
"status.info": "info.solid.bg",
|
|
52
|
+
"status.success": "success.solid.bg",
|
|
53
|
+
"status.warning": "warning.solid.bg",
|
|
54
|
+
"surface.accent": "accent.solid.bg",
|
|
55
|
+
"surface.accent.subtle": "accent.soft.bg",
|
|
56
|
+
"surface.overlay": "backdrop",
|
|
57
|
+
"text.accent": "accent.text",
|
|
58
|
+
"text.default": "text.primary",
|
|
59
|
+
"text.muted": "text.secondary",
|
|
60
|
+
"text.on-accent": "accent.solid.fg",
|
|
61
|
+
"text.on-accent-subtle": "accent.soft.fg",
|
|
62
|
+
"text.subtle": "text.tertiary",
|
|
63
|
+
} as const satisfies Record<keyof LegacyThemeColor, keyof CanonicalThemeColor>;
|
|
64
|
+
|
|
65
|
+
export interface LegacyThemeColor {
|
|
66
|
+
/** @deprecated Use `accent.solid.bg`. */
|
|
67
|
+
"action.bg.primary": string;
|
|
68
|
+
/** @deprecated Use `accent.solid.bg.pressed`. */
|
|
69
|
+
"action.bg.primary.active": string;
|
|
70
|
+
/** @deprecated Use `accent.solid.bg.disabled`. */
|
|
71
|
+
"action.bg.primary.disabled": string;
|
|
72
|
+
/** @deprecated Use `accent.solid.bg.hover`. */
|
|
73
|
+
"action.bg.primary.hover": string;
|
|
74
|
+
/** @deprecated Use `accent.soft.bg`. */
|
|
75
|
+
"action.bg.primary.subtle": string;
|
|
76
|
+
/** @deprecated Use `accent.soft.bg.pressed`. */
|
|
77
|
+
"action.bg.primary.subtle.active": string;
|
|
78
|
+
/** @deprecated Use `accent.soft.bg.disabled`. */
|
|
79
|
+
"action.bg.primary.subtle.disabled": string;
|
|
80
|
+
/** @deprecated Use `accent.soft.bg.hover`. */
|
|
81
|
+
"action.bg.primary.subtle.hover": string;
|
|
82
|
+
/** @deprecated Use `neutral.solid.bg`. */
|
|
83
|
+
"action.bg.secondary": string;
|
|
84
|
+
/** @deprecated Use `neutral.soft.bg`. */
|
|
85
|
+
"action.bg.secondary.subtle": string;
|
|
86
|
+
/** @deprecated Use `neutral.soft.bg.pressed`. */
|
|
87
|
+
"action.bg.secondary.subtle.active": string;
|
|
88
|
+
/** @deprecated Use `neutral.soft.bg.disabled`. */
|
|
89
|
+
"action.bg.secondary.subtle.disabled": string;
|
|
90
|
+
/** @deprecated Use `neutral.soft.bg.hover`. */
|
|
91
|
+
"action.bg.secondary.subtle.hover": string;
|
|
92
|
+
/** @deprecated Use `accent.solid.fg`. */
|
|
93
|
+
"action.fg.primary": string;
|
|
94
|
+
/** @deprecated Use `accent.soft.fg`. */
|
|
95
|
+
"action.fg.primary.subtle": string;
|
|
96
|
+
/** @deprecated Use `neutral.solid.fg`. */
|
|
97
|
+
"action.fg.secondary": string;
|
|
98
|
+
/** @deprecated Use `neutral.soft.fg`. */
|
|
99
|
+
"action.fg.secondary.subtle": string;
|
|
100
|
+
/** @deprecated Use `danger.solid.bg`. */
|
|
101
|
+
"status.danger.bg": string;
|
|
102
|
+
/** @deprecated Use `danger.soft.bg`. */
|
|
103
|
+
"status.danger.bg.subtle": string;
|
|
104
|
+
/** @deprecated Use `danger.solid.border`. */
|
|
105
|
+
"status.danger.border": string;
|
|
106
|
+
/** @deprecated Use `danger.soft.border`. */
|
|
107
|
+
"status.danger.border.subtle": string;
|
|
108
|
+
/** @deprecated Use `danger.solid.fg`. */
|
|
109
|
+
"status.danger.fg": string;
|
|
110
|
+
/** @deprecated Use `danger.soft.fg`. */
|
|
111
|
+
"status.danger.fg.subtle": string;
|
|
112
|
+
/** @deprecated Use `info.solid.bg`. */
|
|
113
|
+
"status.info.bg": string;
|
|
114
|
+
/** @deprecated Use `info.soft.bg`. */
|
|
115
|
+
"status.info.bg.subtle": string;
|
|
116
|
+
/** @deprecated Use `info.solid.border`. */
|
|
117
|
+
"status.info.border": string;
|
|
118
|
+
/** @deprecated Use `info.soft.border`. */
|
|
119
|
+
"status.info.border.subtle": string;
|
|
120
|
+
/** @deprecated Use `info.solid.fg`. */
|
|
121
|
+
"status.info.fg": string;
|
|
122
|
+
/** @deprecated Use `info.soft.fg`. */
|
|
123
|
+
"status.info.fg.subtle": string;
|
|
124
|
+
/** @deprecated Use `success.solid.bg`. */
|
|
125
|
+
"status.success.bg": string;
|
|
126
|
+
/** @deprecated Use `success.soft.bg`. */
|
|
127
|
+
"status.success.bg.subtle": string;
|
|
128
|
+
/** @deprecated Use `success.solid.border`. */
|
|
129
|
+
"status.success.border": string;
|
|
130
|
+
/** @deprecated Use `success.soft.border`. */
|
|
131
|
+
"status.success.border.subtle": string;
|
|
132
|
+
/** @deprecated Use `success.solid.fg`. */
|
|
133
|
+
"status.success.fg": string;
|
|
134
|
+
/** @deprecated Use `success.soft.fg`. */
|
|
135
|
+
"status.success.fg.subtle": string;
|
|
136
|
+
/** @deprecated Use `warning.solid.bg`. */
|
|
137
|
+
"status.warning.bg": string;
|
|
138
|
+
/** @deprecated Use `warning.soft.bg`. */
|
|
139
|
+
"status.warning.bg.subtle": string;
|
|
140
|
+
/** @deprecated Use `warning.solid.border`. */
|
|
141
|
+
"status.warning.border": string;
|
|
142
|
+
/** @deprecated Use `warning.soft.border`. */
|
|
143
|
+
"status.warning.border.subtle": string;
|
|
144
|
+
/** @deprecated Use `warning.solid.fg`. */
|
|
145
|
+
"status.warning.fg": string;
|
|
146
|
+
/** @deprecated Use `warning.soft.fg`. */
|
|
147
|
+
"status.warning.fg.subtle": string;
|
|
148
|
+
/** @deprecated Use `surface.canvas`. */
|
|
149
|
+
"background": string;
|
|
150
|
+
/** @deprecated Use `accent.border`. */
|
|
151
|
+
"border.accent": string;
|
|
152
|
+
/** @deprecated Use `focus.ring`. */
|
|
153
|
+
"border.focus": string;
|
|
154
|
+
/** @deprecated Use `danger.solid.bg`. */
|
|
155
|
+
"status.danger": string;
|
|
156
|
+
/** @deprecated Use `info.solid.bg`. */
|
|
157
|
+
"status.info": string;
|
|
158
|
+
/** @deprecated Use `success.solid.bg`. */
|
|
159
|
+
"status.success": string;
|
|
160
|
+
/** @deprecated Use `warning.solid.bg`. */
|
|
161
|
+
"status.warning": string;
|
|
162
|
+
/** @deprecated Use `accent.solid.bg`. */
|
|
163
|
+
"surface.accent": string;
|
|
164
|
+
/** @deprecated Use `accent.soft.bg`. */
|
|
165
|
+
"surface.accent.subtle": string;
|
|
166
|
+
/** @deprecated Use `backdrop`. */
|
|
167
|
+
"surface.overlay": string;
|
|
168
|
+
/** @deprecated Use `accent.text`. */
|
|
169
|
+
"text.accent": string;
|
|
170
|
+
/** @deprecated Use `text.primary`. */
|
|
171
|
+
"text.default": string;
|
|
172
|
+
/** @deprecated Use `text.secondary`. */
|
|
173
|
+
"text.muted": string;
|
|
174
|
+
/** @deprecated Use `accent.solid.fg`. */
|
|
175
|
+
"text.on-accent": string;
|
|
176
|
+
/** @deprecated Use `accent.soft.fg`. */
|
|
177
|
+
"text.on-accent-subtle": string;
|
|
178
|
+
/** @deprecated Use `text.tertiary`. */
|
|
179
|
+
"text.subtle": string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Normalize each authored layer before merging, so aliases respect layer precedence. */
|
|
183
|
+
export function normalizeTokenOverride(override?: TerraThemeOverride): TerraThemeOverride | undefined {
|
|
184
|
+
if (!override) return override;
|
|
185
|
+
const next = { ...override };
|
|
186
|
+
if (override.color) {
|
|
187
|
+
const color = { ...override.color };
|
|
188
|
+
for (const [legacy, canonical] of Object.entries(legacyColorAliases)) {
|
|
189
|
+
const value = override.color[legacy as keyof LegacyThemeColor];
|
|
190
|
+
if (color[canonical] === undefined && value !== undefined) color[canonical] = value;
|
|
191
|
+
delete color[legacy as keyof LegacyThemeColor];
|
|
192
|
+
}
|
|
193
|
+
next.color = color;
|
|
194
|
+
}
|
|
195
|
+
const screen = override.layout?.screen;
|
|
196
|
+
if (screen) {
|
|
197
|
+
const { margin, padding, ...rest } = screen;
|
|
198
|
+
next.layout = {
|
|
199
|
+
...override.layout,
|
|
200
|
+
screen: { ...rest, padding: deepMerge(margin ?? {}, padding) },
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return next;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Materialize aliases for direct theme reads as well as component color props. */
|
|
207
|
+
export function withLegacyTokens(
|
|
208
|
+
theme: Omit<TerraTheme, "color" | "layout"> & {
|
|
209
|
+
color: CanonicalThemeColor;
|
|
210
|
+
layout: Omit<TerraTheme["layout"], "screen"> & {
|
|
211
|
+
screen: Pick<TerraTheme["layout"]["screen"], "padding">;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
): TerraTheme {
|
|
215
|
+
const color = { ...theme.color } as TerraTheme["color"];
|
|
216
|
+
for (const [legacy, canonical] of Object.entries(legacyColorAliases)) {
|
|
217
|
+
color[legacy as keyof LegacyThemeColor] = color[canonical];
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
...theme,
|
|
221
|
+
color,
|
|
222
|
+
layout: {
|
|
223
|
+
...theme.layout,
|
|
224
|
+
screen: { ...theme.layout.screen, margin: theme.layout.screen.padding },
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
package/src/theme/registry.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Installation lifecycle: `configureTerraUI` / `bootstrapTerraUI` and the
|
|
3
|
+
* read-only getters components use (icons, image renderer, component defaults).
|
|
4
|
+
*
|
|
5
|
+
* Theme resolution lives in `resolve-config.ts`; native calls in
|
|
6
|
+
* `unistyles-adapter.ts`; the selection snapshot and installed config in
|
|
7
|
+
* `selection-store.ts`. This module orchestrates them in a fixed order:
|
|
8
|
+
* build and validate (pure, may throw) → native work → publish state.
|
|
9
|
+
*/
|
|
6
10
|
import { defaultIcons } from "./defaults/icons";
|
|
7
11
|
import { defaultImage } from "./defaults/image";
|
|
8
|
-
import {
|
|
12
|
+
import { warnContrastDiagnostics } from "./diagnostics";
|
|
13
|
+
import { normalizeThemeInput, resolveThemeScheme, resolveThemes } from "./resolve-config";
|
|
14
|
+
import { getInstalledConfig, publishThemeSelection, setInstalledConfig } from "./selection-store";
|
|
9
15
|
import type {
|
|
10
16
|
ComponentDefaults,
|
|
11
17
|
DefaultRadiusToken,
|
|
12
18
|
ElevationKey,
|
|
13
|
-
NormalizedAccent,
|
|
14
19
|
RadiusComponent,
|
|
15
20
|
Scheme,
|
|
16
21
|
TerraConfig,
|
|
@@ -18,8 +23,10 @@ import type {
|
|
|
18
23
|
TerraImageComponent,
|
|
19
24
|
TerraSemanticIconName,
|
|
20
25
|
TerraTheme,
|
|
21
|
-
|
|
26
|
+
TerraThemeInput,
|
|
27
|
+
ThemeMode,
|
|
22
28
|
} from "./types";
|
|
29
|
+
import { applyMode, configureUnistyles, hasConfiguredUnistyles, updateThemes } from "./unistyles-adapter";
|
|
23
30
|
|
|
24
31
|
// ─── Radius / elevation defaults ─────────────────────────────────────────────
|
|
25
32
|
|
|
@@ -28,7 +35,7 @@ const DEFAULT_RADIUS: DefaultRadiusToken = "md";
|
|
|
28
35
|
/** Fallback when the surface elevation is not configured. */
|
|
29
36
|
const DEFAULT_ELEVATION: ElevationKey = "none";
|
|
30
37
|
|
|
31
|
-
type ResolvedRadius = Record<RadiusComponent, DefaultRadiusToken
|
|
38
|
+
type ResolvedRadius = Readonly<Record<RadiusComponent, DefaultRadiusToken>>;
|
|
32
39
|
|
|
33
40
|
/** Resolves each component's default radius from the `components` config. */
|
|
34
41
|
const resolveDefaultRadius = (components?: ComponentDefaults): ResolvedRadius => ({
|
|
@@ -44,111 +51,93 @@ declare module "react-native-unistyles" {
|
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
imageComponent: TerraImageComponent;
|
|
56
|
-
configured: boolean;
|
|
54
|
+
// ─── Private registry state ──────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
/** Adapters and component defaults, installed at configure time only. */
|
|
57
|
+
interface RegistrySettings {
|
|
58
|
+
readonly defaultRadius: ResolvedRadius;
|
|
59
|
+
readonly surfaceElevation: ElevationKey;
|
|
60
|
+
readonly icons: Readonly<Partial<Record<string, TerraIconComponent>>>;
|
|
61
|
+
readonly imageComponent: TerraImageComponent;
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
const buildSettings = (config: TerraConfig): RegistrySettings => ({
|
|
65
|
+
defaultRadius: resolveDefaultRadius(config.components),
|
|
66
|
+
surfaceElevation: config.components?.surface?.elevation ?? DEFAULT_ELEVATION,
|
|
67
|
+
icons: { ...(config.icons ?? {}) },
|
|
68
|
+
imageComponent: config.image ?? defaultImage,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
let settings: RegistrySettings = buildSettings({});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Installation state. `unconfigured` → nothing has run; `fallback` → the
|
|
75
|
+
* provider's placeholder defaults are live and an app call still replaces
|
|
76
|
+
* them; `app` → the app configured, later calls are ignored with a warning.
|
|
77
|
+
*/
|
|
78
|
+
let installation: "unconfigured" | "fallback" | "app" = "unconfigured";
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
export const getRegistry = (): Registry => registry;
|
|
80
|
+
// ─── Getters (read-only) ─────────────────────────────────────────────────────
|
|
73
81
|
|
|
74
|
-
export const getIsConfigured = (): boolean =>
|
|
82
|
+
export const getIsConfigured = (): boolean => installation !== "unconfigured";
|
|
75
83
|
|
|
76
|
-
|
|
84
|
+
/** Names of the registered accents, in declaration order. Returns a fresh array. */
|
|
85
|
+
export const getAccentNames = (): string[] => [...getInstalledConfig().accentNames];
|
|
77
86
|
|
|
78
|
-
export const getImageComponent = (): TerraImageComponent =>
|
|
87
|
+
export const getImageComponent = (): TerraImageComponent => settings.imageComponent;
|
|
79
88
|
|
|
80
89
|
export const getIcon = (name: string): TerraIconComponent | undefined =>
|
|
81
|
-
|
|
90
|
+
settings.icons[name] ?? defaultIcons[name as TerraSemanticIconName];
|
|
82
91
|
|
|
83
92
|
export const getRequiredIcon = (name: TerraSemanticIconName): TerraIconComponent =>
|
|
84
|
-
|
|
93
|
+
settings.icons[name] ?? defaultIcons[name];
|
|
85
94
|
|
|
86
95
|
/**
|
|
87
96
|
* The configured default corner radius for a component (Button, Surface).
|
|
88
97
|
* Set via {@link configureTerraUI}; defaults to `'md'`.
|
|
89
98
|
*/
|
|
90
99
|
export const getDefaultRadius = (component: RadiusComponent): DefaultRadiusToken =>
|
|
91
|
-
|
|
100
|
+
settings.defaultRadius[component];
|
|
92
101
|
|
|
93
102
|
/**
|
|
94
103
|
* The configured default drop-shadow depth for Surface (`'none'` = no shadow).
|
|
95
104
|
* Set via {@link configureTerraUI}; defaults to `'none'`.
|
|
96
105
|
*/
|
|
97
|
-
export const getSurfaceElevation = (): ElevationKey =>
|
|
106
|
+
export const getSurfaceElevation = (): ElevationKey => settings.surfaceElevation;
|
|
98
107
|
|
|
99
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Resolves one scheme's theme from the installed configuration with the named
|
|
110
|
+
* accent overlaid. Omitting `accentName` selects the base theme (no accent —
|
|
111
|
+
* not the configured `defaultAccent`). An unknown name warns in development
|
|
112
|
+
* and falls back to the base theme. Pure with respect to runtime state: it
|
|
113
|
+
* never changes the applied selection.
|
|
114
|
+
*/
|
|
100
115
|
export function resolveTheme(scheme: Scheme, accentName?: string): TerraTheme {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const { radius, spacing, ...rest } = override;
|
|
110
|
-
let next = deepMerge(theme, rest);
|
|
111
|
-
|
|
112
|
-
if (radius) {
|
|
113
|
-
const { base, ...radiusTokens } = radius;
|
|
114
|
-
if (base != null) {
|
|
115
|
-
next = deepMerge(next, { radius: buildRadiusScale(base) });
|
|
116
|
-
}
|
|
117
|
-
next = deepMerge(next, { radius: radiusTokens });
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (spacing) {
|
|
121
|
-
const { base, ...spacingTokens } = spacing;
|
|
122
|
-
if (base != null) {
|
|
123
|
-
next = deepMerge(next, { spacing: buildSpacingScale(base) });
|
|
116
|
+
const config = getInstalledConfig();
|
|
117
|
+
let accent: string | null = null;
|
|
118
|
+
if (accentName !== undefined) {
|
|
119
|
+
if (config.accentNames.includes(accentName)) {
|
|
120
|
+
accent = accentName;
|
|
121
|
+
} else if (__DEV__) {
|
|
122
|
+
console.warn(`[react-native-terra-ui] Unknown accent "${accentName}"; resolving the base theme.`);
|
|
124
123
|
}
|
|
125
|
-
next = deepMerge(next, { spacing: spacingTokens });
|
|
126
124
|
}
|
|
125
|
+
return resolveThemeScheme(config, scheme, accent).theme;
|
|
126
|
+
}
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Whether the live configuration is the provider's fallback rather than an
|
|
133
|
-
* app's own call. A fallback is a placeholder, so a real call still replaces
|
|
134
|
-
* it; two real calls remain an error.
|
|
135
|
-
*/
|
|
136
|
-
let configuredByFallback = false;
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Whether `StyleSheet.configure` has run. Tracked separately from
|
|
140
|
-
* {@link Registry.configured} because it may only happen once per app.
|
|
141
|
-
*/
|
|
142
|
-
let unistylesConfigured = false;
|
|
128
|
+
// ─── Configuration ───────────────────────────────────────────────────────────
|
|
143
129
|
|
|
144
130
|
/**
|
|
145
131
|
* Configure Terra UI's themes. Call ONCE, as early as possible — before any
|
|
146
132
|
* component renders (e.g. top of the app entry, imported from
|
|
147
133
|
* `react-native-terra-ui/theme`). With no arguments it registers the default
|
|
148
134
|
* theme; `<TerraUIProvider>` calls it for you if you haven't.
|
|
135
|
+
*
|
|
136
|
+
* Invalid input throws {@link TerraConfigError} before anything is installed,
|
|
137
|
+
* so a corrected retry is still the app's one configure call.
|
|
149
138
|
*/
|
|
150
139
|
export function configureTerraUI(config: TerraConfig = {}): void {
|
|
151
|
-
if (
|
|
140
|
+
if (installation === "app") {
|
|
152
141
|
if (__DEV__ && Object.keys(config).length > 0) {
|
|
153
142
|
console.warn(
|
|
154
143
|
"[react-native-terra-ui] configureTerraUI() was called more than once; the later call was ignored."
|
|
@@ -157,8 +146,7 @@ export function configureTerraUI(config: TerraConfig = {}): void {
|
|
|
157
146
|
return;
|
|
158
147
|
}
|
|
159
148
|
|
|
160
|
-
|
|
161
|
-
applyConfig(config);
|
|
149
|
+
applyConfig(config, "app");
|
|
162
150
|
}
|
|
163
151
|
|
|
164
152
|
/**
|
|
@@ -174,68 +162,62 @@ export function configureTerraUI(config: TerraConfig = {}): void {
|
|
|
174
162
|
* @internal
|
|
175
163
|
*/
|
|
176
164
|
export function bootstrapTerraUI(): void {
|
|
177
|
-
if (
|
|
165
|
+
if (installation !== "unconfigured") {
|
|
178
166
|
return;
|
|
179
167
|
}
|
|
180
168
|
|
|
181
|
-
applyConfig({});
|
|
182
|
-
configuredByFallback = true;
|
|
169
|
+
applyConfig({}, "fallback");
|
|
183
170
|
}
|
|
184
171
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
registry.defaultRadius = resolveDefaultRadius(config.components);
|
|
198
|
-
registry.surfaceElevation = config.components?.surface?.elevation ?? DEFAULT_ELEVATION;
|
|
199
|
-
registry.icons = config.icons ?? {};
|
|
200
|
-
registry.imageComponent = config.image ?? defaultImage;
|
|
201
|
-
|
|
202
|
-
registry.accents = {};
|
|
203
|
-
for (const [name, accent] of Object.entries(config.accents ?? {})) {
|
|
204
|
-
registry.accents[name] = normalizeAccent(accent);
|
|
205
|
-
}
|
|
206
|
-
const { defaultAccent } = config;
|
|
207
|
-
registry.currentAccent = defaultAccent && registry.accents[defaultAccent] ? defaultAccent : undefined;
|
|
208
|
-
|
|
209
|
-
const themes = {
|
|
210
|
-
light: resolveTheme("light", registry.currentAccent),
|
|
211
|
-
dark: resolveTheme("dark", registry.currentAccent),
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const adaptive = config.adaptiveThemes ?? true;
|
|
215
|
-
const settings = config.initialScheme
|
|
216
|
-
? { initialTheme: config.initialScheme }
|
|
217
|
-
: adaptive
|
|
218
|
-
? { adaptiveThemes: true as const }
|
|
219
|
-
: { initialTheme: "light" as const };
|
|
220
|
-
|
|
221
|
-
if (unistylesConfigured) {
|
|
222
|
-
// `StyleSheet.configure` is a one-time startup call — calling it again
|
|
223
|
-
// leaves the themes it already registered in place, which would strand an
|
|
224
|
-
// app's config behind the fallback's defaults. Hand the rebuilt themes to
|
|
225
|
-
// the runtime instead, the same way `applyAccent` swaps a palette.
|
|
226
|
-
UnistylesRuntime.updateTheme("light", () => themes.light);
|
|
227
|
-
UnistylesRuntime.updateTheme("dark", () => themes.dark);
|
|
228
|
-
|
|
229
|
-
if ("adaptiveThemes" in settings) {
|
|
230
|
-
UnistylesRuntime.setAdaptiveThemes(true);
|
|
231
|
-
} else {
|
|
232
|
-
UnistylesRuntime.setAdaptiveThemes(false);
|
|
233
|
-
UnistylesRuntime.setTheme(settings.initialTheme);
|
|
172
|
+
/**
|
|
173
|
+
* Derives the starting theme mode. `mode` wins; otherwise the deprecated
|
|
174
|
+
* settings keep their existing meaning: `initialScheme` pins that scheme,
|
|
175
|
+
* `adaptiveThemes: false` starts in light, and the default follows the system.
|
|
176
|
+
*/
|
|
177
|
+
function deriveMode(config: TerraConfig): ThemeMode {
|
|
178
|
+
const hasLegacy = config.initialScheme !== undefined || config.adaptiveThemes !== undefined;
|
|
179
|
+
if (config.mode !== undefined) {
|
|
180
|
+
if (__DEV__ && hasLegacy) {
|
|
181
|
+
console.warn(
|
|
182
|
+
"[react-native-terra-ui] configureTerraUI(): `mode` was supplied together with the deprecated `initialScheme` / `adaptiveThemes`; `mode` wins and the deprecated settings are ignored."
|
|
183
|
+
);
|
|
234
184
|
}
|
|
185
|
+
return config.mode;
|
|
186
|
+
}
|
|
187
|
+
if (config.initialScheme !== undefined) return config.initialScheme;
|
|
188
|
+
if (config.adaptiveThemes === false) return "light";
|
|
189
|
+
return "system";
|
|
190
|
+
}
|
|
235
191
|
|
|
236
|
-
|
|
192
|
+
const pickThemeInput = (config: TerraConfig): TerraThemeInput => ({
|
|
193
|
+
shared: config.shared,
|
|
194
|
+
schemes: config.schemes,
|
|
195
|
+
accents: config.accents,
|
|
196
|
+
defaultAccent: config.defaultAccent,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
function applyConfig(config: TerraConfig, kind: "fallback" | "app"): void {
|
|
200
|
+
// (a) Pure: validate and build everything. Throws leave ALL state untouched.
|
|
201
|
+
const themeConfig = normalizeThemeInput(pickThemeInput(config));
|
|
202
|
+
const mode = deriveMode(config);
|
|
203
|
+
const { themes, diagnostics } = resolveThemes(themeConfig, themeConfig.defaultAccent);
|
|
204
|
+
const nextSettings = buildSettings(config);
|
|
205
|
+
|
|
206
|
+
// (b) Native. `StyleSheet.configure` runs once per app; after that the
|
|
207
|
+
// rebuilt themes reach the runtime the same way an accent change does, so an
|
|
208
|
+
// app's config is never stranded behind the fallback's defaults.
|
|
209
|
+
if (hasConfiguredUnistyles()) {
|
|
210
|
+
updateThemes(themes);
|
|
211
|
+
applyMode(mode);
|
|
212
|
+
} else {
|
|
213
|
+
configureUnistyles({ themes, mode });
|
|
237
214
|
}
|
|
238
215
|
|
|
239
|
-
|
|
240
|
-
|
|
216
|
+
// (c) Publish only after native work succeeded.
|
|
217
|
+
installation = kind;
|
|
218
|
+
settings = nextSettings;
|
|
219
|
+
setInstalledConfig(themeConfig);
|
|
220
|
+
publishThemeSelection({ accent: themeConfig.defaultAccent ?? undefined, mode });
|
|
221
|
+
|
|
222
|
+
warnContrastDiagnostics(diagnostics);
|
|
241
223
|
}
|