colorScheme.ts

 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}