theme.ts

 1import {
 2    SingleBoxShadowToken,
 3    SingleColorToken,
 4    SingleOtherToken,
 5    TokenTypes,
 6} from "@tokens-studio/types"
 7import { Shadow, SyntaxHighlightStyle, ThemeSyntax } from "../create_theme"
 8import { LayerToken, layer_token } from "./layer"
 9import { PlayersToken, players_token } from "./players"
10import { color_token } from "./token"
11import { Syntax } from "../syntax"
12import editor from "../../style_tree/editor"
13import { useTheme } from "../../../src/common"
14
15interface ThemeTokens {
16    name: SingleOtherToken
17    appearance: SingleOtherToken
18    lowest: LayerToken
19    middle: LayerToken
20    highest: LayerToken
21    players: PlayersToken
22    popover_shadow: SingleBoxShadowToken
23    modal_shadow: SingleBoxShadowToken
24    syntax?: Partial<ThemeSyntaxColorTokens>
25}
26
27const create_shadow_token = (
28    shadow: Shadow,
29    token_name: string
30): SingleBoxShadowToken => {
31    return {
32        name: token_name,
33        type: TokenTypes.BOX_SHADOW,
34        value: `${shadow.offset[0]}px ${shadow.offset[1]}px ${shadow.blur}px 0px ${shadow.color}`,
35    }
36}
37
38const popover_shadow_token = (): SingleBoxShadowToken => {
39    const theme = useTheme()
40    const shadow = theme.popover_shadow
41    return create_shadow_token(shadow, "popover_shadow")
42}
43
44const modal_shadow_token = (): SingleBoxShadowToken => {
45    const theme = useTheme()
46    const shadow = theme.modal_shadow
47    return create_shadow_token(shadow, "modal_shadow")
48}
49
50type ThemeSyntaxColorTokens = Record<keyof ThemeSyntax, SingleColorToken>
51
52function syntax_highlight_style_color_tokens(
53    syntax: Syntax
54): ThemeSyntaxColorTokens {
55    const style_keys = Object.keys(syntax) as (keyof Syntax)[]
56
57    return style_keys.reduce((acc, style_key) => {
58        // Hack: The type of a style could be "Function"
59        // This can happen because we have a "constructor" property on the syntax object
60        // and a "constructor" property on the prototype of the syntax object
61        // To work around this just assert that the type of the style is not a function
62        if (!syntax[style_key] || typeof syntax[style_key] === "function")
63            return acc
64        const { color } = syntax[style_key] as Required<SyntaxHighlightStyle>
65        return { ...acc, [style_key]: color_token(style_key, color) }
66    }, {} as ThemeSyntaxColorTokens)
67}
68
69const syntax_tokens = (): ThemeTokens["syntax"] => {
70    const syntax = editor().syntax
71
72    return syntax_highlight_style_color_tokens(syntax)
73}
74
75export function theme_tokens(): ThemeTokens {
76    const theme = useTheme()
77
78    return {
79        name: {
80            name: "themeName",
81            value: theme.name,
82            type: TokenTypes.OTHER,
83        },
84        appearance: {
85            name: "themeAppearance",
86            value: theme.is_light ? "light" : "dark",
87            type: TokenTypes.OTHER,
88        },
89        lowest: layer_token(theme.lowest, "lowest"),
90        middle: layer_token(theme.middle, "middle"),
91        highest: layer_token(theme.highest, "highest"),
92        popover_shadow: popover_shadow_token(),
93        modal_shadow: modal_shadow_token(),
94        players: players_token(),
95        syntax: syntax_tokens(),
96    }
97}