alouette
Version:
A modern, customizable design system built on top of NativeWind v5 with configurable defaults
61 lines (52 loc) • 1.88 kB
text/typescript
import { createContext, use } from "react";
import type {
Accent,
AccentOrNeutral,
AlouetteModeTheme,
AlouetteScopedTheme,
AlouetteTheme,
ColorModePreference,
} from "./AlouetteConfig";
import { useSystemColorMode } from "./useSystemColorMode";
/**
* Tracks the applied theme name as `ScopedTheme` received it (e.g.
* "system_brand"), so accent composition (`AccentScope`) derives nested scopes
* from it and keeps `system` resolved in CSS. Set by `ScopedTheme`.
*
* Defaults to "light", matching the light defaults in the global `@theme` block.
*/
export const ThemeContext = createContext<AlouetteScopedTheme>("light");
export function resolveTheme(
theme: AlouetteScopedTheme,
systemMode: AlouetteModeTheme,
): AlouetteTheme {
return theme.replace(/^system/, systemMode) as AlouetteTheme;
}
export function getThemeAccent(theme: AlouetteScopedTheme): Accent | undefined {
const [, accent] = theme.split("_") as [
ColorModePreference,
Accent | undefined,
];
return accent;
}
export function useCurrentScopedTheme(): AlouetteScopedTheme {
return use(ThemeContext);
}
export function useCurrentColorMode(): ColorModePreference {
const [colorMode] = use(ThemeContext).split("_") as [ColorModePreference];
return colorMode;
}
/** The applied theme with `system` resolved; hydration-safe on web. */
export function useCurrentTheme(): AlouetteTheme {
return resolveTheme(use(ThemeContext), useSystemColorMode());
}
/** The applied mode with `system` resolved; hydration-safe on web. */
export function useCurrentMode(): AlouetteModeTheme {
return useCurrentTheme().startsWith("dark") ? "dark" : "light";
}
export function useAccentOrInheritedOrBrand<T extends AccentOrNeutral>(
accent: T | undefined,
): Accent | T {
const inheritedAccent = getThemeAccent(use(ThemeContext));
return accent ?? inheritedAccent ?? "brand";
}