├── .gitignore ├── LICENSE ├── README.md ├── core-asset-repository ├── LICENSE ├── README.md ├── lib │ ├── hosting │ │ └── index.ts │ ├── image-repository │ │ ├── base-image-repository.ts │ │ ├── image-asset.ts │ │ ├── image-repository.ts │ │ ├── index.ts │ │ ├── main-image-repository.ts │ │ └── temporary-image-asset-url-reservation.ts │ └── index.ts ├── package.json └── tsconfig.json ├── core-flags-dashdash ├── LICENSE ├── README.md ├── index.d.ts ├── index.js └── package.json ├── core-flags ├── @special │ ├── README.md │ ├── index.ts │ └── keys.ts ├── README.md ├── __test__ │ ├── parsing-strategy-dashdash.test.ts │ ├── parsing-strategy-parentheses.test.ts │ └── parsing-strategy-unique.test.ts ├── index.ts ├── jest.config.js ├── package.json ├── parsing-strategy-dashdash │ ├── README.md │ └── index.ts ├── parsing-strategy-parentheses │ └── README.md ├── parsing-strategy-unique │ ├── README.md │ └── index.ts ├── support-data-mapping │ └── README.md ├── tsconfig.json └── yarn.lock ├── core-query ├── README.md ├── index.ts ├── jest.config.js ├── package.json ├── query-node.test.ts ├── query-node.ts └── tsconfig.json ├── core-types ├── design-provider.ts ├── index.ts ├── package.json └── tsconfig.json ├── core ├── README.md ├── index.ts ├── jest.config.js ├── package.json ├── platform │ └── index.ts ├── tsconfig.json ├── utils │ ├── colors │ │ ├── gradient.ts │ │ ├── index.ts │ │ └── retrieve-colors.ts │ ├── common-padding.ts │ ├── common-position.ts │ ├── coordinates.ts │ ├── index.ts │ ├── node-width-height.ts │ ├── retrieve-colliding-children.ts │ └── used-colors.ts └── yarn.lock ├── design-diff ├── README.md ├── _types │ └── index.ts ├── diff-fills │ └── index.ts ├── diff-instance │ └── index.ts ├── diff-text-data │ └── index.ts ├── diff-text │ └── index.ts ├── diff-utils │ └── index.ts ├── diff-vector │ └── README.md ├── index.ts ├── package.json └── tsconfig.json ├── design-sdk ├── lib │ ├── figma.ts │ └── index.ts ├── package.json └── tsconfig.json ├── docs ├── figma-stores.md └── index.md ├── figma-auth-store ├── LICENSE ├── README.md ├── index.ts ├── jest.config.js ├── lib │ ├── access-token-oauth.ts │ ├── access-token-personal.ts │ ├── access-token.ts │ ├── figma-auth-store.ts │ ├── index.ts │ ├── is-browser.ts │ └── keys.ts ├── package.json └── tsconfig.json ├── figma-checksum ├── README.md ├── base │ └── index.ts ├── index.ts ├── k │ └── index.ts ├── package.json ├── service │ ├── CONTRIBUTING.md │ ├── README.md │ └── index.ts ├── strategy-with-otp-node │ └── index.ts ├── strategy-with-pages-signature │ └── index.ts ├── strategy-with-root-node-store │ └── index.ts └── tsconfig.json ├── figma-core ├── LICENSE ├── README.md ├── filekey.ts ├── index.ts ├── mixed.ts ├── package.json └── tsconfig.json ├── figma-node-conversion ├── lib │ ├── conversion │ │ ├── conversion.ts │ │ ├── force-convert-rect-to-frame.ts │ │ └── index.ts │ ├── converters │ │ ├── README.md │ │ ├── blend-mode.convert.ts │ │ ├── color.convert.ts │ │ ├── corner-radius.convert.ts │ │ ├── cross-axis-alignment.convert.ts │ │ ├── font-style.convert.ts │ │ ├── index.ts │ │ ├── layout-align.convert.ts │ │ ├── layout-grow.convert.ts │ │ ├── layout-mode.convert.ts │ │ ├── letter-spacing.convert.ts │ │ ├── line-height.convert.ts │ │ ├── main-axis-alignment.convert.ts │ │ ├── tetx-decoration.convert.ts │ │ ├── text-align.converter.ts │ │ ├── text-case.ts │ │ └── text-style.convert.ts │ └── index.ts ├── package.json └── tsconfig.json ├── figma-node-repository ├── lib │ ├── README.md │ ├── index.ts │ └── node-repository.ts ├── package.json └── tsconfig.json ├── figma-oauth-react ├── README.md ├── index.ts ├── lib │ ├── index.ts │ └── use-figma-auth-state │ │ └── index.ts ├── package.json └── tsconfig.json ├── figma-oauth ├── LICENSE ├── README.md ├── __test__ │ ├── .env.defaults │ ├── oauth.test.ts │ └── url-build.test.ts ├── index.ts ├── jest.config.js ├── lib │ ├── configure.ts │ ├── index.ts │ ├── oauth.ts │ ├── request.ts │ ├── types.ts │ └── urls.ts ├── package.json ├── tsconfig.json └── yarn.lock ├── figma-reflect-node-types ├── index.d.ts ├── index.js └── package.json ├── figma-reflect-node ├── LICENSE ├── README.md ├── lib │ ├── base.node.ts │ ├── boolean-operation.node.ts │ ├── ellipse.node.ts │ ├── frame.node.ts │ ├── group.node.ts │ ├── index.ts │ ├── interfaces │ │ └── default-shape-mixin.ts │ ├── line.node.ts │ ├── make-reflect-node-reference.ts │ ├── mixins │ │ ├── blend.mixin.ts │ │ ├── children.mixin.ts │ │ ├── constraint.mixin.ts │ │ ├── corner.mixin.ts │ │ ├── default-shape.mixin.ts │ │ ├── geometry.mixin.ts │ │ ├── index.ts │ │ └── layout.mixin.ts │ ├── node-type-alias.ts │ ├── node-type.ts │ ├── rectangle.node.ts │ ├── reflect-node-reference.ts │ ├── text.node.ts │ └── vector.node.ts ├── package.json └── tsconfig.json ├── figma-remote-api ├── LICENSE ├── README.md ├── __test__ │ ├── .gitignore │ ├── README.md │ └── dummy.test.ts ├── index.ts ├── jest.config.js ├── package.json └── tsconfig.json ├── figma-remote-types ├── LICENSE ├── README.md ├── index.d.ts ├── index.js └── package.json ├── figma-remote ├── README.md ├── __test__ │ ├── .env.example │ ├── .gitignore │ ├── README.md │ ├── fecth.test.ts │ └── setup.ts ├── jest.config.js ├── lib │ ├── README.md │ ├── asset-repository │ │ ├── image-repository │ │ │ └── index.ts │ │ └── index.ts │ ├── blenders │ │ ├── _in.ts │ │ ├── corner.blend.ts │ │ ├── general.blend.ts │ │ ├── index.ts │ │ └── vector.blend.ts │ ├── configure-auth-credentials │ │ ├── __internal__.ts │ │ ├── export-me.ts │ │ └── index.ts │ ├── converters │ │ ├── constraints-mixin.convert.ts │ │ ├── effect.convert.ts │ │ ├── fills.convert.ts │ │ ├── index.ts │ │ ├── layout-constraints.convert.ts │ │ ├── line-height.convert.ts │ │ ├── paint.convert.ts │ │ ├── stroke-cap.convert.ts │ │ └── strokes.convert.ts │ ├── fetch │ │ ├── demo.ts │ │ ├── errors.ts │ │ ├── figma-default-set.ts │ │ ├── index.ts │ │ └── types.ts │ ├── index.ts │ └── mapper │ │ ├── boolean-operation.mapper.ts │ │ ├── component.mapper.ts │ │ ├── ellipse.mapper.ts │ │ ├── frame.mapper.ts │ │ ├── group.mapper.ts │ │ ├── index.ts │ │ ├── instance.mapper.ts │ │ ├── line.mapper.ts │ │ ├── mapper.ts │ │ ├── mapping-instance.ts │ │ ├── polygon.mapper.ts │ │ ├── rectangle.mapper.ts │ │ ├── star.mapper.ts │ │ ├── text.mapper.ts │ │ └── vector.mapper.ts ├── package.json └── tsconfig.json ├── figma-types ├── LICENSE ├── README.md ├── __test__ │ ├── README.md │ └── main.test.ts ├── lib │ ├── boolean-operation.ts │ ├── color.ts │ ├── corner-radius.ts │ ├── counter-axis-align-items.ts │ ├── counter-axis-sizing-mode.ts │ ├── figma-node-action-navigation.ts │ ├── figma-reaction-action.ts │ ├── figma-reaction-node-action.ts │ ├── figma-reaction-pop-action.ts │ ├── figma-reaction-url-action.ts │ ├── index.ts │ ├── layout-align.ts │ ├── layout-grow.ts │ ├── layout-mode.ts │ ├── primary-axis-align-items.ts │ ├── primary-axis-sizing-mode.ts │ ├── text-alignment.ts │ ├── text-auto-resize.ts │ ├── text-decoration.ts │ └── v1.ts ├── package.json └── tsconfig.json ├── figma-url ├── LICENSE ├── REAMDE.md ├── __test__ │ ├── analyze.test.ts │ ├── embed.test.ts │ └── parse.test.ts ├── jest.config.js ├── lib │ ├── access-check.ts │ ├── analyze-url.ts │ ├── compare-url.ts │ ├── constants.ts │ ├── embed-url.ts │ ├── index.ts │ ├── parse-url.ts │ └── target-node-config.ts ├── package.json └── tsconfig.json ├── figma-utils ├── README.md ├── lib │ ├── check-if-auto-layout.ts │ ├── check-if-root.ts │ ├── children.ts │ ├── filter-fills.ts │ ├── has-image.ts │ ├── index.ts │ ├── lcrs.ts │ ├── paint-to-color.ts │ ├── primary-color.ts │ ├── retrieve-fill.ts │ └── retrieve-image-fills.ts ├── package.json └── tsconfig.json ├── figma-xpath ├── README.md ├── lib │ ├── index-path │ │ └── index.ts │ └── index.ts ├── package.json └── tsconfig.json ├── figma ├── README.md ├── asset-repository │ ├── image-repository │ │ └── index.ts │ └── index.ts ├── features │ ├── index.ts │ └── variant │ │ ├── README.md │ │ ├── index.ts │ │ ├── swap-instance.ts │ │ ├── variant-name-utils.ts │ │ ├── variant-property-parser.ts │ │ ├── variant-property-type.ts │ │ └── variant-property.ts ├── index.ts ├── node-analysis │ ├── component-like-type-analysis │ │ ├── analyze.ts │ │ ├── index.ts │ │ └── type.ts │ └── index.ts ├── package.json ├── tsconfig.json └── utils │ ├── index.ts │ ├── is-route-action.ts │ └── text-style.figma.ts ├── grida └── README.md ├── lerna.json ├── package.json ├── sampler ├── .env.example ├── .gitignore ├── README.md ├── index.ts ├── out │ └── .gitignore ├── package.json ├── sampler.ts ├── tsconfig.json └── yarn.lock ├── sketch-node-conversion ├── lib │ ├── converters │ │ ├── index.ts │ │ └── text-align.convert.ts │ └── index.ts └── package.json ├── sketch-types ├── README.md ├── lib │ ├── index.ts │ └── v3.ts ├── package.json ├── tsconfig.json └── yarn.lock ├── sketch ├── README.md ├── lib │ └── index.ts ├── package.json └── tsconfig.json ├── tsconfig.build.json ├── tsconfig.json ├── universal ├── index.ts ├── package.json └── tsconfig.json ├── url-analysis ├── lib │ └── index.ts ├── package.json └── tsconfig.json ├── vanilla ├── lib │ ├── index.ts │ └── make │ │ ├── cgrect.make.ts │ │ └── index.ts ├── package.json └── tsconfig.json ├── xd-node-conversion ├── index.ts ├── package.json └── tsconfig.json ├── xd-types ├── README.md ├── package.json └── tsconfig.json ├── xd ├── README.md ├── index.ts ├── package.json └── tsconfig.json └── yarn.lock /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DESIGN SDK 2 | 3 | > Build a single app that supports all figma, sketch, xd and bridged. 4 | 5 | A mid wrapper for building consistant figma & sketch & reflection plugin, with single api reference 6 | 7 | > Powers [Grida Figma Assistant](https://github.com/gridaco/assistant) 8 | 9 | ## Features 10 | 11 | - mocks desing platform environment - faster development. 12 | - single api reference - write once, run everywhere. 13 | - reflect standard in the box - based on [reflect](https://reflect-ui.com) DSL, develop with unified api structure. 14 | - UI support - different ui feedback features by platform such as modals (xd), notify (figma) is supported by ui library 15 | - OOP Based design access objects 16 | - General UI Related utilities in the box 17 | - Testing supported 18 | - Provides Web based development environment 19 | 20 | ## Packages & Usage 21 | 22 | ```sh 23 | yarn add @design-sdk/ 24 | ``` 25 | 26 | **Packages** 27 | 28 | - figma 29 | - figma-remote 30 | - figma-url 31 | - xd 32 | - sketch 33 | 34 | ## Are you looking for universal design converter? 35 | 36 | Take a look at [design-file-converter](https://github.com/gridaco/design-file-converter) 37 | 38 | ## Sketch reference 39 | 40 | - https://developer.sketch.com/plugins/javascript-api 41 | - https://developer.sketch.com/reference/api/ 42 | 43 | ## Figma reference 44 | 45 | - https://www.figma.com/plugin-docs/api/ 46 | 47 | ## XD reference 48 | 49 | - https://adobexdplatform.com/plugin-docs/reference/xd-index.html 50 | -------------------------------------------------------------------------------- /core-asset-repository/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /core-asset-repository/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Asset Repository 4 | 5 | ```bash 6 | yarn add @design-sdk/asset-repository 7 | ``` 8 | 9 | ```ts 10 | import R, { resolve } from "@design-sdk/asset-repository"; 11 | import {} from "@design-sdk/asset-repository-plugin-figma"; 12 | const provider = new FigmaAssetProvider({}); 13 | 14 | R.register(); 15 | ``` 16 | 17 | ## Use cases 18 | 19 | - When you mark required assets on code generation. once the code generation is complete, fetch those images and replace the source. 20 | - When you export node json on figma plugin. you can export each layer on final step. 21 | -------------------------------------------------------------------------------- /core-asset-repository/lib/image-repository/image-asset.ts: -------------------------------------------------------------------------------- 1 | import { MainImageRepository } from "./main-image-repository"; 2 | import { build_temp_static_remote_asset_uri_to_be_replaced_later__dangerous } from "./temporary-image-asset-url-reservation"; 3 | 4 | export abstract class TemporaryAsset { 5 | data?: T; 6 | url: string; 7 | constructor( 8 | readonly key: string, 9 | args?: { 10 | url?: string; 11 | data?: T; 12 | } 13 | ) { 14 | this.url = args?.url; 15 | this.data = args?.data; 16 | } 17 | 18 | abstract fetchData(): T | Promise; 19 | } 20 | 21 | export interface ImageAsset { 22 | data: Uint8Array; 23 | key: string; 24 | url: string; 25 | } 26 | 27 | export class TemporaryImageAsset< 28 | P extends string = string 29 | > extends TemporaryAsset { 30 | data?: Uint8Array; 31 | url: P; 32 | constructor( 33 | readonly key: string, 34 | readonly hash: string, 35 | readonly prefix: P, 36 | args?: { 37 | data?: Uint8Array; 38 | } 39 | ) { 40 | super(key, args); 41 | this.url = this.makeUrl(key); 42 | } 43 | 44 | makeUrl(key: string): P { 45 | return build_temp_static_remote_asset_uri_to_be_replaced_later__dangerous

( 46 | this.prefix, 47 | key 48 | ); 49 | } 50 | 51 | async fetchData(config?: { type: "original" }): Promise { 52 | if (this.data) { 53 | // if data exists, return it. 54 | return this.data; 55 | } 56 | // return await ImageRepositories.fetchDataByHash(this.hash) 57 | return await MainImageRepository.instance.fetchDataById(this.key, config); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core-asset-repository/lib/image-repository/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./base-image-repository"; 2 | export * from "./image-asset"; 3 | export * from "./image-repository"; 4 | export * from "./main-image-repository"; 5 | -------------------------------------------------------------------------------- /core-asset-repository/lib/image-repository/main-image-repository.ts: -------------------------------------------------------------------------------- 1 | import type { BaseImageRepositories } from "./base-image-repository"; 2 | 3 | /** 4 | * singleton reference holder class since BaseImageRepositories is abstract and gets override by platform 5 | */ 6 | export class MainImageRepository { 7 | private static _main: BaseImageRepositories; 8 | static set instance(instance: BaseImageRepositories) { 9 | this._main = instance; 10 | } 11 | 12 | static get instance(): BaseImageRepositories { 13 | if (!this._main) { 14 | throw "cannot get main ImageRepositories. set it via `MainImageRepository.set()` before calling this."; 15 | } 16 | return this._main; 17 | } 18 | 19 | static get isReady(): boolean { 20 | return !!this._main; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core-asset-repository/lib/image-repository/temporary-image-asset-url-reservation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param prefix full uri scheme like prefix, e.g. `https://domain.com/` 4 | * @param key 5 | * @returns 6 | */ 7 | export function build_temp_static_remote_asset_uri_to_be_replaced_later__dangerous< 8 | P extends string = string 9 | >(prefix: P, key: string): P { 10 | return `${prefix || ""}${key}` as P; 11 | } 12 | -------------------------------------------------------------------------------- /core-asset-repository/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./hosting"; 2 | export * from "./image-repository"; 3 | -------------------------------------------------------------------------------- /core-asset-repository/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/asset-repository", 3 | "version": "0.0.53", 4 | "license": "Apache 2.0", 5 | "author": "grida.co", 6 | "private": false, 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "scripts": { 10 | "clean": "rimraf dist", 11 | "build": "tsc" 12 | }, 13 | "dependencies": { 14 | "@base-sdk/hosting": "^0.1.2" 15 | }, 16 | "devDependencies": { 17 | "@base-sdk/base": "^0.1.4", 18 | "typescript": "^4.2.4" 19 | }, 20 | "files": [ 21 | "dist", 22 | "README", 23 | "LICENSE" 24 | ], 25 | "publishConfig": { 26 | "access": "public" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core-asset-repository/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "./dist" 6 | }, 7 | "include": ["./lib"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /core-flags-dashdash/LICENSE: -------------------------------------------------------------------------------- 1 | # This is the MIT license 2 | 3 | Copyright (c) 2021 Grida, INC. All rights reserved. 4 | Copyright (c) 2013 Trent Mick. All rights reserved. 5 | Copyright (c) 2013 Joyent Inc. All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included 16 | in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /core-flags-dashdash/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/core-flags-dashdash", 3 | "description": "dashdash", 4 | "version": "0.0.53", 5 | "private": false, 6 | "main": "index.js", 7 | "types": "index.d.ts", 8 | "scripts": { 9 | "build": "exit 0" 10 | }, 11 | "devDependencies": { 12 | "@types/node": "^16.10.3" 13 | }, 14 | "files": [ 15 | "index.js", 16 | "index.d.ts", 17 | "README.md", 18 | "LICENSE" 19 | ], 20 | "publishConfig": { 21 | "access": "public" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /core-flags/@special/README.md: -------------------------------------------------------------------------------- 1 | # Special Node Layer key indication 2 | 3 | All special layers are by default, ignored on the result data. 4 | 5 | ## `@ignore` - Ignore All indication 6 | 7 | ## Features : Ignore 8 | 9 | > ignores node with names, or plugin data 10 | -------------------------------------------------------------------------------- /core-flags/@special/index.ts: -------------------------------------------------------------------------------- 1 | import { SpecialKeys, _all_keys } from "./keys"; 2 | import { parse as parseunique } from "../parsing-strategy-unique"; 3 | export * from "./keys"; 4 | 5 | export function shouldIgnore(name: string): boolean { 6 | const _maybe_special = parseunique(name, [SpecialKeys.ignore_all.key]); 7 | return _maybe_special == SpecialKeys.ignore_all.key; 8 | } 9 | 10 | export function parse(name: string): string | false { 11 | return parseunique(name, _all_keys); 12 | } 13 | -------------------------------------------------------------------------------- /core-flags/@special/keys.ts: -------------------------------------------------------------------------------- 1 | export const SPECIAL_KEY_PREFIX_TOKEN = "//@"; 2 | /** 3 | * ignore keys contains special keys such as simply ignore, data source + .. 4 | */ 5 | export const SpecialKeys = { 6 | /** 7 | * key to be fully ignored 8 | */ 9 | ignore_all: { 10 | key: "ignore", 11 | pattern: "//@ignore", 12 | }, 13 | /** 14 | * key to represent that this is a datasource node and (which will not be converted anyway) 15 | */ 16 | data_source: { 17 | key: "data-source", 18 | pattern: "//@data-source", 19 | }, 20 | 21 | /** 22 | * this key specified unmanaged node (non-component) to be explicitly detected by data mapper 23 | * so, "//@data-target/name" will be a property target corresponding to "name" 24 | */ 25 | data_mapper_target: { 26 | key: "data-target", 27 | pattern: "//@data-target/", 28 | }, 29 | }; 30 | 31 | export const _all_keys = Object.keys(SpecialKeys).map( 32 | (k) => SpecialKeys[k].key 33 | ); 34 | 35 | export interface SpecialKeyResult { 36 | type?: SpecialKeyType; 37 | specified: boolean; 38 | reason?: string[]; 39 | } 40 | 41 | export type SpecialKeyType = 42 | | typeof SpecialKeys.data_source 43 | | typeof SpecialKeys.ignore_all 44 | | typeof SpecialKeys.data_mapper_target; 45 | -------------------------------------------------------------------------------- /core-flags/README.md: -------------------------------------------------------------------------------- 1 | # flags on layer name or in meta data 2 | 3 | - ignore - indicating layer that should be ignored 4 | - base component - indicating base layer that having nested component structure for state (variant) representation on design tools. 5 | - content component - component(symbol) that is only marked as component because it contains re-usable content, not for marking that it is a component with specific layout or style. 6 | - data source - layer / instance that is only existing for holding a specific data that can be referenced by other nodes. 7 | - data target - for mapping the single data to be targetted from data source (can be another node, or remote api with structured data) 8 | 9 | ## `--flags` flag args 10 | 11 | > `--flag` is a standard way for passing arguments in cli environments across various ecosystems. 12 | 13 | using `dashdash flag` (as we call it) is usefull for passing development related arguments and passing countinuous arguments. 14 | 15 | ## `//@special` tokens 16 | 17 | > The syntax is inspired from typescript's `//@ts-ignore` 18 | 19 | The list of special tokens [can be found here](./@special/README.md). 20 | 21 | ## `(value)` tokens 22 | 23 | for passing dedicated arguments in design tools, the most intuitive way is to inject the minimal data throught the layer's name. And we often use `()` to descrive the design's state. 24 | 25 | Inspired from this, we also support `(value)` flags by deafult. In this way, we can keep the layer names human readable & managable. 26 | -------------------------------------------------------------------------------- /core-flags/__test__/parsing-strategy-dashdash.test.ts: -------------------------------------------------------------------------------- 1 | import { parse } from "../parsing-strategy-dashdash"; 2 | 3 | test("anonymous flags parsing", () => { 4 | const parsed = parse("--foo=bar --ignore-constaints"); 5 | expect(parsed).toEqual({ 6 | _order: ["foo", "ignore-constaints"], 7 | foo: "bar", 8 | "ignore-constaints": true, 9 | }); 10 | }); 11 | 12 | // test("anonymous flags with leading name parsing", () => { 13 | // const parsed = parse("Frame13 --foo=bar --ignore-constaints"); 14 | // expect(parsed).toEqual({ 15 | // _order: ["foo", "ignore-constaints"], 16 | // foo: "bar", 17 | // "ignore-constaints": true, 18 | // }); 19 | // }); 20 | -------------------------------------------------------------------------------- /core-flags/__test__/parsing-strategy-parentheses.test.ts: -------------------------------------------------------------------------------- 1 | describe("Logger", () => { 2 | test.todo("please pass"); 3 | }); 4 | -------------------------------------------------------------------------------- /core-flags/__test__/parsing-strategy-unique.test.ts: -------------------------------------------------------------------------------- 1 | import { parse } from "../parsing-strategy-unique"; 2 | 3 | test("match simple unique symbol", () => { 4 | const parsed = parse("//@ignore", ["ignore"]); 5 | expect(parsed).toBe("ignore"); 6 | }); 7 | 8 | test("match simple unique symbol with '__' prefix", () => { 9 | const parsed = parse("__//@ignore", ["ignore"]); 10 | expect(parsed).toBe("ignore"); 11 | }); 12 | 13 | test("don't match simple unique symbol with no empty space between token and name.", () => { 14 | const parsed = parse("//@ignoreFrame12", ["ignore"]); 15 | expect(parsed).toBe(false); 16 | }); 17 | 18 | test("match simple unique symbol with empty space between token and name.", () => { 19 | const parsed = parse("//@ignore Frame12", ["ignore"]); 20 | expect(parsed).toBe("ignore"); 21 | }); 22 | 23 | test("match first unique symbol with empty space between token and name.", () => { 24 | const parsed = parse("//@ignore //@second Frame12", ["ignore", "second"]); 25 | expect(parsed).toBe("ignore"); 26 | }); 27 | -------------------------------------------------------------------------------- /core-flags/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./@special"; 2 | import { parse as parse_special } from "./@special"; 3 | import { parse as parse_dashdash } from "./parsing-strategy-dashdash"; 4 | export function parseFromName(name: string) { 5 | const _maybe_special = parse_special(name); 6 | if (_maybe_special) { 7 | return { [_maybe_special]: true }; 8 | } 9 | 10 | // otherwise, parse for normal flags 11 | return parse_dashdash(name); 12 | } 13 | -------------------------------------------------------------------------------- /core-flags/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/lib/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /core-flags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/flags", 3 | "description": "extend your design with flags", 4 | "version": "0.0.53", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "clean": "rimraf dist", 10 | "build": "tsc", 11 | "test": "jest --config=jest.config.js" 12 | }, 13 | "exports": { 14 | ".": "./dist/index.js", 15 | "./parsing-strategy-dashdash": "./dist/parsing-strategy-dashdash/index.js" 16 | }, 17 | "typesVersions": { 18 | "*": { 19 | ".": [ 20 | "dist/index.d.ts" 21 | ], 22 | "parsing-strategy-dashdash": [ 23 | "dist/parsing-strategy-dashdash/index.d.ts" 24 | ] 25 | } 26 | }, 27 | "dependencies": { 28 | "@design-sdk/core-flags-dashdash": "^0.0.53" 29 | }, 30 | "devDependencies": { 31 | "@types/assert": "^1.5.6", 32 | "@types/jest": "^27.0.2", 33 | "@types/node": "^16.10.3", 34 | "jest": "^27.2.4", 35 | "ts-jest": "^27.0.5", 36 | "typescript": "^4.4.3" 37 | }, 38 | "files": [ 39 | "dist", 40 | "README.md", 41 | "LICENSE" 42 | ], 43 | "publishConfig": { 44 | "access": "public" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core-flags/parsing-strategy-dashdash/README.md: -------------------------------------------------------------------------------- 1 | # `--flag` parsing strategy 2 | 3 | ## Syntax 4 | 5 | ``` 6 | [--(<=>)?]+ 7 | ❌ key 8 | ❌ -key 9 | ❌ --key= 10 | ❌ --key== 11 | ❌ --1 12 | 👌 --key 13 | 👌 --key="=" 14 | 👌 --key==1 15 | 👌 --key=value 16 | 17 | 👌 --key=value --key2 18 | ``` 19 | 20 | ```ts 21 | // "--key=value" 22 | { 23 | key: "value"; 24 | } 25 | 26 | // "--key=[1, 2]" 27 | { 28 | key: [1, 2]; 29 | } 30 | 31 | // "--one=1 --two=2" 32 | { 33 | one: 1, 34 | two: 2 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /core-flags/parsing-strategy-parentheses/README.md: -------------------------------------------------------------------------------- 1 | # Parsing Strategy parentheses - `(value)` 2 | 3 | ## Syntax 4 | 5 | `(key-and/or-value)` 6 | 7 | ``` 8 | (size=xl) 9 | (docs) 10 | (base) 11 | ``` 12 | 13 | ## Default usecase - Base component indicator 14 | 15 | ### What is base component? 16 | 17 | ### Syntax 18 | 19 | `(base) component-name` 20 | -------------------------------------------------------------------------------- /core-flags/parsing-strategy-unique/README.md: -------------------------------------------------------------------------------- 1 | # Unique flag token parsing - Special token parsing 2 | 3 | ## Syntax 4 | 5 | ``` 6 | (__)?//@(( )())? 7 | ``` 8 | 9 | - 👌 `//@ignore` 10 | - 👌 `__//@ignore` 11 | - ❌ `_//@ignore` 12 | - ❌ `//@unknown_token` 13 | - ❌ `//@ignore/whatever` 14 | - ❌ ` //@ignore` 15 | - ❌ `Frame12 //@ignore` 16 | - 👌 `//@ignore Frame12` 17 | - 👌 `//@ignore /whatever` 18 | - 👌 `//@ignore /whatever //@ignore //@ignore` - only first token will be parsed 19 | 20 | **What is `__`?** 21 | 22 | > Like in programming, some design tools such as figma supports internal component with prefix `__`. Using special tokens on component is a valid scenario, as also exporting them or using them internally. For this reason, we take prefix `__` as a valid input. P.s. only special token requires to be `starts with`, you can understand this as that every other flags containing name supports `__` prefix. 23 | -------------------------------------------------------------------------------- /core-flags/parsing-strategy-unique/index.ts: -------------------------------------------------------------------------------- 1 | const prefix = /(__)?\/\/@/gy; 2 | const pattern = /(__)?\/\/@([a-zA-Z-]+)/gy; 3 | 4 | export function parse( 5 | from: string, 6 | patterns: string | string[] | "*" 7 | ): string | false { 8 | patterns = Array.isArray(patterns) 9 | ? patterns 10 | : patterns === "*" 11 | ? "*" 12 | : [patterns]; 13 | const matches = from.match(pattern); 14 | const _valid_prefix = matches?.length > 0; 15 | if (_valid_prefix) { 16 | const token = matches[0].replace(prefix, ""); 17 | if (patterns === "*" || (patterns as []).some((p) => p == token)) { 18 | return token; 19 | } 20 | } 21 | return false; 22 | } 23 | -------------------------------------------------------------------------------- /core-flags/support-data-mapping/README.md: -------------------------------------------------------------------------------- 1 | # Data mapping support with flags 2 | 3 | > WIP 4 | 5 | ## Datasource object indication 6 | 7 | ## Data target indication 8 | -------------------------------------------------------------------------------- /core-flags/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "allowJs": true 6 | }, 7 | "include": ["./"], 8 | "exclude": ["node_modules", "dist", "__test__", "jest.config.js"] 9 | } 10 | -------------------------------------------------------------------------------- /core-query/README.md: -------------------------------------------------------------------------------- 1 | # `@design-sdk/query` 2 | 3 | ```bash 4 | yarn add @design-sdk/query 5 | ``` 6 | 7 | ## Usage 8 | 9 | ```ts 10 | import q from "@design-sdk/query"; 11 | 12 | // performance efficient on reuse 13 | const doc = q.document(seed); 14 | doc.getNodeById(id); 15 | doc.getNodeAndRootById(id); 16 | 17 | // single use 18 | q.getNodeByIdFrom(id, seed); 19 | q.getNodeAndRootByIdFrom(id, seed); 20 | ``` 21 | -------------------------------------------------------------------------------- /core-query/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | document, 3 | getNodeByIdFrom, 4 | getNodeAndRootByIdFrom, 5 | } from "./query-node"; 6 | 7 | export default { 8 | document, 9 | getNodeByIdFrom, 10 | getNodeAndRootByIdFrom, 11 | }; 12 | -------------------------------------------------------------------------------- /core-query/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/dist/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /core-query/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/query", 3 | "version": "0.0.53", 4 | "license": "Apache 2.0", 5 | "author": "grida.co", 6 | "private": false, 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "scripts": { 10 | "clean": "rimraf dist", 11 | "test": "jest", 12 | "build": "tsc" 13 | }, 14 | "devDependencies": { 15 | "@types/jest": "^29.2.0", 16 | "jest": "^29.2.1", 17 | "ts-jest": "^29.0.3", 18 | "typescript": "^4.8.4" 19 | }, 20 | "files": [ 21 | "dist/index.js", 22 | "dist/index.d.ts", 23 | "dist/**/*.js", 24 | "dist/**/*.d.ts", 25 | "README", 26 | "LICENSE" 27 | ], 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core-query/query-node.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | getNodeByIdFrom, 3 | getNodeAndRootByIdFrom, 4 | document, 5 | } from "./query-node"; 6 | 7 | const a = { 8 | id: "A", 9 | children: [ 10 | { 11 | id: "a1", 12 | }, 13 | { 14 | id: "a2", 15 | }, 16 | ], 17 | }; 18 | 19 | const b = { 20 | id: "B", 21 | children: [ 22 | { 23 | id: "b1", 24 | }, 25 | { 26 | id: "b2", 27 | children: [ 28 | { 29 | id: "b2-1", 30 | 31 | children: [ 32 | { 33 | id: "b2-1-1", 34 | }, 35 | ], 36 | }, 37 | ], 38 | }, 39 | ], 40 | }; 41 | 42 | const c = { 43 | id: "C", 44 | children: [ 45 | { 46 | id: "c1", 47 | }, 48 | ], 49 | }; 50 | 51 | const page = [a, b, c]; 52 | 53 | test("find nested item under node", () => { 54 | expect(getNodeByIdFrom("b2-1-1", b).id).toBe("b2-1-1"); 55 | }); 56 | 57 | test("find the root of the target under the page nodes by target's id", () => { 58 | const { node, root } = getNodeAndRootByIdFrom("b2-1-1", page); 59 | expect(root.id).toBe("B"); 60 | expect(node.id).toBe("b2-1-1"); 61 | }); 62 | 63 | test("builder pattern #1", () => { 64 | const doc = document(page); 65 | const node = doc.getNodeById("b2-1-1"); 66 | expect(node.id).toBe("b2-1-1"); 67 | }); 68 | 69 | test("builder pattern #2", () => { 70 | const doc = document(a); 71 | const node = doc.getNodeById("b2-1-1"); 72 | expect(node).toBe(null); 73 | }); 74 | -------------------------------------------------------------------------------- /core-query/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "skipLibCheck": true, 6 | "strict": false 7 | }, 8 | "exclude": [ 9 | "node_modules", 10 | "dist", 11 | "__test__", 12 | "**/*.spec.ts", 13 | "**/*.test.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /core-types/design-provider.ts: -------------------------------------------------------------------------------- 1 | export type DesignProvider = 2 | | "grida" 3 | | "nothing" 4 | | "figma" 5 | | "sketch" 6 | | "unknown"; 7 | -------------------------------------------------------------------------------- /core-types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./design-provider"; 2 | -------------------------------------------------------------------------------- /core-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/core-types", 3 | "description": "Core typings for design representetives", 4 | "authors": "Grida.co", 5 | "version": "0.0.53", 6 | "private": false, 7 | "main": "dist/index.js", 8 | "scripts": { 9 | "clean": "rimraf dist", 10 | "build": "tsc" 11 | }, 12 | "files": [ 13 | "dist", 14 | "README.md", 15 | "LICENSE" 16 | ], 17 | "publishConfig": { 18 | "access": "public" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /core-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "skipLibCheck": true, 6 | "strict": false 7 | }, 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /core/README.md: -------------------------------------------------------------------------------- 1 | # Design SDK Core definition & utilities 2 | -------------------------------------------------------------------------------- /core/index.ts: -------------------------------------------------------------------------------- 1 | // platform 2 | export * as _platform from "./platform"; 3 | -------------------------------------------------------------------------------- /core/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/dist/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/core", 3 | "version": "0.0.53", 4 | "license": "Apache 2.0", 5 | "author": "grida.co", 6 | "private": false, 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "scripts": { 10 | "clean": "rimraf dist", 11 | "test": "jest", 12 | "build": "tsc" 13 | }, 14 | "exports": { 15 | ".": "./dist/index.js", 16 | "./utils": "./dist/utils/index.js" 17 | }, 18 | "typesVersions": { 19 | "*": { 20 | ".": [ 21 | "dist/index.d.ts" 22 | ], 23 | "utils": [ 24 | "dist/utils/index.d.ts" 25 | ] 26 | } 27 | }, 28 | "dependencies": { 29 | "@base-sdk/base": "0.1.4", 30 | "@design-sdk/figma-node": "^0.0.53", 31 | "@design-sdk/figma-types": "^0.0.53", 32 | "@design-sdk/figma-utils": "^0.0.53", 33 | "@design-sdk/flags": "^0.0.17", 34 | "@reflect-ui/core": "0.0.5", 35 | "@reflect-ui/namings": "0.0.3" 36 | }, 37 | "devDependencies": { 38 | "@types/jest": "^29.2.0", 39 | "jest": "^29.2.1", 40 | "ts-jest": "^29.0.3", 41 | "typescript": "^4.8.4" 42 | }, 43 | "files": [ 44 | "dist/index.js", 45 | "dist/index.d.ts", 46 | "dist/**/*.js", 47 | "dist/**/*.d.ts", 48 | "README", 49 | "LICENSE" 50 | ], 51 | "publishConfig": { 52 | "access": "public" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/platform/index.ts: -------------------------------------------------------------------------------- 1 | ///////// README - THIS IS DEPRECATED AND WILL BE DELETED 2 | /// the living logic lives on plugin-sdk and this will no longer be used 3 | /// the raeson not deleting this now is cause of submodule usage and mismatching branch, after things are clean, we will remove this file. 4 | 5 | /** 6 | * @deprecated Target platform this ui runs on. this gloval variable will be set on initial entry on each platform's main ui import 7 | */ 8 | export let TARGET_PLATFORM: TargetPlatform; 9 | 10 | /** 11 | * @deprecated DO NOT USE 12 | * @param platform 13 | */ 14 | export function initializeTargetPlatform(platform: TargetPlatform) { 15 | TARGET_PLATFORM = platform; 16 | console.info(`target platform set as ${platform}`); 17 | } 18 | 19 | /** 20 | * @deprecated DO NOT USE 21 | */ 22 | export enum TargetPlatform { 23 | bridged = "xyz.bridged.bridged", 24 | figma = "com.figma.Desktop", 25 | sketch = "com.bohemiancoding.sketch3", 26 | xd = "xd", 27 | zeplin = "zeplin", 28 | webdev = "xyz.bridged.assistant-web-dev", 29 | } 30 | -------------------------------------------------------------------------------- /core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "skipLibCheck": true, 6 | "strict": false 7 | }, 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /core/utils/colors/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./retrieve-colors"; 2 | export * from "./gradient"; 3 | -------------------------------------------------------------------------------- /core/utils/coordinates.ts: -------------------------------------------------------------------------------- 1 | import { ReflectSceneNode, ReflectSceneNodeType } from "@design-sdk/figma-node"; 2 | 3 | /** 4 | * In Figma, Groups have absolute position while Frames have relative. 5 | * This is a helper to retrieve the node.parent.x without worries. 6 | * Usually, after this is called, node.x - parentX is done to solve that scenario. 7 | * 8 | * Input is expected to be node.parent. 9 | * TODO - inspect this. 10 | */ 11 | export function coordinates(node: ReflectSceneNode): [number, number] { 12 | if (node.type !== ReflectSceneNodeType.group) { 13 | return [0, 0]; 14 | } else { 15 | return [node.x, node.y]; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./common-padding"; 2 | export * from "./common-position"; 3 | export * from "./coordinates"; 4 | export * from "./node-width-height"; 5 | export * from "./retrieve-colliding-children"; 6 | export * from "./used-colors"; 7 | export * from "./colors"; 8 | -------------------------------------------------------------------------------- /core/utils/retrieve-colliding-children.ts: -------------------------------------------------------------------------------- 1 | import type { ReflectSceneNode } from "@design-sdk/figma-node"; 2 | 3 | /** 4 | * Iterate over each Rectangle and check if it has any child on top. 5 | * This is O(n^2), but is optimized to only do j=i+1 until length, and avoid repeated entries. 6 | * A Node can only have a single parent. The order is defined by layer order. 7 | */ 8 | export function retrieveCollidingChildren( 9 | children: ReadonlyArray 10 | ): Record> { 11 | const used: Record = {}; 12 | const groups: Record> = {}; 13 | 14 | for (let i = 0; i < children.length - 1; i++) { 15 | const item1 = children[i]; 16 | 17 | // ignore items that are not Rectangles 18 | if (item1.type !== "RECTANGLE") { 19 | continue; 20 | } 21 | 22 | for (let j = i + 1; j < children.length; j++) { 23 | const item2 = children[j]; 24 | 25 | if ( 26 | !used[item2.id] && 27 | item1.x <= item2.x && 28 | item1.y <= item2.y && 29 | item1.x + item1.width >= item2.x + item2.width && 30 | item1.y + item1.height >= item2.y + item2.height 31 | ) { 32 | if (!groups[item1.id]) { 33 | groups[item1.id] = [item2]; 34 | } else { 35 | groups[item1.id].push(item2); 36 | } 37 | used[item2.id] = true; 38 | } 39 | } 40 | } 41 | 42 | return groups; 43 | } 44 | -------------------------------------------------------------------------------- /core/utils/used-colors.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ReflectChildrenMixin, 3 | ReflectDefaultShapeMixin, 4 | ReflectSceneNode, 5 | } from "@design-sdk/figma-node"; 6 | 7 | export function getAllUsedColors( 8 | node: ReflectSceneNode, 9 | options?: { 10 | runOnGrandchild: boolean; 11 | } 12 | ): ReadonlyArray { 13 | const colors = []; 14 | 15 | // organize targets 16 | const targetNodes: Array = []; 17 | if (options?.runOnGrandchild) { 18 | if (node instanceof ReflectChildrenMixin) { 19 | targetNodes.push(...node.getGrandchildren({ includeThis: true })); 20 | } 21 | } else { 22 | targetNodes.push(node); 23 | } 24 | // 25 | 26 | // run color extractions on nodes 27 | for (const tn of targetNodes) { 28 | (tn as ReflectDefaultShapeMixin).primaryColor; 29 | } 30 | 31 | return; 32 | } 33 | -------------------------------------------------------------------------------- /design-diff/README.md: -------------------------------------------------------------------------------- 1 | # Diff checking of the design. 2 | 3 | ## Usecase 4 | 5 | Diff check is essential for scenarios like, pattern detection, component override extraction and so on. 6 | 7 | ### Pattern detection 8 | 9 | - check if two or more nodes are identical, yet not set as a component - `WARNING: Nodes should be a component` 10 | 11 | ### Component-Instance override data 12 | 13 | - check if instance has a override data 14 | 15 | ### Suggest interface 16 | 17 | - suggest user specific property when defining a interface for component. 18 | 19 | ## Kinds of diff 20 | 21 | - tree diff 22 | - structural diff 23 | - count diff 24 | - property diff 25 | - text diff 26 | - text characters diff 27 | - mixed text style diff 28 | -------------------------------------------------------------------------------- /design-diff/_types/index.ts: -------------------------------------------------------------------------------- 1 | export interface IDiff { 2 | diff: boolean; 3 | /** 4 | * - `[0]` - origin value 5 | * - `[1]` - new value (with diff) 6 | */ 7 | values: [O, O]; 8 | } 9 | 10 | /** 11 | * e.g. type PaintTypeDiff = ITypeDiff<"solid" | "image" | "gradient"> 12 | */ 13 | export interface ITypeDiff extends IDiff {} 14 | -------------------------------------------------------------------------------- /design-diff/diff-text-data/index.ts: -------------------------------------------------------------------------------- 1 | export function text_data(a: string, b: string): boolean { 2 | return a !== b; 3 | } 4 | -------------------------------------------------------------------------------- /design-diff/diff-utils/index.ts: -------------------------------------------------------------------------------- 1 | export function same_typeof(a, b) { 2 | return typeof a === typeof b; 3 | } 4 | 5 | /** 6 | * if nested or non neseted array is equal. 7 | * @param a 8 | * @param b 9 | * @returns 10 | */ 11 | export function equals(a: readonly any[], b: readonly any[]) { 12 | // if the other array is a falsy value, return 13 | if (!b) return false; 14 | 15 | // compare lengths - can save a lot of time 16 | if (a.length != b.length) return false; 17 | 18 | for (var i = 0, l = a.length; i < l; i++) { 19 | // Check if we have nested arrays 20 | if (a[i] instanceof Array && b[i] instanceof Array) { 21 | // recurse into the nested arrays 22 | if (!equals(a[i], b[i])) return false; 23 | } else if (a[i] != b[i]) { 24 | // Warning - two different object instances will never be equal: {x:20} != {x:20} 25 | return false; 26 | } 27 | } 28 | return true; 29 | } 30 | -------------------------------------------------------------------------------- /design-diff/diff-vector/README.md: -------------------------------------------------------------------------------- 1 | # Vector diff 2 | 3 | ## Usecase 4 | 5 | ### Shape similarity 6 | 7 | Checks if vector is visually similar (without using cv) 8 | 9 | ### Same path with variants (color / scale / w / h / etc..) 10 | 11 | Checks if vector is the same path, but with a different post-effective attributes such like color and scale. 12 | 13 | ## References 14 | 15 | - [svgjs](https://svgjs.dev/docs/3.0/) 16 | - [diffsvg (python / archived)](https://github.com/jrsmith3/diffsvg) 17 | - [svg path editor](https://github.com/yqnn/svg-path-editor) ([site](https://yqnn.github.io/svg-path-editor/)) 18 | - [svgo](https://github.com/svg/svgo) / [svgomg](https://jakearchibald.github.io/svgomg/) 19 | - [existing-tools-attempts-for-diffing-svg](https://discourse.opensourcedesign.net/t/existing-tools-attempts-for-diffing-svg/763) 20 | - [mdn - svg path commands](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands) 21 | 22 | **Example of svgo flattening** 23 | 24 | original 25 | 26 | ```xml 27 | 28 | ``` 29 | 30 | minimized 31 | 32 | ```xml 33 | 34 | 35 | 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /design-diff/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./diff-text"; 2 | export * from "./diff-instance"; 3 | 4 | // ------------------------------------------------------------ 5 | import type { InstanceDiff_1on1, MultichildDiff } from "./diff-instance"; 6 | import type { TextDiff } from "./diff-text"; 7 | export type NodeDiff = TextDiff | InstanceDiff_1on1 | MultichildDiff; 8 | -------------------------------------------------------------------------------- /design-diff/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/diff", 3 | "description": "diff utils for design", 4 | "main": "dist/index.js", 5 | "types": "dist/index.d.ts", 6 | "keywords": [ 7 | "design", 8 | "diff" 9 | ], 10 | "version": "0.0.53", 11 | "authors": "Grida.co", 12 | "private": false, 13 | "scripts": { 14 | "clean": "rimraf dist", 15 | "build": "tsc" 16 | }, 17 | "dependencies": { 18 | "@design-sdk/figma-types": "^0.0.53", 19 | "@design-sdk/figma-xpath": "^0.0.53" 20 | }, 21 | "files": [ 22 | "dist", 23 | "README.md", 24 | "LICENSE" 25 | ], 26 | "publishConfig": { 27 | "access": "public" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /design-diff/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | -------------------------------------------------------------------------------- /design-sdk/lib/figma.ts: -------------------------------------------------------------------------------- 1 | export * from "@design-sdk/figma"; 2 | -------------------------------------------------------------------------------- /design-sdk/lib/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gridaco/figma-sdk/5784ab284f17fcb2b20bc821fc140fd004964d7e/design-sdk/lib/index.ts -------------------------------------------------------------------------------- /design-sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "design-sdk", 3 | "version": "0.0.33", 4 | "private": false, 5 | "scripts": { 6 | "build": "tsc" 7 | }, 8 | "dependencies": { 9 | "@design-sdk/core": "0.0.33", 10 | "@design-sdk/figma": "0.0.33", 11 | "@design-sdk/diff": "0.0.33", 12 | "@design-sdk/flags": "0.0.33", 13 | "@design-sdk/vanilla": "0.0.33" 14 | }, 15 | "files": [ 16 | "dist", 17 | "README.md", 18 | "LICENSE" 19 | ], 20 | "publishConfig": { 21 | "access": "public" 22 | } 23 | } -------------------------------------------------------------------------------- /design-sdk/tsconfig.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gridaco/figma-sdk/5784ab284f17fcb2b20bc821fc140fd004964d7e/design-sdk/tsconfig.json -------------------------------------------------------------------------------- /docs/figma-stores.md: -------------------------------------------------------------------------------- 1 | # Understanding figma's storing api 2 | 3 | ## The Client storage 4 | 5 | - Does it share data across files? - YES 6 | - Does it share data across devices? - NO 7 | - Does it share data across users? - NO 8 | - Does it clears on cache clear? - YES 9 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Design SDK Documentation -------------------------------------------------------------------------------- /figma-auth-store/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /figma-auth-store/README.md: -------------------------------------------------------------------------------- 1 | # `Figma-Auth-Store` _(`@design-sdk/figma-auth-store`)_ 2 | 3 | > Figma Auth Store, Crendentials storage & management for nodejs 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @design-sdk/figma-auth-store 9 | 10 | # or with npm 11 | npm i @design-sdk/figma-auth-store 12 | ``` 13 | 14 | ## Usage 15 | 16 | ```ts 17 | import { getAccessToken, getAccessToken_safe, personal, oauth, FigmaAuthStore } "@design-sdk/figma-auth-store"; 18 | 19 | FigmaAuthStore.configure({ 20 | prefix: "figma/" // optional, defaults to "figma/" 21 | }) 22 | 23 | 24 | // this throws when token is not available. 25 | const accessToken = getAccessToken() 26 | 27 | // this returns null when token is not available. 28 | const accessToken_safe = getAccessToken_safe() 29 | 30 | 31 | // set token 32 | personal.set('') 33 | oauth.set('') 34 | ``` 35 | -------------------------------------------------------------------------------- /figma-auth-store/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib"; 2 | -------------------------------------------------------------------------------- /figma-auth-store/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/lib/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /figma-auth-store/lib/access-token-oauth.ts: -------------------------------------------------------------------------------- 1 | import { FigmaAuthStore } from "./figma-auth-store"; 2 | import { isBrowser } from "./is-browser"; 3 | import { _dev_env_var_figma_personal_access_token, __FIGMA_OAUTH_ACCESS_TOKEN_DANGER_LOCAL_DEV } from "./keys"; 4 | 5 | const ___key = __FIGMA_OAUTH_ACCESS_TOKEN_DANGER_LOCAL_DEV 6 | const key = () => { 7 | return FigmaAuthStore.makekey(___key) 8 | } 9 | 10 | export function setOAuthAccessToken(figmaToken: string) { 11 | if (isBrowser) { 12 | window.localStorage.setItem(key(), figmaToken); 13 | } 14 | } 15 | 16 | export function getOAuthAccessToken(): string | undefined { 17 | if (isBrowser) { 18 | const stored = window.localStorage.getItem(key()) as string; 19 | return stored || _dev_env_var_figma_personal_access_token; 20 | } 21 | } 22 | 23 | export function clearOAuthAccessToken() { 24 | if (isBrowser) { 25 | window.localStorage.removeItem( 26 | key() 27 | ); 28 | } 29 | } 30 | 31 | export function refreshFigmaToken() { 32 | throw 'refresh token not implemented.' 33 | } 34 | 35 | export const oauth = { 36 | get: getOAuthAccessToken, 37 | set: setOAuthAccessToken, 38 | clear: clearOAuthAccessToken 39 | } -------------------------------------------------------------------------------- /figma-auth-store/lib/access-token.ts: -------------------------------------------------------------------------------- 1 | import { personal } from "./access-token-personal" 2 | import { oauth } from "./access-token-oauth" 3 | 4 | export function getAccessToken(): string { 5 | const accesstokenany = oauth.get() || personal.get() 6 | if (accesstokenany) { 7 | return accesstokenany; 8 | } 9 | throw new Error("No access token found") 10 | } 11 | 12 | export function getAccessToken_safe(): string | null { 13 | try { 14 | return getAccessToken() 15 | } catch (e) { 16 | return null 17 | } 18 | } -------------------------------------------------------------------------------- /figma-auth-store/lib/figma-auth-store.ts: -------------------------------------------------------------------------------- 1 | export interface FigmaAuthStoreOptions { 2 | /** e.g prefix = 'figma/' => 'figma/persianl-access-token' 3 | * 4 | * defaults to 'figma/' 5 | */ 6 | prefix?: string; 7 | } 8 | 9 | const default_prefix = "figma/"; 10 | const default_options: FigmaAuthStoreOptions = { 11 | prefix: default_prefix, 12 | }; 13 | 14 | export class FigmaAuthStore { 15 | static __options: FigmaAuthStoreOptions = default_options; 16 | static get options(): FigmaAuthStoreOptions { 17 | return this.__options; 18 | } 19 | 20 | static configure({ prefix = default_prefix }: FigmaAuthStoreOptions) { 21 | this.__options.prefix = prefix; 22 | } 23 | 24 | static makekey(key: string): string { 25 | return this.options.prefix + key; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /figma-auth-store/lib/index.ts: -------------------------------------------------------------------------------- 1 | 2 | export * from "./figma-auth-store" 3 | export * from "./access-token" 4 | export { oauth } from "./access-token-oauth" 5 | export { personal } from "./access-token-personal" -------------------------------------------------------------------------------- /figma-auth-store/lib/is-browser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * process.browser is for nextjs / webpack - refer: https://github.com/vercel/next.js/issues/2177 3 | */ 4 | export const isBrowser: boolean = (('browser' in process) && ((process as any).browser as boolean)) || typeof window !== 'undefined'; 5 | -------------------------------------------------------------------------------- /figma-auth-store/lib/keys.ts: -------------------------------------------------------------------------------- 1 | export const __FIGMA_PERSONAL_ACCESS_TOKEN_DANGER_LOCAL_DEV = 2 | "personal-access-token"; 3 | 4 | export const __FIGMA_OAUTH_ACCESS_TOKEN_DANGER_LOCAL_DEV = 5 | "oauth-access-token"; 6 | 7 | 8 | 9 | // ======= region envs ======== 10 | export const _dev_env_var_figma_personal_access_token = process.env.FIGMA_PERSONAL_ACCESS_TOKEN 11 | // ======= endregion envs ======== -------------------------------------------------------------------------------- /figma-auth-store/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-auth-store", 3 | "description": "Authentication credential management for figma on nodejs", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "keywords": [ 8 | "figma", 9 | "oauth", 10 | "auth", 11 | "access-token", 12 | "sdk", 13 | "design-sdk", 14 | "token", 15 | "passport" 16 | ], 17 | "homepage": "https://github.com/gridaco/design-sdk/", 18 | "repository": "https://github.com/gridaco/design-sdk/tree/main/figma-auth-store/", 19 | "authors": [ 20 | "grida.co", 21 | "softmarshmallow " 22 | ], 23 | "version": "0.0.53", 24 | "scripts": { 25 | "clean": "rimraf dist", 26 | "build": "tsc", 27 | "test": "jest" 28 | }, 29 | "devDependencies": { 30 | "@types/jest": "^26.0.24", 31 | "@types/node": "^16.3.3", 32 | "dotenv": "^10.0.0", 33 | "jest": "^27.0.6", 34 | "ts-jest": "^27.0.3", 35 | "typescript": "^4.3.5" 36 | }, 37 | "files": [ 38 | "dist/index.js", 39 | "dist/index.d.ts", 40 | "dist/**/*.js", 41 | "dist/**/*.d.ts", 42 | "README", 43 | "LICENSE" 44 | ], 45 | "publishConfig": { 46 | "access": "public" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /figma-auth-store/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "./dist" 6 | }, 7 | "exclude": ["dist", "node_modules", "__test__"] 8 | } 9 | -------------------------------------------------------------------------------- /figma-checksum/base/index.ts: -------------------------------------------------------------------------------- 1 | import assert from "assert"; 2 | import { nanoid } from "nanoid/non-secure"; /* we don't need secure id since it will only generate a otp-like hash per user-session */ 3 | import { getAccessToken } from "@design-sdk/figma-auth-store"; 4 | 5 | export abstract class FigmaChecksumBase { 6 | readonly signature: string; 7 | readonly fileKeyUserProvided: string; 8 | abstract remoteMethod(): Promise; 9 | 10 | constructor({ filekey, signature }: { filekey: string; signature?: string }) { 11 | assert(filekey); 12 | 13 | this.signature = signature ?? nanoid(); 14 | this.fileKeyUserProvided = filekey; 15 | } 16 | 17 | abstract prewarm(): Promise; 18 | 19 | abstract clear(); 20 | 21 | private getSignatureRemotely(): Promise { 22 | return this.remoteMethod(); 23 | } 24 | 25 | async verify(): Promise { 26 | const resultfromRemote = await this.getSignatureRemotely(); 27 | return this.signature == resultfromRemote; 28 | } 29 | 30 | private __accessToken: string; 31 | get accessToken(): string { 32 | return this.__accessToken ?? getAccessToken(); 33 | } 34 | 35 | set accessToken(accessToken: string) { 36 | this.__accessToken = accessToken; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /figma-checksum/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./strategy-with-otp-node"; 2 | export * from "./strategy-with-pages-signature"; 3 | export * from "./strategy-with-root-node-store"; 4 | -------------------------------------------------------------------------------- /figma-checksum/k/index.ts: -------------------------------------------------------------------------------- 1 | export const SIGNATURE_STORE_KEY = "signature"; 2 | export const GLOBAL_NAMESPACE_KEY = "global"; 3 | -------------------------------------------------------------------------------- /figma-checksum/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-checksum", 3 | "version": "0.0.53", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "clean": "rimraf dist", 9 | "build": "tsc" 10 | }, 11 | "dependencies": { 12 | "@design-sdk/figma": "^0.0.53", 13 | "nanoid": "^3.1.30" 14 | }, 15 | "devDependencies": { 16 | "@design-sdk/figma-types": "^0.0.53", 17 | "@figma/plugin-typings": "1.37.0" 18 | }, 19 | "files": [ 20 | "dist", 21 | "README", 22 | "LICENSE" 23 | ], 24 | "publishConfig": { 25 | "access": "public" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /figma-checksum/service/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## The figma file key checksum logic 4 | 5 | 1. user copies the file url from the design file 6 | 2. 3rd party parses the file key from the url 7 | 3. 3rd party requests checksum of the file key to this service with 8 | - file key 9 | - the page ids of the file 10 | - the user's figma token for api access 11 | 4. this service looks up the file with the file key, checks if the file contains the same page info from the input. 12 | 13 | ## About the 3rd Party 14 | 15 | The `3rd party` described above is your application, probably a figma plugin app. 16 | From your figma plugin app, while requesting the checksum, you'll need to prompt user 2 data 17 | 18 | - file key 19 | - authentication to your figma app 20 | 21 | This flow is implemented for production on [Grida Assistant](https://github.com/gridaco/assistant), you can see how it works. 22 | -------------------------------------------------------------------------------- /figma-checksum/service/README.md: -------------------------------------------------------------------------------- 1 | # Figma file key checksum service (Server side) 2 | 3 | > Validates the figma file key entered by user to check if the file key is trust worthy, via figma api verification. 4 | 5 | ## This is not a SDK. this is a server side application. 6 | 7 | To use this service via sdk, use figma-file-checksum instead. 8 | -------------------------------------------------------------------------------- /figma-checksum/service/index.ts: -------------------------------------------------------------------------------- 1 | import { Client } from "@design-sdk/figma-remote-api"; 2 | import { SIGNATURE_STORE_KEY, GLOBAL_NAMESPACE_KEY } from "../k"; 3 | 4 | async function withRootPluginData({ 5 | accessToken, 6 | filekey, 7 | pluginId, 8 | }: { 9 | accessToken: string; 10 | filekey: string; 11 | pluginId?: string; 12 | }): Promise { 13 | const client = Client({ 14 | // no support for `personalAccessToken` (only `accessToken`), since this is a package for verifying the checksum in production use. 15 | accessToken: accessToken, 16 | }); 17 | 18 | const res = await client.file(filekey, { 19 | depth: 1, 20 | plugin_data: pluginId ? [pluginId] : "shared", // automatic fallback to "shared", namespace defaults to "global" 21 | }); 22 | 23 | const signature = 24 | res.data.document.pluginData?.[pluginId]?.[SIGNATURE_STORE_KEY] ?? 25 | // fallback 26 | res.data.document.sharedPluginData?.[GLOBAL_NAMESPACE_KEY]?.[ 27 | SIGNATURE_STORE_KEY 28 | ]; 29 | 30 | return signature; 31 | } 32 | 33 | export const checkSignature = { 34 | withRootPluginData, 35 | }; 36 | -------------------------------------------------------------------------------- /figma-checksum/strategy-with-pages-signature/index.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from "@design-sdk/figma"; 2 | 3 | const IDENTITY_KEY = "figma-file-checksum-identity"; 4 | 5 | interface FigmaIdentityStore { 6 | [key: string]: FigmaIdentityByPages; 7 | } 8 | 9 | interface FigmaIdentityByPages { 10 | /** 11 | * the name of root node - file name. 12 | * we don't actually use this for identity check, it's for debug purpose. (this can easily be changed by user) 13 | */ 14 | name: string; 15 | /** 16 | * ids of pages 17 | */ 18 | pages: string[]; 19 | } 20 | 21 | function getIdentity() {} 22 | 23 | function setIdentity() { 24 | const identity = makeIdentity(); 25 | plugin.clientStorage.setAsync(IDENTITY_KEY, identity); 26 | } 27 | 28 | function setIdentityFrom(name: string, ...pages: string[]) { 29 | const identity = makeIdentityFrom(name, ...pages); 30 | plugin.clientStorage.setAsync(IDENTITY_KEY, identity); 31 | } 32 | 33 | function makeIdentity(): FigmaIdentityByPages { 34 | const pages = plugin.root.children; 35 | const pagesids = pages.map((page) => page.id); 36 | return makeIdentityFrom(plugin.root.name, ...pagesids); 37 | } 38 | 39 | function makeIdentityFrom( 40 | name: string, 41 | ...pages: string[] 42 | ): FigmaIdentityByPages { 43 | return { 44 | name, 45 | pages, 46 | }; 47 | } 48 | 49 | function saveonRoot() { 50 | plugin.root.setPluginData( 51 | "filekey", 52 | "" // TODO: get the file key 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /figma-checksum/strategy-with-root-node-store/index.ts: -------------------------------------------------------------------------------- 1 | import { plugin } from "@design-sdk/figma"; 2 | import { SIGNATURE_STORE_KEY } from "../k"; 3 | import { nanoid } from "nanoid/non-secure"; 4 | import { FigmaChecksumBase } from "../base"; 5 | import { checkSignature } from "../service"; 6 | 7 | export class FigmaRootNodeStoreVerification extends FigmaChecksumBase { 8 | remoteMethod(): Promise { 9 | return checkSignature.withRootPluginData({ 10 | accessToken: this.accessToken, 11 | filekey: this.fileKeyUserProvided, 12 | }); 13 | } 14 | 15 | async prewarm() { 16 | await Promise.resolve(); 17 | 18 | if (!exists()) { 19 | set(); 20 | } 21 | } 22 | 23 | clear() { 24 | update(""); // `""` is `null` equivalent on figma pluginData 25 | } 26 | } 27 | 28 | function get(): string { 29 | return plugin.root.getPluginData(SIGNATURE_STORE_KEY); 30 | } 31 | 32 | function exists(): boolean { 33 | // will return false when get() is `""` 34 | return Boolean(get()); 35 | } 36 | 37 | function update(signature: string) { 38 | plugin.root.setPluginData(SIGNATURE_STORE_KEY, signature); 39 | } 40 | 41 | function set(): string { 42 | const _ = nanoid(); 43 | update(_); 44 | return _; 45 | } 46 | -------------------------------------------------------------------------------- /figma-checksum/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | -------------------------------------------------------------------------------- /figma-core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /figma-core/README.md: -------------------------------------------------------------------------------- 1 | # `@design-sdk/figma-core` 2 | 3 | This is used internally by the `@design-sdk/figma` family of packages. 4 | 5 | ```sh 6 | yarn add @design-sdk/figma-core 7 | ``` 8 | 9 | ## File Key 10 | 11 | ```ts 12 | import type { FigmaFileKey } from "@design-sdk/figma-core"; 13 | import { figma_special_filekeys } from "@design-sdk/figma-core"; 14 | 15 | const figmafilekey: FigmaFileKey = 16 | figma_special_filekeys.anonymous_figma_plugin_file_key; 17 | ``` 18 | 19 | ## Mixed 20 | 21 | ```ts 22 | import { mixed } from "@design-sdk/figma-core"; 23 | 24 | // define type 25 | interface SomeFigmaNode { 26 | propertyA: number | typeof mixed; 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /figma-core/filekey.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * on figma plugin, the file key is not provided by defaylt. grida assistant asks user to input the fileey, but this cannot be 100% trusted and can be empty. 3 | * in this case, use this symbol to represent the file key. 4 | */ 5 | const anonymous_figma_plugin_file_key = Symbol("figma-plugin"); 6 | const unknown_figma_file_key = Symbol("unknown"); 7 | export const figma_special_filekeys = { 8 | anonymous_plugin_file: anonymous_figma_plugin_file_key, 9 | unknown_file: unknown_figma_file_key, 10 | } as const; 11 | 12 | export type FigmaAnonymousFileKey = 13 | | typeof anonymous_figma_plugin_file_key 14 | | typeof unknown_figma_file_key; 15 | 16 | export type FigmaFileKey = string | FigmaAnonymousFileKey; 17 | -------------------------------------------------------------------------------- /figma-core/index.ts: -------------------------------------------------------------------------------- 1 | // filekey 2 | export { figma_special_filekeys } from "./filekey"; 3 | export type { FigmaAnonymousFileKey, FigmaFileKey } from "./filekey"; 4 | 5 | // mixed 6 | export { mixed } from "./mixed"; 7 | -------------------------------------------------------------------------------- /figma-core/mixed.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Unique symbol for representing mixed figma value 3 | */ 4 | export const mixed: unique symbol = Symbol("mixed-figma-reflect-node-property"); 5 | -------------------------------------------------------------------------------- /figma-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-core", 3 | "version": "0.0.53", 4 | "description": "core definitions", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "clean": "rimraf dist", 10 | "build": "tsc" 11 | }, 12 | "files": [ 13 | "dist", 14 | "README.md", 15 | "LICENSE" 16 | ], 17 | "publishConfig": { 18 | "access": "public" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /figma-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "typeRoots": ["node_modules/@types"] 6 | }, 7 | "exclude": ["node_modules", "dist", "__test__"] 8 | } 9 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/conversion/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./conversion"; 2 | export * from "./force-convert-rect-to-frame"; 3 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/README.md: -------------------------------------------------------------------------------- 1 | # List of converters, Figma types to Reflect types. -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/color.convert.ts: -------------------------------------------------------------------------------- 1 | import { Color as ReflectColor, ColorFormat } from "@reflect-ui/core"; 2 | import { converters } from "@reflect-ui/core"; 3 | import { 4 | FigmaColor, 5 | FigmaColorFormat, 6 | FigmaRGB, 7 | FigmaRGBA, 8 | } from "@design-sdk/figma-types"; 9 | 10 | export function reflectColorToFigmaColor( 11 | reflectColor: ReflectColor, 12 | format: FigmaColorFormat = FigmaColorFormat.rgb 13 | ): FigmaColor { 14 | const convertedColor = converters.color.colorToRGBA( 15 | reflectColor, 16 | ColorFormat.rgbaF 17 | ); 18 | if (format == FigmaColorFormat.rgb) { 19 | return { 20 | r: convertedColor.r, 21 | g: convertedColor.g, 22 | b: convertedColor.b, 23 | }; 24 | } else if (format == FigmaColorFormat.rgba) { 25 | return { 26 | r: convertedColor.r, 27 | g: convertedColor.g, 28 | b: convertedColor.b, 29 | a: convertedColor.a, 30 | }; 31 | } 32 | 33 | throw "unsupported format type"; 34 | } 35 | 36 | export function reflectColorToFigmaRGB(reflectColor: ReflectColor): FigmaRGB { 37 | return reflectColorToFigmaColor( 38 | reflectColor, 39 | FigmaColorFormat.rgb 40 | ) as FigmaRGB; 41 | } 42 | 43 | export function reflectColorToFigmaRGBA(reflectColor: ReflectColor): FigmaRGBA { 44 | return reflectColorToFigmaColor( 45 | reflectColor, 46 | FigmaColorFormat.rgba 47 | ) as FigmaRGBA; 48 | } 49 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/corner-radius.convert.ts: -------------------------------------------------------------------------------- 1 | import { BorderRadiusManifest } from "@reflect-ui/core"; 2 | import { FigmaCornerRadius } from "@design-sdk/figma-types"; 3 | 4 | export function convertFigmaCornerRadiusToBorderRadius( 5 | origin: FigmaCornerRadius 6 | ): BorderRadiusManifest { 7 | return { 8 | all: 9 | origin.topLeftRadius == origin.topRightRadius && 10 | origin.topLeftRadius == origin.bottomLeftRadius && 11 | origin.topLeftRadius == origin.bottomRightRadius 12 | ? origin.topLeftRadius 13 | : undefined, 14 | tl: origin.topLeftRadius, 15 | tr: origin.topRightRadius, 16 | bl: origin.bottomLeftRadius, 17 | br: origin.bottomRightRadius, 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/cross-axis-alignment.convert.ts: -------------------------------------------------------------------------------- 1 | import { CrossAxisAlignment } from "@reflect-ui/core"; 2 | import { FigmaCrossAxisAligment } from "@design-sdk/figma-types"; 3 | 4 | export function convertCounterAxisAlignItemsToCrossAxisAlignment( 5 | origin: FigmaCrossAxisAligment 6 | ): CrossAxisAlignment { 7 | switch (origin) { 8 | case "MIN": 9 | return CrossAxisAlignment.start; 10 | case "CENTER": 11 | return CrossAxisAlignment.center; 12 | case "MAX": 13 | return CrossAxisAlignment.end; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/font-style.convert.ts: -------------------------------------------------------------------------------- 1 | import { FontStyle } from "@reflect-ui/core"; 2 | import { FontName } from "@design-sdk/figma-types"; 3 | export function convertFontStyleToReflect( 4 | original: FontName 5 | ): FontStyle | undefined { 6 | if (!original) { 7 | return; 8 | } 9 | 10 | // itallic 11 | if (original && original.style?.toLowerCase().match("italic")) { 12 | return FontStyle.italic; 13 | } 14 | 15 | return FontStyle.normal; 16 | } 17 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./color.convert"; 2 | export * from "./corner-radius.convert"; 3 | export * from "./cross-axis-alignment.convert"; 4 | export * from "./font-style.convert"; 5 | export * from "./layout-mode.convert"; 6 | export * from "./letter-spacing.convert"; 7 | export * from "./line-height.convert"; 8 | export * from "./main-axis-alignment.convert"; 9 | export * from "./tetx-decoration.convert"; 10 | export * from "./text-align.converter"; 11 | export * from "./text-style.convert"; 12 | export * from "./text-case"; 13 | export * from "./layout-grow.convert"; 14 | export * from "./layout-align.convert"; 15 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/layout-grow.convert.ts: -------------------------------------------------------------------------------- 1 | export function convertLayoutGrowToReflect(layoutGrow: number): number { 2 | if (layoutGrow === undefined) { 3 | return undefined; 4 | } 5 | 6 | if (layoutGrow === 0) { 7 | return 0; 8 | } else if (layoutGrow === 1) { 9 | return 1; 10 | } else { 11 | console.error( 12 | "not handled figma api is updated. layout grow value not supported : ", 13 | layoutGrow 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/layout-mode.convert.ts: -------------------------------------------------------------------------------- 1 | import { Axis } from "@reflect-ui/core"; 2 | import { FigmaLayoutMode } from "@design-sdk/figma-types"; 3 | 4 | export function convertLayoutModeToAxis(origin: FigmaLayoutMode): Axis { 5 | switch (origin) { 6 | case "NONE": 7 | return undefined; 8 | case "HORIZONTAL": 9 | return Axis.horizontal; 10 | case "VERTICAL": 11 | return Axis.vertical; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/letter-spacing.convert.ts: -------------------------------------------------------------------------------- 1 | import type { TextNode, LetterSpacing } from "@design-sdk/figma-types"; 2 | import { plugin } from "@design-sdk/figma-types"; 3 | 4 | export function convertLetterSpacingToReflect( 5 | origin: LetterSpacing, 6 | node?: TextNode 7 | ): LetterSpacing { 8 | if (origin && Math.round(origin.value) !== 0) { 9 | if (origin.unit === "PIXELS") { 10 | return origin; 11 | } else { 12 | if (node) { 13 | if (node.fontSize !== plugin.mixed) { 14 | // read [commonLineHeight] comment to understand what is going on here. 15 | const _value = 16 | ((node.fontSize as number) * 17 | ((node.letterSpacing as LetterSpacing).value as number)) / 18 | 100; 19 | 20 | return { 21 | ...origin, 22 | value: _value, 23 | }; 24 | } 25 | } 26 | } 27 | } 28 | 29 | // default 30 | return { 31 | value: 0, 32 | unit: "PIXELS", 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/line-height.convert.ts: -------------------------------------------------------------------------------- 1 | import type { LineHeight } from "@design-sdk/figma-types"; 2 | 3 | export function figma_lineheight_to_reflect_ling_height( 4 | origin: LineHeight 5 | ): number | `${number}%` { 6 | switch (origin?.unit) { 7 | case "PIXELS": 8 | return origin.value; 9 | case "AUTO": 10 | // auto means non specified. 11 | return undefined; 12 | case "PERCENT": 13 | return `${origin.value}%`; 14 | case undefined: 15 | return; 16 | default: 17 | throw new Error(`Unknown line height unit: ${origin["unit"]}`); 18 | } 19 | } 20 | 21 | export function figma_lineheight_to_reflect_ling_height__px_only( 22 | origin: LineHeight 23 | ): number { 24 | const maybepx = figma_lineheight_to_reflect_ling_height(origin); 25 | if (typeof maybepx === "number") { 26 | return maybepx; 27 | } 28 | return undefined; 29 | } 30 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/main-axis-alignment.convert.ts: -------------------------------------------------------------------------------- 1 | import type { FigmaMainAxisAlignment } from "@design-sdk/figma-types"; 2 | import { MainAxisAlignment } from "@reflect-ui/core"; 3 | 4 | export function convertPrimaryAxisAlignItemsToMainAxisAlignment( 5 | origin: FigmaMainAxisAlignment 6 | ): MainAxisAlignment { 7 | switch (origin) { 8 | case "CENTER": 9 | return MainAxisAlignment.center; 10 | case "MAX": 11 | return MainAxisAlignment.end; 12 | case "MIN": 13 | return MainAxisAlignment.start; 14 | case "SPACE_BETWEEN": 15 | return MainAxisAlignment.spaceBetween; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/tetx-decoration.convert.ts: -------------------------------------------------------------------------------- 1 | import type { FigmaTextDecoration } from "@design-sdk/figma-types"; 2 | import { TextDecoration } from "@reflect-ui/core"; 3 | 4 | export function convertTextDecorationToReflect( 5 | origin: FigmaTextDecoration 6 | ): TextDecoration { 7 | switch (origin) { 8 | case "NONE": 9 | return TextDecoration.none; 10 | case "STRIKETHROUGH": 11 | return TextDecoration.linethrough; 12 | case "UNDERLINE": 13 | return TextDecoration.underline; 14 | default: 15 | return TextDecoration.none; 16 | } 17 | return; 18 | } 19 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/text-align.converter.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | FigmaTextHorizontalAligment, 3 | FigmaTextVerticalAligment, 4 | } from "@design-sdk/figma-types"; 5 | import { TextAlignVertical, TextAlign } from "@reflect-ui/core"; 6 | 7 | export function convertTextAlignHorizontalToReflect( 8 | origin: FigmaTextHorizontalAligment 9 | ): TextAlign { 10 | switch (origin) { 11 | case "CENTER": 12 | return TextAlign.center; 13 | case "JUSTIFIED": 14 | return TextAlign.justify; 15 | case "LEFT": 16 | return TextAlign.left; 17 | case "RIGHT": 18 | return TextAlign.right; 19 | case undefined: 20 | return TextAlign.left; 21 | default: 22 | return TextAlign.left; 23 | } 24 | throw `cannot convert figma text horizontal align value "${origin}" to reflect "TextAlign"`; 25 | } 26 | 27 | export function convertTextAlignVerticalToReflect( 28 | origin: FigmaTextVerticalAligment 29 | ): TextAlignVertical { 30 | switch (origin) { 31 | case "CENTER": 32 | return TextAlignVertical.center; 33 | case "TOP": 34 | return TextAlignVertical.start; 35 | case "BOTTOM": 36 | return TextAlignVertical.bottom; 37 | case undefined: 38 | return TextAlignVertical.start; 39 | default: 40 | return TextAlignVertical.start; 41 | } 42 | throw `cannot convert figma text vertical align value "${origin}" to reflect "TextAlignVertical"`; 43 | } 44 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/converters/text-case.ts: -------------------------------------------------------------------------------- 1 | import type { TextCase as FigmaTextCase } from "@design-sdk/figma-types"; 2 | import { TextTransform } from "@reflect-ui/core"; 3 | 4 | export function convertTextCaseToReflectTextTransform( 5 | origin: FigmaTextCase 6 | ): TextTransform { 7 | switch (origin) { 8 | case "LOWER": 9 | return TextTransform.lowercase; 10 | case "UPPER": 11 | return TextTransform.uppercase; 12 | case "TITLE": 13 | return TextTransform.capitalize; 14 | case "ORIGINAL": 15 | return TextTransform.none; 16 | default: 17 | return TextTransform.none; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /figma-node-conversion/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * as convert from "./conversion"; 2 | export * from "./converters"; 3 | -------------------------------------------------------------------------------- /figma-node-conversion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-node-conversion", 3 | "description": "convert figma nodes into a universal version - to reflect design nodes", 4 | "version": "0.0.53", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "keywords": [ 9 | "figma", 10 | "design", 11 | "converter" 12 | ], 13 | "authors": [ 14 | "grida.co", 15 | "softmarshmallow " 16 | ], 17 | "scripts": { 18 | "clean": "rimraf dist", 19 | "build": "tsc", 20 | "test": "jest" 21 | }, 22 | "dependencies": { 23 | "@design-sdk/figma-node": "^0.0.53", 24 | "@design-sdk/figma-types": "^0.0.53", 25 | "@design-sdk/figma-utils": "^0.0.53", 26 | "@design-sdk/flags": "^0.0.53", 27 | "@reflect-ui/cg": "^0.0.5", 28 | "@reflect-ui/core": "^0.0.5", 29 | "@reflect-ui/font-utils": "^0.0.5" 30 | }, 31 | "peerDependencies": { 32 | "@design-sdk/figma-core": "^0.0.23" 33 | }, 34 | "files": [ 35 | "dist", 36 | "README", 37 | "LICENSE" 38 | ], 39 | "publishConfig": { 40 | "access": "public" 41 | }, 42 | "devDependencies": { 43 | "@types/node": "^18.6.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /figma-node-conversion/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["./lib"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-node-repository/lib/README.md: -------------------------------------------------------------------------------- 1 | # A Transportable node repository (a fs mock) 2 | 3 | This contains a class of node repository that can be provided to modules that accepts complex design as input, containing file informations, components references and more. 4 | -------------------------------------------------------------------------------- /figma-node-repository/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./node-repository"; 2 | -------------------------------------------------------------------------------- /figma-node-repository/lib/node-repository.ts: -------------------------------------------------------------------------------- 1 | import type { ReflectSceneNode } from "@design-sdk/figma-node"; 2 | import type { InstanceNode, ComponentNode } from "@design-sdk/figma-types"; 3 | 4 | type Node = ReflectSceneNode; 5 | 6 | /** 7 | * A simple node repository that can contain component relations 8 | */ 9 | export class NodeRepository { 10 | constructor({ 11 | components = [], 12 | nodes, 13 | }: { 14 | components?: ComponentNode[] | null; 15 | nodes: Node[]; 16 | }) { 17 | this.nodes = nodes; 18 | this.components = components; 19 | } 20 | 21 | readonly nodes: Array; 22 | readonly components: Array; 23 | 24 | get(id: string): Node { 25 | return this.nodes.find((node) => node.id === id); 26 | } 27 | 28 | mainComponentOf(instance: InstanceNode): ComponentNode { 29 | return this.components.find( 30 | (master) => master.id === instance.mainComponentId 31 | ) as ComponentNode; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /figma-node-repository/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-node-repository", 3 | "version": "0.0.53", 4 | "authors": "Grida.co", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "clean": "rimraf dist", 10 | "build": "tsc" 11 | }, 12 | "dependencies": { 13 | "@design-sdk/figma-node": "^0.0.53", 14 | "@design-sdk/figma-types": "^0.0.53" 15 | }, 16 | "files": [ 17 | "dist", 18 | "README.md", 19 | "LICENSE" 20 | ], 21 | "publishConfig": { 22 | "access": "public" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /figma-node-repository/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["./lib"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-oauth-react/README.md: -------------------------------------------------------------------------------- 1 | # Figma OAuth component for React `@design-sdk/figma-oauth-react` 2 | 3 | ## Installation 4 | 5 | ```sh 6 | yarn add @design-sdk/figma-oauth-react 7 | # or with npm 8 | npm i @design-sdk/figma-oauth-react 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```tsx 14 | import { FigmaOAuthProvider } from "@design-sdk/figma-oauth-react"; 15 | 16 | export default function App() { 17 | return ( 18 | 19 | 20 | 21 | ); 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /figma-oauth-react/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib"; 2 | -------------------------------------------------------------------------------- /figma-oauth-react/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./use-figma-auth-state"; 2 | -------------------------------------------------------------------------------- /figma-oauth-react/lib/use-figma-auth-state/index.ts: -------------------------------------------------------------------------------- 1 | export function useFigmaAuthState() { 2 | // 3 | } 4 | -------------------------------------------------------------------------------- /figma-oauth-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-oauth-react", 3 | "description": "Ready to use Figma oauth component for react", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "version": "0.0.53", 8 | "authors": [ 9 | "grida.co", 10 | "softmarshmallow " 11 | ], 12 | "scripts": { 13 | "clean": "rimraf dist", 14 | "build": "tsc", 15 | "test": "jest" 16 | }, 17 | "files": [ 18 | "dist/index.js", 19 | "dist/index.d.ts", 20 | "dist/**/*.js", 21 | "dist/**/*.d.ts", 22 | "README", 23 | "LICENSE" 24 | ], 25 | "publishConfig": { 26 | "access": "public" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /figma-oauth-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "./dist", 6 | "jsx": "react" 7 | }, 8 | "include": ["."], 9 | "exclude": ["node_modules", "dist", "__test__"] 10 | } 11 | -------------------------------------------------------------------------------- /figma-oauth/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /figma-oauth/__test__/.env.defaults: -------------------------------------------------------------------------------- 1 | # dummy client secret (safe to be exposed) 2 | FIGMA_APP_CLIENT_SECRET=pk4D9pwAMWqvOHCI8oor -------------------------------------------------------------------------------- /figma-oauth/__test__/oauth.test.ts: -------------------------------------------------------------------------------- 1 | import { OAuth, configure } from "../lib"; 2 | import { config } from "dotenv"; 3 | config({ 4 | path: ".env.defaults", 5 | }); 6 | 7 | configure({ 8 | client_id: process.env.FIGMA_APP_CLIENT_ID, 9 | client_secret: process.env.FIGMA_APP_CLIENT_SECRET, 10 | redirect_uri: "http://example.com/callback", 11 | }); 12 | 13 | const oauthproc = OAuth.new({ 14 | redirect_uri: "http://example.com/callback", 15 | }); 16 | 17 | test("oauth.new auth url", () => { 18 | expect(oauthproc.authUrl).toBe( 19 | `https://www.figma.com/oauth?client_id=undefined&redirect_uri=http%3A%2F%2Fexample.com%2Fcallback&scope=file_read&state=${oauthproc.state}&response_type=code` 20 | ); 21 | }); 22 | 23 | // test("oauth.new token request", async () => { 24 | // expect( 25 | // await oauthproc.authenticate({ 26 | // code: "code", 27 | // }) 28 | // ).toMatchObject({}); 29 | // }); 30 | -------------------------------------------------------------------------------- /figma-oauth/__test__/url-build.test.ts: -------------------------------------------------------------------------------- 1 | import { oauthBrowserUrl, oauthTokenRequestUrl } from "../"; 2 | 3 | test("oauth link building with params", () => { 4 | expect( 5 | oauthBrowserUrl({ 6 | client_id: "USz3HnKVO6Y2HUED98ZEzf", 7 | redirect_uri: "https://accounts.grida.co/callback/figma-app-oauth", 8 | state: "", 9 | }), 10 | ).toBe( 11 | "https://www.figma.com/oauth?client_id=USz3HnKVO6Y2HUED98ZEzf&redirect_uri=https%3A%2F%2Faccounts.grida.co%2Fcallback%2Ffigma-app-oauth&scope=file_read&state=&response_type=code", 12 | ); 13 | }); 14 | 15 | test("oauth token request url building with params", () => { 16 | expect( 17 | oauthTokenRequestUrl({ 18 | client_id: "USz3HnKVO6Y2HUED98ZEzf", 19 | client_secret: "pk4D9pwAMWqvOHCI8oor", // this is dummy client sefret - no worry 20 | redirect_uri: "https://accounts.grida.co/callback/figma-app-oauth", 21 | code: "r5RpCppGRwFpflPZ0suP9xRRu", // code generated from previous browser auth. (this is also a dummy code) 22 | }), 23 | ).toBe( 24 | "https://www.figma.com/api/oauth/token?client_id=USz3HnKVO6Y2HUED98ZEzf&client_secret=pk4D9pwAMWqvOHCI8oor&grant_type=authorization_code&redirect_uri=https%3A%2F%2Faccounts.grida.co%2Fcallback%2Ffigma-app-oauth&code=r5RpCppGRwFpflPZ0suP9xRRu", 25 | ); 26 | }); 27 | -------------------------------------------------------------------------------- /figma-oauth/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./lib"; 2 | -------------------------------------------------------------------------------- /figma-oauth/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/lib/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /figma-oauth/lib/configure.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * configure figma app in a global scope. 3 | * if you've already loaded env variables, without explicitely calling this method, 4 | * still the package will work with referenced variable **`FIGMA_APP_CLIENT_ID`** and **`FIGMA_APP_CLIENT_SECRET`** 5 | */ 6 | export function configure({ 7 | client_id, 8 | client_secret, 9 | redirect_uri, 10 | }: { 11 | client_id?: string; 12 | client_secret?: string; 13 | redirect_uri?: string; 14 | }) { 15 | __client_id = client_id; 16 | __client_secret = client_secret; 17 | __redirect_uri = redirect_uri; 18 | } 19 | 20 | let __client_id: string = process.env.FIGMA_APP_CLIENT_ID; 21 | let __client_secret: string = process.env.FIGMA_APP_CLIENT_SECRET; 22 | let __redirect_uri: string = process.env.FIGMA_OAUTH_CALLBACL_URI; 23 | export function __cfg_get_client_id(): string { 24 | return __client_id; 25 | } 26 | export function __cfg_get_client_secret(): string { 27 | return __client_secret; 28 | } 29 | export function __cfg_get_redirect_uri(): string { 30 | return __redirect_uri; 31 | } 32 | -------------------------------------------------------------------------------- /figma-oauth/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | export * from "./request"; 3 | export * from "./urls"; 4 | export { configure } from "./configure"; 5 | export * from "./oauth"; 6 | -------------------------------------------------------------------------------- /figma-oauth/lib/types.ts: -------------------------------------------------------------------------------- 1 | export interface FigmaOAuthUrlParam { 2 | client_id: string; 3 | 4 | redirect_uri: string; 5 | 6 | /** 7 | * Currently this value can only be file_read signifying 8 | * read-only access to the user's files. 9 | */ 10 | scope?: "file_read"; 11 | 12 | /** 13 | * This is a value that you should randomly generate and store. 14 | * When we call back to your callback endpoint, 15 | * you should check that the state value we pass back to you matches the state value that you initially used in your request. 16 | */ 17 | state: string; 18 | 19 | /** 20 | * Currently we only support the authorization code flow for OAuth 2, 21 | * so the only valid value here is code. 22 | * We may support other values in the future. 23 | */ 24 | response_type?: "code"; 25 | } 26 | 27 | export interface FigmaOAuthTokenRequestParam { 28 | client_id: string; 29 | client_secret: string; 30 | grant_type?: string; 31 | redirect_uri: string; 32 | code: string; 33 | } 34 | 35 | export interface FigmaOAuthTokenRefreshParam { 36 | client_id: string; 37 | client_secret: string; 38 | refresh_token: string; 39 | } 40 | 41 | /** 42 | * [Authenticate users](https://www.figma.com/developers/api#auth-oauth2) 43 | */ 44 | export interface FigmaOAuthTokenResponse { 45 | user_id: string; 46 | access_token: string; 47 | expires_in: number; 48 | refresh_token: string; 49 | } 50 | 51 | /** 52 | * [Refreshing OAuth tokens](https://www.figma.com/developers/api#refresh-oauth2) 53 | */ 54 | export interface FigmaOAuthTokenRefreshResponse { 55 | access_token: string; 56 | expires_in: number; 57 | } 58 | 59 | export type OAuthStage = 60 | | "started" 61 | // 62 | | "authorize" 63 | | "token"; 64 | -------------------------------------------------------------------------------- /figma-oauth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-oauth", 3 | "description": "OAuth management for figma", 4 | "main": "dist/index.js", 5 | "private": false, 6 | "keywords": [ 7 | "figma", 8 | "oauth", 9 | "sdk", 10 | "design-sdk", 11 | "api", 12 | "token", 13 | "passport" 14 | ], 15 | "homepage": "https://github.com/gridaco/design-sdk/", 16 | "repository": "https://github.com/gridaco/design-sdk/tree/main/figma-oauth/", 17 | "authors": "Grida.co", 18 | "version": "0.0.53", 19 | "scripts": { 20 | "clean": "rimraf dist", 21 | "prepack": "tsc", 22 | "test": "jest" 23 | }, 24 | "peerDependencies": { 25 | "axios": "^0.21.1" 26 | }, 27 | "devDependencies": { 28 | "@types/jest": "^26.0.24", 29 | "dotenv": "^10.0.0", 30 | "jest": "^27.0.6", 31 | "ts-jest": "^27.0.3", 32 | "typescript": "^4.3.5" 33 | }, 34 | "files": [ 35 | "dist/index.js", 36 | "dist/index.d.ts", 37 | "dist/**/*.js", 38 | "dist/**/*.d.ts", 39 | "README", 40 | "LICENSE" 41 | ], 42 | "publishConfig": { 43 | "access": "public" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /figma-oauth/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | -------------------------------------------------------------------------------- /figma-reflect-node-types/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gridaco/figma-sdk/5784ab284f17fcb2b20bc821fc140fd004964d7e/figma-reflect-node-types/index.js -------------------------------------------------------------------------------- /figma-reflect-node-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-node-types", 3 | "version": "0.0.53", 4 | "description": "Abstract type definitions for Figma node types with reflect property typings", 5 | "private": false, 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /figma-reflect-node/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /figma-reflect-node/README.md: -------------------------------------------------------------------------------- 1 | # Figma Reflect Node Alias (Temporary) 2 | 3 | > Currently, Reflect design nodes rely on figma node definitions. This will be migrated to native reflect-ui core definitions in the future. Meanwhile, Reflect node definitions are based on figma and this is the main node definitions package. 4 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/boolean-operation.node.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Constraints, 3 | FigmaBooleanOpeartionType, 4 | } from "@design-sdk/figma-types"; 5 | import { 6 | IReflectCornerMixin, 7 | ReflectDefaultShapeMixin, 8 | IReflectConstraintMixin, 9 | } from "./mixins"; 10 | import { ReflectSceneNodeType } from "./node-type"; 11 | import type { ReflectSceneNode } from "./node-type-alias"; 12 | 13 | export class ReflectBooleanOperationNode 14 | extends ReflectDefaultShapeMixin 15 | implements IReflectCornerMixin, IReflectConstraintMixin 16 | { 17 | readonly type: ReflectSceneNodeType.boolean_operation = 18 | ReflectSceneNodeType.boolean_operation; 19 | constraints: Constraints; 20 | 21 | // --------------- BOOL OP ----------------- 22 | booleanOperation: FigmaBooleanOpeartionType; 23 | shapeCornerRadius: number; 24 | cornerSmoothing: number; 25 | 26 | /** 27 | * @deprecated - this exists on plugin typings, but no document is available. update this property's doc later. 28 | * https://www.figma.com/plugin-docs/api/BooleanOperationNode/ 29 | */ 30 | expanded: boolean; 31 | // --------------- BOOL OP ----------------- 32 | 33 | children: Array = []; 34 | } 35 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/ellipse.node.ts: -------------------------------------------------------------------------------- 1 | import type { ArcData } from "@design-sdk/figma-types"; 2 | import { ReflectDefaultShapeMixin } from "./mixins"; 3 | import { ReflectSceneNodeType } from "./node-type"; 4 | 5 | export class ReflectEllipseNode extends ReflectDefaultShapeMixin { 6 | readonly type: ReflectSceneNodeType.ellipse = ReflectSceneNodeType.ellipse; 7 | 8 | arcData: ArcData; 9 | } 10 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/group.node.ts: -------------------------------------------------------------------------------- 1 | import { ReflectChildrenMixin } from "./mixins/children.mixin"; 2 | import type { IReflectBlendMixin, IReflectLayoutMixin } from "./mixins"; 3 | import type { ReflectSceneNode } from "./node-type-alias"; 4 | import type { BlendMode } from "@reflect-ui/cg"; 5 | import type { 6 | // FIXME: - migrate this 7 | Effect, 8 | FigmaLayoutGrow, 9 | FigmaLayoutAlign, 10 | } from "@design-sdk/figma-types"; 11 | import { ReflectSceneNodeType } from "./node-type"; 12 | import { types } from "@reflect-ui/uiutils"; 13 | 14 | //#region group node 15 | export class ReflectGroupNode 16 | extends ReflectChildrenMixin 17 | implements ReflectChildrenMixin, IReflectBlendMixin, IReflectLayoutMixin 18 | { 19 | readonly type: ReflectSceneNodeType.group = ReflectSceneNodeType.group; 20 | 21 | opacity: number; 22 | blendMode: "PASS_THROUGH" | BlendMode; 23 | isMask: boolean; 24 | effects: readonly Effect[]; 25 | effectStyleId: string; 26 | visible: boolean; 27 | radius: number; 28 | absoluteTransform: types.Transform; 29 | x: number; 30 | y: number; 31 | rotation: number; 32 | width: number; 33 | height: number; 34 | layoutAlign: FigmaLayoutAlign; 35 | layoutGrow: FigmaLayoutGrow; 36 | 37 | children: Array; 38 | } 39 | 40 | //#endregion 41 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./base.node"; 2 | export * from "./mixins/children.mixin"; 3 | export * from "./mixins/constraint.mixin"; 4 | export * from "./boolean-operation.node"; 5 | export * from "./ellipse.node"; 6 | export * from "./frame.node"; 7 | export * from "./group.node"; 8 | export * from "./line.node"; 9 | export * from "./rectangle.node"; 10 | export * from "./mixins"; 11 | export * from "./node-type"; 12 | export * from "./node-type-alias"; 13 | export * from "./text.node"; 14 | export * from "./vector.node"; 15 | 16 | // reference nodes 17 | export * from "./reflect-node-reference"; 18 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/interfaces/default-shape-mixin.ts: -------------------------------------------------------------------------------- 1 | import type { IReflectGeometryMixin } from "../mixins/geometry.mixin"; 2 | import type { IReflectLayoutMixin } from "../mixins/layout.mixin"; 3 | 4 | export interface IReflectDefaultShapeMixin 5 | extends IReflectGeometryMixin, 6 | IReflectLayoutMixin {} 7 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/line.node.ts: -------------------------------------------------------------------------------- 1 | import { ReflectDefaultShapeMixin } from "./mixins"; 2 | import { ReflectSceneNodeType } from "./node-type"; 3 | 4 | export class ReflectLineNode extends ReflectDefaultShapeMixin { 5 | readonly type: ReflectSceneNodeType.line = ReflectSceneNodeType.line; 6 | } 7 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/blend.mixin.ts: -------------------------------------------------------------------------------- 1 | // FIXME 2 | import type { Effect } from "@design-sdk/figma-types"; 3 | import type { BlendMode } from "@reflect-ui/cg"; 4 | 5 | export interface IReflectBlendMixin { 6 | opacity: number; 7 | blendMode: "PASS_THROUGH" | BlendMode; 8 | isMask: boolean; 9 | effects: ReadonlyArray; 10 | effectStyleId: string; 11 | visible: boolean; 12 | radius: number; 13 | } 14 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/children.mixin.ts: -------------------------------------------------------------------------------- 1 | import type { ReflectSceneNode } from "../node-type-alias"; 2 | import { ReflectConstraintMixin } from "./constraint.mixin"; 3 | import { types } from "@reflect-ui/uiutils"; 4 | 5 | export interface IChildrenMixin { 6 | children: Array; 7 | } 8 | 9 | export interface IReflectChildrenMixin 10 | extends IChildrenMixin { 11 | children: Array; 12 | } 13 | export abstract class ReflectChildrenMixin 14 | extends ReflectConstraintMixin 15 | implements IReflectChildrenMixin { 16 | children: Array; 17 | get constraintableChildren(): Array { 18 | return filterConstraintableChildren(this); 19 | } 20 | isRelative?: boolean; 21 | 22 | get mostUsedColor(): ReadonlyArray { 23 | throw "not implemented"; 24 | } 25 | } 26 | 27 | function filterConstraintableChildren(node: ReflectChildrenMixin) { 28 | const constraintables: Array = []; 29 | for (const childNode of node.children) { 30 | if ( 31 | childNode.origin == "INSTANCE" || 32 | childNode.origin == "COMPONENT" || 33 | childNode.origin == "FRAME" || 34 | childNode.origin == "RECTANGLE" || 35 | childNode.origin == "GROUP" || 36 | childNode.origin == "LINE" || 37 | childNode.origin == "ELLIPSE" || 38 | childNode.origin == "TEXT" 39 | ) { 40 | constraintables.push(childNode as ReflectConstraintMixin); 41 | } 42 | } 43 | return constraintables; 44 | } 45 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/constraint.mixin.ts: -------------------------------------------------------------------------------- 1 | import { ReflectBaseNode } from "../base.node"; 2 | import { 3 | LCRS, 4 | getNodeActualLCRS, 5 | getReletiveLCRS, 6 | } from "@design-sdk/figma-utils"; 7 | import type { ReflectSceneNode } from "../node-type-alias"; 8 | 9 | // FIXME - migrate this to reflect core cg 10 | import type { Constraints } from "@design-sdk/figma-types"; 11 | export interface IReflectConstraintMixin { 12 | constraints: Constraints; 13 | } 14 | 15 | export class ReflectConstraintMixin 16 | extends ReflectBaseNode 17 | implements IReflectConstraintMixin 18 | { 19 | constraints: Constraints; 20 | 21 | /** 22 | * the current node's constraint LCRS positioning. as is. 23 | */ 24 | get constraintLcrs(): LCRS { 25 | return getNodeActualLCRS(this as any); 26 | } 27 | 28 | /** 29 | * the cureent node's visual LCRS positioning actually relative to parent. 30 | */ 31 | get relativeLcrs(): LCRS { 32 | return getReletiveLCRS(this, this.parent); 33 | } 34 | 35 | getRelativeToLcrs(to: ReflectSceneNode) { 36 | // TODO add validation if 'to' node is somewhere on the parent tree of this node 37 | return getReletiveLCRS(this, to); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/corner.mixin.ts: -------------------------------------------------------------------------------- 1 | import type { BorderRadiusManifest } from "@reflect-ui/core"; 2 | 3 | export interface IReflectRectangleCornerMixin { 4 | cornerRadius: BorderRadiusManifest; 5 | cornerSmoothing: number; 6 | } 7 | 8 | export interface IReflectCornerMixin { 9 | cornerSmoothing: number; 10 | shapeCornerRadius: number; 11 | } 12 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/default-shape.mixin.ts: -------------------------------------------------------------------------------- 1 | import { ReflectConstraintMixin } from "./constraint.mixin"; 2 | import type { BorderRadiusManifest } from "@reflect-ui/core"; 3 | import type { IReflectDefaultShapeMixin } from "../interfaces/default-shape-mixin"; 4 | import type { BlendMode } from "@reflect-ui/cg"; 5 | 6 | // FIXME - migrate this 7 | import type { 8 | Paint, 9 | Effect, 10 | StrokeCap, 11 | StrokeJoin, 12 | FigmaLayoutAlign, 13 | VectorPaths, 14 | } from "@design-sdk/figma-types"; 15 | import { FigmaLayoutGrow } from "@design-sdk/figma-types"; 16 | 17 | export class ReflectDefaultShapeMixin 18 | extends ReflectConstraintMixin 19 | implements IReflectDefaultShapeMixin 20 | { 21 | layoutGrow: FigmaLayoutGrow; 22 | layoutAlign: FigmaLayoutAlign; 23 | opacity: number; 24 | blendMode: "PASS_THROUGH" | BlendMode; 25 | isMask: boolean; 26 | effects: ReadonlyArray; 27 | effectStyleId: string; 28 | visible: boolean; 29 | radius: number; 30 | 31 | fills: ReadonlyArray | undefined; 32 | strokes: ReadonlyArray; 33 | strokeWeight: number; 34 | strokeMiterLimit: number; 35 | strokeAlign: "CENTER" | "INSIDE" | "OUTSIDE"; 36 | strokeCap: StrokeCap | undefined; 37 | strokeJoin: StrokeJoin | undefined; 38 | strokeGeometry: VectorPaths; 39 | dashPattern: ReadonlyArray; 40 | fillStyleId: string | undefined; 41 | strokeStyleId: string; 42 | 43 | cornerRadius: BorderRadiusManifest; 44 | cornerSmoothing: number; 45 | 46 | x: number; 47 | y: number; 48 | rotation: number; 49 | width: number; 50 | height: number; 51 | } 52 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/geometry.mixin.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Paint, 3 | StrokeCap, 4 | StrokeJoin, 5 | VectorPaths, 6 | } from "@design-sdk/figma-types"; 7 | 8 | export interface IReflectGeometryMixin { 9 | fills: ReadonlyArray | undefined; 10 | // TODO: add fillGeometry 11 | strokes: ReadonlyArray; 12 | strokeWeight: number; 13 | strokeMiterLimit: number; 14 | strokeAlign: "CENTER" | "INSIDE" | "OUTSIDE"; 15 | strokeCap: StrokeCap | undefined; 16 | strokeJoin: StrokeJoin | undefined; 17 | strokeGeometry: VectorPaths; 18 | dashPattern: ReadonlyArray; 19 | fillStyleId: string | undefined; 20 | strokeStyleId: string; 21 | } 22 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./blend.mixin"; 2 | export * from "./corner.mixin"; 3 | export * from "./default-shape.mixin"; 4 | export * from "./geometry.mixin"; 5 | export * from "./layout.mixin"; 6 | export * from "./constraint.mixin"; 7 | export type { 8 | IChildrenMixin, 9 | IReflectChildrenMixin, 10 | ReflectChildrenMixin, 11 | } from "./children.mixin"; 12 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/mixins/layout.mixin.ts: -------------------------------------------------------------------------------- 1 | import type { FigmaLayoutAlign } from "@design-sdk/figma-types"; 2 | import { types } from "@reflect-ui/uiutils"; 3 | 4 | export interface IReflectLayoutMixin { 5 | absoluteTransform: types.Transform; 6 | x: number; 7 | y: number; 8 | rotation: number; // In degrees 9 | 10 | width: number; 11 | height: number; 12 | 13 | /** 14 | * fimgma: this property is only applicable when frame is auto-layout frame. 15 | */ 16 | layoutAlign: FigmaLayoutAlign; 17 | 18 | /** 19 | * figma: [layout grow](https://www.figma.com/plugin-docs/api/properties/nodes-layoutgrow) 20 | */ 21 | layoutGrow: number; 22 | } 23 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/node-type-alias.ts: -------------------------------------------------------------------------------- 1 | import type { ReflectEllipseNode } from "./ellipse.node"; 2 | import type { ReflectFrameNode } from "./frame.node"; 3 | import type { ReflectGroupNode } from "./group.node"; 4 | import type { ReflectLineNode } from "./line.node"; 5 | import type { ReflectRectangleNode } from "./rectangle.node"; 6 | import type { ReflectTextNode } from "./text.node"; 7 | import type { ReflectVectorNode } from "."; 8 | import type { ReflectBooleanOperationNode } from "./boolean-operation.node"; 9 | 10 | type ReflectSceneNode = 11 | | ReflectFrameNode 12 | | ReflectGroupNode 13 | | ReflectRectangleNode 14 | | ReflectEllipseNode 15 | | ReflectVectorNode 16 | | ReflectTextNode 17 | | ReflectLineNode 18 | | ReflectBooleanOperationNode; 19 | // TODO 20 | // | StarNode 21 | // | PolygonNode; 22 | 23 | export type { ReflectSceneNode }; 24 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/rectangle.node.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ReflectDefaultShapeMixin, 3 | IReflectRectangleCornerMixin, 4 | } from "./mixins"; 5 | import { ReflectSceneNodeType } from "./node-type"; 6 | 7 | export class ReflectRectangleNode 8 | extends ReflectDefaultShapeMixin 9 | implements IReflectRectangleCornerMixin { 10 | readonly type: ReflectSceneNodeType.rectangle = 11 | ReflectSceneNodeType.rectangle; 12 | } 13 | -------------------------------------------------------------------------------- /figma-reflect-node/lib/vector.node.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HandleMirroring, 3 | VectorNetwork, 4 | VectorPaths, 5 | } from "@design-sdk/figma-types"; 6 | import { ReflectDefaultShapeMixin } from "./mixins"; 7 | import { ReflectSceneNodeType } from "./node-type"; 8 | 9 | export class ReflectVectorNode extends ReflectDefaultShapeMixin { 10 | readonly type: ReflectSceneNodeType.vector = ReflectSceneNodeType.vector; 11 | /** 12 | * Exposes a simple, but incomplete representation of vectors as path. See VectorPaths 13 | */ 14 | vectorPaths: VectorPaths; 15 | /** 16 | * Exposes a complete, but more complex representation of vectors as a network of edges between vectices. See VectorNetwork. 17 | */ 18 | vectorNetwork: VectorNetwork; 19 | /** 20 | * Whether the vector handles are mirrored or independent. 21 | */ 22 | handleMirroring: HandleMirroring; // TODO: mixed type not supported. 23 | } 24 | -------------------------------------------------------------------------------- /figma-reflect-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-node", 3 | "description": "A temporary reflect node definition alias based on figma typings", 4 | "version": "0.0.53", 5 | "author": "Grida.co", 6 | "private": false, 7 | "license": "MIT", 8 | "main": "dist/index.js", 9 | "types": "dist/index.d.ts", 10 | "scripts": { 11 | "clean": "rimraf dist", 12 | "build": "tsc", 13 | "prepack": "yarn build" 14 | }, 15 | "files": [ 16 | "dist", 17 | "README.md", 18 | "LICENSE" 19 | ], 20 | "dependencies": { 21 | "@design-sdk/figma-core": "^0.0.53", 22 | "@design-sdk/figma-types": "^0.0.53", 23 | "@design-sdk/figma-utils": "^0.0.53", 24 | "@reflect-ui/font-utils": "^0.0.1" 25 | }, 26 | "peerDependencies": { 27 | "@design-sdk/figma-core": "0.0.23", 28 | "@reflect-ui/cg": "^0.1.1", 29 | "@reflect-ui/core": "^0.0.5", 30 | "@reflect-ui/font-utils": "^0.0.1", 31 | "@reflect-ui/uiutils": "^0.1.2-2" 32 | }, 33 | "devDependencies": { 34 | "@reflect-ui/cg": "^0.1.1", 35 | "@reflect-ui/core": "^0.0.5", 36 | "typescript": "^4.7.4" 37 | }, 38 | "publishConfig": { 39 | "access": "public" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /figma-reflect-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "declarationDir": "./dist" 6 | }, 7 | "include": ["./lib/**/*"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-remote-api/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jon Gold 4 | Copyright (c) 2021 Grida 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /figma-remote-api/README.md: -------------------------------------------------------------------------------- 1 | # `Figma-Remote-Api` _(`@design-sdk/figma-remote-api`)_ 2 | 3 | > figma remote api (figma rest api) for nodejs 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @design-sdk/figma-remote-api 9 | 10 | # or with npm 11 | npm i @design-sdk/figma-remote-api 12 | ``` 13 | 14 | ## Usage 15 | 16 | ```ts 17 | import { Client } from "@design-sdk/figma-remote-api"; 18 | 19 | const client = Client({ 20 | accessToken: "", 21 | }); 22 | ``` 23 | 24 | ## Disclamer 25 | 26 | The figma remote api responce type definitions from "[figma-js](https://github.com/jongold/figma-js/blob/master/src/figmaTypes.ts)" (MIT) 27 | -------------------------------------------------------------------------------- /figma-remote-api/__test__/.gitignore: -------------------------------------------------------------------------------- 1 | *.data.json -------------------------------------------------------------------------------- /figma-remote-api/__test__/README.md: -------------------------------------------------------------------------------- 1 | # Figma Remote API & Formatting Tests 2 | -------------------------------------------------------------------------------- /figma-remote-api/__test__/dummy.test.ts: -------------------------------------------------------------------------------- 1 | test("dummy", () => { 2 | return expect("").toMatch(""); 3 | }); 4 | -------------------------------------------------------------------------------- /figma-remote-api/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/lib/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /figma-remote-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-remote-api", 3 | "description": "Light-weight Figma Remote api wrapper with types & authentication", 4 | "main": "dist/index.js", 5 | "private": false, 6 | "keywords": [ 7 | "figma", 8 | "oauth", 9 | "sdk", 10 | "design-sdk", 11 | "api", 12 | "token", 13 | "passport", 14 | "figma-types" 15 | ], 16 | "homepage": "https://github.com/gridaco/design-sdk/", 17 | "repository": "https://github.com/gridaco/design-sdk/tree/main/figma-remote-api/", 18 | "authors": "Grida.co", 19 | "version": "0.0.53", 20 | "license": "MIT", 21 | "scripts": { 22 | "clean": "rimraf dist", 23 | "prepack": "tsc", 24 | "test": "jest" 25 | }, 26 | "peerDependencies": { 27 | "axios": "^0.21.1" 28 | }, 29 | "devDependencies": { 30 | "@design-sdk/figma-remote-types": "^0.0.53", 31 | "@types/jest": "^26.0.24", 32 | "dotenv": "^10.0.0", 33 | "jest": "^27.0.6", 34 | "ts-jest": "^27.0.3", 35 | "typescript": "^4.3.5" 36 | }, 37 | "files": [ 38 | "dist/index.js", 39 | "dist/index.d.ts", 40 | "dist/**/*.js", 41 | "dist/**/*.d.ts", 42 | "README", 43 | "LICENSE" 44 | ], 45 | "publishConfig": { 46 | "access": "public" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /figma-remote-api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "./dist" 6 | }, 7 | "include": ["."], 8 | "exclude": ["dist", "node_modules", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-remote-types/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jon Gold 4 | Copyright (c) 2021 Grida 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /figma-remote-types/README.md: -------------------------------------------------------------------------------- 1 | # `Figma-Remote-Types` _(`@design-sdk/figma-remote-types`)_ 2 | 3 | > Type definitions of figma remote api (figma rest api) 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @design-sdk/figma-remote-types 9 | 10 | # or with npm 11 | npm i @design-sdk/figma-remote-types 12 | ``` 13 | 14 | ## Usage: Importing types 15 | 16 | ```ts 17 | import { Paint } from "@design-sdk/figma-remote-types"; 18 | ``` 19 | 20 | ## Disclamer 21 | 22 | The figma remote api responce type definitions from "[figma-js](https://github.com/jongold/figma-js/blob/master/src/figmaTypes.ts)" (MIT) 23 | -------------------------------------------------------------------------------- /figma-remote-types/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /figma-remote-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-remote-types", 3 | "description": "Light-weight Figma Remote api wrapper with types & authentication", 4 | "main": "index.js", 5 | "types": "index.d.ts", 6 | "version": "0.0.53", 7 | "private": false, 8 | "keywords": [ 9 | "figma", 10 | "oauth", 11 | "sdk", 12 | "design-sdk", 13 | "api", 14 | "token", 15 | "passport", 16 | "figma-types" 17 | ], 18 | "homepage": "https://github.com/gridaco/design-sdk/", 19 | "repository": "https://github.com/gridaco/design-sdk/tree/main/figma-remote-api/", 20 | "authors": "Grida.co", 21 | "license": "MIT", 22 | "scripts": { 23 | "build": "echo 'this package does not require build' && exit 0", 24 | "test": "jest" 25 | }, 26 | "devDependencies": { 27 | "@types/jest": "^26.0.24", 28 | "jest": "^27.0.6", 29 | "ts-jest": "^27.0.3", 30 | "typescript": "^4.3.5" 31 | }, 32 | "files": [ 33 | "index.d.ts", 34 | "index.js", 35 | "README", 36 | "LICENSE" 37 | ], 38 | "publishConfig": { 39 | "access": "public" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /figma-remote/README.md: -------------------------------------------------------------------------------- 1 | # Figma Remote 2 | -------------------------------------------------------------------------------- /figma-remote/__test__/.env.example: -------------------------------------------------------------------------------- 1 | FIGMA_PERSONAL_ACCESS_TOKEN="..." 2 | FIGMA_PERSONAL_ACCESS_TOKEN_ELSES="..." 3 | # this is a expired token and safe to share on git 4 | FIGMA_PERSONAL_ACCESS_TOKEN_EXPIRED="figd_Pxmds7sXCnqDYVvMc2yrIHXkLadhZnitqDUq8Rna" -------------------------------------------------------------------------------- /figma-remote/__test__/.gitignore: -------------------------------------------------------------------------------- 1 | .env.test -------------------------------------------------------------------------------- /figma-remote/__test__/README.md: -------------------------------------------------------------------------------- 1 | # Figma Remote API & Formatting Tests 2 | -------------------------------------------------------------------------------- /figma-remote/__test__/fecth.test.ts: -------------------------------------------------------------------------------- 1 | import { fetch } from "../lib"; 2 | 3 | test("valid token, invalid file", async () => { 4 | const resolve = async () => 5 | await fetch.fetchTargetAsReflect({ 6 | file: "", 7 | node: "", 8 | auth: { 9 | personalAccessToken: process.env.FIGMA_PERSONAL_ACCESS_TOKEN, 10 | }, 11 | }); 12 | 13 | expect(resolve).rejects.toThrow(fetch.NotfoundError); 14 | }); 15 | 16 | test("valid file, invalid token for that file. (no write access)", async () => { 17 | const resolve = async () => 18 | await fetch.fetchTargetAsReflect({ 19 | // some file that (FIGMA_PERSONAL_ACCESS_TOKEN_ELSES) does not have write access to. 20 | file: "eBRgVmrNBFPuCxjULSrXkj", 21 | node: "520:15648", 22 | auth: { 23 | personalAccessToken: process.env.FIGMA_PERSONAL_ACCESS_TOKEN_ELSES, 24 | }, 25 | }); 26 | 27 | expect(resolve).rejects.toThrow(fetch.UnauthorizedError); 28 | }); 29 | 30 | test("expired token, valid file", async () => { 31 | // Define the async function that iterates over the generator 32 | const iterateGenerator = async () => { 33 | const iter = fetch.fetchFile({ 34 | file: "eBRgVmrNBFPuCxjULSrXkj", 35 | auth: { 36 | personalAccessToken: process.env.FIGMA_PERSONAL_ACCESS_TOKEN_EXPIRED, 37 | }, 38 | }); 39 | 40 | // Iterate over the generator and await each result 41 | for await (const _ of iter) { 42 | // Normally process each value here, but we're expecting an error 43 | } 44 | }; 45 | 46 | // Assert that iterating over the generator throws an UnauthorizedError 47 | await expect(iterateGenerator()).rejects.toThrow( 48 | fetch.TokenExpiredUnauthorizedError 49 | ); 50 | }); 51 | -------------------------------------------------------------------------------- /figma-remote/__test__/setup.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import dotenv from "dotenv"; 3 | 4 | const file = path.resolve(__dirname, "./.env.test"); 5 | 6 | // if .env.test not found, throw. 7 | if (!dotenv.config({ path: file }).parsed) { 8 | throw new Error( 9 | `.env.test not found at "${file}" To run this test, you need to setup your FIGMA_PERSONAL_ACCESS_TOKEN in .env.test` 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /figma-remote/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/lib/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | // extra setup required for this package. 9 | setupFiles: ["/__test__/setup.ts"], 10 | collectCoverage: true, 11 | }; 12 | -------------------------------------------------------------------------------- /figma-remote/lib/README.md: -------------------------------------------------------------------------------- 1 | # Figma remote API support 2 | 3 | ## What's the difference with plain 'figma'? 4 | 5 | figma - the figma plugin typings 6 | figma-remote - the figma api fetched via remote request. (official figma api) 7 | -------------------------------------------------------------------------------- /figma-remote/lib/asset-repository/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./image-repository"; 2 | -------------------------------------------------------------------------------- /figma-remote/lib/blenders/_in.ts: -------------------------------------------------------------------------------- 1 | import { MappingNode } from "../mapper/mapping-instance"; 2 | import { 3 | Frame, 4 | Group, 5 | Vector, 6 | Star, 7 | Line, 8 | Ellipse, 9 | BooleanGroup, 10 | Text, 11 | RegularPolygon, 12 | Rectangle, 13 | Component, 14 | Instance, 15 | } from "@design-sdk/figma-remote-types"; 16 | 17 | /** 18 | * Type like Node, but without 19 | */ 20 | export type MappableNode = 21 | | Frame 22 | | Group 23 | | Vector 24 | | Star 25 | | Line 26 | | Ellipse 27 | | RegularPolygon 28 | | Rectangle 29 | | Text 30 | | BooleanGroup 31 | | Component 32 | | RegularPolygon 33 | | Instance; 34 | 35 | export type MappingBlendInput = { 36 | target: T; 37 | source: S; 38 | parent?: MappableNode; 39 | }; 40 | -------------------------------------------------------------------------------- /figma-remote/lib/blenders/corner.blend.ts: -------------------------------------------------------------------------------- 1 | import { CornerMixin, RectangleCornerMixin } from "@design-sdk/figma-types"; 2 | import { Frame, Rectangle } from "@design-sdk/figma-remote-types"; 3 | import { MappingBlendInput } from "./_in"; 4 | 5 | type CornerMixinRemoteNode = Rectangle | Frame; 6 | 7 | export function blendCornerNode( 8 | p: MappingBlendInput 9 | ) { 10 | const { target, source } = p; 11 | 12 | target.cornerRadius = source.cornerRadius ?? 0; 13 | // target.cornerSmoothing - not supported 14 | } 15 | 16 | export function blendRectangleCornerNode( 17 | p: MappingBlendInput 18 | ) { 19 | const { target, source } = p; 20 | 21 | target.topLeftRadius = 22 | source.rectangleCornerRadii?.[0] ?? source.cornerRadius ?? 0; 23 | target.topRightRadius = 24 | source.rectangleCornerRadii?.[1] ?? source.cornerRadius ?? 0; 25 | target.bottomRightRadius = 26 | source.rectangleCornerRadii?.[2] ?? source.cornerRadius ?? 0; 27 | target.bottomLeftRadius = 28 | source.rectangleCornerRadii?.[3] ?? source.cornerRadius ?? 0; 29 | } 30 | -------------------------------------------------------------------------------- /figma-remote/lib/blenders/index.ts: -------------------------------------------------------------------------------- 1 | //// 2 | //// this is internally used by "mapper". there is no need to export this package. 3 | //// 4 | export { blendBaseNode } from "./general.blend"; 5 | export { blendCornerNode, blendRectangleCornerNode } from "./corner.blend"; 6 | export { blendVectorNode } from "./vector.blend"; 7 | -------------------------------------------------------------------------------- /figma-remote/lib/configure-auth-credentials/__internal__.ts: -------------------------------------------------------------------------------- 1 | import type { AuthenticationCredential } from "../fetch"; 2 | 3 | /** 4 | * set me by calling `setGlobalAuthCredential(...)` <- `configure_auth_credentials(...)` 5 | */ 6 | export let FIGMA_REMOTE_LIB_AUTH_CREDENTIAL_GLOBAL: AuthenticationCredential; 7 | export function setGlobalAuthCredential( 8 | authCredential: AuthenticationCredential 9 | ): void { 10 | FIGMA_REMOTE_LIB_AUTH_CREDENTIAL_GLOBAL = authCredential; 11 | } 12 | -------------------------------------------------------------------------------- /figma-remote/lib/configure-auth-credentials/export-me.ts: -------------------------------------------------------------------------------- 1 | import type { AuthenticationCredential } from "../fetch"; 2 | import { setGlobalAuthCredential } from "./__internal__"; 3 | 4 | /** 5 | * design-sdk/figma-remote works as a singleton. 6 | * user can set figma auth credential via this function, so that other static functions will work without 403. 7 | */ 8 | export function configure_auth_credentials(creds: AuthenticationCredential) { 9 | setGlobalAuthCredential(creds); 10 | } 11 | -------------------------------------------------------------------------------- /figma-remote/lib/configure-auth-credentials/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./export-me"; 2 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/constraints-mixin.convert.ts: -------------------------------------------------------------------------------- 1 | import { ConstraintMixin } from "@design-sdk/figma-types"; 2 | import { LayoutConstraint } from "@design-sdk/figma-remote-types"; 3 | import { convertFigmaRemoteLayoutConstraintsToFigmaConstraints } from "./layout-constraints.convert"; 4 | export function convertForFigmaConstraintsMixin( 5 | _do: LayoutConstraint, 6 | _for: ConstraintMixin 7 | ) { 8 | _for.constraints = convertFigmaRemoteLayoutConstraintsToFigmaConstraints(_do); 9 | return _for; 10 | } 11 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/effect.convert.ts: -------------------------------------------------------------------------------- 1 | import { Effect as RemEffect } from "@design-sdk/figma-remote-types"; 2 | import { Effect, ShadowEffect, BlurEffect } from "@design-sdk/figma-types"; 3 | export function convertFigmaRemoteEffectToFigma(remEffect: RemEffect): Effect { 4 | switch (remEffect.type) { 5 | // blurs 6 | case "BACKGROUND_BLUR": 7 | case "LAYER_BLUR": 8 | return { 9 | type: remEffect.type, 10 | radius: remEffect.radius, 11 | visible: remEffect.visible, 12 | }; 13 | // shadows 14 | case "DROP_SHADOW": 15 | case "INNER_SHADOW": 16 | return { 17 | type: remEffect.type, 18 | color: remEffect.color, 19 | offset: remEffect.offset, 20 | radius: remEffect.radius, 21 | spread: remEffect.spread, 22 | visible: remEffect.visible, 23 | blendMode: remEffect.blendMode, 24 | }; 25 | default: 26 | throw `cannot handle input data from remote - ${JSON.stringify( 27 | remEffect, 28 | null, 29 | 2 30 | )}`; 31 | break; 32 | } 33 | } 34 | 35 | export function convertFigmaRemoteEffectsToFigma( 36 | ...remEffects: RemEffect[] 37 | ): Effect[] { 38 | return remEffects.map((re) => convertFigmaRemoteEffectToFigma(re)); 39 | } 40 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/fills.convert.ts: -------------------------------------------------------------------------------- 1 | import { Paint as RemPaint } from "@design-sdk/figma-remote-types"; 2 | import { Paint } from "@design-sdk/figma-types"; 3 | import { figmaRemotePaintToFigma } from "./paint.convert"; 4 | 5 | export function convertFigmaRemoteFillsToFigma(...fills: RemPaint[]): Paint[] { 6 | return fills.map((f) => figmaRemotePaintToFigma(f)); 7 | } 8 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./constraints-mixin.convert"; 2 | export * from "./effect.convert"; 3 | export * from "./fills.convert"; 4 | export * from "./layout-constraints.convert"; 5 | export * from "./line-height.convert"; 6 | export * from "./paint.convert"; 7 | export * from "./stroke-cap.convert"; 8 | export * from "./strokes.convert"; 9 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/layout-constraints.convert.ts: -------------------------------------------------------------------------------- 1 | import { LayoutConstraint } from "@design-sdk/figma-remote-types"; 2 | import { Constraints, ConstraintType } from "@design-sdk/figma-types"; 3 | /** 4 | * 5 | * from : https://www.figma.com/developers/api#layoutconstraint-type 6 | * 7 | * to: https://www.figma.com/plugin-docs/api/Constraints/ 8 | */ 9 | export function convertFigmaRemoteLayoutConstraintsToFigmaConstraints( 10 | remLayoutConstraints: LayoutConstraint 11 | ): Constraints { 12 | return { 13 | vertical: __vert_mapping[remLayoutConstraints.vertical], 14 | horizontal: __horiz_mapping[remLayoutConstraints.horizontal], 15 | }; 16 | } 17 | 18 | const __vert_mapping: { [s: string]: ConstraintType } = { 19 | TOP: "MIN", 20 | BOTTOM: "MAX", 21 | CENTER: "CENTER", 22 | TOP_BOTTOM: "STRETCH", 23 | SCALE: "SCALE", 24 | }; 25 | 26 | const __horiz_mapping: { [s: string]: ConstraintType } = { 27 | LEFT: "MIN", 28 | RIGHT: "MAX", 29 | CENTER: "CENTER", 30 | LEFT_RIGHT: "STRETCH", 31 | SCALE: "SCALE", 32 | }; 33 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/line-height.convert.ts: -------------------------------------------------------------------------------- 1 | import { LineHeight } from "@design-sdk/figma-types"; 2 | import { TypeStyle } from "@design-sdk/figma-remote-types"; 3 | 4 | export function figmaRemoteLineHeightToFigma(params: TypeStyle): LineHeight { 5 | switch (params.lineHeightUnit) { 6 | case "PIXELS": 7 | return { 8 | unit: "PIXELS", 9 | value: params.lineHeightPx, 10 | }; 11 | 12 | /** 13 | * README: https://www.figma.com/developers/api 14 | * issue: https://github.com/gridaco/designto-code/issues/27 - `line-height percentage calculation error` 15 | * Change the previously used `lineHeightPercent` to `lineHeightPercentFontSize` according to the description of the api document below. 16 | * "Line height as a percentage of normal line height. 17 | * This is deprecated; in a future version of the API only lineHeightPx and lineHeightPercentFontSize will be returned." 18 | */ 19 | case "FONT_SIZE_%": 20 | return { 21 | unit: "PERCENT", 22 | value: params.lineHeightPercentFontSize, 23 | }; 24 | case "INTRINSIC_%": 25 | return { 26 | unit: "AUTO", 27 | }; 28 | 29 | case undefined: 30 | return undefined; 31 | 32 | default: 33 | _warnNotHandled(params); 34 | // safely return fallback 35 | return { 36 | unit: "AUTO", 37 | }; 38 | } 39 | } 40 | 41 | function _warnNotHandled(params) { 42 | console.warn( 43 | `cannot perform "figmaRemoteLineHeightToFigma" with givven parameters. figma api version might have been updated. this cannot be thrown. check this.`, 44 | "the input param was", 45 | params 46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/stroke-cap.convert.ts: -------------------------------------------------------------------------------- 1 | import type { StrokeCap } from "@design-sdk/figma"; 2 | import type { VectorBase } from "@design-sdk/figma-remote-types"; 3 | 4 | /** 5 | * 6 | * from : ... 7 | * 8 | * to: https://www.figma.com/plugin-docs/api/StrokeCap/ 9 | */ 10 | export function convertFigmaRemoteStrokeCapToFigmaStrokeCap( 11 | remStrokeCap: VectorBase["strokeCap"] 12 | ): StrokeCap { 13 | switch (remStrokeCap) { 14 | case "NONE": 15 | return "NONE"; 16 | case "ROUND": 17 | return "ROUND"; 18 | case "SQUARE": 19 | return "SQUARE"; 20 | case "LINE_ARROW": 21 | return "ARROW_LINES"; 22 | case "TRIANGLE_ARROW": 23 | return "ARROW_EQUILATERAL"; 24 | default: 25 | return "NONE"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /figma-remote/lib/converters/strokes.convert.ts: -------------------------------------------------------------------------------- 1 | import { Paint as RemPaint } from "@design-sdk/figma-remote-types"; 2 | import { Paint } from "@design-sdk/figma-types"; 3 | import { figmaRemotePaintToFigma } from "./paint.convert"; 4 | 5 | export function convertFigmaRemoteStrokesToFigma( 6 | ...fills: RemPaint[] 7 | ): Paint[] { 8 | return fills.map((f) => figmaRemotePaintToFigma(f)); 9 | } 10 | -------------------------------------------------------------------------------- /figma-remote/lib/fetch/demo.ts: -------------------------------------------------------------------------------- 1 | import { default_set } from "./figma-default-set"; 2 | import type { AuthenticationCredential, FigmaRemoteImportPack } from "./types"; 3 | import * as api from "@design-sdk/figma-remote-api"; 4 | 5 | export async function fetchDemo( 6 | auth: AuthenticationCredential 7 | ): Promise { 8 | const _nid = default_set.FIGMA_BRIDGED_DEMO_APP_ENTRY_NODE_ID; 9 | const _fid = default_set.FIGMA_BRIDGED_DEMO_APP_FILE_ID; 10 | const client = api.Client({ 11 | ...auth, 12 | }); 13 | 14 | const nodesRes = await client.fileNodes(_fid, { 15 | ids: [_nid], 16 | geometry: "paths", 17 | }); 18 | 19 | const nodes = nodesRes.data.nodes; 20 | 21 | const demoEntryNode = nodes[_nid]; 22 | 23 | const d = demoEntryNode.document; 24 | return { 25 | file: _fid, 26 | node: _nid, 27 | remote: d, 28 | components: [], 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /figma-remote/lib/fetch/errors.ts: -------------------------------------------------------------------------------- 1 | export type FigmaRemoteErrors = UnauthorizedError | NotfoundError; 2 | 3 | export class UnauthorizedError extends Error { 4 | readonly status = 403; 5 | readonly type = "UnauthorizedError"; 6 | constructor(message: string) { 7 | super(message); 8 | this.name = "UnauthorizedError"; 9 | } 10 | } 11 | 12 | /** 13 | * This error is thrown when the token is expired. 14 | * 15 | * Example response: 16 | * ``` 17 | * { 18 | * "status": 403, 19 | * "err": "Token expired" 20 | * } 21 | * ``` 22 | */ 23 | export class TokenExpiredUnauthorizedError extends Error { 24 | readonly status = 403; 25 | readonly type = "403_token_expired"; 26 | constructor(message: string) { 27 | super(message); 28 | this.name = "403_token_expired"; 29 | } 30 | } 31 | 32 | export class NotfoundError extends Error { 33 | readonly status = 404; 34 | readonly type = "NotFound"; 35 | constructor(message: string) { 36 | super(message); 37 | this.name = "NotFoundError"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /figma-remote/lib/fetch/figma-default-set.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.figma.com/file/iypAHagtcSp3Osfo2a7EDz 3 | */ 4 | export const FIGMA_DEFAULT_FILE_ID = "iypAHagtcSp3Osfo2a7EDz"; 5 | 6 | /** 7 | * https://www.figma.com/file/iypAHagtcSp3Osfo2a7EDz/engine?node-id=1017%3A2740 8 | */ 9 | export const FIGMA_DEFAULT_FILE_ENTRY_NODE_ID = "1017:2740"; 10 | 11 | /** 12 | * https://www.figma.com/file/x7RRK6RwWtZuNakmbMLTVH 13 | */ 14 | export const FIGMA_BRIDGED_DEMO_APP_FILE_ID = "x7RRK6RwWtZuNakmbMLTVH"; 15 | 16 | /** 17 | * https://www.figma.com/file/x7RRK6RwWtZuNakmbMLTVH/examples?node-id=1%3A120 18 | */ 19 | export const FIGMA_BRIDGED_DEMO_APP_ENTRY_NODE_ID = "1:120"; 20 | 21 | export const default_set = { 22 | FIGMA_DEFAULT_FILE_ID, 23 | FIGMA_DEFAULT_FILE_ENTRY_NODE_ID, 24 | FIGMA_BRIDGED_DEMO_APP_FILE_ID, 25 | FIGMA_BRIDGED_DEMO_APP_ENTRY_NODE_ID, 26 | }; 27 | -------------------------------------------------------------------------------- /figma-remote/lib/fetch/types.ts: -------------------------------------------------------------------------------- 1 | import type { Node } from "@design-sdk/figma-remote-types"; 2 | import type { SceneNode } from "@design-sdk/figma-types"; 3 | import type { ReflectSceneNode } from "@design-sdk/figma-node"; 4 | import type { 5 | Component as RemoteComponentNode, 6 | Node as RemoteNode, 7 | } from "@design-sdk/figma-remote-types"; 8 | 9 | export interface AuthenticationCredential { 10 | /** access token returned from OAuth authentication */ 11 | readonly accessToken?: string; 12 | /** personal access token obtained from account settings */ 13 | readonly personalAccessToken?: string; 14 | } 15 | 16 | export interface FigmaRemoteImportPack { 17 | file: string; 18 | node: string; 19 | raw?: T; 20 | remote?: Node; 21 | figma?: SceneNode; 22 | reflect?: ReflectSceneNode; 23 | components?: FigmaRemoteImportPack[]; 24 | } 25 | 26 | export interface RawNodeResponse { 27 | file: string; 28 | components: { [key: string]: RemoteComponentNode }; 29 | ids: string[]; 30 | nodes: { [key: string]: RemoteNode }; 31 | } 32 | -------------------------------------------------------------------------------- /figma-remote/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * as types from "@design-sdk/figma-remote-types"; 2 | export * as mapper from "./mapper"; 3 | export { configure_auth_credentials } from "./configure-auth-credentials"; 4 | /* this will be removed ->> */ export * as fetch from "./fetch"; 5 | /* preserve this only ->> */ export * from "./fetch"; 6 | 7 | export * from "./asset-repository"; 8 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/boolean-operation.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Figma } from "@design-sdk/figma-types"; 2 | import { blendBaseNode } from "../blenders"; 3 | import { BooleanGroup } from "@design-sdk/figma-remote-types"; 4 | import { MappingBooleanOperationNode } from "./mapping-instance"; 5 | 6 | export function mapFigmaRemoteBooleanOperationToFigma( 7 | remBool: BooleanGroup, 8 | parent? 9 | ): Figma.BooleanOperationNode { 10 | const mapping: MappingBooleanOperationNode = {} as any; 11 | blendBaseNode({ 12 | target: mapping, 13 | source: remBool, 14 | parent, 15 | }); 16 | 17 | return { 18 | ...mapping, 19 | type: "BOOLEAN_OPERATION", 20 | booleanOperation: remBool.booleanOperation, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/component.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Figma } from "@design-sdk/figma-types"; 2 | import { Component, Frame } from "@design-sdk/figma-remote-types"; 3 | import { MappingComponentNode } from "./mapping-instance"; 4 | import { mapFigmaRemoteFrameToFigma } from "./frame.mapper"; 5 | 6 | export function mapFigmaRemoteComponentToFigma( 7 | remComponent: Component, 8 | parent? 9 | ): Figma.ComponentNode { 10 | const mapping: MappingComponentNode = {} as any; 11 | const frame = mapFigmaRemoteFrameToFigma( 12 | remComponent as any as Frame, 13 | parent 14 | ); 15 | 16 | return { 17 | ...mapping, 18 | // @ts-ignore 19 | ...(frame as Figma.ComponentNode), 20 | type: "COMPONENT", 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/ellipse.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Ellipse } from "@design-sdk/figma-remote-types"; 2 | import { EllipseNode } from "@design-sdk/figma-types"; 3 | import { MappingEllipseNode } from "./mapping-instance"; 4 | import { blendBaseNode, blendVectorNode } from "../blenders"; 5 | 6 | export function mapFigmaRemoteEllipseToFigma( 7 | remEllipse: Ellipse, 8 | parent? 9 | ): EllipseNode { 10 | const mapping: MappingEllipseNode = {} as any; 11 | 12 | blendBaseNode({ 13 | target: mapping, 14 | source: remEllipse, 15 | parent, 16 | }); 17 | 18 | blendVectorNode({ 19 | target: mapping, 20 | source: remEllipse, 21 | parent, 22 | }); 23 | 24 | // ellipse specific 25 | mapping.arcData = remEllipse.arcData ?? { 26 | startingAngle: 0, 27 | endingAngle: 0, 28 | innerRadius: 0, 29 | }; 30 | 31 | return { 32 | ...mapping, 33 | type: "ELLIPSE", 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/frame.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Figma } from "@design-sdk/figma-types"; 2 | import { 3 | blendBaseNode, 4 | blendCornerNode, 5 | blendRectangleCornerNode, 6 | } from "../blenders"; 7 | import { Frame } from "@design-sdk/figma-remote-types"; 8 | import { MappingFrameNode } from "./mapping-instance"; 9 | 10 | export function mapFigmaRemoteFrameToFigma( 11 | remFrame: Frame, 12 | parent? 13 | ): Figma.FrameNode { 14 | const mapping: MappingFrameNode = {} as any; 15 | blendBaseNode({ 16 | target: mapping, 17 | source: remFrame, 18 | parent, 19 | }); 20 | 21 | blendCornerNode({ 22 | target: mapping, 23 | source: remFrame, 24 | }); 25 | 26 | blendRectangleCornerNode({ 27 | target: mapping, 28 | source: remFrame, 29 | }); 30 | 31 | return { 32 | ...mapping, 33 | type: "FRAME", 34 | 35 | layoutMode: remFrame.layoutMode ?? "NONE", 36 | primaryAxisSizingMode: remFrame.primaryAxisSizingMode ?? "AUTO", 37 | counterAxisSizingMode: remFrame.counterAxisSizingMode ?? "AUTO", 38 | primaryAxisAlignItems: remFrame.primaryAxisAlignItems ?? "MIN", 39 | counterAxisAlignItems: remFrame.counterAxisAlignItems ?? "MIN", 40 | itemSpacing: remFrame.itemSpacing ?? 0, 41 | clipsContent: remFrame.clipsContent ?? false, 42 | paddingLeft: remFrame.paddingLeft ?? 0, 43 | paddingRight: remFrame.paddingRight ?? 0, 44 | paddingTop: remFrame.paddingTop ?? 0, 45 | paddingBottom: remFrame.paddingBottom ?? 0, 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/group.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Figma } from "@design-sdk/figma-types"; 2 | import { blendBaseNode } from "../blenders"; 3 | import { Group } from "@design-sdk/figma-remote-types"; 4 | import { MappingGroupNode } from "./mapping-instance"; 5 | 6 | export function mapFigmaRemoteGroupToFigma( 7 | remGroup: Group, 8 | parent? 9 | ): Figma.GroupNode { 10 | const mapping: MappingGroupNode = {} as any; 11 | blendBaseNode({ 12 | target: mapping, 13 | source: remGroup, 14 | parent, 15 | }); 16 | 17 | return { 18 | ...mapping, 19 | type: "GROUP", 20 | layoutAlign: remGroup.layoutAlign, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./mapper"; 2 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/instance.mapper.ts: -------------------------------------------------------------------------------- 1 | import type { Instance, Frame } from "@design-sdk/figma-remote-types"; 2 | import type { MappingInstanceNode } from "./mapping-instance"; 3 | import { Figma } from "@design-sdk/figma-types"; 4 | import { mapFigmaRemoteFrameToFigma } from "./frame.mapper"; 5 | 6 | export function mapFigmaRemoteInstanceToFigma( 7 | remInstance: Instance, 8 | parent? 9 | ): Figma.InstanceNode { 10 | const mapping: MappingInstanceNode = {} as any; 11 | 12 | const frame = mapFigmaRemoteFrameToFigma(remInstance as any as Frame, parent); 13 | 14 | return { 15 | ...mapping, 16 | // @ts-ignore 17 | ...(frame as Figma.InstanceNode), 18 | type: "INSTANCE", 19 | mainComponent: undefined, // TODO: support main component 20 | mainComponentId: remInstance.componentId, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/line.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Line } from "@design-sdk/figma-remote-types"; 2 | import { Figma } from "@design-sdk/figma-types"; 3 | import { MappingLineNode } from "./mapping-instance"; 4 | import { blendBaseNode, blendVectorNode } from "../blenders"; 5 | 6 | export function mapFigmaRemoteLineToFigma( 7 | remLine: Line, 8 | parent? 9 | ): Figma.LineNode { 10 | const mapping: MappingLineNode = {} as any; 11 | blendBaseNode({ 12 | target: mapping, 13 | source: remLine, 14 | parent, 15 | }); 16 | 17 | blendVectorNode({ 18 | target: mapping, 19 | source: remLine, 20 | parent, 21 | }); 22 | 23 | return { 24 | ...mapping, 25 | type: "LINE", 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/polygon.mapper.ts: -------------------------------------------------------------------------------- 1 | import { RegularPolygon } from "@design-sdk/figma-remote-types"; 2 | import { Figma } from "@design-sdk/figma-types"; 3 | import { MappingPolygonNode } from "./mapping-instance"; 4 | import { blendBaseNode, blendVectorNode } from "../blenders"; 5 | 6 | export function mapFigmaRemotePolygonToFigma( 7 | remPol: RegularPolygon, 8 | parent? 9 | ): Figma.PolygonNode { 10 | const mapping: MappingPolygonNode = {} as any; 11 | 12 | blendBaseNode({ 13 | target: mapping, 14 | source: remPol, 15 | parent, 16 | }); 17 | 18 | blendVectorNode({ 19 | target: mapping, 20 | source: remPol, 21 | parent, 22 | }); 23 | 24 | return { 25 | ...mapping, 26 | type: "POLYGON", 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/rectangle.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Rectangle } from "@design-sdk/figma-remote-types"; 2 | import { Figma } from "@design-sdk/figma-types"; 3 | import { MappingRectangleNode } from "./mapping-instance"; 4 | import { blendBaseNode } from "../blenders"; 5 | import { 6 | blendCornerNode, 7 | blendRectangleCornerNode, 8 | } from "../blenders/corner.blend"; 9 | export function mapFigmaRemoteRectangleToFigma( 10 | remRect: Rectangle, 11 | parent? 12 | ): Figma.RectangleNode { 13 | const mapping: MappingRectangleNode = {} as any; 14 | 15 | blendBaseNode({ 16 | target: mapping, 17 | source: remRect, 18 | parent, 19 | }); 20 | 21 | blendCornerNode({ 22 | target: mapping, 23 | source: remRect, 24 | }); 25 | 26 | blendRectangleCornerNode({ 27 | target: mapping, 28 | source: remRect, 29 | }); 30 | 31 | return { 32 | ...mapping, 33 | type: "RECTANGLE", 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/star.mapper.ts: -------------------------------------------------------------------------------- 1 | import { Star } from "@design-sdk/figma-remote-types"; 2 | import { Figma } from "@design-sdk/figma-types"; 3 | import { MAppingStarNode } from "./mapping-instance"; 4 | import { blendBaseNode, blendVectorNode } from "../blenders"; 5 | export function mapFigmaRemoteStarToFigma( 6 | remRect: Star, 7 | parent? 8 | ): Figma.StarNode { 9 | const mapping: MAppingStarNode = {} as any; 10 | blendBaseNode({ 11 | target: mapping, 12 | source: remRect, 13 | parent, 14 | }); 15 | 16 | blendVectorNode({ 17 | target: mapping, 18 | source: remRect, 19 | parent, 20 | }); 21 | 22 | return { 23 | ...mapping, 24 | type: "STAR", 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /figma-remote/lib/mapper/vector.mapper.ts: -------------------------------------------------------------------------------- 1 | import { VectorNode } from "@design-sdk/figma-types"; 2 | import { Vector } from "@design-sdk/figma-remote-types"; 3 | import { MappingVectorNode } from "./mapping-instance"; 4 | import { blendBaseNode } from "../blenders"; 5 | import { blendVectorNode } from "../blenders/vector.blend"; 6 | 7 | export function mapFigmaRemoteVectorToFigma( 8 | remRect: Vector, 9 | parent? 10 | ): VectorNode { 11 | const mapping: MappingVectorNode = {} as any; 12 | 13 | blendBaseNode({ 14 | target: mapping, 15 | source: remRect, 16 | parent, 17 | }); 18 | 19 | blendVectorNode({ 20 | target: mapping, 21 | source: remRect, 22 | parent, 23 | }); 24 | 25 | // this is only available via plugin api 26 | // learn more at https://www.figma.com/plugin-docs/api/VectorNetwork/ 27 | mapping.vectorNetwork = undefined; 28 | mapping.handleMirroring = "NONE"; 29 | 30 | return { 31 | ...mapping, 32 | type: "VECTOR", 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /figma-remote/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-remote", 3 | "version": "0.0.53", 4 | "private": false, 5 | "description": "Figma remote api & formats", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "homepage": "https://github.com/gridaco/design-sdk", 10 | "repository": "https://github.com/gridaco/design-sdk", 11 | "scripts": { 12 | "clean": "rimraf dist", 13 | "build": "tsc", 14 | "test": "jest" 15 | }, 16 | "exports": { 17 | ".": "./dist/index.js", 18 | "./asset-repository": "./dist/asset-repository/index.js" 19 | }, 20 | "typesVersions": { 21 | "*": { 22 | ".": [ 23 | "dist/index.d.ts" 24 | ], 25 | "asset-repository": [ 26 | "dist/asset-repository/index.d.ts" 27 | ] 28 | } 29 | }, 30 | "dependencies": { 31 | "@design-sdk/asset-repository": "^0.0.53", 32 | "@design-sdk/figma-node": "^0.0.53", 33 | "@design-sdk/figma-node-conversion": "^0.0.53", 34 | "@design-sdk/figma-remote-api": "^0.0.53", 35 | "@design-sdk/figma-utils": "^0.0.53" 36 | }, 37 | "devDependencies": { 38 | "@design-sdk/figma-remote-types": "^0.0.53", 39 | "typescript": "^4.3.5" 40 | }, 41 | "files": [ 42 | "dist/index.js", 43 | "dist/index.d.ts", 44 | "dist/**/*.js", 45 | "dist/**/*.d.ts", 46 | "README", 47 | "LICENSE" 48 | ], 49 | "publishConfig": { 50 | "access": "public" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /figma-remote/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "./lib", 5 | "outDir": "./dist" 6 | }, 7 | "include": ["lib", "__test__/fecth.test.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-types/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /figma-types/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gridaco/figma-sdk/5784ab284f17fcb2b20bc821fc140fd004964d7e/figma-types/README.md -------------------------------------------------------------------------------- /figma-types/__test__/README.md: -------------------------------------------------------------------------------- 1 | # Figma Remote API & Formatting Tests 2 | -------------------------------------------------------------------------------- /figma-types/__test__/main.test.ts: -------------------------------------------------------------------------------- 1 | // TODO: add test script to compare typings with @figma/types 2 | 3 | // dummy test 4 | test("dummy test", () => { 5 | expect(true).toBe(true); 6 | }); 7 | -------------------------------------------------------------------------------- /figma-types/lib/boolean-operation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.figma.com/plugin-docs/api/BooleanOperationNode/#booleanoperation 3 | */ 4 | export type FigmaBooleanOpeartionType = 5 | | "UNION" 6 | | "INTERSECT" 7 | | "SUBTRACT" 8 | | "EXCLUDE"; 9 | -------------------------------------------------------------------------------- /figma-types/lib/color.ts: -------------------------------------------------------------------------------- 1 | 2 | export type FigmaColor = FigmaRGBA | FigmaRGB 3 | 4 | export enum FigmaColorFormat { 5 | rgb = 'figma.rgb', 6 | rgba = 'figma.rgba' 7 | } 8 | 9 | /** 10 | * figma rgb format. the r,g,b channels' value is devided by 255. the max value is 1. min is 0. 11 | */ 12 | export interface FigmaRGB { 13 | r: number 14 | g: number 15 | b: number 16 | } 17 | 18 | /** 19 | * figma rgb, alpha channel extended. 20 | */ 21 | export interface FigmaRGBA { 22 | r: number 23 | g: number 24 | b: number 25 | a: number 26 | } -------------------------------------------------------------------------------- /figma-types/lib/corner-radius.ts: -------------------------------------------------------------------------------- 1 | export interface FigmaCornerRadius { 2 | // @deprecated 3 | // import { mixed } from "@design-sdk/core"; 4 | // cornerRadius: number | typeof mixed; 5 | topLeftRadius: number; 6 | topRightRadius: number; 7 | bottomLeftRadius: number; 8 | bottomRightRadius: number; 9 | } 10 | -------------------------------------------------------------------------------- /figma-types/lib/counter-axis-align-items.ts: -------------------------------------------------------------------------------- 1 | export type FigmaMainAxisAlignment = "MIN" | "MAX" | "CENTER" | "SPACE_BETWEEN"; 2 | -------------------------------------------------------------------------------- /figma-types/lib/counter-axis-sizing-mode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.figma.com/plugin-docs/api/properties/nodes-counteraxissizingmode 3 | */ 4 | export type FigmaCounterAxisSizingMode = "FIXED" | "AUTO"; 5 | -------------------------------------------------------------------------------- /figma-types/lib/figma-node-action-navigation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.figma.com/plugin-docs/api/Action/#node-action 3 | */ 4 | export type FigmaNodeActionNavigation = 5 | /** 6 | * Replaces the current screen with the destination, also closing all overlays 7 | */ 8 | | "NAVIGATE" 9 | /** 10 | * Opens the destination as an overlay on the current screen. 11 | */ 12 | | "OVERLAY" 13 | /** 14 | * On an overlay, replaces the current (topmost) overlay with the destination. On a top-level frame, behaves the same as "NAVIGATE" except that no entry is added to the navigation history. 15 | */ 16 | | "SWAP" 17 | /** 18 | * Scrolls to the destination on the current screen. 19 | */ 20 | | "SCROLL_TO" 21 | /** 22 | * Changes the closest ancestor instance of source node to the specified variant. 23 | */ 24 | | "CHANGE_TO"; 25 | -------------------------------------------------------------------------------- /figma-types/lib/figma-reaction-action.ts: -------------------------------------------------------------------------------- 1 | import type { FigmaReactionNodeAction } from "./figma-reaction-node-action"; 2 | import type { FigmaReactionPopAction } from "./figma-reaction-pop-action"; 3 | import type { FigmaReactionUrlAction } from "./figma-reaction-url-action"; 4 | 5 | export type FigmaReactionAction = 6 | | FigmaReactionPopAction 7 | | FigmaReactionUrlAction 8 | | FigmaReactionNodeAction; 9 | -------------------------------------------------------------------------------- /figma-types/lib/figma-reaction-node-action.ts: -------------------------------------------------------------------------------- 1 | import { FigmaNodeActionNavigation } from "./figma-node-action-navigation"; 2 | 3 | /* figma types for transition is not ready. using native type instead. */ import type { Transition } from "./v1"; 4 | 5 | export type FigmaReactionNodeAction = { 6 | readonly type: "NODE"; 7 | readonly destinationId: string | null; 8 | readonly navigation: FigmaNodeActionNavigation; 9 | readonly transition: Transition | null; 10 | readonly preserveScrollPosition: boolean; 11 | 12 | /** 13 | * Only present if navigation == "OVERLAY" and the destination uses 14 | * overlay position export type "RELATIVE" 15 | */ 16 | readonly overlayRelativePosition?: { x: number; y: number }; 17 | }; 18 | -------------------------------------------------------------------------------- /figma-types/lib/figma-reaction-pop-action.ts: -------------------------------------------------------------------------------- 1 | export type FigmaReactionPopAction = { readonly type: "BACK" | "CLOSE" }; 2 | -------------------------------------------------------------------------------- /figma-types/lib/figma-reaction-url-action.ts: -------------------------------------------------------------------------------- 1 | export type FigmaReactionUrlAction = { readonly type: "URL"; url: string }; 2 | -------------------------------------------------------------------------------- /figma-types/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./boolean-operation"; 2 | export * from "./color"; 3 | export * from "./corner-radius"; 4 | export * from "./counter-axis-align-items"; 5 | export * from "./counter-axis-sizing-mode"; 6 | export * from "./layout-align"; 7 | export * from "./layout-mode"; 8 | export * from "./layout-grow"; 9 | export * from "./primary-axis-align-items"; 10 | export * from "./primary-axis-sizing-mode"; 11 | export * from "./text-alignment"; 12 | export * from "./text-auto-resize"; 13 | export * from "./text-decoration"; 14 | 15 | // figma actions 16 | export * from "./figma-node-action-navigation"; 17 | export * from "./figma-reaction-action"; 18 | export * from "./figma-reaction-node-action"; 19 | export * from "./figma-reaction-pop-action"; 20 | export * from "./figma-reaction-url-action"; 21 | // figma actions 22 | 23 | // plugin typings 24 | export * as v1 from "./v1"; 25 | // default v1 export 26 | export * from "./v1"; 27 | export * as Figma from "./v1"; 28 | -------------------------------------------------------------------------------- /figma-types/lib/layout-align.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * [Figma#LayoutAlign](https://www.figma.com/plugin-docs/api/properties/nodes-layoutalign/) 3 | * Changing this property will cause the x, y, size, and relativeTransform properties on this node to change, if applicable (inside an auto-layout frame). 4 | * 5 | * Setting "STRETCH" will make the node "stretch" to fill the width of the parent vertical auto-layout frame, or the height of the parent horizontal auto-layout frame excluding the frame's padding. 6 | * If the current node is an auto layout frame (e.g. an auto layout frame inside a parent auto layout frame) if you set layoutAlign to “STRETCH” you should set the corresponding axis – either primaryAxisSizingMode or counterAxisSizingMode – to be“FIXED”. This is because an auto-layout frame cannot simultaneously stretch to fill its parent and shrink to hug its children. 7 | * Setting "INHERIT" does not "stretch" the node. 8 | * 9 | * - applicable only inside auto-layout frames 10 | * 11 | * > ⚠️ Previously, layoutAlign also determined counter axis alignment of auto-layout frame children. Counter axis alignment is now set on the auto-layout frame itself through counterAxisAlignItems. Note that this means all layers in an auto-layout frame must now have the same counter axis alignment. This means "MIN", "CENTER", and "MAX" are now deprecated values of layoutAlign. 12 | */ 13 | export type FigmaLayoutAlign = "STRETCH" | "INHERIT"; 14 | -------------------------------------------------------------------------------- /figma-types/lib/layout-grow.ts: -------------------------------------------------------------------------------- 1 | export type FigmaLayoutGrow = 0 | 1; 2 | -------------------------------------------------------------------------------- /figma-types/lib/layout-mode.ts: -------------------------------------------------------------------------------- 1 | export type FigmaLayoutMode = "NONE" | "HORIZONTAL" | "VERTICAL" -------------------------------------------------------------------------------- /figma-types/lib/primary-axis-align-items.ts: -------------------------------------------------------------------------------- 1 | export type FigmaCrossAxisAligment = "MIN" | "MAX" | "CENTER" 2 | -------------------------------------------------------------------------------- /figma-types/lib/primary-axis-sizing-mode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * https://www.figma.com/plugin-docs/api/properties/nodes-primaryaxissizingmode 3 | */ 4 | export type FigmaPrimaryAxisSizingMode = "FIXED" | "AUTO"; 5 | -------------------------------------------------------------------------------- /figma-types/lib/text-alignment.ts: -------------------------------------------------------------------------------- 1 | export type FigmaTextHorizontalAligment = 2 | | "LEFT" 3 | | "CENTER" 4 | | "RIGHT" 5 | | "JUSTIFIED"; 6 | export type FigmaTextVerticalAligment = "TOP" | "CENTER" | "BOTTOM"; 7 | -------------------------------------------------------------------------------- /figma-types/lib/text-auto-resize.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * [Figma#TextAutoResize](https://www.figma.com/plugin-docs/api/properties/TextNode-textautoresize/) 3 | */ 4 | export type TextAutoResize = 5 | /** 6 | * The size of the textbox is fixed and is independent of its content. 7 | * 8 | * e.g. css `overflow: visible;` - which will fix the size without scrolling or resizing, yet visible. 9 | * 10 | * Means: Fixed width, fixed height 11 | */ 12 | | "NONE" 13 | /** 14 | * The width of the textbox is fixed. Characters wrap to fit in the textbox. The height of the textbox automatically adjusts to fit its content. 15 | * 16 | * Means: Fixed width, auto height 17 | */ 18 | | "HEIGHT" 19 | /** 20 | * Both the width and height of the textbox automatically adjusts to fit its content. Characters do not wrap. 21 | * 22 | * Means: Auto width, auto height based on the text content 23 | * This can't be used with flex. when using autolayout & making the text to fill-width, the text will be wrapped and change the type to "HEIGHT" 24 | */ 25 | | "WIDTH_AND_HEIGHT"; 26 | -------------------------------------------------------------------------------- /figma-types/lib/text-decoration.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Figma text decoration 3 | */ 4 | export type FigmaTextDecoration = "NONE" | "UNDERLINE" | "STRIKETHROUGH"; 5 | -------------------------------------------------------------------------------- /figma-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-types", 3 | "version": "0.0.53", 4 | "description": "Figma remote api & formats", 5 | "license": "MIT", 6 | "private": false, 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "homepage": "https://github.com/gridaco/design-sdk", 10 | "repository": "https://github.com/gridaco/design-sdk", 11 | "scripts": { 12 | "clean": "rimraf dist", 13 | "build": "tsc", 14 | "test": "jest" 15 | }, 16 | "files": [ 17 | "dist", 18 | "README.md", 19 | "LICENSE" 20 | ], 21 | "publishConfig": { 22 | "access": "public" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /figma-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["./lib"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-url/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Grida 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /figma-url/__test__/analyze.test.ts: -------------------------------------------------------------------------------- 1 | import { analyze, FigmaUrlType } from "../lib"; 2 | 3 | test("analyze url - full url with node id", () => { 4 | const _url = 5 | "https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49"; 6 | expect(analyze(_url)) 7 | // 8 | .toBe(FigmaUrlType.node); 9 | }); 10 | 11 | test("analyze url - url with only file id", () => { 12 | const _url = "https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/"; 13 | expect(analyze(_url)) 14 | // 15 | .toBe(FigmaUrlType.file); 16 | }); 17 | 18 | test("analyze url - valid embedding url", () => { 19 | const _url = 20 | "https://www.figma.com/embed?embed_host=astra&url=https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49"; 21 | expect(analyze(_url)) 22 | // 23 | .toBe(FigmaUrlType.embed); 24 | }); 25 | 26 | test("analyze url - invalid embedding url (only inspecting structure)", () => { 27 | const _url = // this is not embeddable 'case of missing "www." 28 | "https://figma.com/embed?embed_host=astra&url=https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49"; 29 | expect(() => { 30 | analyze(_url); 31 | }) 32 | // 33 | .toThrow("not a valid figma url."); 34 | }); 35 | 36 | test("analyze url - empty embedding url", () => { 37 | const _url = undefined; // this is not embeddable 'case of missing "www." 38 | expect(analyze(_url as any as string)) 39 | // 40 | .toBe(FigmaUrlType.empty); 41 | }); 42 | -------------------------------------------------------------------------------- /figma-url/__test__/embed.test.ts: -------------------------------------------------------------------------------- 1 | import { embed } from "../lib"; 2 | 3 | test("build embed url", () => { 4 | const _url = 5 | "https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49"; 6 | expect(embed(_url)).toBe( 7 | "https://www.figma.com/embed?embed_host=astra&url=https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49" 8 | ); 9 | }); 10 | 11 | test("build embed url with file & node id", () => { 12 | expect(embed({ fileid: "Y0Gh77AqBoHH7dG1GtK3xF", nodeid: "264%3A49" })).toBe( 13 | "https://www.figma.com/embed?embed_host=astra&url=https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49" 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /figma-url/__test__/parse.test.ts: -------------------------------------------------------------------------------- 1 | import { parseFileAndNodeId, parseFileId } from "../lib/parse-url"; 2 | import { 3 | __FIGMA_DEMO_DEFAULT_FILE_ID, 4 | __FIGMA_DEMO_DEFAULT_FILE_URL, 5 | __FIGMA_DEMO_DEFAULT_FILE_NODE_URL, 6 | } from "../lib"; 7 | 8 | test("parse fileid from url", () => { 9 | expect(parseFileId(__FIGMA_DEMO_DEFAULT_FILE_URL)).toBe( 10 | __FIGMA_DEMO_DEFAULT_FILE_ID 11 | ); 12 | }); 13 | 14 | test("parse nodeid and fileid from url v1 (old figma url via copy link / plain)", () => { 15 | const url = 16 | "https://www.figma.com/file/Gaznaw1QHppxvs9UkqNOb0/grida.co?node-id=5683:31451&t=ttMsIZRdkBv78VUQ-0"; 17 | expect(parseFileAndNodeId(url)).toEqual({ 18 | file: "Gaznaw1QHppxvs9UkqNOb0", 19 | node: "5683:31451", 20 | url, 21 | }); 22 | }); 23 | 24 | test("parse nodeid and fileid from url v1 (old figma url via copy link / url encoded)", () => { 25 | const url = 26 | "https://www.figma.com/file/Gaznaw1QHppxvs9UkqNOb0/grida.co?node-id=5683%3A31451&t=ttMsIZRdkBv78VUQ-0"; 27 | expect(parseFileAndNodeId(url)).toEqual({ 28 | file: "Gaznaw1QHppxvs9UkqNOb0", 29 | node: "5683:31451", 30 | url, 31 | }); 32 | }); 33 | 34 | test("parse nodeid and fileid from url v2 (updated figma url via copy link)", () => { 35 | const url = 36 | "https://www.figma.com/file/Gaznaw1QHppxvs9UkqNOb0/grida.co?node-id=5683-31451&t=ttMsIZRdkBv78VUQ-0"; 37 | expect(parseFileAndNodeId(url)).toEqual({ 38 | file: "Gaznaw1QHppxvs9UkqNOb0", 39 | node: "5683:31451", 40 | url, 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /figma-url/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 6 | testPathIgnorePatterns: ["/lib/", "/node_modules/"], 7 | moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], 8 | collectCoverage: true, 9 | }; 10 | -------------------------------------------------------------------------------- /figma-url/lib/access-check.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// simple functions to check if file is accessible by public. 3 | /// 4 | 5 | import { analyze, FigmaUrlType } from "./analyze-url"; 6 | 7 | /** 8 | * e.g. 9 | * 10 | * - **ok**: (public file) - https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/grida?node-id=1545%3A247 11 | * - **not found**: (private file) - https://www.figma.com/file/8R57Uv5Siu1ZhhGkVIyyQg/private-file-api-demo?node-id=2%3A2 12 | * 13 | */ 14 | export async function isPublic(url: string): Promise { 15 | const type = analyze(url); 16 | if (type == FigmaUrlType.embed || FigmaUrlType.file || FigmaUrlType.node) { 17 | try { 18 | const res = await fetch(url); 19 | return res.status == 200; 20 | } catch (e) { 21 | return false; 22 | } 23 | } 24 | return false; 25 | } 26 | -------------------------------------------------------------------------------- /figma-url/lib/compare-url.ts: -------------------------------------------------------------------------------- 1 | import { analyze, FigmaUrlType } from "./analyze-url"; 2 | import { parseFileAndNodeId } from "./parse-url"; 3 | 4 | export function isSameDesignUrl(url1: string, url2: string): boolean { 5 | const analysis = analyze(url1); 6 | switch (analysis) { 7 | case FigmaUrlType.embed: 8 | case FigmaUrlType.empty: 9 | case FigmaUrlType.file: 10 | return false; 11 | case FigmaUrlType.node: 12 | const parsed = parseFileAndNodeId(url1); 13 | const _this_parsed = parseFileAndNodeId(url2); 14 | return ( 15 | _this_parsed.file === parsed.file && _this_parsed.node === parsed.node 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /figma-url/lib/constants.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * e.g. full url should look like - 3 | * https://www.figma.com/embed?embed_host=astra&url=https://www.figma.com/file/HSozKEVWhh8saZa2vr1Nxd?node-id=111%3A0 4 | * 5 | * ref: https://www.figma.com/developers/embed 6 | */ 7 | export const _FIGMA_EMBED_URL_PREFIX = "https://www.figma.com/embed"; 8 | 9 | /** 10 | * e.g. full url should look like - 11 | * https://www.figma.com/file/HSozKEVWhh8saZa2vr1Nxd?node-id=111%3A0 12 | */ 13 | export const _FIGMA_FILE_URL_PREFIX = "https://www.figma.com/file"; 14 | 15 | /** 16 | * param key for node id specification. 17 | * 18 | * e.g. - `https://www.figma.com/file/ABC/?node-id=1234` `(node-id = 1234)` 19 | */ 20 | export const _PARAM_NODE_ID = "node-id"; 21 | 22 | // ====================================================================================================== 23 | // escape with __ for "super-internal" usage 24 | /** 25 | * file id of Grida design - https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/ 26 | */ 27 | export const __FIGMA_DEMO_DEFAULT_FILE_ID = "Y0Gh77AqBoHH7dG1GtK3xF"; 28 | export const __FIGMA_DEMO_DEFAULT_FILE_URL = 29 | "https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/"; 30 | export const __FIGMA_DEMO_DEFAULT_FILE_NODE_URL = 31 | "https://www.figma.com/file/Y0Gh77AqBoHH7dG1GtK3xF/?node-id=264%3A49"; 32 | // ====================================================================================================== 33 | -------------------------------------------------------------------------------- /figma-url/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./embed-url"; 2 | export * from "./parse-url"; 3 | export * from "./access-check"; 4 | export * from "./analyze-url"; 5 | export * from "./target-node-config"; 6 | export * from "./constants"; 7 | export * from "./compare-url"; 8 | -------------------------------------------------------------------------------- /figma-url/lib/target-node-config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * target node configuration for figma node that contains all fileid, nodeid and the figma url of the target. 3 | */ 4 | export interface FigmaTargetNodeConfig { 5 | /** 6 | * url of target node originated from figma 7 | */ 8 | url: string; 9 | /** 10 | * id of the file originated from figma 11 | */ 12 | file: string; 13 | /** 14 | * id of the node originated from figma 15 | */ 16 | node: string; 17 | } 18 | -------------------------------------------------------------------------------- /figma-url/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-url", 3 | "version": "0.0.53", 4 | "description": "Figma url utils for sharing & embeding and url inspection", 5 | "license": "MIT", 6 | "private": false, 7 | "main": "dist/index.js", 8 | "types": "dist/index.d.ts", 9 | "homepage": "https://github.com/gridaco/design-sdk", 10 | "repository": "https://github.com/gridaco/design-sdk", 11 | "authors": [ 12 | "grida.co", 13 | "softmarshmallow " 14 | ], 15 | "scripts": { 16 | "clean": "rimraf dist", 17 | "build": "tsc", 18 | "test": "jest" 19 | }, 20 | "files": [ 21 | "dist", 22 | "README", 23 | "LICENSE" 24 | ], 25 | "publishConfig": { 26 | "access": "public" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /figma-url/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["lib/**/*.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-utils/README.md: -------------------------------------------------------------------------------- 1 | # `@design-sdk/figma-utils` 2 | -------------------------------------------------------------------------------- /figma-utils/lib/check-if-auto-layout.ts: -------------------------------------------------------------------------------- 1 | import type { Axis } from "@reflect-ui/core"; 2 | export function checkIfAutoLayout(node: { 3 | layoutMode?: Axis | "NONE" | "HORIZONTAL" | "VERTICAL"; 4 | }): boolean { 5 | return checkWithProps({ 6 | layoutMode: node.layoutMode, 7 | }); 8 | } 9 | 10 | // FIXME ? 11 | // This part needs to be fixed. this may not be a correct way to detemine autolayout. -> this.layoutMode !== undefined 12 | function checkWithProps(props: { layoutMode }): boolean { 13 | return props.layoutMode !== undefined; 14 | } 15 | -------------------------------------------------------------------------------- /figma-utils/lib/check-if-root.ts: -------------------------------------------------------------------------------- 1 | import type { SceneNode } from "@design-sdk/figma-types"; 2 | 3 | /** 4 | * returns if giveen node is a root node. 5 | * @param node 6 | */ 7 | export function checkIfRoot(node: SceneNode) { 8 | // if no parent is provided, it means it is from api or manually generated data, and it is okay to be considered as root. 9 | // but we need caution to this logic. (WARNING) 10 | if (!node.parent) { 11 | return true; 12 | } 13 | if (node.parent.type == "PAGE") { 14 | return true; 15 | } 16 | return false; 17 | } 18 | -------------------------------------------------------------------------------- /figma-utils/lib/filter-fills.ts: -------------------------------------------------------------------------------- 1 | import type { Paint } from "@design-sdk/figma-types"; 2 | 3 | export function filterFills( 4 | fills: ReadonlyArray, 5 | options?: { 6 | visibleOnly?: boolean; 7 | } 8 | ): ReadonlyArray { 9 | return fills.filter((f) => { 10 | // 1. visible filter 11 | if (options?.visibleOnly) { 12 | if (!f.visible && f.opacity > 0) { 13 | return false; 14 | } 15 | } 16 | // if all filter passed, return true 17 | return true; 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /figma-utils/lib/has-image.ts: -------------------------------------------------------------------------------- 1 | import type { Paint } from "@design-sdk/figma-types"; 2 | 3 | /** 4 | * check if rect, elipes, or frame contains image based on its fills. 5 | * @param fills 6 | */ 7 | export function hasImage(fills: ReadonlyArray): boolean { 8 | if (Array.isArray(fills)) { 9 | return fills.some((el) => { 10 | return isImage(el); 11 | }); 12 | } 13 | return false; 14 | } 15 | 16 | /** 17 | * returns true if fill is visible and type of image. if fill is invisible, always returns false 18 | * @param fill 19 | */ 20 | export function isImage(fill: Paint) { 21 | return fill.visible && fill.type === "IMAGE"; 22 | } 23 | -------------------------------------------------------------------------------- /figma-utils/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./check-if-auto-layout"; 2 | export * from "./check-if-root"; 3 | export * from "./children"; 4 | export * from "./filter-fills"; 5 | export * from "./has-image"; 6 | export * from "./lcrs"; 7 | export * from "./paint-to-color"; 8 | export * from "./primary-color"; 9 | export * from "./retrieve-fill"; 10 | export * from "./retrieve-image-fills"; 11 | -------------------------------------------------------------------------------- /figma-utils/lib/paint-to-color.ts: -------------------------------------------------------------------------------- 1 | import type { SolidPaint } from "@design-sdk/figma-types"; 2 | import type { Color } from "@reflect-ui/core"; 3 | 4 | export function paintToColor(paint: SolidPaint): Color { 5 | return ( 6 | paint && { 7 | r: paint.color.r, 8 | g: paint.color.g, 9 | b: paint.color.b, 10 | a: paint.opacity, 11 | } 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /figma-utils/lib/primary-color.ts: -------------------------------------------------------------------------------- 1 | import { retrieveFill } from "./retrieve-fill"; 2 | import type { SolidPaint, Paint } from "@design-sdk/figma-types"; 3 | import type { RGBAF } from "@reflect-ui/core"; 4 | 5 | export function retrievePrimaryColor(fills: ReadonlyArray): RGBAF { 6 | const solid = retrieveFill(fills, { 7 | onlySolid: true, 8 | }); 9 | if (solid) { 10 | return { 11 | r: solid.color.r, 12 | g: solid.color.g, 13 | b: solid.color.b, 14 | a: solid.opacity, 15 | }; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /figma-utils/lib/retrieve-fill.ts: -------------------------------------------------------------------------------- 1 | import type { Paint } from "@design-sdk/figma-types"; 2 | 3 | /** 4 | * Retrieve the first visible color that is being used by the layer, in case there are more than one. 5 | */ 6 | export function retrieveFill( 7 | fills: ReadonlyArray | Paint, 8 | options?: { 9 | onlySolid?: boolean; 10 | } 11 | ): T | undefined { 12 | if (Array.isArray(fills)) { 13 | const filter = (f: Paint): boolean => { 14 | if (options?.onlySolid) { 15 | if (f.type !== "SOLID") { 16 | return false; 17 | } 18 | } 19 | return f.visible !== false; 20 | }; 21 | 22 | if (fills.length > 0) { 23 | // on Figma, the top layer is always at the last position 24 | // reverse, then try to find the first layer that is visible, if any. 25 | return [...fills].reverse().find(filter) as T; 26 | } 27 | } else { 28 | if (fills) { 29 | return fills as T; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /figma-utils/lib/retrieve-image-fills.ts: -------------------------------------------------------------------------------- 1 | import type { ImagePaint, Paint } from "@design-sdk/figma-types"; 2 | import { isImage } from "./has-image"; 3 | 4 | export function retrieveImageFills( 5 | fills: ReadonlyArray 6 | ): Array { 7 | const imagefills: Array = []; 8 | if (Array.isArray(fills)) { 9 | const imagePaints: Array = fills; 10 | for (const fill of imagePaints) { 11 | if (isImage(fill)) { 12 | imagefills.push(fill); 13 | } 14 | } 15 | } 16 | return imagefills; 17 | } 18 | 19 | export function retrievePrimaryImageFill( 20 | fills: ReadonlyArray 21 | ): ImagePaint { 22 | const images = retrieveImageFills(fills); 23 | if (images && images.length > 0) { 24 | return images[0]; 25 | } else { 26 | throw `no image available in fills`; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /figma-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-utils", 3 | "version": "0.0.53", 4 | "description": "Figma node utilities", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "README.md", 11 | "LICENSE" 12 | ], 13 | "scripts": { 14 | "clean": "rimraf dist", 15 | "build": "tsc" 16 | }, 17 | "devDependencies": { 18 | "@design-sdk/figma-types": "^0.0.53", 19 | "@reflect-ui/core": "^0.0.5" 20 | }, 21 | "publishConfig": { 22 | "access": "public" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /figma-utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["./lib"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma-xpath/README.md: -------------------------------------------------------------------------------- 1 | # Xpath for figma design 2 | 3 | ## Light mode - for navigating only (no property parsing) 4 | 5 | For most cases, xpath on design is used for locating same child on main component, etc.. in this navigating scenario, we only need fraction of xpath's feature, optimized for design format. Light mode xpath is not a real xpath, it only mocks the navigating with similar & limited syntax. + query builder provided. 6 | 7 | ## Full mode - using real xpath (expensive) 8 | 9 | Full mode first converts design to xml string, then runs the same full xpath on it. this is slightly expensive. 10 | 11 | ## JSONPath 12 | 13 | (planned) also supports path finding with json path 14 | 15 | - https://github.com/JSONPath-Plus/JSONPath 16 | -------------------------------------------------------------------------------- /figma-xpath/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./index-path"; 2 | -------------------------------------------------------------------------------- /figma-xpath/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma-xpath", 3 | "version": "0.0.53", 4 | "private": false, 5 | "license": "MIT", 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "clean": "rimraf dist", 10 | "build": "tsc", 11 | "prepack": "yarn clean && yarn build" 12 | }, 13 | "authors": [ 14 | "grida.co", 15 | "softmarshmallow " 16 | ], 17 | "devDependencies": { 18 | "@design-sdk/figma-node": "^0.0.53" 19 | }, 20 | "files": [ 21 | "dist", 22 | "README", 23 | "LICENSE" 24 | ], 25 | "publishConfig": { 26 | "access": "public" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /figma-xpath/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["lib/**/*.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /figma/README.md: -------------------------------------------------------------------------------- 1 | # Design SDK For Figma Desktop and Figma Api 2 | -------------------------------------------------------------------------------- /figma/asset-repository/image-repository/index.ts: -------------------------------------------------------------------------------- 1 | import { BaseImageRepositories } from "@design-sdk/asset-repository"; 2 | import { plugin } from "../../"; 3 | 4 | export class ImageRepositories extends BaseImageRepositories { 5 | async fetchDataById( 6 | id: string, 7 | config?: { 8 | type: "original"; 9 | } 10 | ): Promise { 11 | const node = plugin.getNodeById(id); 12 | if (node.type == "DOCUMENT") { 13 | return; 14 | } else { 15 | if (config?.type == "original") { 16 | return await node.exportAsync({ 17 | format: "PNG", 18 | // no constraints 19 | }); 20 | } 21 | return await node.exportAsync({ 22 | format: "PNG", 23 | constraint: { 24 | value: 300, 25 | type: "WIDTH", 26 | }, 27 | }); 28 | } 29 | } 30 | 31 | async _fetchDataByHash(hash: string): Promise { 32 | const image = plugin.getImageByHash(hash); 33 | return image.getBytesAsync(); 34 | } 35 | 36 | fetchAll(...id: string[]): Promise { 37 | throw new Error("Method not implemented."); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /figma/asset-repository/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./image-repository"; 2 | -------------------------------------------------------------------------------- /figma/features/index.ts: -------------------------------------------------------------------------------- 1 | export * as variant from "./variant"; 2 | -------------------------------------------------------------------------------- /figma/features/variant/README.md: -------------------------------------------------------------------------------- 1 | # Variant related utils 2 | 3 | > the general design is followed by figma's variant policy (which is so poor) 4 | 5 | ## The bridged variant policy. 6 | 7 | > variant utils for Bridged or Nothing.app will be implemented on other directory. currently none available (PRs are welcome) 8 | -------------------------------------------------------------------------------- /figma/features/variant/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./swap-instance"; 2 | export * from "./variant-name-utils"; 3 | export * from "./variant-property-type"; 4 | export * from "./variant-property-parser"; 5 | -------------------------------------------------------------------------------- /figma/features/variant/variant-property-type.ts: -------------------------------------------------------------------------------- 1 | export type FigmaEnum = { 2 | type: "enum"; 3 | values: string[]; 4 | }; 5 | 6 | export type FigmaUnique = { 7 | type: "unique"; 8 | value: string; 9 | }; 10 | 11 | export const FigmaNumber = Symbol("figma/variant-type/number"); 12 | export const FigmaBoolean = Symbol("figma/variant-type/boolean"); 13 | 14 | export type FigmaVariantPropertyCompatType = 15 | | FigmaEnum 16 | | FigmaUnique 17 | | typeof FigmaNumber 18 | | typeof FigmaBoolean; 19 | 20 | export function _FigmaVariantPropertyCompatType_to_string( 21 | t: FigmaVariantPropertyCompatType 22 | ) { 23 | if (t == FigmaNumber) { 24 | return "number"; 25 | } else if (t == FigmaBoolean) { 26 | return "boolean"; 27 | } else if (t.type == "unique") { 28 | return "unique"; 29 | } else if (t.type == "enum") { 30 | return "enum"; 31 | } 32 | } 33 | 34 | /** e.g. on=true is key=on & type=boolean with defaultValue=true*/ 35 | export interface VariantProperty { 36 | key: string; 37 | type: FigmaVariantPropertyCompatType; 38 | defaultValue?: string; 39 | nullable: boolean; 40 | } 41 | 42 | export interface VariantPopertyValue { 43 | key: string; 44 | value: string; 45 | } 46 | -------------------------------------------------------------------------------- /figma/features/variant/variant-property.ts: -------------------------------------------------------------------------------- 1 | // function getProperties() {} 2 | -------------------------------------------------------------------------------- /figma/index.ts: -------------------------------------------------------------------------------- 1 | // export * from "@design-sdk/figma-node-conversion"; 2 | // export * as remote from "@design-sdk/figma-remote"; 3 | // export * as api from "@design-sdk/figma-remote-api"; 4 | // 5 | // export * as url from "@design-sdk/figma-url"; 6 | export * from "./utils"; 7 | 8 | // 9 | // export * as types from "@design-sdk/figma-types"; 10 | export * from "@design-sdk/figma-types"; 11 | export { v1 as Figma } from "@design-sdk/figma-types"; 12 | export { plugin } from "@design-sdk/figma-types"; 13 | -------------------------------------------------------------------------------- /figma/node-analysis/component-like-type-analysis/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./type"; 2 | export { analyzeNode } from "./analyze"; 3 | -------------------------------------------------------------------------------- /figma/node-analysis/component-like-type-analysis/type.ts: -------------------------------------------------------------------------------- 1 | export type ComponentLikeType = 2 | // componennt with/without variant compat (can be used for both, but use it only for non variant component) 3 | | "master-component" 4 | // instance of simple or varianted component 5 | | "instance-component" 6 | // component set frame 7 | | "variant-set" 8 | // the single master variant of variant set 9 | | "master-variant-compoent" 10 | // the single instance variant 11 | | "variant-instance" 12 | | "invalid-target"; 13 | 14 | export type ExtendedComponentLilkeType = 15 | | ComponentLikeType 16 | // base master component that is used as a constraint for variant set variants masters. 17 | | "base-master-component"; 18 | 19 | export type SchemaDefinitionLike = 20 | | ExtendedComponentLilkeType 21 | // single layer - no matter where it lives under a componennt or a raw group, etc. 22 | | "single-layer-property"; 23 | -------------------------------------------------------------------------------- /figma/node-analysis/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./component-like-type-analysis"; 2 | -------------------------------------------------------------------------------- /figma/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/figma", 3 | "version": "0.0.53", 4 | "authors": "Grida.co", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "clean": "rimraf dist", 10 | "build": "tsc" 11 | }, 12 | "dependencies": { 13 | "@design-sdk/asset-repository": "^0.0.53", 14 | "@design-sdk/figma-node": "^0.0.53", 15 | "@design-sdk/figma-node-conversion": "^0.0.53", 16 | "@design-sdk/figma-remote": "^0.0.53", 17 | "@design-sdk/figma-types": "^0.0.53", 18 | "@design-sdk/figma-url": "^0.0.53", 19 | "@reflect-ui/uiutils": "0.1.2-1" 20 | }, 21 | "files": [ 22 | "dist", 23 | "README.md", 24 | "LICENSE" 25 | ], 26 | "publishConfig": { 27 | "access": "public" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /figma/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "declaration": true, 6 | "skipLibCheck": true, 7 | "strict": false 8 | }, 9 | "exclude": ["node_modules", "dist", "__test__"] 10 | } 11 | -------------------------------------------------------------------------------- /figma/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./text-style.figma"; 2 | export * from "./is-route-action"; 3 | -------------------------------------------------------------------------------- /grida/README.md: -------------------------------------------------------------------------------- 1 | # Design SDK For Grida 2 | 3 | ## Grida provided all-in-one packed plugin sdk. you may want to use it instead. 4 | 5 | Goto - https://github.com/gridaco/plugin-sdk 6 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "useNx": true, 4 | "useWorkspaces": true, 5 | "allowBranch": [ 6 | "main" 7 | ], 8 | "version": "0.0.53" 9 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "design-sdk", 3 | "private": true, 4 | "workspaces": [ 5 | "core", 6 | "core-*", 7 | "design-diff", 8 | "key-annotations", 9 | "figma", 10 | "figma-*", 11 | "sketch", 12 | "sketch-types", 13 | "xd", 14 | "universal", 15 | "vanilla", 16 | "url-analysis" 17 | ], 18 | "scripts": { 19 | "clean": "rimraf */dist", 20 | "lerna": "lerna", 21 | "bootstrap": "lerna bootstrap", 22 | "publish:all": "lerna publish", 23 | "build": "yarn clean && lerna run build" 24 | }, 25 | "devDependencies": { 26 | "@types/jest": "^26.0.23", 27 | "@types/node": "^15.12.4", 28 | "jest": "^27.0.5", 29 | "lerna": "^5.3.0", 30 | "rimraf": "^3.0.2", 31 | "ts-jest": "^27.0.3", 32 | "typescript": "^4.3.4" 33 | } 34 | } -------------------------------------------------------------------------------- /sampler/.env.example: -------------------------------------------------------------------------------- 1 | FIGMA_PERSONAL_ACCESS_TOKEN= -------------------------------------------------------------------------------- /sampler/README.md: -------------------------------------------------------------------------------- 1 | # Figma file sapler 2 | 3 | **Setup** 4 | 5 | 1. clone this repository 6 | 2. create `.env` file in this directory 7 | 3. set .env following the `.env.example` 8 | 9 | **Usage** 10 | 11 | ```bash 12 | yarn 13 | yarn sample [node-id...] 14 | # e.g. 15 | # yarn sample vXAxldxvDUBWW8EVZIGmgC 1:2 16 | ``` 17 | -------------------------------------------------------------------------------- /sampler/index.ts: -------------------------------------------------------------------------------- 1 | import yargs from "yargs"; 2 | import sample from "./sampler"; 3 | import path from "path"; 4 | import dotenv from "dotenv"; 5 | 6 | // load .env 7 | dotenv.config(); 8 | 9 | yargs 10 | .scriptName("sampler") 11 | .usage("$0 [args]") 12 | .command( 13 | "fetch [ids...]", 14 | "Fetches data from the API", 15 | (yargs) => { 16 | yargs.positional("key", { 17 | type: "string", 18 | describe: "The key to fetch", 19 | }); 20 | 21 | yargs.positional("ids", { 22 | type: "string", 23 | describe: "The ids to fetch", 24 | }); 25 | // 26 | }, 27 | ({ key, ids }) => { 28 | if (Array.isArray(ids) && ids.length > 0) { 29 | ids = ids.map((id) => decodeURIComponent(id)); 30 | 31 | console.log("sampling", ids, "from", key, "..."); 32 | 33 | sample({ 34 | filekey: key as string, 35 | ids: ids as string[], 36 | auth: { 37 | personalAccessToken: process.env.FIGMA_PERSONAL_ACCESS_TOKEN, 38 | }, 39 | outdir: path.join(__dirname, "out"), 40 | }); 41 | } else { 42 | console.error("no ids provided"); 43 | } 44 | } 45 | ) 46 | .demandCommand() 47 | .help().argv; 48 | -------------------------------------------------------------------------------- /sampler/out/.gitignore: -------------------------------------------------------------------------------- 1 | *.out.json -------------------------------------------------------------------------------- /sampler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sampler", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "sample": "ts-node index.ts" 8 | }, 9 | "dependencies": { 10 | "@design-sdk/figma-remote": "^0.0.43", 11 | "dotenv": "^16.0.3", 12 | "yargs": "^17.6.2" 13 | }, 14 | "devDependencies": { 15 | "@types/node": "^18.13.0", 16 | "@types/yargs": "^17.0.22", 17 | "ts-node": "^10.9.1", 18 | "typescript": "^4.9.5" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sampler/sampler.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { fetch } from "@design-sdk/figma-remote"; 4 | import assert from "assert"; 5 | 6 | export default async function sample({ 7 | outdir, 8 | filekey, 9 | ids, 10 | auth, 11 | }: { 12 | outdir: string; 13 | filekey: string; 14 | ids: string[]; 15 | auth: { 16 | personalAccessToken: string; 17 | }; 18 | }) { 19 | const data = await fetchnode({ 20 | filekey, 21 | ids, 22 | auth, 23 | }); 24 | 25 | Object.keys(data).forEach((key) => { 26 | const node = data[key]; 27 | const dir = path.join(outdir, filekey); 28 | const filename = `${key}.out.json`; 29 | const filepath = path.join(dir, filename); 30 | 31 | if (!fs.existsSync(dir)) { 32 | fs.mkdirSync(dir); 33 | } 34 | 35 | // write file 36 | fs.writeFileSync(filepath, JSON.stringify(node, null, 2)); 37 | }); 38 | } 39 | 40 | async function fetchnode({ 41 | filekey, 42 | ids, 43 | auth, 44 | }: { 45 | filekey: string; 46 | ids: string[]; 47 | auth: { 48 | personalAccessToken: string; 49 | }; 50 | }) { 51 | assert(auth && auth.personalAccessToken, "auth is required"); 52 | assert( 53 | !auth.personalAccessToken.startsWith("<"), 54 | "set your personal access token in .env" 55 | ); 56 | assert(ids.length > 0, "ids is required"); 57 | 58 | try { 59 | const { file, nodes } = await fetch.fetchTarget(filekey, ids, auth, { 60 | with_components: false, 61 | }); 62 | return nodes; 63 | } catch (e) { 64 | console.error(e); 65 | return null; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sampler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /sketch-node-conversion/lib/converters/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./text-align.convert"; 2 | -------------------------------------------------------------------------------- /sketch-node-conversion/lib/converters/text-align.convert.ts: -------------------------------------------------------------------------------- 1 | import { TextHorizontalAlignment } from "@design-sdk/sketch-types"; 2 | import { TextAlign } from "@reflect-ui/core"; 3 | export function convertSketchTextAligntmentToReflectTextAlignment( 4 | sketch: TextHorizontalAlignment 5 | ): TextAlign { 6 | if (sketch === undefined) { 7 | return TextAlign.start; 8 | } 9 | 10 | switch (sketch) { 11 | case TextHorizontalAlignment.Centered: 12 | return TextAlign.center; 13 | case TextHorizontalAlignment.Justified: 14 | return TextAlign.justify; 15 | case TextHorizontalAlignment.Left: 16 | return TextAlign.left; 17 | case TextHorizontalAlignment.Natural: 18 | return TextAlign.start; 19 | case TextHorizontalAlignment.Right: 20 | return TextAlign.right; 21 | } 22 | 23 | throw `${sketch} is not supported for reflect conversion`; 24 | } 25 | -------------------------------------------------------------------------------- /sketch-node-conversion/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./converters"; 2 | -------------------------------------------------------------------------------- /sketch-node-conversion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/sketch-node-conversion", 3 | "description": "Convert Sketch files to Universal reflect-ui design tokens", 4 | "version": "0.0.0", 5 | "private": false, 6 | "keywords": [ 7 | "sketch", 8 | "design", 9 | "converter", 10 | "design-sdk" 11 | ], 12 | "main": "dist/index.js", 13 | "types": "dist/index.d.ts", 14 | "homepage": "https://github.com/gridaco/design-sdk", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/gridaco/design-sdk", 18 | "directory": "sketch-node-conversion" 19 | }, 20 | "authors": [ 21 | "grida.co", 22 | "softmarshmallow " 23 | ], 24 | "scripts": { 25 | "clean": "rimraf dist", 26 | "build": "tsc" 27 | }, 28 | "dependencies": {}, 29 | "files": [ 30 | "dist/index.js", 31 | "dist/index.d.ts", 32 | "dist/**/*.js", 33 | "dist/**/*.d.ts", 34 | "README", 35 | "LICENSE" 36 | ], 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } -------------------------------------------------------------------------------- /sketch-types/README.md: -------------------------------------------------------------------------------- 1 | # Sketch file format & types 2 | 3 | - https://developer.sketch.com/file-format/ 4 | - https://github.com/sketch-hq/sketch-document 5 | -------------------------------------------------------------------------------- /sketch-types/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./v3"; 2 | -------------------------------------------------------------------------------- /sketch-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/sketch-types", 3 | "version": "0.0.53", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "clean": "rimraf dist", 9 | "build": "tsc" 10 | }, 11 | "files": [ 12 | "dist/index.js", 13 | "dist/index.d.ts", 14 | "dist/**/*.js", 15 | "dist/**/*.d.ts", 16 | "README", 17 | "LICENSE" 18 | ], 19 | "publishConfig": { 20 | "access": "public" 21 | }, 22 | "devDependencies": { 23 | "typescript": "^4.7.4" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sketch-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["lib/**/*.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /sketch-types/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | typescript@^4.7.4: 6 | version "4.7.4" 7 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" 8 | integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== 9 | -------------------------------------------------------------------------------- /sketch/README.md: -------------------------------------------------------------------------------- 1 | # Design SDK For Adobe XD 2 | -------------------------------------------------------------------------------- /sketch/lib/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gridaco/figma-sdk/5784ab284f17fcb2b20bc821fc140fd004964d7e/sketch/lib/index.ts -------------------------------------------------------------------------------- /sketch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/sketch", 3 | "version": "0.0.53", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "clean": "rimraf dist", 9 | "build": "tsc" 10 | }, 11 | "files": [ 12 | "dist", 13 | "README", 14 | "LICENSE" 15 | ], 16 | "publishConfig": { 17 | "access": "public" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /sketch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["lib/**/*.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "lib": ["esnext", "es2019", "dom"], 6 | "declaration": true, 7 | "esModuleInterop": true, 8 | "sourceMap": false, 9 | "experimentalDecorators": true, 10 | "noUnusedLocals": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "lib": ["esnext", "es2019", "dom"], 7 | "declaration": true, 8 | "esModuleInterop": true, 9 | "sourceMap": true, 10 | "experimentalDecorators": true, 11 | "noUnusedLocals": false, 12 | "skipLibCheck": true, 13 | "typeRoots": ["./node_modules/@types"] 14 | }, 15 | "include": ["**/*.ts"], 16 | "exclude": ["node_modules", "dist", "example", "doc", "__test__"] 17 | } 18 | -------------------------------------------------------------------------------- /universal/index.ts: -------------------------------------------------------------------------------- 1 | // platform 2 | export { _platform } from "@design-sdk/core"; 3 | -------------------------------------------------------------------------------- /universal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/universal", 3 | "version": "0.0.53", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "authors": [ 8 | "grida.co", 9 | "softmarshmallow " 10 | ], 11 | "dependencies": { 12 | "@design-sdk/core": "^0.0.53", 13 | "@design-sdk/figma": "^0.0.53", 14 | "@design-sdk/sketch": "^0.0.53", 15 | "@design-sdk/vanilla": "^0.0.53" 16 | }, 17 | "scripts": { 18 | "clean": "rimraf dist", 19 | "build": "tsc" 20 | }, 21 | "files": [ 22 | "dist/index.js", 23 | "dist/index.d.ts", 24 | "dist/**/*.js", 25 | "dist/**/*.d.ts", 26 | "README", 27 | "LICENSE" 28 | ], 29 | "publishConfig": { 30 | "access": "public" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /universal/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | -------------------------------------------------------------------------------- /url-analysis/lib/index.ts: -------------------------------------------------------------------------------- 1 | import type { DesignProvider } from "@design-sdk/core-types"; 2 | export type { DesignProvider }; 3 | 4 | export function analyzeDesignUrl(url: string): DesignProvider { 5 | try { 6 | const u = new URL(url); 7 | switch (u.hostname) { 8 | /** 9 | * https://figma.com/file/~ 10 | */ 11 | case "figma.com": 12 | case "www.figma.com": 13 | return "figma"; 14 | break; 15 | /** 16 | * https://sketch.com/s/~ 17 | */ 18 | case "www.sketch.com": 19 | case "sketch.com": 20 | return "sketch"; 21 | break; 22 | 23 | /** 24 | * powered by nothing graphics engine 25 | */ 26 | case "www.nothing.app": 27 | case "nothing.app": 28 | return "nothing"; 29 | case "www.bridged.xyz": 30 | case "www.grida.co": 31 | case "grida.co": 32 | case "bridged.xyz": // legacy bridged.xyz urls 33 | return "grida"; 34 | default: 35 | return "unknown"; 36 | } 37 | } catch (_) { 38 | // console.warn(`failed analyzing url. the url "${url}" is not a valid url.`) 39 | return "unknown"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /url-analysis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/url-analysis", 3 | "description": "A library for analyzing design URLs from multiple platforms (sketch, figma, ..)", 4 | "version": "0.0.53", 5 | "private": false, 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "authors": [ 9 | "grida.co", 10 | "softmarshmallow " 11 | ], 12 | "scripts": { 13 | "clean": "rimraf dist", 14 | "build": "tsc" 15 | }, 16 | "devDependencies": { 17 | "@design-sdk/core-types": "^0.0.53" 18 | }, 19 | "files": [ 20 | "dist", 21 | "README", 22 | "LICENSE" 23 | ], 24 | "publishConfig": { 25 | "access": "public" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /url-analysis/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["lib/**/*.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /vanilla/lib/make/cgrect.make.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | ReflectFrameNode, 3 | ReflectRectangleNode, 4 | } from "@design-sdk/figma-node"; 5 | import type { CGRectManifest } from "@reflect-ui/core"; 6 | 7 | export function makeCGRect( 8 | node: ReflectFrameNode | ReflectRectangleNode 9 | ): CGRectManifest { 10 | const fill = node.primaryColor; 11 | const borderRadius = node.cornerRadius; 12 | const shadow = node.primaryShadow; 13 | // TODO border support 14 | // TODO gradient support 15 | 16 | return { 17 | borderRadius: borderRadius, 18 | width: node.width, 19 | height: node.height, 20 | shadow: shadow, 21 | fill: fill, 22 | opacity: node.opacity, 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /vanilla/lib/make/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cgrect.make" -------------------------------------------------------------------------------- /vanilla/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/vanilla", 3 | "version": "0.0.53", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "authors": [ 8 | "grida.co", 9 | "softmarshmallow " 10 | ], 11 | "scripts": { 12 | "clean": "rimraf dist", 13 | "build": "tsc", 14 | "test": "jest" 15 | }, 16 | "dependencies": { 17 | "@design-sdk/asset-repository": "^0.0.53" 18 | }, 19 | "peerDependencies": { 20 | "@design-sdk/core": "*", 21 | "@design-sdk/figma-node": "*" 22 | }, 23 | "files": [ 24 | "dist", 25 | "README", 26 | "LICENSE" 27 | ], 28 | "publishConfig": { 29 | "access": "public" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vanilla/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "rootDir": "lib", 5 | "outDir": "dist" 6 | }, 7 | "include": ["lib/**/*.ts"], 8 | "exclude": ["node_modules", "dist", "__test__"] 9 | } 10 | -------------------------------------------------------------------------------- /xd-node-conversion/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gridaco/figma-sdk/5784ab284f17fcb2b20bc821fc140fd004964d7e/xd-node-conversion/index.ts -------------------------------------------------------------------------------- /xd-node-conversion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/xd-node-conversion", 3 | "description": "Convert XD files to Universal reflect-ui design tokens", 4 | "version": "0.0.0", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "private": false, 8 | "authors": [ 9 | "grida.co", 10 | "softmarshmallow " 11 | ], 12 | "keywords": [ 13 | "xd", 14 | "design", 15 | "converter", 16 | "design-sdk" 17 | ], 18 | "homepage": "https://github.com/gridaco/design-sdk", 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/gridaco/design-sdk", 22 | "directory": "xd-node-conversion" 23 | }, 24 | "scripts": { 25 | "clean": "rimraf dist", 26 | "build": "tsc" 27 | }, 28 | "dependencies": {}, 29 | "files": [ 30 | "dist/index.js", 31 | "dist/index.d.ts", 32 | "dist/**/*.js", 33 | "dist/**/*.d.ts", 34 | "README", 35 | "LICENSE" 36 | ], 37 | "publishConfig": { 38 | "access": "public" 39 | } 40 | } -------------------------------------------------------------------------------- /xd-node-conversion/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | -------------------------------------------------------------------------------- /xd-types/README.md: -------------------------------------------------------------------------------- 1 | # XD Types 2 | 3 | https://github.com/AdobeXD/typings/blob/master/types/scenegraph.d.ts 4 | -------------------------------------------------------------------------------- /xd-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/xd-types", 3 | "version": "0.0.0", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "clean": "rimraf dist", 9 | "build": "tsc" 10 | }, 11 | "files": [ 12 | "dist/index.js", 13 | "dist/index.d.ts", 14 | "dist/**/*.js", 15 | "dist/**/*.d.ts", 16 | "README", 17 | "LICENSE" 18 | ], 19 | "publishConfig": { 20 | "access": "public" 21 | } 22 | } -------------------------------------------------------------------------------- /xd-types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | -------------------------------------------------------------------------------- /xd/README.md: -------------------------------------------------------------------------------- 1 | # Design SDK For Adobe XD 2 | -------------------------------------------------------------------------------- /xd/index.ts: -------------------------------------------------------------------------------- 1 | export const dummy = ""; 2 | -------------------------------------------------------------------------------- /xd/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@design-sdk/xd", 3 | "version": "0.0.53", 4 | "private": false, 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "clean": "rimraf dist", 9 | "build": "tsc" 10 | }, 11 | "files": [ 12 | "dist/index.js", 13 | "dist/index.d.ts", 14 | "dist/**/*.js", 15 | "dist/**/*.d.ts", 16 | "README", 17 | "LICENSE" 18 | ], 19 | "publishConfig": { 20 | "access": "public" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /xd/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "exclude": ["node_modules", "dist", "__test__"] 7 | } 8 | --------------------------------------------------------------------------------