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}