Skip to content

Instantly share code, notes, and snippets.

@ligabloo
Created November 4, 2021 22:28
Show Gist options
  • Save ligabloo/61ef06f802f771b81adc869a85a0985b to your computer and use it in GitHub Desktop.
Save ligabloo/61ef06f802f771b81adc869a85a0985b to your computer and use it in GitHub Desktop.
Generate React Native atomic styles from theme configuration
import { StyleSheet } from "react-native";
type ThemeConfigKey = "colors" | "space" | "fontSizes";
type ThemeConfigEntry = Record<string, unknown>;
type ThemeConfig = Record<ThemeConfigKey, ThemeConfigEntry>;
type FlattenedThemeEntry = {
token: keyof ThemeConfig[ThemeConfigKey];
property: ThemeConfigKey;
value: unknown;
};
const theme: ThemeConfig = {
colors: {
$text: colors.gray[8],
$background: colors.white,
$muted: colors.gray[3],
$highlight: colors.red[2],
$primary: colors.red[6],
$secondary: colors.gray[8],
$accent: colors.red[2],
},
space: {
$0: 0,
$1: 4,
$2: 8,
$3: 16,
$4: 32,
$5: 64,
$6: 128,
$7: 256,
},
fontSizes: {
$0: 12,
$1: 14,
$2: 16,
$3: 18,
$4: 24,
$5: 28,
$6: 32,
},
};
// Mapeia quais estilos vão ser gerados a partir de cada tipo de configuração.
// Futuramente deve suportar múltiplas propriedades pra cada classe, e também talvez deixar isso configurável?
const variants: Record<ThemeConfigKey, Record<string, string>> = {
fontSizes: {
fontSize: "fontSize",
},
colors: {
color: "color",
bg: "backgroundColor",
},
space: {
ml: "marginLeft",
mr: "marginRight",
mb: "marginBottom",
mt: "marginTop",
pl: "paddingLeft",
pr: "paddingRight",
pb: "paddingBottom",
pt: "paddingTop",
},
};
function flattenThemeConfig(theme: ThemeConfig) {
const themeKeys: ThemeConfigKey[] = Object.keys(theme) as ThemeConfigKey[];
const flattenedTheme = themeKeys
.map((property) =>
Object.keys(theme[property]).map((token) => ({
token,
property,
value: theme[property][token],
}))
)
.flat() as FlattenedThemeEntry[];
return flattenedTheme;
}
function getStylesForEntry({ token, property, value }: FlattenedThemeEntry) {
const variant = variants[property];
let styles: Record<string, Record<string, unknown>> = {};
Object.entries(variant).forEach(([variant, property]) => {
styles[`${variant}-${token}`] = {
[property]: value,
};
});
return styles;
}
function generateAtomicThemeStyleSheet(theme: ThemeConfig) {
let styles: Record<string, Record<string, unknown>> = {};
const flattenedTheme = flattenThemeConfig(theme);
flattenedTheme.forEach((themeEntry) => {
styles = {
...styles,
...getStylesForEntry(themeEntry),
};
});
return StyleSheet.create(styles);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment