Skip to content

Commit

Permalink
feat: add variables plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jakub-hajduk committed Mar 12, 2024
1 parent 495f192 commit 65824c3
Show file tree
Hide file tree
Showing 15 changed files with 491 additions and 458 deletions.
8 changes: 4 additions & 4 deletions packages/figma-parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@
"types": "./dist/index.d.ts",
"module": "./dist/index.mjs",
"devDependencies": {
"@types/mdast": "^4.0.1",
"@types/node": "^20.8.0",
"@types/picomatch": "^2.3.2",
"typescript": "^5.0.2",
"vite": "^4.4.9",
"vite-plugin-dts": "^3.6.0",
"vitest": "^0.34.6",
"wsrun": "^5.2.4"
},
"dependencies": {
"@types/mdast": "^4.0.1",
"@types/node": "^20.7.1",
"@types/picomatch": "^2.3.2",
"@figma/rest-api-spec": "^0.10.0",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser": "^6.13.2",
"flat": "^6.0.1",
Expand All @@ -45,7 +45,7 @@
"mdast-util-to-markdown": "^2.1.0",
"picomatch": "^2.3.1",
"remark": "^15.0.1",
"type-fest": "^4.8.3",
"type-fest": "^4.12.0",
"unist-builder": "^4.0.0"
},
"publishConfig": {
Expand Down
91 changes: 0 additions & 91 deletions packages/figma-parser/src/collection.ts

This file was deleted.

5 changes: 2 additions & 3 deletions packages/figma-parser/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FigmaParser, FigmaParserOptions, FigmaPAT } from './parser';

export * from './parser/index';
export * from './plugins/styles/index';
export * from './types'
export * from './types';

// decode-named-character-reference dependency of one of mdast plugins causes errors
// by introducing unnecesary document.createElement() calls.
Expand All @@ -15,5 +15,4 @@ export default function (token: FigmaPAT, options?: Partial<FigmaParserOptions>)
return new FigmaParser(token, options) as FigmaParser;
}


export { VariablesPlugin } from './plugins/variables/variables.plugin'
export { VariablesPlugin } from './plugins/variables/variables.plugin';
10 changes: 9 additions & 1 deletion packages/figma-parser/src/parser/parser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { NodeCollectionMixin, NodeMixin, NodesPlugin, SingleNode } from '../plugins/nodes';
import { StylesPlugin } from '../plugins/styles';
import { StylesProcessor } from '../plugins/styles/styles-processor';
import { CollectionsSet } from '../plugins/variables/collections-set';
import { VariablesPlugin } from '../plugins/variables/variables.plugin';
import { HardCache } from './hard-cache';
import { loggerFactory } from './logger';
import { FigmaParserPlugin, FigmaParserPluginConstructor, FigmaParserPluginFunction, FigmaParserPluginInterface } from './types';
Expand Down Expand Up @@ -29,7 +31,7 @@ export class FigmaParser {
cache: HardCache;

readonly options: FigmaParserOptions = {
plugins: [NodesPlugin, StylesPlugin],
plugins: [NodesPlugin, StylesPlugin, VariablesPlugin],
nodeMixins: [],
nodeCollectionMixins: [],
hardCache: true,
Expand Down Expand Up @@ -114,4 +116,10 @@ export class FigmaParser {

return plugin.styles(fileId);
}

async variables(fileId: string, published: boolean = true): Promise<CollectionsSet> {
const plugin = this.plugins.get('variables-plugin')! as ReturnType<typeof VariablesPlugin>;

return plugin.variables(fileId, published);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, test } from 'vitest';
import { ColorTokenValue, DesignTokens, GradientStop, GradientTokenValue, ShadowStop, ShadowTokenValue, TypographyTokenValue } from './design-tokens.transformer';
import { ColorTokenValue, GradientStop, GradientTokenValue, ShadowStop, ShadowTokenValue, TypographyTokenValue } from '../../shared/design-tokens-format.types';
import { DesignTokens } from './design-tokens.transformer';
import { DEFINITIONS_FIXTURE } from './tests/definitions.fixture';

describe('Design Tokens Transformer', () => {
Expand All @@ -10,13 +11,13 @@ describe('Design Tokens Transformer', () => {
describe('Solid Color Token', () => {
test('Should transform solid color definition', async () => {
const output = DesignTokens()(DEFINITIONS_FIXTURE);
const colorToken = output['color/token']['$value'];
const colorToken = output['color.token']['$value'];
expect(colorToken).toBeTypeOf('string');
});

test('Should take alpha value from parent definition', async () => {
const output = DesignTokens()(DEFINITIONS_FIXTURE);
const alphaHexValue = output['color/token']['$value'] as ColorTokenValue;
const alphaHexValue = output['color.token']['$value'] as ColorTokenValue;

const fillOpacity = 0.5; // ( FILE_NODES_FIXTURE['1171:10749'].document.fills[0].opacity )
const hexOpacity = Math.round(fillOpacity * 255)
Expand All @@ -36,7 +37,7 @@ describe('Design Tokens Transformer', () => {

const designTokens = DesignTokens();
const output = designTokens(DEFINITIONS_FIXTURE);
const gradientToken = output['gradient/token']['$value'] as GradientTokenValue;
const gradientToken = output['gradient.token']['$value'] as GradientTokenValue;

gradientToken.forEach((gradientStop: GradientStop) => expect(gradientStop).toMatchSchema(valueSchema));
});
Expand All @@ -53,7 +54,7 @@ describe('Design Tokens Transformer', () => {
};

const output = DesignTokens()(DEFINITIONS_FIXTURE);
const shadowToken = output['shadow/token']['$value'] as ShadowTokenValue;
const shadowToken = output['shadow.token']['$value'] as ShadowTokenValue;

shadowToken.forEach((shadow: ShadowStop) => expect(shadow).toMatchSchema(valueSchema));
});
Expand All @@ -70,7 +71,7 @@ describe('Design Tokens Transformer', () => {
};

const output = DesignTokens()(DEFINITIONS_FIXTURE);
const textToken = output['text/token']['$value'] as TypographyTokenValue;
const textToken = output['text.token']['$value'] as TypographyTokenValue;

expect(textToken).toMatchSchema(valueSchema);
});
Expand Down
110 changes: 15 additions & 95 deletions packages/figma-parser/src/plugins/styles/design-tokens.transformer.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,9 @@
import { DesignToken, DesignTokensFormat, DesignTokensFormatDeep, DesignTokensFormatFlat } from '../../shared/design-tokens-format.types';
import { entriesToDeepObject } from '../../shared/entriesToDeepObject.util';
import { rgbaToHexa } from '../../shared/rgba-to-hex.util';
import type { Effect, Paint, TypeStyle } from '../../types';
import { FigmaStyleDfeinition, FigmaStylesTransformer, isEffectDefinition, isFillDefinition, isTextDefinition } from './types';

export interface TypographyTokenValue {
fontFamily: string;
fontSize: number;
fontWeight: number;
letterSpacing: number;
lineHeight: number;
}

export interface GradientStop {
color: string;
position: number;
}

export type ColorTokenValue = `#${string}`;

export interface ShadowStop {
color: string;
offsetX: number;
offsetY: number;
blur: number;
spread: number;
}

export type ShadowTokenValue = ShadowStop[];

export type GradientTokenValue = GradientStop[];

export interface DesignToken {
$type: 'typography' | 'color' | 'shadow' | 'gradient';
$value: TypographyTokenValue | ColorTokenValue | GradientTokenValue | ShadowTokenValue;
}

export interface ColorToken extends DesignToken {
$type: 'color';
$value: ColorTokenValue;
}

export interface TypographyToken extends DesignToken {
$type: 'typography';
$value: TypographyTokenValue;
}

export interface ShadowToken extends DesignToken {
$type: 'shadow';
$value: ShadowTokenValue;
}

export interface GradientToken extends DesignToken {
$type: 'gradient';
$value: GradientTokenValue;
}

export const isShadowToken = (token: DesignToken): token is GradientToken => token.$type === 'shadow';

export const isColorToken = (token: DesignToken): token is ColorToken => token.$type === 'color';

export const isTypographyToken = (token: DesignToken): token is TypographyToken => token.$type === 'typography';

export const isGradientToken = (token: DesignToken): token is GradientToken => token.$type === 'gradient';

export interface DesignTokensFormatFlat {
[k: string]: DesignToken;
}

export interface DesignTokensFormatDeep {
[k: string]: DesignTokensFormatDeep;
}

const gradientTransform = (style: Paint) => {
if (!style || !style.gradientStops) throw new Error('Expected Paint style with gradientStops definitions!');
return style.gradientStops.map((stop) => ({
Expand Down Expand Up @@ -113,15 +47,18 @@ const shadowTransform = (style: Effect[]) => {
});
};

export function DesignTokens (deep: true): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormatDeep>;
export function DesignTokens (deep: false): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormatFlat>;
export function DesignTokens (deep: boolean = false): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormatFlat | DesignTokensFormatDeep> {
export function DesignTokens(): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormatFlat>;
export function DesignTokens(deep: true): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormatDeep>;
export function DesignTokens(deep: false): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormatFlat>;
export function DesignTokens(deep?: boolean): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormat>;
export function DesignTokens(deep: boolean = false): FigmaStylesTransformer<FigmaStyleDfeinition[], DesignTokensFormat> {
return (input: FigmaStyleDfeinition[]) => {
const stylesArray = input
.map((definition) => {
const tokenName = definition.name.replaceAll('/', '.').replaceAll(' ', '-');
if (isFillDefinition(definition) && definition.definition[0].type === 'SOLID') {
return [
definition.name,
tokenName,
{
$type: 'color',
$value: solidTransform(definition.definition[0]),
Expand All @@ -131,7 +68,7 @@ export function DesignTokens (deep: boolean = false): FigmaStylesTransformer<Fig

if (isFillDefinition(definition) && definition.definition[0].type === 'GRADIENT_LINEAR') {
return [
definition.name,
tokenName,
{
$type: 'gradient',
$value: gradientTransform(definition.definition[0]),
Expand All @@ -141,7 +78,7 @@ export function DesignTokens (deep: boolean = false): FigmaStylesTransformer<Fig

if (isTextDefinition(definition)) {
return [
definition.name,
tokenName,
{
$type: 'typography',
$value: typographyTransform(definition.definition),
Expand All @@ -151,7 +88,7 @@ export function DesignTokens (deep: boolean = false): FigmaStylesTransformer<Fig

if (isEffectDefinition(definition)) {
return [
definition.name,
tokenName,
{
$type: 'shadow',
$value: shadowTransform(definition.definition),
Expand All @@ -162,26 +99,9 @@ export function DesignTokens (deep: boolean = false): FigmaStylesTransformer<Fig
.filter(Boolean) as [string, DesignToken][];

if (deep) {
const output = {};

stylesArray.forEach(([name, value]) => {
const path = name.split('/');
path.reduce((acc: Record<string, object>, key: string, i: number) => {
if (acc[key] === undefined) acc[key] = {};

if (i === path.length - 1) {
acc[key] = {
...acc[key],
...value,
};
}

return acc[key];
}, output);
});

return output;
entriesToDeepObject(stylesArray);
}

return Object.fromEntries(stylesArray);
};
};
}
Loading

0 comments on commit 65824c3

Please sign in to comment.