1import { resolveTextScaleVariables } from "./appearancePreferences";
2import { BUILT_IN_THEME_IDS, type BuiltInThemeId } from "@t3tools/shared/themePalettes";
3import {
4 DEFAULT_MOBILE_THEME_ID,
5 type MobileThemeAppearance,
6 type MobileThemeId,
7 type MobileThemeMode,
8} from "./mobileTheme";
9
10export type MobileUniwindThemeName =
11 | MobileThemeAppearance
12 | `${BuiltInThemeId}-${MobileThemeAppearance}`;
13
14export interface MobileThemeRuntimeState {
15 readonly baseFontSize: number;
16 readonly themeAppearance: MobileThemeAppearance;
17 readonly themeMode: MobileThemeMode;
18}
19
20export type MobileThemeRuntimeOperation =
21 | {
22 readonly kind: "update-text-variables";
23 readonly themeName: "light" | "dark" | MobileUniwindThemeName;
24 readonly variables: Readonly<Record<string, number>>;
25 }
26 | {
27 readonly kind: "set-appearance-mode";
28 readonly appearance: MobileThemeAppearance;
29 readonly themeMode: MobileThemeMode;
30 };
31
32const UNIWIND_THEME_NAMES: ReadonlyArray<"light" | "dark" | MobileUniwindThemeName> = [
33 "light",
34 "dark",
35 ...BUILT_IN_THEME_IDS.flatMap((themeId) => [
36 `${themeId}-light` as const,
37 `${themeId}-dark` as const,
38 ]),
39];
40
41export function getMobileUniwindThemeName(
42 themeId: MobileThemeId,
43 appearance: MobileThemeAppearance,
44): MobileUniwindThemeName {
45 return themeId === DEFAULT_MOBILE_THEME_ID || themeId === "material-you"
46 ? appearance
47 : `${themeId}-${appearance}`;
48}
49
50/**
51 * Plans imperative runtime work separately from theme selection. Palette
52 * changes are handled by one root ScopedTheme render; only typography and the
53 * native appearance override need imperative Uniwind/React Native updates.
54 */
55export function createMobileThemeRuntimeOperations(
56 previous: MobileThemeRuntimeState | null,
57 next: MobileThemeRuntimeState,
58): ReadonlyArray<MobileThemeRuntimeOperation> {
59 const operations: MobileThemeRuntimeOperation[] = [];
60
61 if (previous === null || previous.baseFontSize !== next.baseFontSize) {
62 const variables = resolveTextScaleVariables(next.baseFontSize);
63 for (const themeName of UNIWIND_THEME_NAMES) {
64 operations.push({ kind: "update-text-variables", themeName, variables });
65 }
66 }
67
68 if (previous === null || previous.themeMode !== next.themeMode) {
69 operations.push({
70 kind: "set-appearance-mode",
71 appearance: next.themeAppearance,
72 themeMode: next.themeMode,
73 });
74 }
75
76 return operations;
77}