Recommended theming workflow for SolidJS app using vanilla-extract #1005
-
I just recently discovered // your typical light vs dark mode
export type ColorMode = "light" | "dark";
// the density value affects spacing, font-sizes, line-height, etc. across all custom components
export type Density = "narrow" | "regular" | "wide"; The key thing to focus is on the In my head, this is what I was thinking of doing but I don't know if this is the right approach to the problem in optimal export type ColorMode = "light" | "dark";
/** Object map of values to be associated to the color modes */
export type ColorModeValues<T> = {
readonly l: T;
readonly d: T;
};
/** A `ColorMode` context resolver function */
export type ColorModeResolver = <T>(values: ColorModeValues<T>) => T;
export type Density = "narrow" | "regular" | "wide";
/** Object map of values to be associated to the density values */
export type DensityValues<T> = {
readonly n: T;
readonly r: T;
readonly w: T;
};
/** A `Density` context resolver function */
export type DensityResolver = <T>(values: DensityValues<T>) => T;
/** The app-level theme values */
export type AppTheme = {
readonly colorMode: ColorMode;
readonly density: Density;
};
export const themeSignal = createLocalStorageSignal<AppTheme>("appTheme", {
colorMode: "light",
density: "regular",
});
export type FullAppTheme = {
readonly innerTheme: Accessor<Theme>; // this should contain the entirety of the design system theme (tokens and all)
readonly appTheme: Accessor<AppTheme>; // contains colorMode / density
readonly setAppTheme: Setter<AppTheme>;
};
export const AppThemeContext = createContext<FullAppTheme>();
export type Props = Partial<AppTheme> & {
readonly children: JSX.Element;
};
function AppThemeProvider(props: Props) {
const [, partialTheme] = splitProps(props, ["children"]);
const [appTheme, setAppTheme] = appThemeSignal
const withC = (c: ColorMode): ColorModeResolver => ({ l, d }) => c === "light" ? l : d;
const withD = (d: Density): DensityResolver => ({ n, r, w }) => ({
narrow: n,
regular: r,
wide: w
}[d]);
const innerTheme = () => {
const colorResolver = withC(partialTheme.colorMode ?? appTheme().colorMode);
const densityResolver = withD(partialTheme.density ?? appTheme().density);
// THIS IS WHERE I AM STUCK!
// The idea is to generate the full theme structure taking in the values of `colorMode` and `density` set by the user
// So this should update as a sideEffect via use of createEffect really.
// However, this feels 'off' and not in line with the vanilla-extract workflow
return makeTheme({
colors,
fonts,
fontSizes: fontSizes(densityResolver), // the font sizes list should update when the density changes
lineHeights: lineHeights(densityResolver),
styles: htmlElementStyles(colorResolver),
radii,
space,
});
}
const mergedTheme = () => ({ ...appTheme(), ...partialTheme });
return (
<AppThemeContext.Provider value={{ appTheme: mergedTheme, setAppTheme, innerTheme }}>
{props.children}
</AppThemeContext.Provider>
);
}
export default AppThemeProvider; |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
After understanding |
Beta Was this translation helpful? Give feedback.
After understanding
vanilla-extract
a bit more, this discussion post is now irrelevant and doesn't need an answer. I reframed this question in discussion post #1012. So feel free to close this discussion post in favor of that one. Sorry for the inconvenience!