Add `resolveToken` method to theme that resolves stitches tokens to css values
It would be useful to expose a native way to resolve stitches css tokens from theme.
const color = theme.resolveToken('$colors$neutral400') //'#a3a3a3'
This would increase the interoperability with other libraries that rely on styles like framer-motion, react-spring
<motion.div whileHover={color: theme.resolveToken('$colors$neutral400')}/>
Since we cannot apply opacity to css variables, we have to resolve the token first
const color = theme.resolveToken('$colors$red00')
const colorAlpha = setAlpha(color, 0.5)
We can use this for colored box shadows https://tailwindcss.com/docs/box-shadow-color.
Manual implementation:
//Since stitches themes are strings (classname) and also contains the theme object it is created from
const resolveToken = (token, theme) => {
const matches = token.match(/^\$(?<scale>[^\$]+)\$(?<value>[^\$]+)/)
if (matches?.groups) {
const { scale, value } = matches.groups
const token: Token | null = theme[scale][value] ?? null
if (token) {
//If the token value points to a css variable, resolve it recursively
return token.value.match(/^var/) ? resolveToken(cssVarToToken(token.value), theme) : token.value
}
}
return null
}
function cssVarToToken(cssVar: string) {
console.log(cssVar)
const { scale, value } = cssVar.match(/^var\(--(?<scale>\w+)-(?<value>\w+)\)/)?.groups!
return `$${scale}$${value}`
}
But since we are manually accessing theme data and not through stitches own token resolution process. The styles are not appended to the critical css path with getCssText()
Use Case: Create a hook that resolves themeTokens
Since token resolution depends on what theme is applied in the dom tree. Check which theme is currently applied and fallback to baseTheme
//baseTheme is from const {theme} = createStitches()
//type BaseTheme = typeof theme
//BaseTheme is string (classname) and also contains the original theme object
export const ResolveTokenProvider: FC<{ baseTheme: BaseTheme }> = ({ children, baseTheme }) => {
const theme = useTheme().theme as BaseTheme //From ThemeProvider that keeps track of which theme is applied currently
const resolveToken = useCallback(
(token: string) => {
//use natively if implemented
//return theme.resolveToken(token) ?? baseTheme.resolveToken(token) ?? null
//manual implmentation
const matches = token.match(/^\$(?<scale>[^\$]+)\$(?<value>[^\$]+)/)
if (matches?.groups) {
const { scale, value } = matches.groups
const token: Token | null = theme[scale][value] ?? baseTheme[scale][value] ?? null
if (token) {
//If the token value points to a css variable, resolve it recursively
return token.value.match(/^var/) ? resolveToken(cssVarToToken(token.value)) : token.value
}
}
return null
},
[baseTheme, theme]
)
return (
<ResolveTokenContext.Provider value={resolveToken}>{children}</ResolveTokenContext.Provider>
)
}