Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/figma-code-connect-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Figma Code Connect Publish

on:
workflow_dispatch:
push:
branches:
- main

permissions: {}

concurrency:
group: '${{ github.workflow }} @ ${{ github.ref }}'
cancel-in-progress: false # Ensure that previous runs aren't cancelled and leave the publish in a broken state.

jobs:
publish:
name: Publish
runs-on: ubuntu-latest

if: github.repository_owner == 'drivenets'

permissions:
contents: read

steps:
- name: Checkout source code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
persist-credentials: false

- name: Install Dependencies
uses: ./.github/actions/install

- name: Publish
run: pnpm figma:publish
env:
FIGMA_ACCESS_TOKEN: ${{ secrets.FIGMA_ACCESS_TOKEN }}
29 changes: 29 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,32 @@ jobs:
env:
ACTIONLINT: ${{ steps.install_actionlint.outputs.executable }}
run: '"$ACTIONLINT" -color'

figma-code-connect-lint:
name: Figma Code Connect Lint
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Checkout source code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0
filter: 'blob:none'
persist-credentials: false

- name: Install Dependencies
uses: ./.github/actions/install

- name: Cache turbo
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: .turbo
key: ${{ runner.os }}-turbo-figma-lint-${{ github.sha }}
restore-keys: |
${{ runner.os }}-turbo-figma-lint-

- name: Lint
run: pnpm figma:lint
1 change: 1 addition & 0 deletions knip.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"ignore": [
"**/*.figma.ts",
"**/*.scss",
"**/simple-file-upload-adapter.ts",
"./packages/eslint-plugin-internal/src/rules/__tests__/fixtures/*.ts"
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"test:requires-build": "turbo run test:requires-build",
"build": "turbo run build",
"build:storybook": "turbo run build:storybook",
"figma:lint": "turbo run figma:lint",
"figma:publish": "pnpm run --filter @drivenets/design-system figma:publish",
"changelog": "changeset",
"prepare": "husky",
"pre-commit": "lint-staged"
Expand Down
11 changes: 11 additions & 0 deletions packages/design-system/figma.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"codeConnect": {
"include": ["**/*.figma.ts"],
"importPaths": {
"src/components/*": "@drivenets/design-system"
},
Comment thread
iromanchuk-dn marked this conversation as resolved.
"label": "React",
"language": "tsx",
"parser": "react"
}
}
3 changes: 3 additions & 0 deletions packages/design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"lint:build": "publint && attw --pack",
"typecheck": "pnpm generate-scss-dts && tsgo; EXIT_CODE=$?; rm -rf .scss-dts; exit $EXIT_CODE",
"generate-scss-dts": "typed-scss-modules ./src -o ./.scss-dts --nameFormat all --exportType default > /dev/null 2>&1",
"figma:lint": "figma connect parse --exit-on-unreadable-files",
"figma:publish": "figma connect publish --exit-on-unreadable-files",
"test": "vitest --project=\"!requires-build\"",
"test:coverage": "pnpm test --coverage",
"test:unit": "vitest --project=unit",
Expand Down Expand Up @@ -84,6 +86,7 @@
"@drivenets/vite-plugin-design-system": "workspace:*",
"@eslint/compat": "^2.1.0",
"@faker-js/faker": "^10.3.0",
"@figma/code-connect": "^1.4.8",
"@hookform/resolvers": "^5.4.0",
"@rolldown/plugin-babel": "^0.2.3",
"@storybook/addon-a11y": "^10.4.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=31065-2352
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-button-v3
// component=DsButtonV3
import figma from 'figma';

const instance = figma.selectedInstance;

const variant = instance.getEnum('Variant', {
primary: 'primary',
secondary: 'secondary',
tertiary: 'tertiary',
});
const size = instance.getEnum('Size', {
tiny: 'tiny',
small: 'small',
medium: 'medium',
large: 'large',
});
const colorVariant = instance.getEnum('Color', { default: 'default', error: 'error' });
const isLight = instance.getEnum('light', { true: true, false: false });
const color = isLight ? 'light' : colorVariant;
const disabled = instance.getEnum('State', {
default: false,
hover: false,
focus: false,
active: false,
disabled: true,
});
const iconOnly = instance.getEnum('Icon', { 'icon-only': true, text: false });

const structure = instance.findInstance('.button-structure', { traverseInstances: true });
const showIcon = structure.type === 'INSTANCE' ? structure.getBoolean('Show icon') : false;

const labelNode = instance.findText('Button', { traverseInstances: true });
const label = labelNode.type === 'TEXT' ? labelNode.textContent : 'Button';

export default {
example: iconOnly
? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}" ${disabled ? 'disabled' : ''} icon="check_circle" aria-label="${label}" />`
: showIcon
? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}" ${disabled ? 'disabled' : ''} icon="check_circle">${label}</DsButtonV3>`
: figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}" ${disabled ? 'disabled' : ''}>${label}</DsButtonV3>`,
imports: ["import { DsButtonV3 } from '@drivenets/design-system'"],
id: 'ds-button-v3',
metadata: { nestable: true },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=34877-158343
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-modal
// component=DsModal.Body
//
// `DAP_modal-content_v02` maps to `DsModal.Body`. Its freeform `Modal content slot`
// becomes the body children.
import figma from 'figma';

const instance = figma.selectedInstance;

const content = instance.getSlot('Modal content slot');

export default {
example: figma.code`<DsModal.Body>${content}</DsModal.Body>`,
imports: ["import { DsModal } from '@drivenets/design-system'"],
id: 'ds-modal-content',
metadata: { nestable: true },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=32014-16402
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-modal
// component=DsModal.Footer
//
// `DAP_modal-footer_v02` maps to `DsModal.Footer` > `DsModal.Actions`. The
// `right side buttons` slot resolves its `DAP_Button_v03` instances via the
// existing `ds-button-v3` Code Connect.
import figma from 'figma';

const instance = figma.selectedInstance;

const rightButtons = instance.getSlot('right side buttons');

export default {
example: figma.code`<DsModal.Footer><DsModal.Actions>${rightButtons}</DsModal.Actions></DsModal.Footer>`,
imports: ["import { DsModal } from '@drivenets/design-system'"],
id: 'ds-modal-footer',
metadata: { nestable: true },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=32030-12809
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-modal
// component=DsModal.Header
//
// `DAP_modal-header_v02` maps to the composed `DsModal.Header` (title + close
// trigger). The `Type=drill-down` variant (back breadcrumb) and the optional
// booleans (status badge, description, tags, etc.) have no code-component prop and
// are omitted.
import figma from 'figma';

const instance = figma.selectedInstance;

const titleNode = instance.findText('Left side', { traverseInstances: true });
const title = titleNode.type === 'TEXT' ? titleNode.textContent : 'Modal title';

export default {
example: figma.code`<DsModal.Header><DsModal.Title>${title}</DsModal.Title><DsModal.CloseTrigger /></DsModal.Header>`,
imports: ["import { DsModal } from '@drivenets/design-system'"],
id: 'ds-modal-header',
metadata: { nestable: true },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=34877-158966
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-modal
// component=DsModal
//
// `DAP_modal_v02` is the full modal. It composes the header, content, and footer
// parts, each of which has its own Code Connect template; resolve them dynamically
// so swapped variants stay in sync. The `Type` variant (confirmation/form) has no
// `DsModal` prop equivalent — both render the same composition.
import figma from 'figma';

const instance = figma.selectedInstance;

const header = instance.findInstance('DAP_modal-header_v02', { traverseInstances: true });
let headerCode: figma.ResultSection[] | undefined;
if (header.type === 'INSTANCE') {
headerCode = header.executeTemplate().example;
}

const content = instance.findInstance('DAP_modal-content_v02', { traverseInstances: true });
let contentCode: figma.ResultSection[] | undefined;
if (content.type === 'INSTANCE') {
contentCode = content.executeTemplate().example;
}

const footer = instance.findInstance('DAP_modal-footer_v02', { traverseInstances: true });
let footerCode: figma.ResultSection[] | undefined;
if (footer.type === 'INSTANCE') {
footerCode = footer.executeTemplate().example;
}

export default {
example: figma.code`<DsModal open columns={6} onOpenChange={() => {}}>${headerCode}${contentCode}${footerCode}</DsModal>`,
imports: ["import { DsModal } from '@drivenets/design-system'"],
id: 'ds-modal',
metadata: { nestable: false },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=34428-16204
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-status-badge-v2
// component=DsStatusBadgeV2
import figma from 'figma';

const instance = figma.selectedInstance;

const phase = instance.getEnum('status', {
'not-started': 'not-started',
temporary: 'temporary',
'in-review': 'in-review',
pending: 'pending',
active: 'active',
execution: 'execution',
'result-succeeded': 'result-succeeded',
'result-warning': 'result-warning',
'result-failed': 'result-failed',
deprecated: 'deprecated',
});
const variant = instance.getEnum('variant', { primary: 'primary', secondary: 'secondary' });
const size = instance.getEnum('Size', { medium: 'medium', small: 'small' });
const structure = instance.getEnum('structure', {
'icon+text': 'icon+text',
'icon-only': 'icon-only',
'text-only': 'text-only',
});

const labelNode = instance.findText('Active', { traverseInstances: true });
const label = labelNode.type === 'TEXT' ? labelNode.textContent : 'Active';

export default {
example:
structure === 'icon-only'
Comment thread
iromanchuk-dn marked this conversation as resolved.
? figma.code`<DsStatusBadgeV2 phase="${phase}" label="${label}" variant="${variant}" size="${size}" iconOnly />`
: structure === 'text-only'
? figma.code`<DsStatusBadgeV2 phase="${phase}" label="${label}" variant="${variant}" size="${size}" icon={null} />`
: figma.code`<DsStatusBadgeV2 phase="${phase}" label="${label}" variant="${variant}" size="${size}" />`,
imports: ["import { DsStatusBadgeV2 } from '@drivenets/design-system'"],
id: 'ds-status-badge-v2',
Comment thread
iromanchuk-dn marked this conversation as resolved.
metadata: { nestable: true },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=13346-18325
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-text-input
// component=DsTextInput
//
// The Figma component `DAP_input_v01` is a single multi-type input. Its `Type`
// variant selects which code component to render:
// Number -> DsNumberInput
// Password -> DsPasswordInput
// Standard/Error/Read -> DsTextInput
import figma from 'figma';

const instance = figma.selectedInstance;

const type = instance.getEnum('Type', {
Standard: 'standard',
Error: 'error',
'Read Only': 'readOnly',
Number: 'number',
Password: 'password',
});

const size = instance.getEnum('Size', {
Small: 'small',
Default: 'default',
Large: 'default',
});

const state = instance.getEnum('State', {
Default: 'default',
Hover: 'hover',
'Focus/ Typing': 'focus',
Disabled: 'disabled',
'Read only': 'readOnly',
});

const disabled = state === 'disabled';
const readOnly = type === 'readOnly' || state === 'readOnly';

const sizeAttr = size === 'small' ? 'size="small"' : '';

const componentName =
type === 'number' ? 'DsNumberInput' : type === 'password' ? 'DsPasswordInput' : 'DsTextInput';

export default {
example:
type === 'number'
? figma.code`<DsNumberInput ${sizeAttr} ${disabled ? 'disabled' : ''} />`
: type === 'password'
? figma.code`<DsPasswordInput ${sizeAttr} ${disabled ? 'disabled' : ''} />`
: figma.code`<DsTextInput ${sizeAttr} ${disabled ? 'disabled' : ''} ${readOnly ? 'readOnly' : ''} />`,
imports: [`import { ${componentName} } from '@drivenets/design-system'`],
id: 'ds-text-input',
metadata: { nestable: true },
};
2 changes: 1 addition & 1 deletion packages/design-system/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDirs": ["./", "./.scss-dts"],
"types": ["vite/client"],
"types": ["vite/client", "@figma/code-connect/figma-types"],
"plugins": [{ "name": "typescript-plugin-css-modules" }]
},
"include": ["**/*", ".storybook/**/*"]
Expand Down
4 changes: 4 additions & 0 deletions packages/design-system/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"build:storybook": {
"outputs": ["storybook-static/**"],
"inputs": ["$TURBO_DEFAULT$", "$TURBO_ROOT$/packages/vite-plugin/**"]
},
"figma:lint": {
"dependsOn": [],
"inputs": ["**/*.figma.ts", "figma.config.json"]
}
}
}
Loading
Loading