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