,
511 | |};
512 | type CustomBase = $Shape ;
513 |
514 | type CustomFoundation = $Shape<{|
515 | palette: CustomPalette,
516 | base: CustomBase,
517 | |}>;
518 |
519 | export type FromPlainObject = (themePaletteColors: ThemePaletteColors) => Tokens;
520 | export type GetTokens = (customFoundation?: CustomFoundation) => Tokens;
521 |
522 | declare export var getTokens: GetTokens;
523 | declare export var fromPlainObject: FromPlainObject;
524 | declare export var defaultTokens: Tokens;
525 |
--------------------------------------------------------------------------------
/src/theo/generate-theo-parser.js:
--------------------------------------------------------------------------------
1 | const parser = require("@babel/parser");
2 | const fs = require("fs");
3 | const path = require("path");
4 |
5 | const { defaultTokens } = require("../../lib/index");
6 |
7 | const code = fs.readFileSync(path.resolve(__dirname, "../../lib/index.js"), "utf8");
8 |
9 | const ast = parser.parse(code, {
10 | sourceType: "module", // allow export
11 | allowImportExportEverywhere: true,
12 | plugins: ["flow"],
13 | });
14 |
15 | const findDeclaration = x => x.id.name === "getTokens";
16 | const findGetTokens = x => x.type === "VariableDeclaration" && x.declarations.find(findDeclaration);
17 |
18 | const ar = ast.program.body.find(findGetTokens);
19 | const tokenProps = ar.declarations[0].init.body.body[1].argument.properties
20 |
21 | const camelCaseToText = text => {
22 | let result = text.replace(/([A-Z])/g, " $1");
23 | result = result.charAt(0).toUpperCase() + result.slice(1); // capitalize the first letter
24 | return result;
25 | };
26 |
27 | const getType = (value, hint) => {
28 | if (typeof value !== "string") return typeof value;
29 | if (value.startsWith("#") || value.startsWith("rgb")) return "color";
30 | if (value.includes("px")) return "size";
31 | if (value[value.length - 1] === "%") return "size";
32 | return "string";
33 | };
34 |
35 | const getCategory = (category, key) => {
36 | // Workarounds
37 | if (category === "color") return "text-color";
38 | if (category === "zIndex") return "spacing";
39 | if (category === "size") return "sizing";
40 | return category.replace(/([A-Z])/g, g => `-${g[0].toLowerCase()}`);
41 | };
42 |
43 | const getProps = (tokenProps, category) =>
44 | tokenProps.reduce((p, c) => Object.assign(p, getInfo(c, category)), {});
45 |
46 | let category = "";
47 | let categoryDescription = "";
48 | let comment;
49 |
50 | const categoryCommentFn = c => c.startsWith("category:");
51 | const categoryDescriptionFn = c => c.startsWith("description:");
52 | const itemCommentFn = c => !categoryCommentFn(c) && !categoryDescriptionFn(c);
53 |
54 | const getInfo = (tokenProp, xcategory) => {
55 | const key = tokenProp.key.name;
56 | const value = xcategory ? defaultTokens[xcategory][key] : defaultTokens[key];
57 | if (value == null) {
58 | console.error("Wrong value for", key);
59 | throw new Error(`Wrong value for ${key}`);
60 | }
61 | const type = typeof value;
62 | if (type === "object") return getProps(tokenProp.value.properties, key);
63 | comment = undefined;
64 | const hasComment = tokenProp.leadingComments && tokenProp.leadingComments.length;
65 | if (hasComment) {
66 | const comments = tokenProp.leadingComments.map(x => x.value.trimLeft());
67 | const categoryComment = comments.find(categoryCommentFn);
68 | if (categoryComment) category = categoryComment.substr(9);
69 | const categoryDescriptionComm = comments.find(categoryDescriptionFn);
70 | if (categoryDescriptionComm) categoryDescription = categoryDescriptionComm.substr(12);
71 | const itemComment = comments.filter(itemCommentFn);
72 | if (itemComment.length) {
73 | comment = itemComment
74 | .map(c => (c.startsWith("*") ? c.substr(1) : c))
75 | .join(" ")
76 | .trim();
77 | }
78 | }
79 | return {
80 | [key]: {
81 | value,
82 | type: getType(value),
83 | category,
84 | comment,
85 | meta: {
86 | categoryDescription,
87 | },
88 | },
89 | };
90 | };
91 |
92 | const props = getProps(tokenProps);
93 | fs.writeFileSync(path.resolve(__dirname, "./theo-spec.json"), JSON.stringify({ props }, null, 2));
94 |
--------------------------------------------------------------------------------
/src/theo/kiwi-html.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
2 | // Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license
3 |
4 | const groupBy = require("lodash/groupBy");
5 | const camelCase = require("lodash/camelCase");
6 | const upperfirst = require("lodash/upperFirst");
7 |
8 | class Styleguide {
9 | constructor({ props, options }) {
10 | this.options = Object.assign(
11 | {
12 | transformPropName: camelCase,
13 | },
14 | options,
15 | );
16 | this.categories = groupBy(props, "category");
17 | }
18 |
19 | renderRowHeader(id, heading) {
20 | return `
21 |
22 |
23 | ${heading}
24 | Value
25 | Examples
26 | Usage
27 |
28 |
29 | `;
30 | }
31 |
32 | renderRow(prop, example) {
33 | const name = prop.name; // this.options.transformPropName(prop.name);
34 | return `
35 |
36 |
37 | ${name}
38 |
39 |
40 | ${prop.value}
41 |
42 | ${example}
43 | ${prop.comment ? prop.comment : ""}
44 |
45 | `;
46 | }
47 |
48 | renderSpacing(props) {
49 | return props.map(prop => {
50 | const example = `
51 |
52 |
53 |
54 | `;
55 | return this.renderRow(prop, example);
56 | });
57 | }
58 |
59 | renderSizing(props) {
60 | return props.map(prop => {
61 | const name = prop.name;
62 | let style = `width: ${prop.value}; height: ${prop.value};`;
63 | if (name.startsWith("widthButtonMinimal")) style = `width: ${prop.value}; min-height: 16px;`;
64 | const example = `
65 |
66 |
67 |
68 | `;
69 | return this.renderRow(prop, example);
70 | });
71 | }
72 |
73 | renderFont(props) {
74 | return props.map(prop => {
75 | const example = `
76 |
77 |
78 | The quick brown fox jumps over the lazy dog.
79 |
80 |
81 | `;
82 | return this.renderRow(prop, example);
83 | });
84 | }
85 |
86 | renderFontStyle(props) {
87 | return props.map(prop => {
88 | const example = `
89 |
90 |
91 | The quick brown fox jumps over the lazy dog.
92 |
93 |
94 | `;
95 | return this.renderRow(prop, example);
96 | });
97 | }
98 |
99 | renderFontWeight(props) {
100 | return props.map(prop => {
101 | const example = `
102 |
103 |
104 | The quick brown fox jumps over the lazy dog.
105 |
106 |
107 | `;
108 | return this.renderRow(prop, example);
109 | });
110 | }
111 |
112 | renderFontSize(props) {
113 | return props.map(prop => {
114 | const example = `
115 |
116 |
117 | The quick brown fox jumps over the lazy dog.
118 |
119 |
120 | `;
121 | return this.renderRow(prop, example);
122 | });
123 | }
124 |
125 | renderLineHeight(props) {
126 | return props.map(prop => {
127 | const vHeight = !isNaN(prop.value) ? `${prop.value}em` : prop.value;
128 | const example = `
129 |
130 |
133 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
134 | elementum odio et lacus rutrum molestie. Nunc arcu enim, elementum
135 | id feugiat at, venenatis quis erat.
136 |
137 |
138 | `;
139 | return this.renderRow(prop, example);
140 | });
141 | }
142 |
143 | renderFontFamily(props) {
144 | return props.map(prop => {
145 | const example = `
146 |
147 |
148 | The quick brown fox jumps over the lazy dog.
149 |
150 |
151 | `;
152 | return this.renderRow(prop, example);
153 | });
154 | }
155 |
156 | renderBorderStyle(props) {
157 | return props.map(prop => {
158 | const example = ` `;
159 | return this.renderRow(prop, example);
160 | });
161 | }
162 |
163 | renderBorderColor(props) {
164 | return props.map(prop => {
165 | const example = ` `;
166 | return this.renderRow(prop, example);
167 | });
168 | }
169 |
170 | renderHrColor(props) {
171 | return props.map(prop => {
172 | const example = `
173 |
174 |
175 |
176 | `;
177 | return this.renderRow(prop, example);
178 | });
179 | }
180 |
181 | renderRadius(props) {
182 | return props.map(prop => {
183 | const name = this.options.transformPropName(prop.name);
184 | const example = `
185 |
186 |
187 |
188 | `;
189 | return this.renderRow(prop, example);
190 | });
191 | }
192 |
193 | renderBorderRadius(props) {
194 | return props.map(prop => {
195 | const example = `
196 |
197 |
198 |
199 | `;
200 | return this.renderRow(prop, example);
201 | });
202 | }
203 |
204 | renderBackgroundColor(props) {
205 | return props.map(prop => {
206 | const example = ` `;
209 | return this.renderRow(prop, example);
210 | });
211 | }
212 |
213 | renderGradient(props) {
214 | return props.map(prop => {
215 | const example = ` `;
216 | return this.renderRow(prop, example);
217 | });
218 | }
219 |
220 | renderBackgroundGradient(props) {
221 | return props.map(prop => {
222 | const example = ` `;
223 | return this.renderRow(prop, example);
224 | });
225 | }
226 |
227 | renderDropShadow(props) {
228 | return props.map(prop => {
229 | const example = ` `;
230 | return this.renderRow(prop, example);
231 | });
232 | }
233 |
234 | renderBoxShadow(props) {
235 | return props.map(prop => {
236 | const example = ` `;
237 | return this.renderRow(prop, example);
238 | });
239 | }
240 |
241 | renderTextColor(props) {
242 | return props.map(prop => {
243 | const example = `
244 |
245 | The quick brown fox jumps over the lazy dog.
246 |
247 | `;
248 | return this.renderRow(prop, example);
249 | });
250 | }
251 |
252 | renderTextShadow(props) {
253 | return props.map(prop => {
254 | const example = `
255 |
256 | The quick brown fox jumps over the lazy dog.
257 |
258 | `;
259 | return this.renderRow(prop, example);
260 | });
261 | }
262 |
263 | renderTime(props) {
264 | return props.map(prop => {
265 | const example = ` `;
266 | return this.renderRow(prop, example);
267 | });
268 | }
269 |
270 | renderMediaQuery(props) {
271 | return props.map(prop => {
272 | const example = ` `;
273 | return this.renderRow(prop, example);
274 | });
275 | }
276 |
277 | renderValues(props) {
278 | return props.map(prop => this.renderRow(prop, ` `));
279 | }
280 |
281 | renderSection(type, heading, fn) {
282 | const props = this.categories[type];
283 | if (!props) {
284 | return "";
285 | }
286 | const name = upperfirst(camelCase(type));
287 | const render = typeof fn === "function" ? fn : this[`render${name}`];
288 | return `
289 |
290 |
291 | ${this.renderRowHeader(type, heading)}
292 |
293 | ${render
294 | .call(this, props)
295 | .join("")
296 | .trim()}
297 |
298 |
299 |
300 |
301 | `;
302 | }
303 |
304 | render() {
305 | return `
306 |
307 |
308 |
309 |
310 |
311 | Orbit Design Tokens
312 |
313 |
314 |
411 |
412 |
413 |
418 |
419 |
420 | ${this.renderSection("Colors", "Colors", this.renderTextColor)}
421 | ${this.renderSection("Background colors", "Background Colors", this.renderBackgroundColor)}
422 | ${this.renderSection("Font family", "Font Families", this.renderFontFamily)}
423 | ${this.renderSection("Font size", "Font Sizes", this.renderFontSize)}
424 | ${this.renderSection("Font weight", "Font Weights", this.renderFontWeight)}
425 |
426 | ${this.renderSection("Border radius", "Border Radius", this.renderBorderRadius)}
427 | ${this.renderSection("Size (width, height)", "Sizing", this.renderSizing)}
428 | ${this.renderSection("Border color", "Border Colors", this.renderBorderColor)}
429 | ${this.renderSection("Border style", "Border Styles", this.renderBorderStyle)}
430 | ${this.renderSection("Spacing", "Spacing", this.renderSpacing)}
431 | ${this.renderSection("Line height", "Line Heights", this.renderLineHeight)}
432 | ${this.renderSection("Modifier", "Modifier", this.renderValues)}
433 | ${this.renderSection("Text decoration", "Text decoration", this.renderValues)}
434 | ${this.renderSection("Duration", "Duration", this.renderValues)}
435 | ${this.renderSection("Opacity", "Opacity", this.renderValues)}
436 | ${this.renderSection("Z Index", "Z Index", this.renderValues)}
437 | ${this.renderSection("Box shadow", "Box Shadows", this.renderBoxShadow)}
438 |
439 | ${this.renderSection("text-color", "Text Colors")}
440 | ${this.renderSection("text-shadow", "Text Shadows")}
441 | ${this.renderSection("background-color", "Background Colors")}
442 | ${this.renderSection("sizing", "Sizing")}
443 | ${this.renderSection("spacing", "Spacing")}
444 | ${this.renderSection("font", "Fonts")}
445 | ${this.renderSection("font-style", "Font Styles")}
446 | ${this.renderSection("font-weight", "Font Weights")}
447 | ${this.renderSection("font-size", "Font Sizes")}
448 | ${this.renderSection("font-family", "Font Families")}
449 | ${this.renderSection("line-height", "Line Heights")}
450 | ${this.renderSection("border-style", "Border Styles")}
451 | ${this.renderSection("border-color", "Border Colors")}
452 | ${this.renderSection("radius", "Radius")}
453 | ${this.renderSection("border-radius", "Border Radius")}
454 | ${this.renderSection("hr-color", "Horizontal Rule Colors")}
455 | ${this.renderSection("gradient", "Gradients")}
456 | ${this.renderSection("background-gradient", "Background Gradients")}
457 | ${this.renderSection("drop-shadow", "Drop Shadows")}
458 | ${this.renderSection("box-shadow", "Box Shadows")}
459 | ${this.renderSection("inner-shadow", "Inner Drop Shadows", this.renderDropShadow)}
460 | ${this.renderSection("time", "Time")}
461 | ${this.renderSection("media-query", "Media Queries")}
462 |
463 |
464 |
465 |
466 | `;
467 | }
468 | }
469 |
470 | module.exports = result => {
471 | const styleguide = new Styleguide(result.toJS());
472 | return styleguide.render();
473 | };
474 |
--------------------------------------------------------------------------------
/src/theo/setup.js:
--------------------------------------------------------------------------------
1 | const html = require("./kiwi-html");
2 |
3 | module.exports = theo => {
4 | theo.registerValueTransform(
5 | "addpx",
6 | prop => prop.get("type") === "size",
7 | prop => `${prop.get("value")}px`,
8 | );
9 | theo.registerTransform("web", ["addpx"]);
10 | theo.registerFormat("kiwi.html", html);
11 | };
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["esnext", "dom"],
4 | "strict": true,
5 | "noImplicitAny": false,
6 | "moduleResolution": "node",
7 | "jsx": "preserve",
8 | "baseUrl": "./"
9 | },
10 | "include": [
11 | "src/**/*"
12 | ],
13 | "exclude": [
14 | "node_modules",
15 | "lib",
16 | "umd",
17 | "es"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------