Skip to content

Commit d203c97

Browse files
committed
Add color schemas
1 parent 7c63906 commit d203c97

File tree

2 files changed

+218
-0
lines changed

2 files changed

+218
-0
lines changed

docs-language/schemas.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
---
2+
title: Schemas
3+
description: Schema definitions and validation in TokenScript.
4+
sidebar_label: Schemas
5+
---
6+
7+
import TokenScriptCodeBlock from '@site/src/components/TokenScriptCodeBlock';
8+
9+
# Schemas
10+
11+
Schemas are function like packages to extend tokenscript.
12+
13+
They allow you to ship **custom token logic** along with your **design token data** without having to modify source code.
14+
15+
Schemas use Tokenscript nested in a JSON specification to compute values against given input.
16+
17+
Using Schemas you can add:
18+
19+
**Custom types**
20+
21+
- **Color spaces** (rgb, oklch, etc)
22+
- **Custom units** (px, rem, etc)
23+
24+
**Custom functions**
25+
26+
- **Functions** (brighten, darken, etc)
27+
28+
## Schema specification
29+
30+
### Color schemas
31+
32+
```jsonc
33+
{
34+
// The name will be used to defined the type inside tokenscript -> Color.Srgb
35+
"name": "SRGB",
36+
"description": "SRGB color with three channels: red, green & blue.",
37+
38+
"type": "color",
39+
40+
// Input specification for the data properties stored in the color type.
41+
// In most cases this will store the values of your color channels.
42+
"schema": {
43+
"type": "object",
44+
// Order is used for the initializer function e.g.: rgb(r, g, b) and pretty printing of the symbol
45+
"order": ["r", "g", "b"],
46+
"required": ["r", "g", "b"],
47+
"properties": {
48+
"r": { "type": "number" },
49+
"g": { "type": "number" },
50+
"b": { "type": "number" }
51+
}
52+
},
53+
54+
// Initializers allow to construct the color via a function call
55+
// E.g.: variable color: Color.Rgb = rgb(255, 255, 255);
56+
"initializers": [
57+
{
58+
"title": "function",
59+
"keyword": "srgb",
60+
"description": "Creates a RGB color from string",
61+
"script": {
62+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
63+
// The script to initialize the color, takes the properties defined in the input schema and stores them on the color symbol
64+
// Look for minified version below
65+
"script": "variable color_parts: List = {input}; \n variable output: Color.RGB;\n output.r = color_parts.get(0);\n output.g = color_parts.get(1);\n output.b = color_parts.get(2);\n return output;"
66+
}
67+
}
68+
],
69+
70+
71+
// Conversions are used to define conversion to and from other color types
72+
// Tokenscript will automatically find a conversion path, so you dont have to define a conversion for every color type.
73+
// But to enable the a lossless conversion it is important to define the most similar color type for the conversion source and destination.
74+
"conversions": [
75+
{
76+
// The source schema URI for the
77+
// This URI will be used as the id for the lookup in the ColorManager
78+
"source": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/hex-color/0/",
79+
// Target can reference it self with `$self`
80+
"target": "$self",
81+
"description": "Converts HEX to RGB",
82+
"lossless": true,
83+
"script": {
84+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
85+
// The script to convert from hex to rgb
86+
// In this case does splitting of the hex string to fill the `Color.Rgb` type.
87+
"script": "variable color_parts: List = {input}.to_string().split('#'); \n variable color: List = color_parts.get(1).split(); \n variable length: Number = color.length(); \n variable rgb: List = 0, 0, 0; \n if(length == 3) [ \n rgb.update(0, parse_int(color.get(0).concat(color.get(0)), 16)); \n rgb.update(1, parse_int(color.get(1).concat(color.get(1)), 16)); \n rgb.update(2, parse_int(color.get(2).concat(color.get(2)), 16)); \n ] else [ \n rgb.update(0, parse_int(color.get(0).concat(color.get(1)), 16)); \n rgb.update(1, parse_int(color.get(2).concat(color.get(3)), 16)); \n rgb.update(2, parse_int(color.get(4).concat(color.get(5)), 16)); \n ]; \n \n variable output: Color.RGB; \n output.r = rgb.get(0); \n output.g = rgb.get(1); \n output.b = rgb.get(2); \n \n return output; \n"
88+
}
89+
},
90+
// The Reverse of hex to rgb conversion
91+
{
92+
"source": "$self",
93+
"target": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/hex-color/0/",
94+
"description": "Converts RGB to HEX",
95+
"lossless": true,
96+
"script": {
97+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
98+
"script": "variable rgba: List = {input}.r, {input}.g, {input}.b;\n variable hex: String = \"#\";\n variable i: Number = 0;\n variable value: Number = 0;\n // Convert RGBA to Hex\n while( i < min(rgba.length(), 3)) [\n value = rgba.get(i);\n if(value < 16) [\n hex = hex.concat(\"0\").concat(value.to_string(16));\n ] else [\n hex = hex.concat(value.to_string(16));\n ];\n i = i + 1;\n ];\n \n if (rgba.length() == 4) [\n value = rgba.get(3) * 255; // Convert alpha to 0-255 range\n if(value < 16) [\n hex = hex.concat(\"0\").concat(value.to_string(16));\n ] else [\n hex = hex.concat(value.to_string(16));\n ];\n ];\n \n return hex;"
99+
}
100+
}
101+
]
102+
}
103+
```
104+
105+
#### Initializers
106+
107+
Initializers allow to construct a color via a function call.
108+
109+
<TokenScriptCodeBlock mode="script" showResult={true}>
110+
{`srgb(255, 255, 255);`}
111+
</TokenScriptCodeBlock>
112+
113+
This would call our initializer function with the input of `[255, 255, 255]`.
114+
115+
<TokenScriptCodeBlock mode="script" showResult={true} input={[255, 255, 255]}>
116+
{`// Get the input reference
117+
variable color_parts: List = {input};
118+
119+
// Set the channels to the values from the input list
120+
variable output: Color.SRGB;
121+
output.r = color_parts.get(0);
122+
output.g = color_parts.get(1);
123+
output.b = color_parts.get(2);
124+
125+
// Return the constructed color
126+
return output; `}
127+
</TokenScriptCodeBlock>
128+
129+
#### Conversions
130+
131+
Conversions are scripts to convert from a `source` schema type and to a `target` schema type.
132+
133+
Use `$self` to target the current schema.
134+
135+
A type can be converted via `x.to.typename()`
136+
137+
<TokenScriptCodeBlock mode="script" showResult={true} input={"#eb6fb0"}>
138+
{`// Input #eb6fb0
139+
140+
// Convert the input to a string and split the hex symbol
141+
variable color_parts: List = {input}.to_string().split('#');
142+
143+
// Split the hex string into channel parts
144+
variable color: List = color_parts.get(1).split();
145+
146+
// Parse either 3 part or 6 part hex strings
147+
variable rgb: List;
148+
if (color.length() == 3) [
149+
rgb = parse_int(color.get(0).concat(color.get(0)), 16),
150+
parse_int(color.get(1).concat(color.get(1)), 16),
151+
parse_int(color.get(2).concat(color.get(2)), 16);
152+
] else [
153+
rgb = parse_int(color.get(0).concat(color.get(1)), 16),
154+
parse_int(color.get(2).concat(color.get(3)), 16),
155+
parse_int(color.get(4).concat(color.get(5)), 16);
156+
];
157+
158+
// Assemble the output type
159+
variable output: Color.Srgb;
160+
output.r = rgb.get(0);
161+
output.g = rgb.get(1);
162+
output.b = rgb.get(2);
163+
164+
return output;
165+
`}
166+
</TokenScriptCodeBlock>
167+
168+
### Function schemas
169+
170+
```json
171+
{
172+
"name": "Invert Color",
173+
"description": "Inverts a color by inverting each RGB channel (R' = 1 - R, G' = 1 - G, B' = 1 - B), preserving the alpha channel.",
174+
175+
"type": "function",
176+
177+
// The keyword by which the function can be called from: `invert(#333)`
178+
"keyword": "invert",
179+
180+
// The input arguments with the specified type
181+
"input": {
182+
"type": "object",
183+
"properties": {
184+
"color": {
185+
"type": "color",
186+
"description": "The color to invert."
187+
}
188+
}
189+
},
190+
// Script that will be executed on call
191+
"script": {
192+
"type": "https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/core/tokenscript/0/",
193+
"script": "variable input: List = {input};\nvariable baseColor: Color = input.get(0);\n\nvariable rgbColor: Color.Srgb = baseColor.to.srgb();\n\nvariable invertedR: Number = 255 - rgbColor.r;\nvariable invertedG: Number = 255 - rgbColor.g;\nvariable invertedB: Number = 255 - rgbColor.b;\n\nvariable invertedColor: Color.Srgb = srgb(invertedR, invertedG, invertedB);\nreturn invertedColor;"
194+
},
195+
// Schema dependencies, these will have to be set up in the Configuration for the function to work.
196+
"requirements": [
197+
"https://schema.tokenscript.dev.gcp.tokens.studio/api/v1/schema/srgb-color/0.1.0/"
198+
]
199+
}
200+
```
201+
202+
#### Script
203+
204+
<TokenScriptCodeBlock mode="script" showResult={true} input={["#FFF"]}>
205+
{`// Input #FFF
206+
variable input: List = {input};
207+
variable baseColor: Color = input.get(0);
208+
209+
variable rgbColor: Color.Srgb = baseColor.to.srgb();
210+
211+
variable invertedR: Number = 255 - rgbColor.r;
212+
variable invertedG: Number = 255 - rgbColor.g;
213+
variable invertedB: Number = 255 - rgbColor.b;
214+
215+
variable invertedColor: Color.Srgb = srgb(invertedR, invertedG, invertedB);
216+
return invertedColor;`}
217+
</TokenScriptCodeBlock>

sidebars-language.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const sidebars: SidebarsConfig = {
66
"types",
77
"control-flow",
88
"functions",
9+
"schemas",
910
],
1011
};
1112

0 commit comments

Comments
 (0)