@sarjallab09/figma-intelligence 1.1.0 → 1.2.0
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/README.md +67 -36
- package/dist/bin/cli.js +2 -0
- package/dist/design-bridge/bridge.js +2 -0
- package/dist/figma-bridge-plugin/bridge-relay.js +2 -0
- package/dist/figma-bridge-plugin/code.js +1 -0
- package/{figma-bridge-plugin → dist/figma-bridge-plugin}/package-lock.json +0 -3
- package/dist/figma-bridge-plugin/ui.html +4970 -0
- package/dist/figma-intelligence-layer/dist/index.js +2 -0
- package/dist/scripts/clean-existing-chunks.js +2 -0
- package/dist/scripts/connect-ai-tool.js +2 -0
- package/dist/scripts/convert-hub-pdfs.js +2 -0
- package/dist/scripts/figma-mcp-status.js +2 -0
- package/dist/scripts/register-codex-mcp.js +2 -0
- package/dist/scripts/test-copilot-chat.js +2 -0
- package/package.json +11 -8
- package/bin/cli.js +0 -859
- package/design-bridge/bridge.js +0 -196
- package/design-bridge/lib/assets.js +0 -367
- package/design-bridge/lib/prompt.js +0 -85
- package/design-bridge/lib/server.js +0 -66
- package/design-bridge/lib/stitch.js +0 -37
- package/design-bridge/lib/tokens.js +0 -82
- package/design-bridge/package-lock.json +0 -579
- package/figma-bridge-plugin/README.md +0 -97
- package/figma-bridge-plugin/anthropic-chat-runner.js +0 -192
- package/figma-bridge-plugin/bridge-relay.js +0 -2505
- package/figma-bridge-plugin/chat-runner.js +0 -485
- package/figma-bridge-plugin/code.js +0 -1534
- package/figma-bridge-plugin/codex-runner.js +0 -505
- package/figma-bridge-plugin/component-schemas.js +0 -110
- package/figma-bridge-plugin/content-context.js +0 -869
- package/figma-bridge-plugin/create-button.js +0 -216
- package/figma-bridge-plugin/gemini-cli-runner.js +0 -291
- package/figma-bridge-plugin/gemini-runner.js +0 -187
- package/figma-bridge-plugin/html-to-figma.js +0 -927
- package/figma-bridge-plugin/knowledge-hub/.gitkeep +0 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/anatomy-spec.md +0 -159
- package/figma-bridge-plugin/knowledge-hub/uspec-references/api-spec.md +0 -162
- package/figma-bridge-plugin/knowledge-hub/uspec-references/color-spec.md +0 -148
- package/figma-bridge-plugin/knowledge-hub/uspec-references/full-spec-template.md +0 -314
- package/figma-bridge-plugin/knowledge-hub/uspec-references/property-spec.md +0 -175
- package/figma-bridge-plugin/knowledge-hub/uspec-references/screen-reader-spec.md +0 -180
- package/figma-bridge-plugin/knowledge-hub/uspec-references/structure-spec.md +0 -165
- package/figma-bridge-plugin/perplexity-runner.js +0 -188
- package/figma-bridge-plugin/references/SKILL.md +0 -178
- package/figma-bridge-plugin/references/anatomy-spec.md +0 -159
- package/figma-bridge-plugin/references/api-spec.md +0 -162
- package/figma-bridge-plugin/references/color-spec.md +0 -148
- package/figma-bridge-plugin/references/full-spec-template.md +0 -314
- package/figma-bridge-plugin/references/property-spec.md +0 -175
- package/figma-bridge-plugin/references/screen-reader-spec.md +0 -180
- package/figma-bridge-plugin/references/structure-spec.md +0 -165
- package/figma-bridge-plugin/shared-prompt-config.js +0 -645
- package/figma-bridge-plugin/spec-helpers/build-table.js +0 -269
- package/figma-bridge-plugin/spec-helpers/classify-elements.js +0 -189
- package/figma-bridge-plugin/spec-helpers/index.js +0 -35
- package/figma-bridge-plugin/spec-helpers/parse-figma-link.js +0 -49
- package/figma-bridge-plugin/spec-helpers/position-markers.js +0 -158
- package/figma-bridge-plugin/stitch-auth.js +0 -322
- package/figma-bridge-plugin/stitch-runner.js +0 -1427
- package/figma-bridge-plugin/token-resolver.js +0 -107
- package/figma-bridge-plugin/ui.html +0 -4542
- package/figma-intelligence-layer/.env.example +0 -39
- package/figma-intelligence-layer/docs/local-image-generation.md +0 -60
- package/figma-intelligence-layer/examples/comfyui-workflow-template.example.json +0 -101
- package/figma-intelligence-layer/jest.config.js +0 -14
- package/figma-intelligence-layer/mcp-config.json +0 -19
- package/figma-intelligence-layer/package-lock.json +0 -5892
- package/figma-intelligence-layer/scripts/setup-comfyui-local.sh +0 -67
- package/figma-intelligence-layer/scripts/start-comfyui.sh +0 -33
- package/figma-intelligence-layer/src/index.ts +0 -2233
- package/figma-intelligence-layer/src/shared/auto-layout-validator.ts +0 -404
- package/figma-intelligence-layer/src/shared/cache.ts +0 -187
- package/figma-intelligence-layer/src/shared/color-operations.ts +0 -533
- package/figma-intelligence-layer/src/shared/color-utils.ts +0 -138
- package/figma-intelligence-layer/src/shared/component-script-builder.ts +0 -413
- package/figma-intelligence-layer/src/shared/component-templates.ts +0 -2767
- package/figma-intelligence-layer/src/shared/concept-taxonomy.ts +0 -694
- package/figma-intelligence-layer/src/shared/decision-log.ts +0 -128
- package/figma-intelligence-layer/src/shared/design-system-context.ts +0 -568
- package/figma-intelligence-layer/src/shared/design-system-intelligence.ts +0 -131
- package/figma-intelligence-layer/src/shared/design-system-matcher.ts +0 -184
- package/figma-intelligence-layer/src/shared/design-system-normalizers.ts +0 -196
- package/figma-intelligence-layer/src/shared/design-system-tokens.ts +0 -295
- package/figma-intelligence-layer/src/shared/dtcg-validator.ts +0 -530
- package/figma-intelligence-layer/src/shared/enrichment-pipeline.ts +0 -671
- package/figma-intelligence-layer/src/shared/figma-bridge.ts +0 -1418
- package/figma-intelligence-layer/src/shared/font-config.ts +0 -126
- package/figma-intelligence-layer/src/shared/icon-catalog.ts +0 -360
- package/figma-intelligence-layer/src/shared/icon-fetch.ts +0 -80
- package/figma-intelligence-layer/src/shared/prototype-script-builder.ts +0 -162
- package/figma-intelligence-layer/src/shared/response-compression.ts +0 -440
- package/figma-intelligence-layer/src/shared/semantic-token-catalog.ts +0 -324
- package/figma-intelligence-layer/src/shared/token-binder.ts +0 -505
- package/figma-intelligence-layer/src/shared/token-math.ts +0 -427
- package/figma-intelligence-layer/src/shared/token-naming.ts +0 -468
- package/figma-intelligence-layer/src/shared/token-utils.ts +0 -420
- package/figma-intelligence-layer/src/shared/types.ts +0 -346
- package/figma-intelligence-layer/src/shared/typography-presets.ts +0 -94
- package/figma-intelligence-layer/src/shared/unsplash.ts +0 -165
- package/figma-intelligence-layer/src/shared/vision-client.ts +0 -607
- package/figma-intelligence-layer/src/shared/vision-provider-anthropic.ts +0 -334
- package/figma-intelligence-layer/src/shared/vision-provider-openai.ts +0 -446
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotate-handler.ts +0 -782
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotate-renderer.ts +0 -496
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotation-kit.ts +0 -230
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/colorblind-sim.ts +0 -66
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/index.ts +0 -810
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-analyzer.ts +0 -1191
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-figma-page.ts +0 -1346
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-handler.ts +0 -148
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/vpat-figma-page.ts +0 -499
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/vpat-report.ts +0 -910
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/wcag-checker.ts +0 -989
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/wcag-criteria.ts +0 -1160
- package/figma-intelligence-layer/src/tools/phase1-vision/design-from-ref/index.ts +0 -424
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/component-recognizer.ts +0 -38
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/ds-matcher.ts +0 -111
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/font-matcher.ts +0 -114
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/icon-resolver.ts +0 -103
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/index.ts +0 -1060
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/layout-segmenter.ts +0 -18
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/token-inferencer.ts +0 -39
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/vision-pipeline.ts +0 -58
- package/figma-intelligence-layer/src/tools/phase1-vision/sketch-to-design/index.ts +0 -298
- package/figma-intelligence-layer/src/tools/phase1-vision/visual-audit/index.ts +0 -197
- package/figma-intelligence-layer/src/tools/phase2-accuracy/component-audit/index.ts +0 -494
- package/figma-intelligence-layer/src/tools/phase2-accuracy/intent-translator/index.ts +0 -356
- package/figma-intelligence-layer/src/tools/phase2-accuracy/layout-intelligence/container-patterns.ts +0 -123
- package/figma-intelligence-layer/src/tools/phase2-accuracy/layout-intelligence/index.ts +0 -663
- package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/built-in-rules.yaml +0 -56
- package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/index.ts +0 -614
- package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/rule-engine.ts +0 -113
- package/figma-intelligence-layer/src/tools/phase2-accuracy/theme-generator/color-theory.ts +0 -178
- package/figma-intelligence-layer/src/tools/phase2-accuracy/theme-generator/index.ts +0 -470
- package/figma-intelligence-layer/src/tools/phase2-accuracy/variant-expander/index.ts +0 -429
- package/figma-intelligence-layer/src/tools/phase2-accuracy/variant-expander/token-override-maps.ts +0 -226
- package/figma-intelligence-layer/src/tools/phase3-generation/ai-image-insert/index.ts +0 -535
- package/figma-intelligence-layer/src/tools/phase3-generation/component-archaeologist/index.ts +0 -660
- package/figma-intelligence-layer/src/tools/phase3-generation/component-archaeologist/pattern-fingerprints.ts +0 -209
- package/figma-intelligence-layer/src/tools/phase3-generation/composition-builder/index.ts +0 -540
- package/figma-intelligence-layer/src/tools/phase3-generation/figma-animated-build.ts +0 -391
- package/figma-intelligence-layer/src/tools/phase3-generation/page-architect/index.ts +0 -2019
- package/figma-intelligence-layer/src/tools/phase3-generation/page-architect/screen-templates.ts +0 -131
- package/figma-intelligence-layer/src/tools/phase3-generation/prototype-map/index.ts +0 -381
- package/figma-intelligence-layer/src/tools/phase3-generation/prototype-wire/index.ts +0 -565
- package/figma-intelligence-layer/src/tools/phase3-generation/swarm-build/index.ts +0 -764
- package/figma-intelligence-layer/src/tools/phase3-generation/system-drift/index.ts +0 -535
- package/figma-intelligence-layer/src/tools/phase3-generation/unsplash-search/index.ts +0 -84
- package/figma-intelligence-layer/src/tools/phase3-generation/url-to-frame/index.ts +0 -401
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/css-animations.ts +0 -68
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/framer-motion.ts +0 -78
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/swift-animations.ts +0 -93
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/index.ts +0 -596
- package/figma-intelligence-layer/src/tools/phase4-sync/ci-check/index.ts +0 -462
- package/figma-intelligence-layer/src/tools/phase4-sync/export-tokens/index.ts +0 -1470
- package/figma-intelligence-layer/src/tools/phase4-sync/generate-component-code/index.ts +0 -829
- package/figma-intelligence-layer/src/tools/phase4-sync/handoff-spec/index.ts +0 -702
- package/figma-intelligence-layer/src/tools/phase4-sync/icon-library-sync/index.ts +0 -483
- package/figma-intelligence-layer/src/tools/phase4-sync/sync-from-code/index.ts +0 -501
- package/figma-intelligence-layer/src/tools/phase4-sync/sync-from-code/storybook-parser.ts +0 -106
- package/figma-intelligence-layer/src/tools/phase4-sync/watch-docs/index.ts +0 -676
- package/figma-intelligence-layer/src/tools/phase4-sync/webhook-listener/index.ts +0 -560
- package/figma-intelligence-layer/src/tools/phase5-governance/apg-doc/index.ts +0 -1043
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/component-detection.ts +0 -620
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/anatomy.ts +0 -331
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/color-tokens.ts +0 -77
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/properties.ts +0 -54
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/snapshot.ts +0 -287
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/spacing.ts +0 -71
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/states.ts +0 -43
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/typography.ts +0 -71
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/index.ts +0 -221
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/_default.ts +0 -166
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/accordion.ts +0 -232
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/alert.ts +0 -234
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/avatar-group.ts +0 -270
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/avatar.ts +0 -249
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/badge.ts +0 -231
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/banner.ts +0 -293
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/breadcrumb.ts +0 -240
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/button.ts +0 -243
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/calendar.ts +0 -307
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/card.ts +0 -143
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/checkbox.ts +0 -227
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/chip.ts +0 -233
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/combobox.ts +0 -282
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/datepicker.ts +0 -276
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/divider.ts +0 -223
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/drawer.ts +0 -255
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/dropdown-menu.ts +0 -289
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/empty-state.ts +0 -261
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/file-uploader.ts +0 -290
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/form.ts +0 -265
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/grid.ts +0 -238
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/icon.ts +0 -255
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/index.ts +0 -128
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/inline-edit.ts +0 -286
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/inline-message.ts +0 -255
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/input.ts +0 -330
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/link.ts +0 -247
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/list.ts +0 -250
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/menu.ts +0 -247
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/modal.ts +0 -144
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/navbar.ts +0 -264
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/navigation.ts +0 -251
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/number-input.ts +0 -261
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/pagination.ts +0 -248
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/popover.ts +0 -270
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/progress.ts +0 -251
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/radio.ts +0 -142
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/range-slider.ts +0 -282
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/rating.ts +0 -250
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/search.ts +0 -258
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/segmented-control.ts +0 -265
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/select.ts +0 -319
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/skeleton.ts +0 -256
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/slider.ts +0 -232
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/spinner.ts +0 -239
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/status-dot.ts +0 -252
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/stepper.ts +0 -270
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/table.ts +0 -244
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tabs.ts +0 -143
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tag.ts +0 -243
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/textarea.ts +0 -259
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/time-picker.ts +0 -293
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toast.ts +0 -144
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toggle.ts +0 -289
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toolbar.ts +0 -267
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tooltip.ts +0 -232
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/treeview.ts +0 -257
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/typography.ts +0 -319
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/legacy-compat.ts +0 -121
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/anatomy-diagram.ts +0 -430
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/figma-page.ts +0 -312
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/json.ts +0 -129
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/markdown.ts +0 -78
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/visual-doc.ts +0 -2333
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/accessibility.ts +0 -100
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/anatomy.ts +0 -32
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/color-tokens.ts +0 -59
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/content-guidance.ts +0 -18
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/design-tokens.ts +0 -53
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/interaction-rules.ts +0 -19
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/overview.ts +0 -91
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/properties-api.ts +0 -71
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/qa-criteria.ts +0 -19
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/related-components.ts +0 -110
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/responsive.ts +0 -19
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/size-specs.ts +0 -67
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/spacing-structure.ts +0 -58
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/state-specs.ts +0 -79
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/states.ts +0 -50
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/type-hierarchy.ts +0 -33
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/typography.ts +0 -55
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/usage-guidelines.ts +0 -73
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/variants.ts +0 -81
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/types.ts +0 -409
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/index.ts +0 -198
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/renderer.ts +0 -701
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/types.ts +0 -88
- package/figma-intelligence-layer/src/tools/phase5-governance/decision-log/index.ts +0 -135
- package/figma-intelligence-layer/src/tools/phase5-governance/design-decision-log/index.ts +0 -491
- package/figma-intelligence-layer/src/tools/phase5-governance/ds-primitives/index.ts +0 -416
- package/figma-intelligence-layer/src/tools/phase5-governance/ds-scaffolder/index.ts +0 -722
- package/figma-intelligence-layer/src/tools/phase5-governance/ds-variables/index.ts +0 -449
- package/figma-intelligence-layer/src/tools/phase5-governance/health-report/index.ts +0 -393
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/index.ts +0 -406
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/figma-page.ts +0 -292
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/json.ts +0 -24
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/markdown.ts +0 -172
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/naming-guide.ts +0 -409
- package/figma-intelligence-layer/src/tools/phase5-governance/token-analytics/index.ts +0 -594
- package/figma-intelligence-layer/src/tools/phase5-governance/token-docs/index.ts +0 -710
- package/figma-intelligence-layer/src/tools/phase5-governance/token-migrate/index.ts +0 -458
- package/figma-intelligence-layer/src/tools/phase5-governance/token-naming/index.ts +0 -134
- package/figma-intelligence-layer/tests/apg-doc.test.ts +0 -101
- package/figma-intelligence-layer/tests/design-system-context.test.ts +0 -152
- package/figma-intelligence-layer/tests/design-system-matcher.test.ts +0 -144
- package/figma-intelligence-layer/tests/figma-bridge.test.ts +0 -83
- package/figma-intelligence-layer/tests/generate-image-and-insert.test.ts +0 -56
- package/figma-intelligence-layer/tests/screen-cloner-regression.test.ts +0 -69
- package/figma-intelligence-layer/tests/smoke.test.ts +0 -174
- package/figma-intelligence-layer/tests/spec-generator.test.ts +0 -127
- package/figma-intelligence-layer/tests/token-migrate.test.ts +0 -21
- package/figma-intelligence-layer/tests/token-naming.test.ts +0 -30
- package/figma-intelligence-layer/tsconfig.json +0 -19
- package/scripts/clean-existing-chunks.js +0 -179
- package/scripts/connect-ai-tool.js +0 -490
- package/scripts/convert-hub-pdfs.js +0 -425
- package/scripts/figma-mcp-status.js +0 -349
- package/scripts/register-codex-mcp.js +0 -96
- /package/{design-bridge → dist/design-bridge}/.env.example +0 -0
- /package/{design-bridge → dist/design-bridge}/package.json +0 -0
- /package/{figma-bridge-plugin → dist/figma-bridge-plugin}/manifest.json +0 -0
- /package/{figma-bridge-plugin → dist/figma-bridge-plugin}/package.json +0 -0
- /package/{figma-intelligence-layer → dist/figma-intelligence-layer}/package.json +0 -0
|
@@ -1,910 +0,0 @@
|
|
|
1
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
-
// VPAT Report Builder
|
|
3
|
-
// Takes raw audit issues + the criteria registry and produces a structured
|
|
4
|
-
// VPAT-style accessibility conformance report with rich, design-aware remarks.
|
|
5
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
WCAGLevel,
|
|
9
|
-
WCAGPrinciple,
|
|
10
|
-
ConformanceStatus,
|
|
11
|
-
WCAGCriterionDef,
|
|
12
|
-
getCriteriaForLevel,
|
|
13
|
-
} from "./wcag-criteria.js";
|
|
14
|
-
import { WCAGIssue } from "../../../shared/types.js";
|
|
15
|
-
|
|
16
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
-
// Types
|
|
18
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
-
|
|
20
|
-
/** Summary of what the design contains — drives contextual VPAT remarks. */
|
|
21
|
-
export interface DesignContext {
|
|
22
|
-
/** Human-readable name of the audited frame/page */
|
|
23
|
-
frameName: string;
|
|
24
|
-
/** Total node count in the tree */
|
|
25
|
-
totalNodes: number;
|
|
26
|
-
/** Count of TEXT nodes */
|
|
27
|
-
textNodeCount: number;
|
|
28
|
-
/** Count of interactive elements (buttons, links, inputs, etc.) */
|
|
29
|
-
interactiveCount: number;
|
|
30
|
-
/** Count of IMAGE / VECTOR nodes (non-text visuals) */
|
|
31
|
-
imageCount: number;
|
|
32
|
-
/** Count of COMPONENT_SET nodes */
|
|
33
|
-
componentSetCount: number;
|
|
34
|
-
/** Count of FRAME / GROUP containers */
|
|
35
|
-
frameCount: number;
|
|
36
|
-
/** Names of detected landmarks (nav, header, footer, sidebar, etc.) */
|
|
37
|
-
landmarkNames: string[];
|
|
38
|
-
/** Names/labels of detected interactive elements (first N) */
|
|
39
|
-
interactiveLabels: string[];
|
|
40
|
-
/** Whether the design appears to contain form inputs */
|
|
41
|
-
hasFormInputs: boolean;
|
|
42
|
-
/** Whether the design contains navigation-like structures */
|
|
43
|
-
hasNavigation: boolean;
|
|
44
|
-
/** Whether the design contains images or icons */
|
|
45
|
-
hasImages: boolean;
|
|
46
|
-
/** Whether the design contains headings (large/bold text) */
|
|
47
|
-
hasHeadings: boolean;
|
|
48
|
-
/** Sample heading texts found */
|
|
49
|
-
headingTexts: string[];
|
|
50
|
-
/** Whether auto-layout is used on frames */
|
|
51
|
-
hasAutoLayout: boolean;
|
|
52
|
-
/** Sample text content (first few text strings for context) */
|
|
53
|
-
sampleTexts: string[];
|
|
54
|
-
/** Interactive element type breakdown */
|
|
55
|
-
interactiveBreakdown: Record<string, number>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface VPATRow {
|
|
59
|
-
criterionId: string;
|
|
60
|
-
criterionName: string;
|
|
61
|
-
level: WCAGLevel;
|
|
62
|
-
principle: WCAGPrinciple;
|
|
63
|
-
guideline: string;
|
|
64
|
-
conformanceStatus: ConformanceStatus;
|
|
65
|
-
checkType: "automated" | "heuristic" | "manual";
|
|
66
|
-
remarks: string;
|
|
67
|
-
issues: WCAGIssue[];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface VPATSummary {
|
|
71
|
-
totalCriteria: number;
|
|
72
|
-
supports: number;
|
|
73
|
-
partiallySupports: number;
|
|
74
|
-
doesNotSupport: number;
|
|
75
|
-
notApplicable: number;
|
|
76
|
-
notEvaluated: number;
|
|
77
|
-
automatedChecks: number;
|
|
78
|
-
heuristicChecks: number;
|
|
79
|
-
manualReviewRequired: number;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export interface VPATReport {
|
|
83
|
-
title: string;
|
|
84
|
-
wcagVersion: "2.2";
|
|
85
|
-
evaluatedLevel: WCAGLevel;
|
|
86
|
-
evaluationDate: string;
|
|
87
|
-
nodeId: string;
|
|
88
|
-
nodeName: string;
|
|
89
|
-
summary: VPATSummary;
|
|
90
|
-
principles: Record<WCAGPrinciple, VPATRow[]>;
|
|
91
|
-
rows: VPATRow[];
|
|
92
|
-
formattedReport: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
96
|
-
// Conformance determination
|
|
97
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
98
|
-
|
|
99
|
-
function determineConformance(
|
|
100
|
-
criterion: WCAGCriterionDef,
|
|
101
|
-
issues: WCAGIssue[],
|
|
102
|
-
override?: ConformanceStatus
|
|
103
|
-
): ConformanceStatus {
|
|
104
|
-
if (override) return override;
|
|
105
|
-
|
|
106
|
-
const { checkCapability } = criterion;
|
|
107
|
-
|
|
108
|
-
// Manual criteria cannot be evaluated by the tool
|
|
109
|
-
if (checkCapability === "manual") {
|
|
110
|
-
return "Not Evaluated";
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const hasErrors = issues.some((i) => i.severity === "error");
|
|
114
|
-
const hasWarnings = issues.some(
|
|
115
|
-
(i) => i.severity === "warning" || i.severity === "suggestion"
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
if (checkCapability === "automated") {
|
|
119
|
-
if (hasErrors) return "Does Not Support";
|
|
120
|
-
if (hasWarnings) return "Partially Supports";
|
|
121
|
-
return "Supports";
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Heuristic: even with zero issues, we can only claim partial support
|
|
125
|
-
if (checkCapability === "heuristic") {
|
|
126
|
-
if (hasErrors) return "Does Not Support";
|
|
127
|
-
if (hasWarnings) return "Partially Supports";
|
|
128
|
-
// No issues found, but check was not exhaustive
|
|
129
|
-
return "Partially Supports";
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return "Not Evaluated";
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
-
// Context-aware remarks builder
|
|
137
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
138
|
-
|
|
139
|
-
function buildRemarks(
|
|
140
|
-
criterion: WCAGCriterionDef,
|
|
141
|
-
issues: WCAGIssue[],
|
|
142
|
-
conformance: ConformanceStatus,
|
|
143
|
-
ctx: DesignContext
|
|
144
|
-
): string {
|
|
145
|
-
const parts: string[] = [];
|
|
146
|
-
|
|
147
|
-
if (conformance === "Not Applicable") {
|
|
148
|
-
parts.push(getNotApplicableReason(criterion, ctx));
|
|
149
|
-
return parts.join(" ");
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (conformance === "Not Evaluated") {
|
|
153
|
-
parts.push(getDesignAwareManualGuidance(criterion, ctx));
|
|
154
|
-
return parts.join(" ");
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// ── Issues found ──────────────────────────────────────────────────────────
|
|
158
|
-
if (issues.length > 0) {
|
|
159
|
-
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
160
|
-
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
161
|
-
const suggestionCount = issues.filter(
|
|
162
|
-
(i) => i.severity === "suggestion"
|
|
163
|
-
).length;
|
|
164
|
-
|
|
165
|
-
// Severity summary
|
|
166
|
-
const counts: string[] = [];
|
|
167
|
-
if (errorCount > 0) counts.push(`${errorCount} error(s)`);
|
|
168
|
-
if (warningCount > 0) counts.push(`${warningCount} warning(s)`);
|
|
169
|
-
if (suggestionCount > 0) counts.push(`${suggestionCount} suggestion(s)`);
|
|
170
|
-
parts.push(`Found ${counts.join(", ")} across ${ctx.totalNodes} nodes scanned.`);
|
|
171
|
-
|
|
172
|
-
// Group issues by type for a richer summary
|
|
173
|
-
const issuesByType = new Map<string, WCAGIssue[]>();
|
|
174
|
-
for (const issue of issues) {
|
|
175
|
-
const key = issue.issue.split(".")[0].split(":")[0].trim();
|
|
176
|
-
const existing = issuesByType.get(key) || [];
|
|
177
|
-
existing.push(issue);
|
|
178
|
-
issuesByType.set(key, existing);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Show grouped issue summaries (up to 5 groups)
|
|
182
|
-
const groups = Array.from(issuesByType.entries()).slice(0, 5);
|
|
183
|
-
for (const [type, groupIssues] of groups) {
|
|
184
|
-
if (groupIssues.length === 1) {
|
|
185
|
-
const i = groupIssues[0];
|
|
186
|
-
parts.push(`- ${i.nodeName}: ${i.issue}`);
|
|
187
|
-
} else {
|
|
188
|
-
const nodeNames = groupIssues
|
|
189
|
-
.slice(0, 3)
|
|
190
|
-
.map((i) => i.nodeName)
|
|
191
|
-
.join(", ");
|
|
192
|
-
const suffix =
|
|
193
|
-
groupIssues.length > 3
|
|
194
|
-
? ` (+${groupIssues.length - 3} more)`
|
|
195
|
-
: "";
|
|
196
|
-
parts.push(`- ${type} — affects: ${nodeNames}${suffix}`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (issuesByType.size > 5) {
|
|
201
|
-
parts.push(
|
|
202
|
-
`... and ${issuesByType.size - 5} more issue categories.`
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Actionable fix guidance
|
|
207
|
-
const fixes = new Set<string>();
|
|
208
|
-
for (const issue of issues) {
|
|
209
|
-
if (issue.suggestedFix && fixes.size < 3) {
|
|
210
|
-
fixes.add(issue.suggestedFix);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (fixes.size > 0) {
|
|
214
|
-
parts.push("Recommended fixes:");
|
|
215
|
-
for (const fix of fixes) {
|
|
216
|
-
parts.push(` → ${fix}`);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
} else {
|
|
220
|
-
// ── No issues — heuristic or automated pass ───────────────────────────
|
|
221
|
-
parts.push(getPassRemarks(criterion, ctx));
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return parts.join("\n");
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
228
|
-
// Criterion-specific remark generators
|
|
229
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
230
|
-
|
|
231
|
-
function getNotApplicableReason(
|
|
232
|
-
criterion: WCAGCriterionDef,
|
|
233
|
-
ctx: DesignContext
|
|
234
|
-
): string {
|
|
235
|
-
const id = criterion.id;
|
|
236
|
-
|
|
237
|
-
// Time-based media criteria
|
|
238
|
-
if (id.startsWith("1.2")) {
|
|
239
|
-
return `Not applicable — "${ctx.frameName}" is a static UI design with no audio or video content. If the final product introduces media players or video embeds, re-evaluate this criterion.`;
|
|
240
|
-
}
|
|
241
|
-
if (id === "1.4.2") {
|
|
242
|
-
return `Not applicable — no auto-playing audio content detected in this static design. If the implementation adds background audio, sound effects, or media players, ensure a pause/stop/mute control is provided.`;
|
|
243
|
-
}
|
|
244
|
-
return `Not applicable to this design context. Re-evaluate if the implementation introduces related functionality.`;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function getDesignAwareManualGuidance(
|
|
248
|
-
criterion: WCAGCriterionDef,
|
|
249
|
-
ctx: DesignContext
|
|
250
|
-
): string {
|
|
251
|
-
const id = criterion.id;
|
|
252
|
-
const parts: string[] = [];
|
|
253
|
-
parts.push("[Manual Review Required]");
|
|
254
|
-
|
|
255
|
-
switch (id) {
|
|
256
|
-
// ── 1.2.x Time-based Media ──────────────────────────────────────────
|
|
257
|
-
case "1.2.1":
|
|
258
|
-
parts.push(
|
|
259
|
-
`This static design does not contain audio/video, but the final implementation for "${ctx.frameName}" may include media content.`,
|
|
260
|
-
"DEV ACTION: If any audio-only or video-only prerecorded content is added, provide a transcript (audio) or text/audio alternative (video).",
|
|
261
|
-
"QA CHECK: Verify transcripts are accurate and complete."
|
|
262
|
-
);
|
|
263
|
-
break;
|
|
264
|
-
case "1.2.2":
|
|
265
|
-
parts.push(
|
|
266
|
-
`No video content present in this Figma design.`,
|
|
267
|
-
"DEV ACTION: All prerecorded video with audio must include synchronised captions. Use WebVTT format. Ensure captions are accurate, synchronised, and include speaker identification.",
|
|
268
|
-
"QA CHECK: Review captions for accuracy and timing across all video content."
|
|
269
|
-
);
|
|
270
|
-
break;
|
|
271
|
-
case "1.2.3":
|
|
272
|
-
parts.push(
|
|
273
|
-
`No video content in this static design.`,
|
|
274
|
-
"DEV ACTION: Provide audio description or a full text alternative for prerecorded video. Audio descriptions should narrate visual-only information not conveyed through dialogue.",
|
|
275
|
-
"QA CHECK: Verify audio descriptions cover all visual information essential to understanding the content."
|
|
276
|
-
);
|
|
277
|
-
break;
|
|
278
|
-
case "1.2.4":
|
|
279
|
-
parts.push(
|
|
280
|
-
"DEV ACTION: If live video with audio is implemented, real-time captions must be provided. Consider integrating a live captioning service.",
|
|
281
|
-
"QA CHECK: Test live captioning accuracy and latency."
|
|
282
|
-
);
|
|
283
|
-
break;
|
|
284
|
-
case "1.2.5":
|
|
285
|
-
parts.push(
|
|
286
|
-
"DEV ACTION: Provide audio descriptions for all prerecorded video content where the soundtrack alone does not convey all visual information.",
|
|
287
|
-
"QA CHECK: Audio descriptions should cover actions, scene changes, and on-screen text not spoken in dialogue."
|
|
288
|
-
);
|
|
289
|
-
break;
|
|
290
|
-
|
|
291
|
-
// ── 1.3.3 Sensory Characteristics ───────────────────────────────────
|
|
292
|
-
case "1.3.3": {
|
|
293
|
-
parts.push(
|
|
294
|
-
`Design "${ctx.frameName}" contains ${ctx.textNodeCount} text elements.`
|
|
295
|
-
);
|
|
296
|
-
if (ctx.hasFormInputs) {
|
|
297
|
-
parts.push(
|
|
298
|
-
"RISK: Form instructions may rely on visual position (\"the field on the left\") or color (\"fields in red are required\"). Ensure all instructions also use text labels."
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
if (ctx.hasNavigation) {
|
|
302
|
-
parts.push(
|
|
303
|
-
"RISK: Navigation cues must not rely solely on shape or position. Ensure active/current state is conveyed through text (e.g., aria-current) not just color."
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
parts.push(
|
|
307
|
-
"DEV ACTION: Review all instructional text. Replace references like \"click the green button\" or \"see the sidebar\" with explicit labels. Use aria-describedby for supplementary instructions.",
|
|
308
|
-
"QA CHECK: Disable CSS and verify instructions still make sense without visual cues."
|
|
309
|
-
);
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// ── 2.1.x Keyboard Accessible ──────────────────────────────────────
|
|
314
|
-
case "2.1.1": {
|
|
315
|
-
parts.push(
|
|
316
|
-
`Design contains ${ctx.interactiveCount} interactive elements: ${summarizeInteractiveBreakdown(ctx)}.`
|
|
317
|
-
);
|
|
318
|
-
if (ctx.interactiveLabels.length > 0) {
|
|
319
|
-
const sample = ctx.interactiveLabels.slice(0, 6).join(", ");
|
|
320
|
-
parts.push(`Key elements to verify: ${sample}.`);
|
|
321
|
-
}
|
|
322
|
-
parts.push(
|
|
323
|
-
"DEV ACTION: All interactive elements must be operable via keyboard (Tab to focus, Enter/Space to activate). Custom widgets must implement WAI-ARIA APG keyboard patterns.",
|
|
324
|
-
"QA CHECK: Tab through every interactive element. Verify all actions are reachable and operable without a mouse. Test with screen reader in forms mode."
|
|
325
|
-
);
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
case "2.1.2": {
|
|
329
|
-
const trapRisks: string[] = [];
|
|
330
|
-
if (ctx.interactiveBreakdown["modal"] || ctx.interactiveBreakdown["dialog"])
|
|
331
|
-
trapRisks.push("modal dialogs (must trap focus but allow Esc to dismiss)");
|
|
332
|
-
if (ctx.hasFormInputs)
|
|
333
|
-
trapRisks.push("form fields with autocomplete dropdowns");
|
|
334
|
-
if (ctx.interactiveBreakdown["menu"])
|
|
335
|
-
trapRisks.push("menus/dropdowns");
|
|
336
|
-
|
|
337
|
-
parts.push(
|
|
338
|
-
`Design has ${ctx.interactiveCount} interactive elements.`
|
|
339
|
-
);
|
|
340
|
-
if (trapRisks.length > 0) {
|
|
341
|
-
parts.push(`Keyboard trap risk areas: ${trapRisks.join("; ")}.`);
|
|
342
|
-
}
|
|
343
|
-
parts.push(
|
|
344
|
-
"DEV ACTION: Ensure focus can always be moved away using standard keys (Tab, Shift+Tab, Escape). For modals, trap focus within the dialog but allow Escape to close.",
|
|
345
|
-
"QA CHECK: Navigate with keyboard only through all interactive paths. Verify you can always Tab away or Escape out."
|
|
346
|
-
);
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
case "2.1.4":
|
|
350
|
-
parts.push(
|
|
351
|
-
"DEV ACTION: If single character key shortcuts (e.g., 'S' for search, 'N' for next) are implemented, provide settings to remap or disable them. Modifier-key shortcuts (Ctrl+S) are exempt.",
|
|
352
|
-
"QA CHECK: Test that all single-key shortcuts can be turned off or remapped."
|
|
353
|
-
);
|
|
354
|
-
break;
|
|
355
|
-
|
|
356
|
-
// ── 2.2.x Enough Time ──────────────────────────────────────────────
|
|
357
|
-
case "2.2.1":
|
|
358
|
-
parts.push(
|
|
359
|
-
`Review "${ctx.frameName}" implementation for any time-limited interactions (session timeouts, auto-advancing carousels, countdown timers).`,
|
|
360
|
-
"DEV ACTION: For each time limit, provide controls to extend (10x default), turn off, or adjust the limit. Warn users at least 20 seconds before expiry.",
|
|
361
|
-
"QA CHECK: Identify all time-limited interactions and verify extension mechanisms work."
|
|
362
|
-
);
|
|
363
|
-
break;
|
|
364
|
-
case "2.2.2":
|
|
365
|
-
parts.push(
|
|
366
|
-
"DEV ACTION: Any auto-moving, blinking, or auto-updating content must have a pause/stop/hide mechanism. This includes carousels, news tickers, and real-time updates.",
|
|
367
|
-
"QA CHECK: Verify the pause mechanism persists across page interactions."
|
|
368
|
-
);
|
|
369
|
-
break;
|
|
370
|
-
|
|
371
|
-
// ── 2.3.x Seizures ────────────────────────────────────────────────
|
|
372
|
-
case "2.3.1":
|
|
373
|
-
parts.push(
|
|
374
|
-
"DEV ACTION: No content should flash more than 3 times per second. This applies to animations, video, GIFs, and CSS transitions. Use the Photosensitive Epilepsy Analysis Tool (PEAT) to test.",
|
|
375
|
-
"QA CHECK: Review all animations and transitions for flash frequency."
|
|
376
|
-
);
|
|
377
|
-
break;
|
|
378
|
-
|
|
379
|
-
// ── 2.4.x Navigable ───────────────────────────────────────────────
|
|
380
|
-
case "2.4.1": {
|
|
381
|
-
parts.push(
|
|
382
|
-
`Design "${ctx.frameName}" has ${ctx.landmarkNames.length > 0 ? "landmarks: " + ctx.landmarkNames.join(", ") : "no detected landmark regions"}.`
|
|
383
|
-
);
|
|
384
|
-
if (ctx.hasNavigation) {
|
|
385
|
-
parts.push(
|
|
386
|
-
"IMPORTANT: Navigation block detected — a skip link must be provided to bypass repeated navigation and jump to main content."
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
parts.push(
|
|
390
|
-
"DEV ACTION: Add a visually hidden \"Skip to main content\" link as the first focusable element. Implement ARIA landmarks: <nav>, <main>, <header>, <footer>. These provide screen reader skip navigation.",
|
|
391
|
-
"QA CHECK: Tab to the first element — verify a skip link appears. Test with screen reader landmark navigation (NVDA: D key, VoiceOver: rotor)."
|
|
392
|
-
);
|
|
393
|
-
break;
|
|
394
|
-
}
|
|
395
|
-
case "2.4.2":
|
|
396
|
-
parts.push(
|
|
397
|
-
`This page is named "${ctx.frameName}" in Figma. The HTML <title> must describe the page's topic and purpose.`,
|
|
398
|
-
"DEV ACTION: Set a descriptive <title> like \"Checkout - Address Selection | Store Name\". For SPAs, update document.title on route change.",
|
|
399
|
-
"QA CHECK: Check browser tab for a meaningful, unique title on every page/view."
|
|
400
|
-
);
|
|
401
|
-
break;
|
|
402
|
-
case "2.4.5":
|
|
403
|
-
parts.push(
|
|
404
|
-
`Design contains navigation elements.`,
|
|
405
|
-
"DEV ACTION: Provide at least two ways to find any page: navigation menu, site search, sitemap, table of contents, or A-Z index.",
|
|
406
|
-
"QA CHECK: Verify users can reach every page through at least two distinct mechanisms."
|
|
407
|
-
);
|
|
408
|
-
break;
|
|
409
|
-
|
|
410
|
-
// ── 2.5.x Input Modalities ────────────────────────────────────────
|
|
411
|
-
case "2.5.1":
|
|
412
|
-
parts.push(
|
|
413
|
-
"DEV ACTION: All multipoint gestures (pinch-zoom, two-finger scroll, multi-finger swipe) must have single-pointer alternatives (e.g., +/- buttons for zoom).",
|
|
414
|
-
"QA CHECK: Disable multi-touch and verify all features remain accessible via single tap/click."
|
|
415
|
-
);
|
|
416
|
-
break;
|
|
417
|
-
case "2.5.2":
|
|
418
|
-
parts.push(
|
|
419
|
-
"DEV ACTION: Actions must activate on pointer-up (not pointer-down), and the user must be able to abort by moving the pointer away before releasing. This applies to all buttons and interactive elements.",
|
|
420
|
-
"QA CHECK: Press and hold an interactive element, move pointer away, and release — verify no activation occurs."
|
|
421
|
-
);
|
|
422
|
-
break;
|
|
423
|
-
case "2.5.4":
|
|
424
|
-
parts.push(
|
|
425
|
-
"DEV ACTION: Any functionality triggered by device motion (shake to undo, tilt to scroll) must also have a UI button alternative, and motion triggering must be disableable to prevent accidental activation.",
|
|
426
|
-
"QA CHECK: Verify all motion-triggered features have equivalent button controls."
|
|
427
|
-
);
|
|
428
|
-
break;
|
|
429
|
-
case "2.5.7":
|
|
430
|
-
parts.push(
|
|
431
|
-
"DEV ACTION: Drag-and-drop functionality (e.g., reordering lists) must have a single-pointer alternative (e.g., move up/down buttons or a sort dialog).",
|
|
432
|
-
"QA CHECK: Test all drag interactions without dragging — verify alternative controls exist."
|
|
433
|
-
);
|
|
434
|
-
break;
|
|
435
|
-
|
|
436
|
-
// ── 3.1.x Readable ────────────────────────────────────────────────
|
|
437
|
-
case "3.1.1":
|
|
438
|
-
parts.push(
|
|
439
|
-
"DEV ACTION: Set lang attribute on <html> element matching the primary language of the content (e.g., <html lang=\"en\">). This enables correct screen reader pronunciation.",
|
|
440
|
-
"QA CHECK: Inspect <html> element and verify lang attribute is present and correct."
|
|
441
|
-
);
|
|
442
|
-
break;
|
|
443
|
-
case "3.1.2": {
|
|
444
|
-
parts.push(
|
|
445
|
-
"DEV ACTION: Wrap any content in a different language with the appropriate lang attribute (e.g., <span lang=\"fr\">Bonjour</span>). This allows screen readers to switch pronunciation.",
|
|
446
|
-
"QA CHECK: Review text content for foreign-language phrases and verify lang attributes."
|
|
447
|
-
);
|
|
448
|
-
break;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// ── 3.2.x Predictable ─────────────────────────────────────────────
|
|
452
|
-
case "3.2.1":
|
|
453
|
-
parts.push(
|
|
454
|
-
`Design has ${ctx.interactiveCount} focusable elements.`,
|
|
455
|
-
"DEV ACTION: No element should trigger a context change (page navigation, new window, form submission) simply by receiving focus. Activations must require explicit user action (click/Enter).",
|
|
456
|
-
"QA CHECK: Tab through all elements and verify no unexpected navigation or popups occur on focus alone."
|
|
457
|
-
);
|
|
458
|
-
break;
|
|
459
|
-
case "3.2.2": {
|
|
460
|
-
parts.push(
|
|
461
|
-
`Design contains ${ctx.hasFormInputs ? "form inputs that" : "interactive elements that"} must not auto-submit or navigate on value change.`
|
|
462
|
-
);
|
|
463
|
-
if (ctx.hasFormInputs) {
|
|
464
|
-
parts.push(
|
|
465
|
-
"RISK: Dropdowns and radio buttons that immediately navigate or submit without a dedicated \"Apply\" or \"Submit\" button violate this criterion."
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
parts.push(
|
|
469
|
-
"DEV ACTION: Do not auto-submit forms or navigate on select/radio change unless users are warned in advance. Provide explicit submit buttons.",
|
|
470
|
-
"QA CHECK: Change every form control value and verify no unexpected page changes occur."
|
|
471
|
-
);
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
474
|
-
case "3.2.3":
|
|
475
|
-
parts.push(
|
|
476
|
-
`Navigation structure in "${ctx.frameName}" must remain consistent across all pages.`,
|
|
477
|
-
"DEV ACTION: Navigation menus must appear in the same position and order on every page. New items may be added but existing item order must be preserved.",
|
|
478
|
-
"QA CHECK: Compare navigation across multiple pages — verify order and position are consistent."
|
|
479
|
-
);
|
|
480
|
-
break;
|
|
481
|
-
case "3.2.4":
|
|
482
|
-
parts.push(
|
|
483
|
-
"DEV ACTION: Components with the same function must use the same labels and icons across all pages (e.g., don't use \"Search\" on one page and \"Find\" on another for the same feature).",
|
|
484
|
-
"QA CHECK: Cross-reference common actions (search, save, delete) across pages for consistency."
|
|
485
|
-
);
|
|
486
|
-
break;
|
|
487
|
-
case "3.2.6":
|
|
488
|
-
parts.push(
|
|
489
|
-
"DEV ACTION: If help mechanisms exist (contact info, chat widget, FAQ link), place them in the same relative position on every page.",
|
|
490
|
-
"QA CHECK: Verify help mechanism position is consistent across all pages."
|
|
491
|
-
);
|
|
492
|
-
break;
|
|
493
|
-
|
|
494
|
-
// ── 3.3.x Input Assistance ────────────────────────────────────────
|
|
495
|
-
case "3.3.4": {
|
|
496
|
-
parts.push(
|
|
497
|
-
`"${ctx.frameName}" ${ctx.hasFormInputs ? "contains form inputs" : "may involve data submission"}.`
|
|
498
|
-
);
|
|
499
|
-
parts.push(
|
|
500
|
-
"IMPORTANT: If this page involves financial transactions, legal commitments, or user-controlled data: (1) submissions must be reversible, (2) data must be checked for errors and the user given an opportunity to correct, or (3) a confirmation/review step must be provided before final submission.",
|
|
501
|
-
"DEV ACTION: Add a review step before checkout/payment. Show a summary of all entered data with an \"Edit\" option. Provide \"Undo\" for irreversible actions.",
|
|
502
|
-
"QA CHECK: Complete a full transaction flow and verify there is a review/confirmation step before final submission."
|
|
503
|
-
);
|
|
504
|
-
break;
|
|
505
|
-
}
|
|
506
|
-
case "3.3.7": {
|
|
507
|
-
parts.push(
|
|
508
|
-
`"${ctx.frameName}" ${ctx.hasFormInputs ? "contains form fields" : "may be part of a multi-step flow"}.`
|
|
509
|
-
);
|
|
510
|
-
parts.push(
|
|
511
|
-
"DEV ACTION: If the user has already provided information in a previous step (name, address, email), auto-populate it or offer a selection rather than requiring re-entry.",
|
|
512
|
-
"QA CHECK: Walk through multi-step flows and verify previously entered data is not requested again."
|
|
513
|
-
);
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
516
|
-
case "3.3.8":
|
|
517
|
-
parts.push(
|
|
518
|
-
"DEV ACTION: Authentication must not require cognitive function tests (CAPTCHAs, puzzles). Allow password managers, passkeys, and WebAuthn. If CAPTCHAs are used, provide an audio alternative.",
|
|
519
|
-
"QA CHECK: Test login/auth flows with a password manager and verify it works without cognitive tests."
|
|
520
|
-
);
|
|
521
|
-
break;
|
|
522
|
-
|
|
523
|
-
// ── 4.1.x Robust ──────────────────────────────────────────────────
|
|
524
|
-
case "4.1.3": {
|
|
525
|
-
parts.push(
|
|
526
|
-
`Design "${ctx.frameName}" has ${ctx.interactiveCount} interactive elements that may produce status messages.`
|
|
527
|
-
);
|
|
528
|
-
parts.push(
|
|
529
|
-
"DEV ACTION: Status messages (success confirmations, error counts, search result counts, cart updates) must use aria-live regions or appropriate ARIA roles (role=\"status\", role=\"alert\") so screen readers announce them without focus moving.",
|
|
530
|
-
"IMPLEMENTATION: Use role=\"status\" + aria-live=\"polite\" for non-urgent updates (cart count, search results). Use role=\"alert\" + aria-live=\"assertive\" for errors or urgent messages.",
|
|
531
|
-
"QA CHECK: Trigger status messages (add to cart, form submission, search) and verify screen reader announces them without focus change."
|
|
532
|
-
);
|
|
533
|
-
break;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
default:
|
|
537
|
-
// Fallback: use the criterion's manual guidance with design context
|
|
538
|
-
parts.push(criterion.manualGuidance);
|
|
539
|
-
if (ctx.interactiveCount > 0) {
|
|
540
|
-
parts.push(
|
|
541
|
-
`This design contains ${ctx.interactiveCount} interactive elements and ${ctx.textNodeCount} text nodes that should be reviewed against this criterion.`
|
|
542
|
-
);
|
|
543
|
-
}
|
|
544
|
-
parts.push(`DEV ACTION: Review the implementation of "${ctx.frameName}" against this WCAG criterion during development and QA testing.`);
|
|
545
|
-
break;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
return parts.join("\n");
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
/** Provide rich pass remarks for heuristic/automated checks with no issues */
|
|
552
|
-
function getPassRemarks(
|
|
553
|
-
criterion: WCAGCriterionDef,
|
|
554
|
-
ctx: DesignContext
|
|
555
|
-
): string {
|
|
556
|
-
const id = criterion.id;
|
|
557
|
-
const isHeuristic = criterion.checkCapability === "heuristic";
|
|
558
|
-
const prefix = isHeuristic
|
|
559
|
-
? "No issues detected via heuristic analysis."
|
|
560
|
-
: "All automated checks passed.";
|
|
561
|
-
|
|
562
|
-
switch (id) {
|
|
563
|
-
case "1.1.1":
|
|
564
|
-
return `${prefix} Scanned ${ctx.imageCount} image/vector nodes — all have adjacent text labels or descriptive naming.\nDEV ACTION: Verify each image has appropriate alt text in HTML. Decorative images should use alt="" and role="presentation". Icons should use aria-label or sr-only text.\nMANUAL VERIFY: Check that alt text accurately describes the image purpose, not just the file name.`;
|
|
565
|
-
|
|
566
|
-
case "1.3.1":
|
|
567
|
-
return `${prefix} Detected ${ctx.hasHeadings ? "heading hierarchy from font size/weight" : "no clear heading hierarchy"}. Found ${ctx.textNodeCount} text nodes with ${ctx.headingTexts.length > 0 ? "headings: " + ctx.headingTexts.slice(0, 4).join(", ") : "no headings detected"}.\nDEV ACTION: Map visual heading hierarchy to semantic HTML (h1-h6). Use <ul>/<ol> for lists, <table> for tabular data. Group related form fields in <fieldset> with <legend>.\nMANUAL VERIFY: Ensure heading levels don't skip (e.g., h1 → h3) and all sections have headings.`;
|
|
568
|
-
|
|
569
|
-
case "1.3.2":
|
|
570
|
-
return `${prefix} Compared Figma layer order against visual layout positions for ${ctx.frameCount} frames.\nDEV ACTION: Ensure DOM order matches visual reading order (top-to-bottom, left-to-right in LTR layouts). Use CSS for visual positioning, not DOM re-ordering. Test with CSS disabled.\nMANUAL VERIFY: Read the page with styles disabled — content should still make logical sense.`;
|
|
571
|
-
|
|
572
|
-
case "1.3.4":
|
|
573
|
-
return `${prefix} Design layout appears to be single-orientation.\nDEV ACTION: Do not lock viewport orientation with CSS (orientation: portrait). Content must work in both portrait and landscape unless a specific orientation is essential (e.g., piano app).\nMANUAL VERIFY: Test on mobile in both orientations.`;
|
|
574
|
-
|
|
575
|
-
case "1.3.5":
|
|
576
|
-
return `${prefix} Scanned ${ctx.interactiveCount} interactive elements for autocomplete purpose hints.\nDEV ACTION: Add autocomplete attributes to inputs collecting personal data: autocomplete="name", "email", "tel", "address-line1", etc. This enables browser auto-fill and helps users with cognitive disabilities.\nMANUAL VERIFY: Test that browser auto-fill populates form fields correctly.`;
|
|
577
|
-
|
|
578
|
-
case "1.4.1":
|
|
579
|
-
return `${prefix} Checked ${ctx.componentSetCount} component sets for color-only state differentiation.\nDEV ACTION: Ensure states (error, success, active, disabled) use icons, text, or borders in addition to color. Error states should have error icons + text, not just red coloring.\nMANUAL VERIFY: View the interface in grayscale (browser devtools) — all states should still be distinguishable.`;
|
|
580
|
-
|
|
581
|
-
case "1.4.3":
|
|
582
|
-
return `All ${ctx.textNodeCount} text nodes meet WCAG AA minimum contrast ratio (4.5:1 for normal text, 3:1 for large text 18px+/14px bold+).\nPASS DETAILS: All foreground/background pairs analysed from Figma fill properties.\nMANUAL VERIFY: Check contrast for text rendered over images, gradients, or dynamic backgrounds that may not be captured in static design.`;
|
|
583
|
-
|
|
584
|
-
case "1.4.4":
|
|
585
|
-
return `${prefix} No fixed-height containers with text children that would clip on resize were detected.\nDEV ACTION: Use relative units (rem, em, %) for typography and containers. Text must be resizable up to 200% without content loss.\nMANUAL VERIFY: Zoom browser to 200% and verify no text is clipped, overlaps, or becomes unreadable.`;
|
|
586
|
-
|
|
587
|
-
case "1.4.5":
|
|
588
|
-
return `${prefix} No rasterised text (images of text) detected.\nDEV ACTION: Always use real HTML text, not images of text. Exceptions: logos and cases where a particular visual presentation is essential.\nMANUAL VERIFY: Verify no text is embedded in images — select all text on the page to confirm.`;
|
|
589
|
-
|
|
590
|
-
case "1.4.10":
|
|
591
|
-
return `${prefix} Checked ${ctx.frameCount} frames for auto-layout usage and responsive constraints. ${ctx.hasAutoLayout ? "Auto-layout detected — good foundation for reflow." : "Warning: Limited auto-layout usage may indicate reflow issues."}\nDEV ACTION: Content must reflow to single-column at 320px viewport width without horizontal scrolling. Use CSS flexbox/grid with relative units.\nMANUAL VERIFY: Test at 320px wide viewport and 256px tall viewport.`;
|
|
592
|
-
|
|
593
|
-
case "1.4.11":
|
|
594
|
-
return `All ${ctx.interactiveCount} interactive element borders and icons meet 3:1 minimum contrast ratio against their backgrounds.\nDEV ACTION: UI components (buttons, form inputs, focus indicators) and meaningful graphics must maintain 3:1 contrast. This includes borders, icons, and graphical objects.\nMANUAL VERIFY: Check custom UI elements and state changes (hover, focus) maintain contrast.`;
|
|
595
|
-
|
|
596
|
-
case "1.4.12":
|
|
597
|
-
return `All ${ctx.textNodeCount} text nodes pass text spacing requirements.\nPASS DETAILS: Line height ≥ 1.5× font size, paragraph spacing ≥ 2× font size, letter spacing ≥ 0.12× font size, word spacing ≥ 0.16× font size.\nDEV ACTION: No content loss when users override text spacing. Avoid fixed-height containers for text. Use CSS that allows spacing overrides.\nMANUAL VERIFY: Apply the WCAG text spacing bookmarklet and verify no text is clipped.`;
|
|
598
|
-
|
|
599
|
-
case "1.4.13":
|
|
600
|
-
return `${prefix} Checked ${ctx.componentSetCount} component sets for hover/tooltip patterns.\nDEV ACTION: Content appearing on hover/focus must be: (1) dismissable with Escape key without moving focus, (2) hoverable — pointer can move over the new content without it disappearing, (3) persistent — remains visible until dismissed or focus moves.\nMANUAL VERIFY: Test all tooltips and hover content for these three requirements.`;
|
|
601
|
-
|
|
602
|
-
case "2.4.3":
|
|
603
|
-
return `${prefix} Compared interactive element positions against node tree order for ${ctx.interactiveCount} elements.\nDEV ACTION: Tab order should follow the visual reading order (generally top-to-bottom, left-to-right). Use tabindex="0" for custom interactive elements. Avoid tabindex > 0. Use CSS for layout, not DOM order changes.\nMANUAL VERIFY: Tab through the entire page and verify focus moves logically.`;
|
|
604
|
-
|
|
605
|
-
case "2.4.4":
|
|
606
|
-
return `${prefix} All link-like elements have descriptive text labels.\nDEV ACTION: Avoid generic link text ("Click here", "Read more", "Learn more"). If visual design requires short text, use aria-label or visually hidden text for full context (e.g., "Read more about Product Name").\nMANUAL VERIFY: List all links (NVDA: Insert+F7) — each should be understandable out of context.`;
|
|
607
|
-
|
|
608
|
-
case "2.4.6":
|
|
609
|
-
return `${prefix} Checked ${ctx.frameCount} sections for heading and label presence. ${ctx.headingTexts.length > 0 ? "Headings found: " + ctx.headingTexts.slice(0, 5).join(", ") + "." : "No headings detected."}\nDEV ACTION: Every section must have a descriptive heading. Form fields must have visible labels (not just placeholder text). Labels must describe the purpose of the input.\nMANUAL VERIFY: Confirm every section has a heading and every input has a persistent visible label.`;
|
|
610
|
-
|
|
611
|
-
case "2.4.7":
|
|
612
|
-
return `${prefix} Checked component sets for visible focus-state variants.\nDEV ACTION: All focusable elements must show a visible focus indicator. Default browser focus ring is acceptable. Custom focus styles must meet 3:1 contrast and at least 2px outline.\nMANUAL VERIFY: Tab through all elements and verify a clearly visible focus ring appears on each.`;
|
|
613
|
-
|
|
614
|
-
case "2.4.11":
|
|
615
|
-
return `${prefix} Checked component sets for focus indicator obscuration.\nDEV ACTION: When an element receives focus, it must not be completely hidden by other content (sticky headers, modals, toasts). Use scroll-margin to ensure focused elements are visible.\nMANUAL VERIFY: Tab through elements near sticky headers/footers and verify focus is never hidden.`;
|
|
616
|
-
|
|
617
|
-
case "2.5.3":
|
|
618
|
-
return `${prefix} Checked interactive components for label-in-name match.\nDEV ACTION: The accessible name (aria-label, alt text) must include the visible text label. e.g., if a button shows "Search", the accessible name should contain "Search" (not just "Magnifying glass icon").\nMANUAL VERIFY: For each labeled interactive element, verify that speaking the visible text activates it in voice control (Dragon NaturallySpeaking, Voice Control).`;
|
|
619
|
-
|
|
620
|
-
case "2.5.5":
|
|
621
|
-
return `All ${ctx.interactiveCount} interactive elements meet the enhanced 44×44px target size.\nDEV ACTION: Maintain minimum 44×44 CSS pixel click/tap targets. Smaller targets are allowed if an equivalent larger target exists, or spacing ensures no overlap.\nMANUAL VERIFY: Test on actual touch devices — verify all targets are easy to tap accurately.`;
|
|
622
|
-
|
|
623
|
-
case "2.5.8":
|
|
624
|
-
return `All ${ctx.interactiveCount} interactive elements meet the minimum 24×24px target size.\nDEV ACTION: Maintain at least 24×24 CSS pixel targets for pointer inputs. Inline links within text are exempt. Ensure spacing between adjacent targets prevents accidental activation.\nMANUAL VERIFY: Test on mobile — verify no adjacent targets cause mis-taps.`;
|
|
625
|
-
|
|
626
|
-
case "3.3.1":
|
|
627
|
-
return `${prefix} Checked ${ctx.componentSetCount} component sets for error-state variants with descriptive text.\nDEV ACTION: Error messages must: (1) identify the field in error, (2) describe the error in text, (3) not rely solely on color. Use aria-invalid="true" and aria-describedby pointing to the error message.\nMANUAL VERIFY: Trigger validation errors and verify screen reader announces which field has the error and what the error is.`;
|
|
628
|
-
|
|
629
|
-
case "3.3.2":
|
|
630
|
-
return `${prefix} Checked ${ctx.interactiveCount} interactive elements for visible label siblings.\nDEV ACTION: Every input must have a visible label (not just placeholder). Use <label for="id"> associations. Group related inputs in <fieldset> with <legend>. Provide format hints (e.g., "MM/DD/YYYY").\nMANUAL VERIFY: Clear all inputs and verify each has a persistent visible label that describes its purpose.`;
|
|
631
|
-
|
|
632
|
-
case "3.3.3":
|
|
633
|
-
return `${prefix} Error-state variants checked for suggestion text.\nDEV ACTION: When input errors are detected and corrections are known, suggest the fix (e.g., "Email must contain @" not just "Invalid email"). For constrained values, show valid options.\nMANUAL VERIFY: Trigger validation errors and verify helpful correction suggestions appear.`;
|
|
634
|
-
|
|
635
|
-
case "4.1.2":
|
|
636
|
-
return `${prefix} Checked ${ctx.interactiveCount} interactive elements for name/description properties and visible labels.\nDEV ACTION: Every interactive element must expose: (1) name — accessible label (aria-label, <label>, alt text), (2) role — element type (button, link, textbox) via semantic HTML or ARIA, (3) value — current state (checked, expanded, selected) via ARIA properties.\nMANUAL VERIFY: Test with screen reader — each element should announce its name, role, and state.`;
|
|
637
|
-
|
|
638
|
-
default:
|
|
639
|
-
return `${prefix} ${criterion.figmaRelevance}\nMANUAL VERIFY: ${criterion.manualGuidance}`;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
function summarizeInteractiveBreakdown(ctx: DesignContext): string {
|
|
644
|
-
const entries = Object.entries(ctx.interactiveBreakdown);
|
|
645
|
-
if (entries.length === 0) return "no categorized elements";
|
|
646
|
-
return entries
|
|
647
|
-
.filter(([, count]) => count > 0)
|
|
648
|
-
.map(([type, count]) => `${count} ${type}${count > 1 ? "s" : ""}`)
|
|
649
|
-
.join(", ");
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
653
|
-
// Markdown formatter
|
|
654
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
655
|
-
|
|
656
|
-
function formatMarkdownReport(
|
|
657
|
-
report: Omit<VPATReport, "formattedReport">
|
|
658
|
-
): string {
|
|
659
|
-
const lines: string[] = [];
|
|
660
|
-
|
|
661
|
-
lines.push(`# WCAG 2.2 Level ${report.evaluatedLevel} — Accessibility Conformance Report`);
|
|
662
|
-
lines.push("");
|
|
663
|
-
lines.push(`**Product:** ${report.nodeName} (Node ${report.nodeId})`);
|
|
664
|
-
lines.push(`**Date:** ${report.evaluationDate}`);
|
|
665
|
-
lines.push(`**WCAG Version:** ${report.wcagVersion}`);
|
|
666
|
-
lines.push(`**Evaluation Level:** ${report.evaluatedLevel}`);
|
|
667
|
-
lines.push("");
|
|
668
|
-
|
|
669
|
-
// Summary
|
|
670
|
-
lines.push("## Summary");
|
|
671
|
-
lines.push("");
|
|
672
|
-
lines.push(`| Metric | Count |`);
|
|
673
|
-
lines.push(`|--------|-------|`);
|
|
674
|
-
lines.push(`| Total Criteria | ${report.summary.totalCriteria} |`);
|
|
675
|
-
lines.push(`| Supports | ${report.summary.supports} |`);
|
|
676
|
-
lines.push(`| Partially Supports | ${report.summary.partiallySupports} |`);
|
|
677
|
-
lines.push(`| Does Not Support | ${report.summary.doesNotSupport} |`);
|
|
678
|
-
lines.push(`| Not Applicable | ${report.summary.notApplicable} |`);
|
|
679
|
-
lines.push(`| Not Evaluated (Manual Review) | ${report.summary.notEvaluated} |`);
|
|
680
|
-
lines.push("");
|
|
681
|
-
lines.push(
|
|
682
|
-
`> **Automated checks:** ${report.summary.automatedChecks} | **Heuristic checks:** ${report.summary.heuristicChecks} | **Manual review required:** ${report.summary.manualReviewRequired}`
|
|
683
|
-
);
|
|
684
|
-
lines.push("");
|
|
685
|
-
|
|
686
|
-
// Per-principle tables
|
|
687
|
-
const principleOrder: WCAGPrinciple[] = [
|
|
688
|
-
"Perceivable",
|
|
689
|
-
"Operable",
|
|
690
|
-
"Understandable",
|
|
691
|
-
"Robust",
|
|
692
|
-
];
|
|
693
|
-
|
|
694
|
-
for (const principle of principleOrder) {
|
|
695
|
-
const rows = report.principles[principle];
|
|
696
|
-
if (rows.length === 0) continue;
|
|
697
|
-
|
|
698
|
-
lines.push(`## ${principle}`);
|
|
699
|
-
lines.push("");
|
|
700
|
-
lines.push(
|
|
701
|
-
`| SC | Name | Level | Conformance | Check | Remarks |`
|
|
702
|
-
);
|
|
703
|
-
lines.push(
|
|
704
|
-
`|----|------|-------|-------------|-------|---------|`
|
|
705
|
-
);
|
|
706
|
-
|
|
707
|
-
for (const row of rows) {
|
|
708
|
-
const statusIcon = getStatusIcon(row.conformanceStatus);
|
|
709
|
-
// Truncate remarks for table readability
|
|
710
|
-
const shortRemarks = truncateRemarks(row.remarks, 200);
|
|
711
|
-
lines.push(
|
|
712
|
-
`| ${row.criterionId} | ${row.criterionName} | ${row.level} | ${statusIcon} ${row.conformanceStatus} | ${row.checkType} | ${shortRemarks} |`
|
|
713
|
-
);
|
|
714
|
-
}
|
|
715
|
-
lines.push("");
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// Detailed remarks section — full content for every criterion
|
|
719
|
-
lines.push("## Detailed Assessment");
|
|
720
|
-
lines.push("");
|
|
721
|
-
|
|
722
|
-
for (const principle of principleOrder) {
|
|
723
|
-
const rows = report.principles[principle];
|
|
724
|
-
if (rows.length === 0) continue;
|
|
725
|
-
|
|
726
|
-
lines.push(`### ${principle}`);
|
|
727
|
-
lines.push("");
|
|
728
|
-
|
|
729
|
-
for (const row of rows) {
|
|
730
|
-
const statusIcon = getStatusIcon(row.conformanceStatus);
|
|
731
|
-
lines.push(`#### ${row.criterionId} ${row.criterionName} — ${statusIcon} ${row.conformanceStatus}`);
|
|
732
|
-
lines.push("");
|
|
733
|
-
lines.push(row.remarks);
|
|
734
|
-
lines.push("");
|
|
735
|
-
|
|
736
|
-
// Include specific issues if any
|
|
737
|
-
if (row.issues.length > 0) {
|
|
738
|
-
lines.push("**Issues:**");
|
|
739
|
-
for (const issue of row.issues) {
|
|
740
|
-
const severity = issue.severity.toUpperCase();
|
|
741
|
-
lines.push(
|
|
742
|
-
`- **[${severity}]** \`${issue.nodeName}\` (${issue.nodeId}): ${issue.issue}`
|
|
743
|
-
);
|
|
744
|
-
if (issue.currentValue) {
|
|
745
|
-
lines.push(` - Current: ${issue.currentValue}`);
|
|
746
|
-
}
|
|
747
|
-
if (issue.suggestedFix) {
|
|
748
|
-
lines.push(` - Fix: ${issue.suggestedFix}`);
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
lines.push("");
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
return lines.join("\n");
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
function getStatusIcon(status: ConformanceStatus): string {
|
|
760
|
-
switch (status) {
|
|
761
|
-
case "Supports":
|
|
762
|
-
return "[PASS]";
|
|
763
|
-
case "Partially Supports":
|
|
764
|
-
return "[PARTIAL]";
|
|
765
|
-
case "Does Not Support":
|
|
766
|
-
return "[FAIL]";
|
|
767
|
-
case "Not Applicable":
|
|
768
|
-
return "[N/A]";
|
|
769
|
-
case "Not Evaluated":
|
|
770
|
-
return "[REVIEW]";
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
function truncateRemarks(text: string, maxLen: number): string {
|
|
775
|
-
// For table display, take only the first line/sentence
|
|
776
|
-
const firstLine = text.split("\n")[0];
|
|
777
|
-
if (firstLine.length <= maxLen) return firstLine;
|
|
778
|
-
return firstLine.slice(0, maxLen - 3) + "...";
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
782
|
-
// Main builder
|
|
783
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* Build a VPAT-style accessibility conformance report.
|
|
787
|
-
*
|
|
788
|
-
* @param evaluatedLevel - WCAG conformance level to evaluate
|
|
789
|
-
* @param nodeId - Figma node ID that was audited
|
|
790
|
-
* @param nodeName - Human-readable name of the audited node
|
|
791
|
-
* @param issues - All issues found by the checker functions
|
|
792
|
-
* @param designContext - Summary of design contents for contextual remarks
|
|
793
|
-
* @param applicabilityOverrides - Optional overrides for specific SC (e.g. mark media criteria as N/A)
|
|
794
|
-
*/
|
|
795
|
-
export function buildVPATReport(
|
|
796
|
-
evaluatedLevel: WCAGLevel,
|
|
797
|
-
nodeId: string,
|
|
798
|
-
nodeName: string,
|
|
799
|
-
issues: WCAGIssue[],
|
|
800
|
-
designContext?: DesignContext,
|
|
801
|
-
applicabilityOverrides?: Record<string, ConformanceStatus>
|
|
802
|
-
): VPATReport {
|
|
803
|
-
const criteria = getCriteriaForLevel(evaluatedLevel);
|
|
804
|
-
const today = new Date().toISOString().split("T")[0];
|
|
805
|
-
|
|
806
|
-
// Default context if not provided (backwards compatibility)
|
|
807
|
-
const ctx: DesignContext = designContext || {
|
|
808
|
-
frameName: nodeName,
|
|
809
|
-
totalNodes: 0,
|
|
810
|
-
textNodeCount: 0,
|
|
811
|
-
interactiveCount: 0,
|
|
812
|
-
imageCount: 0,
|
|
813
|
-
componentSetCount: 0,
|
|
814
|
-
frameCount: 0,
|
|
815
|
-
landmarkNames: [],
|
|
816
|
-
interactiveLabels: [],
|
|
817
|
-
hasFormInputs: false,
|
|
818
|
-
hasNavigation: false,
|
|
819
|
-
hasImages: false,
|
|
820
|
-
hasHeadings: false,
|
|
821
|
-
headingTexts: [],
|
|
822
|
-
hasAutoLayout: false,
|
|
823
|
-
sampleTexts: [],
|
|
824
|
-
interactiveBreakdown: {},
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
// Group issues by criterion ID (match the leading SC number)
|
|
828
|
-
const issuesByCriterion = new Map<string, WCAGIssue[]>();
|
|
829
|
-
for (const issue of issues) {
|
|
830
|
-
// The criterion field may be "1.4.3" or "1.4.3 Contrast (Minimum)"
|
|
831
|
-
const scId = issue.criterion.split(" ")[0];
|
|
832
|
-
const existing = issuesByCriterion.get(scId) || [];
|
|
833
|
-
existing.push(issue);
|
|
834
|
-
issuesByCriterion.set(scId, existing);
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
const rows: VPATRow[] = [];
|
|
838
|
-
const principles: Record<WCAGPrinciple, VPATRow[]> = {
|
|
839
|
-
Perceivable: [],
|
|
840
|
-
Operable: [],
|
|
841
|
-
Understandable: [],
|
|
842
|
-
Robust: [],
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
for (const criterion of criteria) {
|
|
846
|
-
const scIssues = issuesByCriterion.get(criterion.id) || [];
|
|
847
|
-
const override = applicabilityOverrides?.[criterion.id];
|
|
848
|
-
const conformance = determineConformance(criterion, scIssues, override);
|
|
849
|
-
const remarks = buildRemarks(criterion, scIssues, conformance, ctx);
|
|
850
|
-
|
|
851
|
-
const row: VPATRow = {
|
|
852
|
-
criterionId: criterion.id,
|
|
853
|
-
criterionName: criterion.name,
|
|
854
|
-
level: criterion.level,
|
|
855
|
-
principle: criterion.principle,
|
|
856
|
-
guideline: criterion.guideline,
|
|
857
|
-
conformanceStatus: conformance,
|
|
858
|
-
checkType: criterion.checkCapability,
|
|
859
|
-
remarks,
|
|
860
|
-
issues: scIssues,
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
rows.push(row);
|
|
864
|
-
principles[criterion.principle].push(row);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
// Compute summary
|
|
868
|
-
const summary: VPATSummary = {
|
|
869
|
-
totalCriteria: rows.length,
|
|
870
|
-
supports: rows.filter((r) => r.conformanceStatus === "Supports").length,
|
|
871
|
-
partiallySupports: rows.filter(
|
|
872
|
-
(r) => r.conformanceStatus === "Partially Supports"
|
|
873
|
-
).length,
|
|
874
|
-
doesNotSupport: rows.filter(
|
|
875
|
-
(r) => r.conformanceStatus === "Does Not Support"
|
|
876
|
-
).length,
|
|
877
|
-
notApplicable: rows.filter(
|
|
878
|
-
(r) => r.conformanceStatus === "Not Applicable"
|
|
879
|
-
).length,
|
|
880
|
-
notEvaluated: rows.filter(
|
|
881
|
-
(r) => r.conformanceStatus === "Not Evaluated"
|
|
882
|
-
).length,
|
|
883
|
-
automatedChecks: criteria.filter(
|
|
884
|
-
(c) => c.checkCapability === "automated"
|
|
885
|
-
).length,
|
|
886
|
-
heuristicChecks: criteria.filter(
|
|
887
|
-
(c) => c.checkCapability === "heuristic"
|
|
888
|
-
).length,
|
|
889
|
-
manualReviewRequired: criteria.filter(
|
|
890
|
-
(c) => c.checkCapability === "manual"
|
|
891
|
-
).length,
|
|
892
|
-
};
|
|
893
|
-
|
|
894
|
-
const partial: Omit<VPATReport, "formattedReport"> = {
|
|
895
|
-
title: `WCAG 2.2 Level ${evaluatedLevel} Conformance Report`,
|
|
896
|
-
wcagVersion: "2.2",
|
|
897
|
-
evaluatedLevel,
|
|
898
|
-
evaluationDate: today,
|
|
899
|
-
nodeId,
|
|
900
|
-
nodeName,
|
|
901
|
-
summary,
|
|
902
|
-
principles,
|
|
903
|
-
rows,
|
|
904
|
-
};
|
|
905
|
-
|
|
906
|
-
return {
|
|
907
|
-
...partial,
|
|
908
|
-
formattedReport: formatMarkdownReport(partial),
|
|
909
|
-
};
|
|
910
|
-
}
|