react-native-terra-ui 0.7.2 → 0.8.0
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 +28 -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
package/src/theme/theme.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { unflatten } from "#utils/unflatten";
|
|
2
|
+
import { withLegacyTokens } from "./legacy-tokens";
|
|
2
3
|
import { dark } from "./tokens/dark";
|
|
3
4
|
import { light } from "./tokens/light";
|
|
4
5
|
import { primitives } from "./tokens/primitives";
|
|
5
6
|
import type {
|
|
7
|
+
CanonicalThemeColor,
|
|
6
8
|
ElevationKey,
|
|
7
9
|
ElevationScale,
|
|
8
10
|
ElevationStyle,
|
|
9
11
|
LayoutTokens,
|
|
10
12
|
OpacityTokens,
|
|
11
13
|
RadiusKey,
|
|
14
|
+
Scheme,
|
|
15
|
+
ScreenPaddingTokens,
|
|
12
16
|
SpacingKey,
|
|
17
|
+
TerraColorRegistry,
|
|
13
18
|
TerraTheme,
|
|
14
|
-
ThemeColor,
|
|
15
19
|
Typography,
|
|
16
20
|
} from "./types";
|
|
17
21
|
|
|
@@ -72,8 +76,8 @@ function resolveRefs(
|
|
|
72
76
|
* each key, leaving a flat map per category.
|
|
73
77
|
*
|
|
74
78
|
* Example:
|
|
75
|
-
* { 'color.surface.default': '#fff', 'color.
|
|
76
|
-
* → { color: { 'surface.default': '#fff', '
|
|
79
|
+
* { 'color.surface.default': '#fff', 'color.accent.solid.bg': '#009966' }
|
|
80
|
+
* → { color: { 'surface.default': '#fff', 'accent.solid.bg': '#009966' } }
|
|
77
81
|
*/
|
|
78
82
|
function flattenByCategory(tokens: Record<string, unknown>): Record<string, Record<string, unknown>> {
|
|
79
83
|
const out: Record<string, Record<string, unknown>> = {};
|
|
@@ -97,7 +101,7 @@ function flattenByCategory(tokens: Record<string, unknown>): Record<string, Reco
|
|
|
97
101
|
* spacing BASE are authored here (`radius.base`, `spacing.base`); the full
|
|
98
102
|
* scales are derived via {@link buildRadiusScale} / {@link buildSpacingScale}.
|
|
99
103
|
* `elevation` excludes `shadowColor`, which is layered on per-scheme from each
|
|
100
|
-
* theme's `color.shadow` token (see {@link
|
|
104
|
+
* theme's `color.shadow` token (see {@link resolveElevationScale}).
|
|
101
105
|
*/
|
|
102
106
|
const prim = unflatten<{
|
|
103
107
|
spacing: { base: number };
|
|
@@ -197,49 +201,110 @@ const defaultRadius = buildRadiusScale();
|
|
|
197
201
|
const lightByCategory = flattenByCategory(resolveRefs(light, primitives));
|
|
198
202
|
const darkByCategory = flattenByCategory(resolveRefs(dark, primitives));
|
|
199
203
|
|
|
204
|
+
/** Elevation levels as authored: everything except the per-scheme `shadowColor`. */
|
|
205
|
+
export type ThemeSourceElevation = Record<ElevationKey, Omit<ElevationStyle, "shadowColor">>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The pre-finalization ("source") form of a theme — what the resolver layers
|
|
209
|
+
* overrides onto. It differs from {@link TerraTheme} only in what is DERIVED at
|
|
210
|
+
* the final boundary instead of authored:
|
|
211
|
+
* - `color` holds canonical (and app-declared custom) keys only; deprecated
|
|
212
|
+
* aliases are materialized by {@link finalizeThemeSource}.
|
|
213
|
+
* - `elevation` levels carry no `shadowColor`; it is derived from `color.shadow`
|
|
214
|
+
* (unless explicitly pinned) at finalization.
|
|
215
|
+
* - `layout.screen` has no `margin` alias; it mirrors `padding` at finalization.
|
|
216
|
+
*/
|
|
217
|
+
export interface ThemeSource {
|
|
218
|
+
color: CanonicalThemeColor & TerraColorRegistry;
|
|
219
|
+
spacing: Record<SpacingKey, number>;
|
|
220
|
+
radius: Record<RadiusKey, number>;
|
|
221
|
+
typography: Typography;
|
|
222
|
+
elevation: ThemeSourceElevation;
|
|
223
|
+
opacity: OpacityTokens;
|
|
224
|
+
layout: {
|
|
225
|
+
screen: { padding: ScreenPaddingTokens };
|
|
226
|
+
header: LayoutTokens["header"];
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
200
230
|
/**
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
231
|
+
* Structural deep clone for token data (plain objects, arrays and primitives —
|
|
232
|
+
* the theme never carries functions or class instances). Used so every source
|
|
233
|
+
* and every finalized theme is independently owned.
|
|
204
234
|
*/
|
|
205
|
-
function
|
|
206
|
-
|
|
207
|
-
|
|
235
|
+
export function cloneTokenTree<T>(value: T): T {
|
|
236
|
+
if (Array.isArray(value)) {
|
|
237
|
+
return value.map((item) => cloneTokenTree(item)) as unknown as T;
|
|
238
|
+
}
|
|
239
|
+
if (typeof value === "object" && value !== null) {
|
|
240
|
+
const out: Record<string, unknown> = {};
|
|
241
|
+
for (const [key, item] of Object.entries(value as Record<string, unknown>)) {
|
|
242
|
+
out[key] = cloneTokenTree(item);
|
|
243
|
+
}
|
|
244
|
+
return out as T;
|
|
245
|
+
}
|
|
246
|
+
return value;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Builds the built-in default theme for `scheme` in its source form (see
|
|
251
|
+
* {@link ThemeSource}). Returns a FRESH object on every call, so callers may
|
|
252
|
+
* layer onto or mutate it without affecting the exported defaults or later
|
|
253
|
+
* calls. This is the immutable starting point of the resolution pipeline:
|
|
254
|
+
* `defaults → shared → scheme → accent`.
|
|
255
|
+
*/
|
|
256
|
+
export function createDefaultThemeSource(scheme: Scheme): ThemeSource {
|
|
257
|
+
const byCategory = scheme === "light" ? lightByCategory : darkByCategory;
|
|
258
|
+
return cloneTokenTree({
|
|
259
|
+
color: byCategory.color as unknown as ThemeSource["color"],
|
|
260
|
+
elevation: prim.elevation,
|
|
261
|
+
spacing: defaultSpacing,
|
|
262
|
+
radius: defaultRadius,
|
|
263
|
+
typography: prim.typography,
|
|
264
|
+
opacity: prim.opacity,
|
|
265
|
+
layout: prim.layout,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Resolves each elevation level's `shadowColor`: an explicitly pinned
|
|
271
|
+
* per-level color wins, otherwise the theme's `color.shadow` token is used —
|
|
272
|
+
* rather than authoring it redundantly on every level in `light.ts` / `dark.ts`.
|
|
273
|
+
*/
|
|
274
|
+
export function resolveElevationScale(
|
|
275
|
+
elevation: ThemeSourceElevation,
|
|
276
|
+
shadowColor: string,
|
|
277
|
+
pinnedShadowColors?: Partial<Record<ElevationKey, string>>
|
|
208
278
|
): ElevationScale {
|
|
209
279
|
const out = {} as ElevationScale;
|
|
210
280
|
for (const key of Object.keys(elevation) as ElevationKey[]) {
|
|
211
|
-
out[key] = { ...elevation[key], shadowColor };
|
|
281
|
+
out[key] = { ...elevation[key], shadowColor: pinnedShadowColors?.[key] ?? shadowColor };
|
|
212
282
|
}
|
|
213
283
|
return out;
|
|
214
284
|
}
|
|
215
285
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Turns a {@link ThemeSource} into a complete, independently owned
|
|
288
|
+
* {@link TerraTheme}: derives elevation shadow colors (honouring pinned levels)
|
|
289
|
+
* and materializes every compatibility alias. Neither `source` nor the returned
|
|
290
|
+
* theme share object references with each other.
|
|
291
|
+
*/
|
|
292
|
+
export function finalizeThemeSource(
|
|
293
|
+
source: ThemeSource,
|
|
294
|
+
pinnedShadowColors?: Partial<Record<ElevationKey, string>>
|
|
295
|
+
): TerraTheme {
|
|
296
|
+
const fresh = cloneTokenTree(source);
|
|
297
|
+
return withLegacyTokens({
|
|
298
|
+
color: fresh.color,
|
|
299
|
+
elevation: resolveElevationScale(fresh.elevation, fresh.color.shadow, pinnedShadowColors),
|
|
300
|
+
spacing: fresh.spacing,
|
|
301
|
+
radius: fresh.radius,
|
|
302
|
+
typography: fresh.typography,
|
|
303
|
+
opacity: fresh.opacity,
|
|
304
|
+
layout: fresh.layout,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
226
307
|
|
|
227
|
-
export const defaultLightTheme: TerraTheme =
|
|
228
|
-
color: lightTokens.color,
|
|
229
|
-
elevation: lightTokens.elevation,
|
|
230
|
-
spacing: defaultSpacing,
|
|
231
|
-
radius: defaultRadius,
|
|
232
|
-
typography: prim.typography,
|
|
233
|
-
opacity: prim.opacity,
|
|
234
|
-
layout: prim.layout,
|
|
235
|
-
};
|
|
308
|
+
export const defaultLightTheme: TerraTheme = finalizeThemeSource(createDefaultThemeSource("light"));
|
|
236
309
|
|
|
237
|
-
export const defaultDarkTheme: TerraTheme =
|
|
238
|
-
color: darkTokens.color,
|
|
239
|
-
elevation: darkTokens.elevation,
|
|
240
|
-
spacing: defaultSpacing,
|
|
241
|
-
radius: defaultRadius,
|
|
242
|
-
typography: prim.typography,
|
|
243
|
-
opacity: prim.opacity,
|
|
244
|
-
layout: prim.layout,
|
|
245
|
-
};
|
|
310
|
+
export const defaultDarkTheme: TerraTheme = finalizeThemeSource(createDefaultThemeSource("dark"));
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime list of the built-in canonical colour keys.
|
|
3
|
+
*
|
|
4
|
+
* `CanonicalThemeColor` (types.ts) is the authoritative schema, but it is a
|
|
5
|
+
* type and cannot be iterated at runtime. This object mirrors it key-for-key
|
|
6
|
+
* so the raw-data validator can check `light.ts` / `dark.ts` against the real
|
|
7
|
+
* schema instead of a hand-maintained regex. The `satisfies` clause makes the
|
|
8
|
+
* mirror self-checking: a key missing here fails on the `Record<…>`
|
|
9
|
+
* requirement, and a key that is not in `CanonicalThemeColor` fails the
|
|
10
|
+
* excess-property check.
|
|
11
|
+
*
|
|
12
|
+
* Type-only import — this file stays free of runtime imports like the other
|
|
13
|
+
* token data.
|
|
14
|
+
*/
|
|
15
|
+
import type { CanonicalThemeColor } from "../types";
|
|
16
|
+
|
|
17
|
+
const CANONICAL_COLOR_KEY_MAP = {
|
|
18
|
+
// surfaces
|
|
19
|
+
"surface.canvas": true,
|
|
20
|
+
"surface.default": true,
|
|
21
|
+
"surface.raised": true,
|
|
22
|
+
"surface.sunken": true,
|
|
23
|
+
// text / icons
|
|
24
|
+
"text.primary": true,
|
|
25
|
+
"text.secondary": true,
|
|
26
|
+
"text.tertiary": true,
|
|
27
|
+
"text.disabled": true,
|
|
28
|
+
"text.inverse": true,
|
|
29
|
+
"text.link": true,
|
|
30
|
+
// borders and focus
|
|
31
|
+
"border.subtle": true,
|
|
32
|
+
"border.default": true,
|
|
33
|
+
"border.strong": true,
|
|
34
|
+
"focus.ring": true,
|
|
35
|
+
// effects
|
|
36
|
+
backdrop: true,
|
|
37
|
+
shadow: true,
|
|
38
|
+
// accent
|
|
39
|
+
"accent.text": true,
|
|
40
|
+
"accent.border": true,
|
|
41
|
+
"accent.solid.bg": true,
|
|
42
|
+
"accent.solid.bg.hover": true,
|
|
43
|
+
"accent.solid.bg.pressed": true,
|
|
44
|
+
"accent.solid.bg.disabled": true,
|
|
45
|
+
"accent.solid.fg": true,
|
|
46
|
+
"accent.soft.bg": true,
|
|
47
|
+
"accent.soft.bg.hover": true,
|
|
48
|
+
"accent.soft.bg.pressed": true,
|
|
49
|
+
"accent.soft.bg.disabled": true,
|
|
50
|
+
"accent.soft.fg": true,
|
|
51
|
+
// neutral
|
|
52
|
+
"neutral.solid.bg": true,
|
|
53
|
+
"neutral.solid.fg": true,
|
|
54
|
+
"neutral.soft.bg": true,
|
|
55
|
+
"neutral.soft.bg.hover": true,
|
|
56
|
+
"neutral.soft.bg.pressed": true,
|
|
57
|
+
"neutral.soft.bg.disabled": true,
|
|
58
|
+
"neutral.soft.fg": true,
|
|
59
|
+
// status — success
|
|
60
|
+
"success.text": true,
|
|
61
|
+
"success.solid.bg": true,
|
|
62
|
+
"success.solid.fg": true,
|
|
63
|
+
"success.solid.border": true,
|
|
64
|
+
"success.soft.bg": true,
|
|
65
|
+
"success.soft.fg": true,
|
|
66
|
+
"success.soft.border": true,
|
|
67
|
+
// status — warning
|
|
68
|
+
"warning.text": true,
|
|
69
|
+
"warning.solid.bg": true,
|
|
70
|
+
"warning.solid.fg": true,
|
|
71
|
+
"warning.solid.border": true,
|
|
72
|
+
"warning.soft.bg": true,
|
|
73
|
+
"warning.soft.fg": true,
|
|
74
|
+
"warning.soft.border": true,
|
|
75
|
+
// status — danger
|
|
76
|
+
"danger.text": true,
|
|
77
|
+
"danger.solid.bg": true,
|
|
78
|
+
"danger.solid.fg": true,
|
|
79
|
+
"danger.solid.border": true,
|
|
80
|
+
"danger.soft.bg": true,
|
|
81
|
+
"danger.soft.fg": true,
|
|
82
|
+
"danger.soft.border": true,
|
|
83
|
+
// status — info
|
|
84
|
+
"info.text": true,
|
|
85
|
+
"info.solid.bg": true,
|
|
86
|
+
"info.solid.fg": true,
|
|
87
|
+
"info.solid.border": true,
|
|
88
|
+
"info.soft.bg": true,
|
|
89
|
+
"info.soft.fg": true,
|
|
90
|
+
"info.soft.border": true,
|
|
91
|
+
} as const satisfies Record<keyof CanonicalThemeColor, true>;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Every built-in canonical colour key (without the `color.` category prefix
|
|
95
|
+
* used by the raw token files). Exhaustive and extra-free by construction —
|
|
96
|
+
* see {@link CANONICAL_COLOR_KEY_MAP}.
|
|
97
|
+
*/
|
|
98
|
+
export const CANONICAL_COLOR_KEYS: readonly (keyof CanonicalThemeColor)[] = Object.keys(
|
|
99
|
+
CANONICAL_COLOR_KEY_MAP
|
|
100
|
+
) as (keyof CanonicalThemeColor)[];
|
|
101
|
+
|
|
102
|
+
/** Type-level guard that the map's literal keys and the schema's keys are the same set. */
|
|
103
|
+
type MissingCanonicalKey = Exclude<keyof CanonicalThemeColor, keyof typeof CANONICAL_COLOR_KEY_MAP>;
|
|
104
|
+
type ExtraCanonicalKey = Exclude<keyof typeof CANONICAL_COLOR_KEY_MAP, keyof CanonicalThemeColor>;
|
|
105
|
+
export type CanonicalColorKeysAreExhaustive = [MissingCanonicalKey, ExtraCanonicalKey] extends [never, never]
|
|
106
|
+
? true
|
|
107
|
+
: { missing: MissingCanonicalKey; extra: ExtraCanonicalKey };
|
package/src/theme/tokens/dark.ts
CHANGED
|
@@ -1,108 +1,101 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dark
|
|
3
|
-
*
|
|
4
|
-
* Convention: [category].[context].[property?].[variant].[state]
|
|
5
|
-
*
|
|
6
|
-
* GENERATED-STYLE SOURCE: intended to be replaced by the Figma / design-sync export.
|
|
2
|
+
* Dark semantic colors. See docs/design-tokens.md for naming and references.
|
|
3
|
+
* Generated-style source; naming and contrast updates await the next design-sync export.
|
|
7
4
|
*/
|
|
8
5
|
export const dark = {
|
|
9
|
-
//
|
|
10
|
-
"color.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"color.
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
"color.
|
|
17
|
-
|
|
18
|
-
"color.
|
|
19
|
-
"color.
|
|
20
|
-
"color.surface.accent": "{palette.emerald.500}",
|
|
21
|
-
"color.surface.accent.subtle": "{palette.emerald.950}",
|
|
22
|
-
|
|
23
|
-
// ── color: text / icons (fg implied — no property segment) ──────────────
|
|
24
|
-
"color.text.default": "{palette.neutral.50}",
|
|
25
|
-
// Off-ramp hexes (like light's) rather than neutral.400/500/600: the ramp
|
|
26
|
-
// steps are tuned for dark text on white, and reused as light text they land
|
|
27
|
-
// too dim. Set so `subtle` clears AA 4.5:1 on `surface.raised` — the lightest
|
|
28
|
-
// surface, so the worst case — which keeps the muted/subtle/disabled spacing
|
|
29
|
-
// proportional to light's.
|
|
30
|
-
"color.text.muted": "#b8b8be",
|
|
31
|
-
"color.text.subtle": "#8d8d96",
|
|
6
|
+
// Surfaces
|
|
7
|
+
"color.surface.canvas": "#080a0d",
|
|
8
|
+
"color.surface.default": "#14191f",
|
|
9
|
+
"color.surface.raised": "#1f262e",
|
|
10
|
+
"color.surface.sunken": "#0f1318",
|
|
11
|
+
|
|
12
|
+
// Text
|
|
13
|
+
"color.text.primary": "{palette.neutral.50}",
|
|
14
|
+
// Custom grays preserve supporting-text emphasis on dark surfaces.
|
|
15
|
+
"color.text.secondary": "#b8b8be",
|
|
16
|
+
"color.text.tertiary": "#8d8d96",
|
|
32
17
|
"color.text.disabled": "#606069",
|
|
33
18
|
"color.text.inverse": "{palette.neutral.950}",
|
|
34
19
|
"color.text.link": "{palette.blue.300}",
|
|
35
|
-
"color.text.accent": "{palette.emerald.400}",
|
|
36
|
-
"color.text.on-accent": "{palette.neutral.950}",
|
|
37
|
-
"color.text.on-accent-subtle": "{palette.emerald.300}",
|
|
38
20
|
|
|
39
|
-
//
|
|
21
|
+
// Borders and focus
|
|
40
22
|
"color.border.subtle": "{palette.neutral.800}",
|
|
41
23
|
"color.border.default": "{palette.neutral.700}",
|
|
42
|
-
"color.border.strong": "{palette.neutral.
|
|
43
|
-
"color.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"color.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"color.
|
|
51
|
-
"color.
|
|
52
|
-
|
|
53
|
-
"color.
|
|
54
|
-
"color.
|
|
55
|
-
"color.
|
|
56
|
-
"color.
|
|
57
|
-
"color.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"color.
|
|
63
|
-
"color.
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
"color.
|
|
71
|
-
"color.
|
|
72
|
-
"color.
|
|
73
|
-
"color.
|
|
74
|
-
"color.
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
"color.
|
|
78
|
-
|
|
79
|
-
"color.
|
|
80
|
-
"color.
|
|
81
|
-
"color.
|
|
82
|
-
|
|
83
|
-
"color.
|
|
84
|
-
|
|
85
|
-
"color.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"color.
|
|
89
|
-
|
|
90
|
-
"color.
|
|
91
|
-
"color.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"color.
|
|
95
|
-
"color.
|
|
96
|
-
"color.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
"color.
|
|
100
|
-
|
|
101
|
-
"color.
|
|
102
|
-
"color.
|
|
103
|
-
"color.
|
|
104
|
-
|
|
105
|
-
"color.
|
|
106
|
-
"color.
|
|
107
|
-
"color.
|
|
24
|
+
"color.border.strong": "{palette.neutral.500}",
|
|
25
|
+
"color.focus.ring": "{palette.blue.400}",
|
|
26
|
+
|
|
27
|
+
// Effects
|
|
28
|
+
"color.backdrop": "rgba(0, 0, 0, 0.72)",
|
|
29
|
+
"color.shadow": "{palette.black}",
|
|
30
|
+
|
|
31
|
+
// Accent
|
|
32
|
+
"color.accent.text": "{palette.emerald.400}",
|
|
33
|
+
"color.accent.border": "{palette.emerald.500}",
|
|
34
|
+
|
|
35
|
+
"color.accent.solid.bg": "{palette.emerald.500}",
|
|
36
|
+
"color.accent.solid.bg.hover": "{palette.emerald.400}",
|
|
37
|
+
"color.accent.solid.bg.pressed": "{palette.emerald.300}",
|
|
38
|
+
"color.accent.solid.bg.disabled": "{palette.slate.700}",
|
|
39
|
+
"color.accent.solid.fg": "{palette.slate.950}",
|
|
40
|
+
|
|
41
|
+
"color.accent.soft.bg": "{palette.emerald.950}",
|
|
42
|
+
"color.accent.soft.bg.hover": "{palette.emerald.900}",
|
|
43
|
+
"color.accent.soft.bg.pressed": "{palette.emerald.800}",
|
|
44
|
+
"color.accent.soft.bg.disabled": "{palette.neutral.900}",
|
|
45
|
+
"color.accent.soft.fg": "{palette.emerald.300}",
|
|
46
|
+
|
|
47
|
+
// Neutral
|
|
48
|
+
"color.neutral.solid.bg": "{palette.neutral.600}",
|
|
49
|
+
"color.neutral.solid.fg": "{palette.neutral.50}",
|
|
50
|
+
|
|
51
|
+
// Translucent fills keep soft controls distinct from surrounding surfaces.
|
|
52
|
+
"color.neutral.soft.bg": "{palette.neutral.400}/25",
|
|
53
|
+
"color.neutral.soft.bg.hover": "{palette.neutral.400}/35",
|
|
54
|
+
"color.neutral.soft.bg.pressed": "{palette.neutral.400}/45",
|
|
55
|
+
"color.neutral.soft.bg.disabled": "{palette.neutral.900}",
|
|
56
|
+
"color.neutral.soft.fg": "{palette.neutral.200}",
|
|
57
|
+
|
|
58
|
+
// Success
|
|
59
|
+
"color.success.text": "{palette.green.300}",
|
|
60
|
+
|
|
61
|
+
"color.success.solid.bg": "{palette.green.600}",
|
|
62
|
+
"color.success.solid.fg": "{palette.slate.950}",
|
|
63
|
+
"color.success.solid.border": "{palette.green.700}",
|
|
64
|
+
|
|
65
|
+
"color.success.soft.bg": "{palette.green.600}/30",
|
|
66
|
+
"color.success.soft.fg": "{palette.green.200}",
|
|
67
|
+
"color.success.soft.border": "{palette.green.800}",
|
|
68
|
+
|
|
69
|
+
// Warning
|
|
70
|
+
"color.warning.text": "{palette.yellow.300}",
|
|
71
|
+
|
|
72
|
+
"color.warning.solid.bg": "{palette.yellow.600}",
|
|
73
|
+
"color.warning.solid.fg": "{palette.slate.950}",
|
|
74
|
+
"color.warning.solid.border": "{palette.yellow.700}",
|
|
75
|
+
|
|
76
|
+
"color.warning.soft.bg": "{palette.yellow.600}/30",
|
|
77
|
+
"color.warning.soft.fg": "{palette.yellow.200}",
|
|
78
|
+
"color.warning.soft.border": "{palette.yellow.800}",
|
|
79
|
+
|
|
80
|
+
// Danger
|
|
81
|
+
"color.danger.text": "{palette.red.300}",
|
|
82
|
+
|
|
83
|
+
"color.danger.solid.bg": "{palette.red.700}",
|
|
84
|
+
"color.danger.solid.fg": "{palette.white}",
|
|
85
|
+
"color.danger.solid.border": "{palette.red.800}",
|
|
86
|
+
|
|
87
|
+
"color.danger.soft.bg": "{palette.red.700}/30",
|
|
88
|
+
"color.danger.soft.fg": "{palette.red.200}",
|
|
89
|
+
"color.danger.soft.border": "{palette.red.900}",
|
|
90
|
+
|
|
91
|
+
// Info
|
|
92
|
+
"color.info.text": "{palette.sky.300}",
|
|
93
|
+
|
|
94
|
+
"color.info.solid.bg": "{palette.sky.500}",
|
|
95
|
+
"color.info.solid.fg": "{palette.slate.950}",
|
|
96
|
+
"color.info.solid.border": "{palette.sky.800}",
|
|
97
|
+
|
|
98
|
+
"color.info.soft.bg": "{palette.sky.950}",
|
|
99
|
+
"color.info.soft.fg": "{palette.sky.200}",
|
|
100
|
+
"color.info.soft.border": "{palette.sky.900}",
|
|
108
101
|
};
|