@fprad0/skill-master-mcp 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +43 -9
- package/VERSION.md +3 -3
- package/bin/lib/client-config.mjs +268 -0
- package/bin/lib/menu-core.mjs +678 -33
- package/bin/skill-master-bootstrap-global.mjs +15 -1
- package/bin/skill-master-doctor.mjs +181 -0
- package/bin/skill-master-install-global-skills.mjs +30 -10
- package/bin/skill-master-menu.mjs +184 -36
- package/bin/skill-master-register-clients.mjs +43 -99
- package/dist/index.js +30 -5
- package/dist/index.js.map +1 -1
- package/docs/operations/GUIA_MULTI_COMPUTADOR.md +255 -0
- package/docs/operations/GUIA_NPM_PUBLICO.md +147 -0
- package/docs/skill-candidates/v0.0.10/cli-creator/LICENSE.txt +201 -0
- package/docs/skill-candidates/v0.0.10/cli-creator/SKILL.md +160 -0
- package/docs/skill-candidates/v0.0.10/cli-creator/agents/openai.yaml +4 -0
- package/docs/skill-candidates/v0.0.10/cli-creator/references/agent-cli-patterns.md +154 -0
- package/docs/skill-candidates/v0.0.10/developer-workstation-ops/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.10/figma/LICENSE.txt +2 -0
- package/docs/skill-candidates/v0.0.10/figma/SKILL.md +42 -0
- package/docs/skill-candidates/v0.0.10/figma/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma/references/figma-mcp-config.md +35 -0
- package/docs/skill-candidates/v0.0.10/figma/references/figma-tools-and-prompts.md +34 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/LICENSE.TXT +2 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/SKILL.md +349 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/references/mapping-checklist.md +7 -0
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/scripts/normalize_node_id.py +25 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/LICENSE.TXT +2 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/SKILL.md +537 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/references/rule-template.md +15 -0
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/LICENSE.TXT +2 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/SKILL.md +341 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-design/maintainers.yml +1 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/LICENSE.TXT +2 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/SKILL.md +314 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/maintainers.yml +3 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/code-connect-setup.md +260 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/component-creation.md +1014 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/discovery-phase.md +518 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/documentation-creation.md +834 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/error-recovery.md +540 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/naming-conventions.md +527 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/token-creation.md +962 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/bindVariablesToComponent.js +110 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/cleanupOrphans.js +127 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createComponentWithVariants.js +148 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createDocumentationPage.js +139 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createSemanticTokens.js +108 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createVariableCollection.js +49 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/inspectFileStructure.js +121 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/rehydrateState.js +92 -0
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/validateCreation.js +83 -0
- package/docs/skill-candidates/v0.0.10/figma-implement-design/LICENSE.txt +2 -0
- package/docs/skill-candidates/v0.0.10/figma-implement-design/SKILL.md +258 -0
- package/docs/skill-candidates/v0.0.10/figma-implement-design/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma-use/LICENSE.TXT +2 -0
- package/docs/skill-candidates/v0.0.10/figma-use/SKILL.md +233 -0
- package/docs/skill-candidates/v0.0.10/figma-use/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/figma-use/assets/figma-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/figma-use/assets/figma.png +0 -0
- package/docs/skill-candidates/v0.0.10/figma-use/assets/icon.svg +28 -0
- package/docs/skill-candidates/v0.0.10/figma-use/maintainers.yml +1 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/api-reference.md +301 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/common-patterns.md +512 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/component-patterns.md +488 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/effect-style-patterns.md +123 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/gotchas.md +599 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/maintainers.yml +12 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-patterns.md +513 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.d.ts +11293 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.index.md +441 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/text-style-patterns.md +203 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/validation-and-recovery.md +109 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/variable-patterns.md +354 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/maintainers.yml +9 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--creating.md +17 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--using.md +17 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components.md +50 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-effect-styles.md +52 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-text-styles.md +90 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--creating.md +13 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--using.md +13 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables.md +64 -0
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds.md +41 -0
- package/docs/skill-candidates/v0.0.10/frontend-design/LICENSE.txt +177 -0
- package/docs/skill-candidates/v0.0.10/frontend-design/SKILL.md +55 -0
- package/docs/skill-candidates/v0.0.10/frontend-ui-ux-systems/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.10/github/SKILL.md +74 -0
- package/docs/skill-candidates/v0.0.10/github/agents/openai.yaml +6 -0
- package/docs/skill-candidates/v0.0.10/github/assets/github-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/github/assets/github.png +0 -0
- package/docs/skill-candidates/v0.0.10/image-graphic-design-rendering/SKILL.md +28 -0
- package/docs/skill-candidates/v0.0.10/language-quality-pt-en-fr-it-ru/SKILL.md +28 -0
- package/docs/skill-candidates/v0.0.10/math-physics-reasoning/SKILL.md +28 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/LICENSE.txt +202 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/SKILL.md +236 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/evaluation.md +602 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/mcp_best_practices.md +249 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/node_mcp_server.md +970 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/python_mcp_server.md +719 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/connections.py +151 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/evaluation.py +373 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/requirements.txt +2 -0
- package/docs/skill-candidates/v0.0.10/mcp-client-readiness/SKILL.md +31 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/LICENSE.txt +201 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/SKILL.md +161 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/agents/openai.yaml +14 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/assets/openai-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/assets/openai.png +0 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/references/latest-model.md +37 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/references/prompting-guide.md +244 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/references/upgrade-guide.md +181 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/scripts/fetch-codex-manual.mjs +598 -0
- package/docs/skill-candidates/v0.0.10/openai-docs/scripts/resolve-latest-model-info.js +147 -0
- package/docs/skill-candidates/v0.0.10/playwright/LICENSE.txt +201 -0
- package/docs/skill-candidates/v0.0.10/playwright/NOTICE.txt +14 -0
- package/docs/skill-candidates/v0.0.10/playwright/SKILL.md +147 -0
- package/docs/skill-candidates/v0.0.10/playwright/agents/openai.yaml +6 -0
- package/docs/skill-candidates/v0.0.10/playwright/assets/playwright-small.svg +3 -0
- package/docs/skill-candidates/v0.0.10/playwright/assets/playwright.png +0 -0
- package/docs/skill-candidates/v0.0.10/playwright/references/cli.md +116 -0
- package/docs/skill-candidates/v0.0.10/playwright/references/workflows.md +95 -0
- package/docs/skill-candidates/v0.0.10/playwright/scripts/playwright_cli.sh +25 -0
- package/docs/skill-candidates/v0.0.10/polyglot-backend-engineering/SKILL.md +32 -0
- package/docs/skill-candidates/v0.0.10/screenshot/LICENSE.txt +201 -0
- package/docs/skill-candidates/v0.0.10/screenshot/SKILL.md +267 -0
- package/docs/skill-candidates/v0.0.10/screenshot/agents/openai.yaml +6 -0
- package/docs/skill-candidates/v0.0.10/screenshot/assets/screenshot-small.svg +5 -0
- package/docs/skill-candidates/v0.0.10/screenshot/assets/screenshot.png +0 -0
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/ensure_macos_permissions.sh +54 -0
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_display_info.swift +22 -0
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_permissions.swift +40 -0
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_window_info.swift +126 -0
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.ps1 +163 -0
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.py +585 -0
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/SKILL.md +62 -0
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/agents/openai.yaml +4 -0
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/activation-policy.md +77 -0
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/human-approval-policy.md +83 -0
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/persona-dev-senior-master.md +46 -0
- package/docs/skill-candidates/v0.0.10/terminal-menu-operations/SKILL.md +30 -0
- package/docs/skill-candidates/v0.0.10/terminal-pixel-art-tui/SKILL.md +43 -0
- package/docs/skill-candidates/v0.0.10/webapp-testing/LICENSE.txt +202 -0
- package/docs/skill-candidates/v0.0.10/webapp-testing/SKILL.md +96 -0
- package/docs/skill-candidates/v0.0.10/webapp-testing/examples/console_logging.py +35 -0
- package/docs/skill-candidates/v0.0.10/webapp-testing/examples/element_discovery.py +40 -0
- package/docs/skill-candidates/v0.0.10/webapp-testing/examples/static_html_automation.py +33 -0
- package/docs/skill-candidates/v0.0.10/webapp-testing/scripts/with_server.py +106 -0
- package/docs/skill-candidates/v0.0.10/winui-app/LICENSE.txt +202 -0
- package/docs/skill-candidates/v0.0.10/winui-app/SKILL.md +94 -0
- package/docs/skill-candidates/v0.0.10/winui-app/agents/openai.yaml +5 -0
- package/docs/skill-candidates/v0.0.10/winui-app/assets/winui.png +0 -0
- package/docs/skill-candidates/v0.0.10/winui-app/config.yaml +50 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/_sections.md +96 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/accessibility-input-and-localization.md +51 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/build-run-and-launch-verification.md +72 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/community-toolkit-controls-and-helpers.md +57 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/controls-layout-and-adaptive-ui.md +84 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-environment-audit-and-remediation.md +82 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-setup-and-project-selection.md +67 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-template-first-recovery.md +62 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-winui-app-structure.md +62 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/motion-animations-and-polish.md +45 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/performance-diagnostics-and-responsiveness.md +46 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/sample-source-map.md +37 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/shell-navigation-and-windowing.md +67 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/styling-theming-materials-and-icons.md +71 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/testing-debugging-and-review-checklists.md +77 -0
- package/docs/skill-candidates/v0.0.10/winui-app/references/windows-app-sdk-lifecycle-notifications-and-deployment.md +52 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +399 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +331 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +872 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +502 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +767 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +502 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +501 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +406 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +364 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +428 -0
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +418 -0
- package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -0
- package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -0
- package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -0
- package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -0
- package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -0
- package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -0
- package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -0
- package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +92 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -0
- package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -0
- package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -0
- package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -0
- package/manifests/channels/beta.json +7 -7
- package/manifests/channels/stable.json +8 -8
- package/network/unapproved-skill-candidates.json +34 -1
- package/package.json +7 -2
- package/scripts/verify-menu-actions.mjs +115 -0
package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/bindVariablesToComponent.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bindVariablesToComponent
|
|
3
|
+
*
|
|
4
|
+
* Binds design token variables to the visual properties of a component node.
|
|
5
|
+
* Supports fills, strokes, all padding directions, item spacing, and corner radius.
|
|
6
|
+
* Only binds properties for which a variable ID is provided in `bindings`.
|
|
7
|
+
*
|
|
8
|
+
* This function should be called on each variant individually within a component
|
|
9
|
+
* set, OR on the component set itself for properties shared by all variants.
|
|
10
|
+
*
|
|
11
|
+
* @param {ComponentNode | FrameNode | RectangleNode} component
|
|
12
|
+
* The Figma node to mutate. Usually a ComponentNode or one of its children.
|
|
13
|
+
* @param {{
|
|
14
|
+
* fills?: string,
|
|
15
|
+
* strokes?: string,
|
|
16
|
+
* paddingTop?: string,
|
|
17
|
+
* paddingBottom?: string,
|
|
18
|
+
* paddingLeft?: string,
|
|
19
|
+
* paddingRight?: string,
|
|
20
|
+
* itemSpacing?: string,
|
|
21
|
+
* cornerRadius?: string
|
|
22
|
+
* }} bindings
|
|
23
|
+
* Each key is a visual property name; each value is a Figma Variable ID
|
|
24
|
+
* (e.g. "VariableID:123:456"). Omit a key to skip binding that property.
|
|
25
|
+
* @returns {{ mutatedNodeIds: string[] }}
|
|
26
|
+
* List of node IDs that were mutated (for audit/validation purposes).
|
|
27
|
+
*/
|
|
28
|
+
function bindVariablesToComponent(component, bindings) {
|
|
29
|
+
const mutatedNodeIds = []
|
|
30
|
+
|
|
31
|
+
if (!component) {
|
|
32
|
+
return { mutatedNodeIds }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// --- Fills ---
|
|
36
|
+
if (bindings.fills) {
|
|
37
|
+
const fillVar = figma.variables.getVariableById(bindings.fills)
|
|
38
|
+
if (fillVar) {
|
|
39
|
+
const existingFills = component.fills
|
|
40
|
+
if (Array.isArray(existingFills) && existingFills.length > 0) {
|
|
41
|
+
// Bind the color of the first fill to the variable
|
|
42
|
+
const boundFill = figma.variables.setBoundVariableForPaint(
|
|
43
|
+
existingFills[0],
|
|
44
|
+
'color',
|
|
45
|
+
fillVar,
|
|
46
|
+
)
|
|
47
|
+
component.fills = [boundFill, ...existingFills.slice(1)]
|
|
48
|
+
} else {
|
|
49
|
+
// No existing fill — create a solid fill bound to the variable
|
|
50
|
+
const boundFill = figma.variables.setBoundVariableForPaint(
|
|
51
|
+
{ type: 'SOLID', color: { r: 0.5, g: 0.5, b: 0.5 } },
|
|
52
|
+
'color',
|
|
53
|
+
fillVar,
|
|
54
|
+
)
|
|
55
|
+
component.fills = [boundFill]
|
|
56
|
+
}
|
|
57
|
+
mutatedNodeIds.push(component.id)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// --- Strokes ---
|
|
62
|
+
if (bindings.strokes) {
|
|
63
|
+
const strokeVar = figma.variables.getVariableById(bindings.strokes)
|
|
64
|
+
if (strokeVar) {
|
|
65
|
+
const existingStrokes = component.strokes
|
|
66
|
+
if (Array.isArray(existingStrokes) && existingStrokes.length > 0) {
|
|
67
|
+
const boundStroke = figma.variables.setBoundVariableForPaint(
|
|
68
|
+
existingStrokes[0],
|
|
69
|
+
'color',
|
|
70
|
+
strokeVar,
|
|
71
|
+
)
|
|
72
|
+
component.strokes = [boundStroke, ...existingStrokes.slice(1)]
|
|
73
|
+
} else {
|
|
74
|
+
const boundStroke = figma.variables.setBoundVariableForPaint(
|
|
75
|
+
{ type: 'SOLID', color: { r: 0.5, g: 0.5, b: 0.5 } },
|
|
76
|
+
'color',
|
|
77
|
+
strokeVar,
|
|
78
|
+
)
|
|
79
|
+
component.strokes = [boundStroke]
|
|
80
|
+
}
|
|
81
|
+
if (!mutatedNodeIds.includes(component.id)) {
|
|
82
|
+
mutatedNodeIds.push(component.id)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Spacing properties (FLOAT variables bound via setBoundVariable) ---
|
|
88
|
+
const floatBindings = [
|
|
89
|
+
['paddingTop', 'paddingTop'],
|
|
90
|
+
['paddingBottom', 'paddingBottom'],
|
|
91
|
+
['paddingLeft', 'paddingLeft'],
|
|
92
|
+
['paddingRight', 'paddingRight'],
|
|
93
|
+
['itemSpacing', 'itemSpacing'],
|
|
94
|
+
['cornerRadius', 'cornerRadius'],
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
for (const [bindingKey, figmaProp] of floatBindings) {
|
|
98
|
+
if (bindings[bindingKey]) {
|
|
99
|
+
const variable = figma.variables.getVariableById(bindings[bindingKey])
|
|
100
|
+
if (variable) {
|
|
101
|
+
component.setBoundVariable(figmaProp, variable)
|
|
102
|
+
if (!mutatedNodeIds.includes(component.id)) {
|
|
103
|
+
mutatedNodeIds.push(component.id)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return { mutatedNodeIds }
|
|
110
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cleanupOrphans
|
|
3
|
+
*
|
|
4
|
+
* Finds and removes all Figma nodes (pages, frames, components, variables,
|
|
5
|
+
* and variable collections) that were tagged with the given `dsb_run_id`
|
|
6
|
+
* by a previous build run. This is safe cleanup: it uses plugin data tags,
|
|
7
|
+
* never name-prefix matching, so it cannot accidentally delete user-owned nodes.
|
|
8
|
+
*
|
|
9
|
+
* Use this when a build run fails mid-way and you need to reset to a clean
|
|
10
|
+
* slate before retrying. The function traverses the entire document looking
|
|
11
|
+
* for `dsb_run_id` plugin data matching `runId`.
|
|
12
|
+
*
|
|
13
|
+
* Variables and variable collections are handled separately (they are not
|
|
14
|
+
* scene nodes and cannot be discovered via node traversal).
|
|
15
|
+
*
|
|
16
|
+
* @param {string} runId - The dsb_run_id value to match (e.g. "ds-build-2024-001").
|
|
17
|
+
* @returns {Promise<{
|
|
18
|
+
* removedCount: number,
|
|
19
|
+
* removedIds: string[]
|
|
20
|
+
* }>}
|
|
21
|
+
*/
|
|
22
|
+
async function cleanupOrphans(runId) {
|
|
23
|
+
if (!runId) {
|
|
24
|
+
throw new Error('cleanupOrphans: runId is required.')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const removedIds = []
|
|
28
|
+
const originalPage = figma.currentPage
|
|
29
|
+
|
|
30
|
+
// --- Remove tagged scene nodes (pages, frames, components, etc.) ---
|
|
31
|
+
// Collect pages to remove (can't remove during iteration)
|
|
32
|
+
const pagesToRemove = []
|
|
33
|
+
|
|
34
|
+
for (const page of figma.root.children) {
|
|
35
|
+
if (page.getPluginData('dsb_run_id') === runId) {
|
|
36
|
+
pagesToRemove.push(page)
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Traverse all nodes on this page
|
|
41
|
+
await figma.setCurrentPageAsync(page)
|
|
42
|
+
|
|
43
|
+
const nodesToRemove = []
|
|
44
|
+
page.findAll((node) => {
|
|
45
|
+
if (node.getPluginData('dsb_run_id') === runId) {
|
|
46
|
+
nodesToRemove.push(node)
|
|
47
|
+
return false // Don't descend — removing the parent removes its children
|
|
48
|
+
}
|
|
49
|
+
return true
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// Remove deepest nodes first (children before parents) to avoid
|
|
53
|
+
// "parent no longer exists" errors
|
|
54
|
+
const sorted = nodesToRemove.sort((a, b) => {
|
|
55
|
+
// Sort by depth descending: deeper nodes first
|
|
56
|
+
return getDepth(b) - getDepth(a)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
for (const node of sorted) {
|
|
60
|
+
if (node && node.parent) {
|
|
61
|
+
removedIds.push(node.id)
|
|
62
|
+
node.remove()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Remove tagged pages last
|
|
68
|
+
for (const page of pagesToRemove) {
|
|
69
|
+
// Cannot remove the last page in the document
|
|
70
|
+
if (figma.root.children.length <= 1) {
|
|
71
|
+
break
|
|
72
|
+
}
|
|
73
|
+
removedIds.push(page.id)
|
|
74
|
+
page.remove()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// --- Remove tagged variables ---
|
|
78
|
+
const allVariables = figma.variables.getLocalVariables()
|
|
79
|
+
for (const variable of allVariables) {
|
|
80
|
+
if (variable.getPluginData('dsb_run_id') === runId) {
|
|
81
|
+
removedIds.push(variable.id)
|
|
82
|
+
variable.remove()
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// --- Remove tagged variable collections ---
|
|
87
|
+
// Must be done after variables are removed
|
|
88
|
+
const allCollections = figma.variables.getLocalVariableCollections()
|
|
89
|
+
for (const collection of allCollections) {
|
|
90
|
+
if (collection.getPluginData('dsb_run_id') === runId) {
|
|
91
|
+
removedIds.push(collection.id)
|
|
92
|
+
collection.remove()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Restore original page (if it still exists)
|
|
97
|
+
try {
|
|
98
|
+
await figma.setCurrentPageAsync(originalPage)
|
|
99
|
+
} catch (_) {
|
|
100
|
+
// Original page was removed — switch to first available page
|
|
101
|
+
if (figma.root.children.length > 0) {
|
|
102
|
+
await figma.setCurrentPageAsync(figma.root.children[0])
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
removedCount: removedIds.length,
|
|
108
|
+
removedIds,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns the depth of a node in the document tree.
|
|
114
|
+
* Root children (pages) have depth 1; their children have depth 2; etc.
|
|
115
|
+
*
|
|
116
|
+
* @param {BaseNode} node
|
|
117
|
+
* @returns {number}
|
|
118
|
+
*/
|
|
119
|
+
function getDepth(node) {
|
|
120
|
+
let depth = 0
|
|
121
|
+
let current = node
|
|
122
|
+
while (current.parent) {
|
|
123
|
+
depth++
|
|
124
|
+
current = current.parent
|
|
125
|
+
}
|
|
126
|
+
return depth
|
|
127
|
+
}
|
package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createComponentWithVariants.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createComponentWithVariants
|
|
3
|
+
*
|
|
4
|
+
* Creates a component set by generating all combinations of `variantAxes`,
|
|
5
|
+
* building one Figma component per combination, then calling
|
|
6
|
+
* `figma.combineAsVariants` to produce the component set. After combining,
|
|
7
|
+
* the variants are repositioned into a grid so they don't all stack at (0, 0).
|
|
8
|
+
*
|
|
9
|
+
* @param {{
|
|
10
|
+
* name: string,
|
|
11
|
+
* variantAxes: Record<string, string[]>,
|
|
12
|
+
* baseProps: {
|
|
13
|
+
* width: number,
|
|
14
|
+
* height: number,
|
|
15
|
+
* fills?: Paint[],
|
|
16
|
+
* padding?: {top?: number, bottom?: number, left?: number, right?: number},
|
|
17
|
+
* radius?: number,
|
|
18
|
+
* layoutMode?: 'HORIZONTAL' | 'VERTICAL' | 'NONE',
|
|
19
|
+
* itemSpacing?: number
|
|
20
|
+
* },
|
|
21
|
+
* page: PageNode
|
|
22
|
+
* }} config
|
|
23
|
+
* - `name`: Component set name (e.g. "Button").
|
|
24
|
+
* - `variantAxes`: Each key is a variant property name; each value is an array of
|
|
25
|
+
* allowed values. All combinations are generated (Cartesian product).
|
|
26
|
+
* Example: { Size: ['Small', 'Medium', 'Large'], Style: ['Primary', 'Ghost'] }
|
|
27
|
+
* produces 6 variants.
|
|
28
|
+
* - `baseProps`: Visual properties applied to every variant.
|
|
29
|
+
* - `page`: The PageNode to create components on (must be set as current page by caller).
|
|
30
|
+
* @param {string} [runId] - Optional dsb_run_id to tag every node.
|
|
31
|
+
* @returns {Promise<{
|
|
32
|
+
* componentSet: ComponentSetNode,
|
|
33
|
+
* variants: ComponentNode[]
|
|
34
|
+
* }>}
|
|
35
|
+
*/
|
|
36
|
+
async function createComponentWithVariants(config, runId) {
|
|
37
|
+
const { name, variantAxes, baseProps, page } = config
|
|
38
|
+
|
|
39
|
+
// Ensure we are on the correct page
|
|
40
|
+
await figma.setCurrentPageAsync(page)
|
|
41
|
+
|
|
42
|
+
// Compute Cartesian product of variant axes
|
|
43
|
+
const axisNames = Object.keys(variantAxes)
|
|
44
|
+
const axisValues = axisNames.map((k) => variantAxes[k])
|
|
45
|
+
const combinations = cartesianProduct(axisValues)
|
|
46
|
+
|
|
47
|
+
// Build one component per combination
|
|
48
|
+
const components = []
|
|
49
|
+
for (const combo of combinations) {
|
|
50
|
+
const comp = figma.createComponent()
|
|
51
|
+
|
|
52
|
+
// Name: "Property=Value, Property=Value, ..."
|
|
53
|
+
comp.name = axisNames.map((ax, i) => `${ax}=${combo[i]}`).join(', ')
|
|
54
|
+
|
|
55
|
+
// Base geometry
|
|
56
|
+
comp.resize(baseProps.width, baseProps.height)
|
|
57
|
+
|
|
58
|
+
// Fills
|
|
59
|
+
if (baseProps.fills !== undefined) {
|
|
60
|
+
comp.fills = baseProps.fills
|
|
61
|
+
} else {
|
|
62
|
+
comp.fills = [{ type: 'SOLID', color: { r: 0.9, g: 0.9, b: 0.9 } }]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Corner radius
|
|
66
|
+
if (baseProps.radius !== undefined) {
|
|
67
|
+
comp.cornerRadius = baseProps.radius
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Auto-layout
|
|
71
|
+
if (baseProps.layoutMode && baseProps.layoutMode !== 'NONE') {
|
|
72
|
+
comp.layoutMode = baseProps.layoutMode
|
|
73
|
+
comp.primaryAxisAlignItems = 'CENTER'
|
|
74
|
+
comp.counterAxisAlignItems = 'CENTER'
|
|
75
|
+
if (baseProps.itemSpacing !== undefined) {
|
|
76
|
+
comp.itemSpacing = baseProps.itemSpacing
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Padding
|
|
81
|
+
if (baseProps.padding) {
|
|
82
|
+
comp.paddingTop = baseProps.padding.top ?? 0
|
|
83
|
+
comp.paddingBottom = baseProps.padding.bottom ?? 0
|
|
84
|
+
comp.paddingLeft = baseProps.padding.left ?? 0
|
|
85
|
+
comp.paddingRight = baseProps.padding.right ?? 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Plugin data
|
|
89
|
+
const variantKey = axisNames.map((ax, i) => `${ax}:${combo[i]}`).join('|')
|
|
90
|
+
comp.setPluginData('dsb_key', `component/${name}/${variantKey}`)
|
|
91
|
+
if (runId) {
|
|
92
|
+
comp.setPluginData('dsb_run_id', runId)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
page.appendChild(comp)
|
|
96
|
+
components.push(comp)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Combine into a component set
|
|
100
|
+
const componentSet = figma.combineAsVariants(components, page)
|
|
101
|
+
componentSet.name = name
|
|
102
|
+
componentSet.setPluginData('dsb_key', `componentSet/${name}`)
|
|
103
|
+
if (runId) {
|
|
104
|
+
componentSet.setPluginData('dsb_run_id', runId)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Grid layout — variants stack at (0, 0) after combineAsVariants; reposition them.
|
|
108
|
+
const GRID_GAP = 16
|
|
109
|
+
const cols = Math.max(1, axisValues[axisValues.length - 1]?.length ?? 1)
|
|
110
|
+
const variantWidth = baseProps.width
|
|
111
|
+
const variantHeight = baseProps.height
|
|
112
|
+
|
|
113
|
+
componentSet.children.forEach((variant, idx) => {
|
|
114
|
+
const col = idx % cols
|
|
115
|
+
const row = Math.floor(idx / cols)
|
|
116
|
+
variant.x = col * (variantWidth + GRID_GAP)
|
|
117
|
+
variant.y = row * (variantHeight + GRID_GAP)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Resize component set to wrap its children with padding
|
|
121
|
+
const totalCols = Math.min(cols, combinations.length)
|
|
122
|
+
const totalRows = Math.ceil(combinations.length / cols)
|
|
123
|
+
const PADDING = 40
|
|
124
|
+
componentSet.resize(
|
|
125
|
+
totalCols * variantWidth + (totalCols - 1) * GRID_GAP + PADDING * 2,
|
|
126
|
+
totalRows * variantHeight + (totalRows - 1) * GRID_GAP + PADDING * 2,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
// Position component set at a safe canvas location
|
|
130
|
+
componentSet.x = 480
|
|
131
|
+
componentSet.y = 80
|
|
132
|
+
|
|
133
|
+
return { componentSet, variants: componentSet.children }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Computes the Cartesian product of multiple arrays.
|
|
138
|
+
* cartesianProduct([[A, B], [1, 2]]) → [[A,1], [A,2], [B,1], [B,2]]
|
|
139
|
+
*
|
|
140
|
+
* @param {Array<string[]>} arrays
|
|
141
|
+
* @returns {string[][]}
|
|
142
|
+
*/
|
|
143
|
+
function cartesianProduct(arrays) {
|
|
144
|
+
return arrays.reduce(
|
|
145
|
+
(acc, curr) => acc.flatMap((combo) => curr.map((val) => [...combo, val])),
|
|
146
|
+
[[]],
|
|
147
|
+
)
|
|
148
|
+
}
|
package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createDocumentationPage.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createDocumentationPage
|
|
3
|
+
*
|
|
4
|
+
* Creates a new Figma page with a standardized documentation layout: a page
|
|
5
|
+
* title, optional description, and an ordered list of sections each built by
|
|
6
|
+
* a caller-supplied `contentFn`. The content function receives the section
|
|
7
|
+
* frame and may append any nodes to it.
|
|
8
|
+
*
|
|
9
|
+
* This function is used for standalone documentation pages (e.g. a Foundations
|
|
10
|
+
* page, a Getting Started page, or a component page with documentation).
|
|
11
|
+
* It does not handle component sets — those live on separate pages created by
|
|
12
|
+
* createComponentWithVariants.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} pageName - The Figma page name (e.g. "Foundations", "Getting Started").
|
|
15
|
+
* @param {{
|
|
16
|
+
* title: string,
|
|
17
|
+
* description?: string,
|
|
18
|
+
* sections: Array<{
|
|
19
|
+
* name: string,
|
|
20
|
+
* contentFn: (sectionFrame: FrameNode) => Promise<void>
|
|
21
|
+
* }>
|
|
22
|
+
* }} config
|
|
23
|
+
* - `title`: Large heading displayed at the top of the page.
|
|
24
|
+
* - `description`: Optional subtitle displayed below the heading.
|
|
25
|
+
* - `sections`: Ordered list of sections. Each section gets its own frame
|
|
26
|
+
* with a heading and is passed to `contentFn` for population.
|
|
27
|
+
* @param {string} [runId] - Optional dsb_run_id to tag every created node.
|
|
28
|
+
* @returns {Promise<{
|
|
29
|
+
* page: PageNode,
|
|
30
|
+
* titleNode: TextNode,
|
|
31
|
+
* frameIds: string[]
|
|
32
|
+
* }>}
|
|
33
|
+
* `frameIds` is an ordered list of IDs for the root frame and each section frame.
|
|
34
|
+
*/
|
|
35
|
+
async function createDocumentationPage(pageName, config, runId) {
|
|
36
|
+
await figma.loadFontAsync({ family: 'Inter', style: 'Bold' })
|
|
37
|
+
await figma.loadFontAsync({ family: 'Inter', style: 'Regular' })
|
|
38
|
+
await figma.loadFontAsync({ family: 'Inter', style: 'Medium' })
|
|
39
|
+
|
|
40
|
+
// Create and activate the page
|
|
41
|
+
const page = figma.createPage()
|
|
42
|
+
page.name = pageName
|
|
43
|
+
await figma.setCurrentPageAsync(page)
|
|
44
|
+
|
|
45
|
+
if (runId) {
|
|
46
|
+
page.setPluginData('dsb_run_id', runId)
|
|
47
|
+
page.setPluginData('dsb_key', `page/${pageName}`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const frameIds = []
|
|
51
|
+
|
|
52
|
+
// Root scroll container — 1440px wide, auto-height
|
|
53
|
+
const root = figma.createFrame()
|
|
54
|
+
root.name = pageName
|
|
55
|
+
root.layoutMode = 'VERTICAL'
|
|
56
|
+
root.primaryAxisAlignItems = 'MIN'
|
|
57
|
+
root.counterAxisAlignItems = 'MIN'
|
|
58
|
+
root.itemSpacing = 80
|
|
59
|
+
root.paddingTop = 80
|
|
60
|
+
root.paddingBottom = 120
|
|
61
|
+
root.paddingLeft = 80
|
|
62
|
+
root.paddingRight = 80
|
|
63
|
+
root.layoutSizingHorizontal = 'FIXED'
|
|
64
|
+
root.layoutSizingVertical = 'HUG'
|
|
65
|
+
root.resize(1440, 1)
|
|
66
|
+
root.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]
|
|
67
|
+
root.x = 0
|
|
68
|
+
root.y = 0
|
|
69
|
+
page.appendChild(root)
|
|
70
|
+
|
|
71
|
+
if (runId) {
|
|
72
|
+
root.setPluginData('dsb_run_id', runId)
|
|
73
|
+
root.setPluginData('dsb_key', `frame/root/${pageName}`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
frameIds.push(root.id)
|
|
77
|
+
|
|
78
|
+
// Page header: title + optional description
|
|
79
|
+
const header = figma.createFrame()
|
|
80
|
+
header.name = 'Header'
|
|
81
|
+
header.layoutMode = 'VERTICAL'
|
|
82
|
+
header.itemSpacing = 12
|
|
83
|
+
header.layoutSizingHorizontal = 'FILL'
|
|
84
|
+
header.layoutSizingVertical = 'HUG'
|
|
85
|
+
header.fills = []
|
|
86
|
+
root.appendChild(header)
|
|
87
|
+
|
|
88
|
+
const titleNode = figma.createText()
|
|
89
|
+
titleNode.fontName = { family: 'Inter', style: 'Bold' }
|
|
90
|
+
titleNode.characters = config.title
|
|
91
|
+
titleNode.fontSize = 40
|
|
92
|
+
titleNode.fills = [{ type: 'SOLID', color: { r: 0.07, g: 0.07, b: 0.07 } }]
|
|
93
|
+
titleNode.layoutSizingHorizontal = 'FILL'
|
|
94
|
+
header.appendChild(titleNode)
|
|
95
|
+
|
|
96
|
+
if (config.description) {
|
|
97
|
+
const descNode = figma.createText()
|
|
98
|
+
descNode.fontName = { family: 'Inter', style: 'Regular' }
|
|
99
|
+
descNode.characters = config.description
|
|
100
|
+
descNode.fontSize = 16
|
|
101
|
+
descNode.lineHeight = { value: 24, unit: 'PIXELS' }
|
|
102
|
+
descNode.fills = [{ type: 'SOLID', color: { r: 0.4, g: 0.4, b: 0.4 } }]
|
|
103
|
+
descNode.layoutSizingHorizontal = 'FILL'
|
|
104
|
+
header.appendChild(descNode)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Sections
|
|
108
|
+
for (const section of config.sections) {
|
|
109
|
+
const sectionFrame = figma.createFrame()
|
|
110
|
+
sectionFrame.name = `Section/${section.name}`
|
|
111
|
+
sectionFrame.layoutMode = 'VERTICAL'
|
|
112
|
+
sectionFrame.itemSpacing = 20
|
|
113
|
+
sectionFrame.layoutSizingHorizontal = 'FILL'
|
|
114
|
+
sectionFrame.layoutSizingVertical = 'HUG'
|
|
115
|
+
sectionFrame.fills = []
|
|
116
|
+
root.appendChild(sectionFrame)
|
|
117
|
+
|
|
118
|
+
if (runId) {
|
|
119
|
+
sectionFrame.setPluginData('dsb_run_id', runId)
|
|
120
|
+
sectionFrame.setPluginData('dsb_key', `frame/section/${pageName}/${section.name}`)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Section heading
|
|
124
|
+
const sectionHeading = figma.createText()
|
|
125
|
+
sectionHeading.fontName = { family: 'Inter', style: 'Bold' }
|
|
126
|
+
sectionHeading.characters = section.name
|
|
127
|
+
sectionHeading.fontSize = 24
|
|
128
|
+
sectionHeading.fills = [{ type: 'SOLID', color: { r: 0.07, g: 0.07, b: 0.07 } }]
|
|
129
|
+
sectionHeading.layoutSizingHorizontal = 'FILL'
|
|
130
|
+
sectionFrame.appendChild(sectionHeading)
|
|
131
|
+
|
|
132
|
+
// Invoke the caller's content function to populate the section
|
|
133
|
+
await section.contentFn(sectionFrame)
|
|
134
|
+
|
|
135
|
+
frameIds.push(sectionFrame.id)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { page, titleNode, frameIds }
|
|
139
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createSemanticTokens
|
|
3
|
+
*
|
|
4
|
+
* Creates a batch of Figma variables in the given collection, one per entry in
|
|
5
|
+
* `tokenMap`. Supports raw values, variable alias references, code syntax, and
|
|
6
|
+
* scopes. Returns a map of token name → Variable for use in subsequent steps.
|
|
7
|
+
*
|
|
8
|
+
* @param {VariableCollection} collection - The target variable collection.
|
|
9
|
+
* @param {Record<string, string>} modeIds - Map of {modeName: modeId} from createVariableCollection.
|
|
10
|
+
* @param {Array<{
|
|
11
|
+
* name: string,
|
|
12
|
+
* type: 'COLOR' | 'FLOAT' | 'STRING' | 'BOOLEAN',
|
|
13
|
+
* values: Record<string, string | number | boolean | {type: 'VARIABLE_ALIAS', id: string}>,
|
|
14
|
+
* scopes?: VariableScope[],
|
|
15
|
+
* codeSyntax?: {WEB?: string, ANDROID?: string, iOS?: string}
|
|
16
|
+
* }>} tokenMap - Ordered list of token definitions.
|
|
17
|
+
* - `name`: Variable name using slash hierarchy (e.g. "color/bg/primary").
|
|
18
|
+
* - `type`: Figma variable type.
|
|
19
|
+
* - `values`: Map of {modeName: value}. Values can be raw (hex string for COLOR,
|
|
20
|
+
* number for FLOAT) or alias objects {type: 'VARIABLE_ALIAS', id: variableId}.
|
|
21
|
+
* For COLOR, raw values are accepted as hex strings ("#rrggbb" or "#rrggbbaa")
|
|
22
|
+
* and converted to {r, g, b, a} automatically.
|
|
23
|
+
* - `scopes`: Array of VariableScope strings. Omit to use [] (hidden/primitive).
|
|
24
|
+
* - `codeSyntax`: Platform code syntax strings. Omit to skip.
|
|
25
|
+
* @param {string} [runId] - Optional dsb_run_id to tag every variable.
|
|
26
|
+
* @returns {Promise<{variables: Record<string, Variable>}>}
|
|
27
|
+
* `variables` maps each token name to its created Variable object.
|
|
28
|
+
*/
|
|
29
|
+
async function createSemanticTokens(collection, modeIds, tokenMap, runId) {
|
|
30
|
+
const variables = {}
|
|
31
|
+
|
|
32
|
+
for (const token of tokenMap) {
|
|
33
|
+
// Create the variable
|
|
34
|
+
const variable = figma.variables.createVariable(token.name, collection, token.type)
|
|
35
|
+
|
|
36
|
+
// Tag for cleanup
|
|
37
|
+
variable.setPluginData('dsb_key', `variable/${token.name}`)
|
|
38
|
+
if (runId) {
|
|
39
|
+
variable.setPluginData('dsb_run_id', runId)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Set values for each mode
|
|
43
|
+
for (const [modeName, rawValue] of Object.entries(token.values)) {
|
|
44
|
+
const modeId = modeIds[modeName]
|
|
45
|
+
if (!modeId) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`createSemanticTokens: mode "${modeName}" not found in modeIds for token "${token.name}". ` +
|
|
48
|
+
`Available modes: ${Object.keys(modeIds).join(', ')}`,
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let value = rawValue
|
|
53
|
+
|
|
54
|
+
// Convert hex strings to Figma RGBA for COLOR type
|
|
55
|
+
if (token.type === 'COLOR' && typeof rawValue === 'string' && rawValue.startsWith('#')) {
|
|
56
|
+
value = hexToFigmaColor(rawValue)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
variable.setValueForMode(modeId, value)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Set scopes (default: empty array = hidden from property pickers / primitives)
|
|
63
|
+
variable.scopes = token.scopes || []
|
|
64
|
+
|
|
65
|
+
// Set code syntax per platform
|
|
66
|
+
if (token.codeSyntax) {
|
|
67
|
+
if (token.codeSyntax.WEB) {
|
|
68
|
+
variable.setVariableCodeSyntax('WEB', token.codeSyntax.WEB)
|
|
69
|
+
}
|
|
70
|
+
if (token.codeSyntax.ANDROID) {
|
|
71
|
+
variable.setVariableCodeSyntax('ANDROID', token.codeSyntax.ANDROID)
|
|
72
|
+
}
|
|
73
|
+
if (token.codeSyntax.iOS) {
|
|
74
|
+
variable.setVariableCodeSyntax('iOS', token.codeSyntax.iOS)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
variables[token.name] = variable
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { variables }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Converts a hex color string to a Figma RGBA object.
|
|
86
|
+
* Supports "#rgb", "#rrggbb", and "#rrggbbaa".
|
|
87
|
+
*
|
|
88
|
+
* @param {string} hex
|
|
89
|
+
* @returns {{ r: number, g: number, b: number, a: number }}
|
|
90
|
+
*/
|
|
91
|
+
function hexToFigmaColor(hex) {
|
|
92
|
+
let h = hex.replace('#', '')
|
|
93
|
+
|
|
94
|
+
// Expand shorthand #rgb → #rrggbb
|
|
95
|
+
if (h.length === 3) {
|
|
96
|
+
h = h
|
|
97
|
+
.split('')
|
|
98
|
+
.map((c) => c + c)
|
|
99
|
+
.join('')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const r = parseInt(h.substring(0, 2), 16) / 255
|
|
103
|
+
const g = parseInt(h.substring(2, 4), 16) / 255
|
|
104
|
+
const b = parseInt(h.substring(4, 6), 16) / 255
|
|
105
|
+
const a = h.length === 8 ? parseInt(h.substring(6, 8), 16) / 255 : 1
|
|
106
|
+
|
|
107
|
+
return { r, g, b, a }
|
|
108
|
+
}
|
package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createVariableCollection.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createVariableCollection
|
|
3
|
+
*
|
|
4
|
+
* Creates a new Figma variable collection with the specified name and modes.
|
|
5
|
+
* If `modeNames` has more than one entry, the first mode is renamed from
|
|
6
|
+
* Figma's default "Mode 1" to the first name, and additional modes are added.
|
|
7
|
+
*
|
|
8
|
+
* Every created collection is tagged with `dsb_key` plugin data so it can be
|
|
9
|
+
* found and cleaned up idempotently by `cleanupOrphans`.
|
|
10
|
+
*
|
|
11
|
+
* @param {string} name - The display name of the collection (e.g. "Color", "Spacing").
|
|
12
|
+
* @param {string[]} modeNames - Ordered list of mode names (e.g. ["Light", "Dark"] or ["Value"]).
|
|
13
|
+
* @param {string} [runId] - Optional dsb_run_id to tag for cleanup.
|
|
14
|
+
* @returns {Promise<{
|
|
15
|
+
* collection: VariableCollection,
|
|
16
|
+
* modeIds: Record<string, string>
|
|
17
|
+
* }>}
|
|
18
|
+
* `modeIds` maps each mode name to its modeId string.
|
|
19
|
+
*/
|
|
20
|
+
async function createVariableCollection(name, modeNames, runId) {
|
|
21
|
+
if (!modeNames || modeNames.length === 0) {
|
|
22
|
+
throw new Error('createVariableCollection: modeNames must have at least one entry.')
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Create the collection — Figma always creates it with one mode named "Mode 1".
|
|
26
|
+
const collection = figma.variables.createVariableCollection(name)
|
|
27
|
+
|
|
28
|
+
// Tag for idempotent cleanup
|
|
29
|
+
collection.setPluginData('dsb_key', `collection/${name}`)
|
|
30
|
+
if (runId) {
|
|
31
|
+
collection.setPluginData('dsb_run_id', runId)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// modeIds accumulator
|
|
35
|
+
const modeIds = {}
|
|
36
|
+
|
|
37
|
+
// Rename the default first mode
|
|
38
|
+
const defaultMode = collection.modes[0]
|
|
39
|
+
collection.renameMode(defaultMode.modeId, modeNames[0])
|
|
40
|
+
modeIds[modeNames[0]] = defaultMode.modeId
|
|
41
|
+
|
|
42
|
+
// Add additional modes
|
|
43
|
+
for (let i = 1; i < modeNames.length; i++) {
|
|
44
|
+
const newModeId = collection.addMode(modeNames[i])
|
|
45
|
+
modeIds[modeNames[i]] = newModeId
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { collection, modeIds }
|
|
49
|
+
}
|