@mp3wizard/figma-console-mcp 1.30.1 → 1.32.1
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 +4 -2
- package/dist/cloudflare/core/accessibility-tools.js +55 -0
- package/dist/cloudflare/core/port-discovery.js +130 -9
- package/dist/cloudflare/core/tokens-tools.js +1 -1
- package/dist/cloudflare/core/write-tools.js +8 -5
- package/dist/cloudflare/index.js +3 -3
- package/dist/core/accessibility-tools.d.ts.map +1 -1
- package/dist/core/accessibility-tools.js +55 -0
- package/dist/core/accessibility-tools.js.map +1 -1
- package/dist/core/port-discovery.d.ts +30 -1
- package/dist/core/port-discovery.d.ts.map +1 -1
- package/dist/core/port-discovery.js +130 -9
- package/dist/core/port-discovery.js.map +1 -1
- package/dist/core/tokens-tools.js +1 -1
- package/dist/core/write-tools.d.ts.map +1 -1
- package/dist/core/write-tools.js +8 -5
- package/dist/core/write-tools.js.map +1 -1
- package/dist/local.d.ts +2 -0
- package/dist/local.d.ts.map +1 -1
- package/dist/local.js +40 -10
- package/dist/local.js.map +1 -1
- package/figma-desktop-bridge/README.md +54 -2
- package/figma-desktop-bridge/code.js +53 -12
- package/figma-desktop-bridge/ui.html +983 -111
- package/package.json +6 -3
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
// Plugin version — sent in FILE_INFO for server-side version compatibility checks.
|
|
8
8
|
// The server compares this against its own version to detect stale cached plugins.
|
|
9
|
-
var PLUGIN_VERSION = '1.
|
|
9
|
+
var PLUGIN_VERSION = '1.32.0'; // Kept in sync with package.json by scripts/release.sh — see issue #62.
|
|
10
10
|
|
|
11
11
|
console.log('🌉 [Desktop Bridge] Plugin loaded (v' + PLUGIN_VERSION + ')');
|
|
12
12
|
|
|
13
13
|
// Show minimal UI - compact status indicator
|
|
14
|
-
figma.showUI(__html__, { width:
|
|
14
|
+
figma.showUI(__html__, { width: 240, height: 40, visible: true, themeColors: true });
|
|
15
15
|
|
|
16
16
|
// ============================================================================
|
|
17
17
|
// CONSOLE CAPTURE — Intercept console.* in the QuickJS sandbox and forward
|
|
@@ -3178,7 +3178,7 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3178
3178
|
});
|
|
3179
3179
|
// Short delay to let the response message be sent before reload
|
|
3180
3180
|
setTimeout(function() {
|
|
3181
|
-
figma.showUI(__html__, { width:
|
|
3181
|
+
figma.showUI(__html__, { width: 240, height: 40, visible: true, themeColors: true });
|
|
3182
3182
|
}, 100);
|
|
3183
3183
|
} catch (error) {
|
|
3184
3184
|
var errorMsg = error && error.message ? error.message : String(error);
|
|
@@ -3360,6 +3360,34 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3360
3360
|
return false;
|
|
3361
3361
|
}
|
|
3362
3362
|
|
|
3363
|
+
// Line/paragraph SPACING only affects readability when text actually renders on
|
|
3364
|
+
// 2+ lines (or 2+ paragraphs). Single-line labels, buttons, inputs and headings
|
|
3365
|
+
// gain nothing from a 1.5 line height, so flagging them is false-positive noise.
|
|
3366
|
+
// (WCAG 1.4.12 conformance is a code concern — whether spacing overrides break
|
|
3367
|
+
// layout — not something a design's spacing value can prove. These stay best-practice.)
|
|
3368
|
+
function textRendersMultipleLines(node, effectiveLh) {
|
|
3369
|
+
try {
|
|
3370
|
+
var chars = (typeof node.characters === 'string') ? node.characters : '';
|
|
3371
|
+
// \n = paragraph break; U+2028 = line break (shift-enter) within a Figma paragraph
|
|
3372
|
+
var LINE_SEP = String.fromCharCode(0x2028);
|
|
3373
|
+
if (chars.indexOf(String.fromCharCode(10)) !== -1 || chars.indexOf(LINE_SEP) !== -1) return true;
|
|
3374
|
+
// WIDTH_AND_HEIGHT auto-resize grows horizontally and never wraps on its own
|
|
3375
|
+
if (node.textAutoResize === 'WIDTH_AND_HEIGHT') return false;
|
|
3376
|
+
if (effectiveLh && typeof node.height === 'number' && node.height > 0) {
|
|
3377
|
+
return (node.height / effectiveLh) >= 1.6; // ≈ 2+ rendered lines
|
|
3378
|
+
}
|
|
3379
|
+
} catch (e) { /* mixed/slot — treat as single line */ }
|
|
3380
|
+
return false;
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
function textHasMultipleParagraphs(node) {
|
|
3384
|
+
try {
|
|
3385
|
+
var chars = (typeof node.characters === 'string') ? node.characters : '';
|
|
3386
|
+
return chars.indexOf('\n') !== -1; // \n = paragraph separator in Figma text
|
|
3387
|
+
} catch (e) { /* ignore */ }
|
|
3388
|
+
return false;
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3363
3391
|
// ---- Rule configuration ----
|
|
3364
3392
|
var allRuleIds = [
|
|
3365
3393
|
'wcag-contrast', 'wcag-text-size', 'wcag-target-size', 'wcag-line-height',
|
|
@@ -3373,13 +3401,23 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3373
3401
|
|
|
3374
3402
|
var ruleGroups = {
|
|
3375
3403
|
'all': allRuleIds,
|
|
3404
|
+
// 'wcag' = genuine WCAG conformance criteria only. Readability "best practice"
|
|
3405
|
+
// checks (text size, line/letter/paragraph spacing) live in 'best-practice' so a
|
|
3406
|
+
// conformance audit (rules: ['wcag']) is not polluted by non-normative hints.
|
|
3407
|
+
// In particular, WCAG 1.4.12 Text Spacing is a "support user overrides without
|
|
3408
|
+
// breaking" criterion — NOT a requirement to ship specific spacing values — so a
|
|
3409
|
+
// sub-1.5 line height is not a conformance failure (see 'best-practice' below).
|
|
3376
3410
|
'wcag': [
|
|
3377
|
-
'wcag-contrast', 'wcag-
|
|
3411
|
+
'wcag-contrast', 'wcag-target-size',
|
|
3378
3412
|
'wcag-non-text-contrast', 'wcag-color-only', 'wcag-focus-indicator',
|
|
3379
|
-
'wcag-
|
|
3380
|
-
'wcag-heading-hierarchy', 'wcag-reflow', 'wcag-reading-order',
|
|
3413
|
+
'wcag-image-alt', 'wcag-heading-hierarchy', 'wcag-reflow', 'wcag-reading-order',
|
|
3381
3414
|
'wcag-disabled-no-context'
|
|
3382
3415
|
],
|
|
3416
|
+
// Readability best practices — useful hints, NOT WCAG conformance failures.
|
|
3417
|
+
// Opt in with rules: ['best-practice'] (or ['all']); excluded from the default set.
|
|
3418
|
+
'best-practice': [
|
|
3419
|
+
'wcag-text-size', 'wcag-line-height', 'wcag-letter-spacing', 'wcag-paragraph-spacing'
|
|
3420
|
+
],
|
|
3383
3421
|
'design-system': ['hardcoded-color', 'no-text-style', 'default-name', 'detached-component', 'token-misuse'],
|
|
3384
3422
|
'layout': ['no-autolayout', 'empty-container']
|
|
3385
3423
|
};
|
|
@@ -3437,12 +3475,12 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3437
3475
|
'wcag-contrast': 'Text does not meet WCAG AA contrast ratio (4.5:1 normal, 3:1 large text ≥24px or ≥18.5px bold). Best practice: always target 4.5:1, especially in dark mode.',
|
|
3438
3476
|
'wcag-text-size': 'Text size is below 12px — readability best practice. Note: WCAG 1.4.4 requires supporting 200% text-only zoom (use rem/em units), not a specific minimum size.',
|
|
3439
3477
|
'wcag-target-size': 'Interactive element is smaller than 24x24px minimum target size (WCAG 2.5.8)',
|
|
3440
|
-
'wcag-line-height': '
|
|
3478
|
+
'wcag-line-height': 'Multi-line body text has line height below 1.5x font size — a readability best practice (only flagged on text that wraps to 2+ lines; single-line labels, buttons and headings are exempt). NOT a WCAG failure: 1.4.12 requires content to survive a user overriding line height to 1.5x without loss of content, which is verified in code, not by the default value in the design.',
|
|
3441
3479
|
'wcag-non-text-contrast': 'UI component or graphical object does not meet 3:1 contrast ratio against adjacent color. Also applies to borders and chart elements against adjacent elements (WCAG 1.4.11)',
|
|
3442
3480
|
'wcag-color-only': 'Information is conveyed only through color change (e.g., error state uses red border without an error message or icon). Color can supplement but must not be the sole indicator (WCAG 1.4.1)',
|
|
3443
3481
|
'wcag-focus-indicator': 'Interactive component is missing a focus/focused variant or the focus indicator is insufficient. A visible focus state is critical — without it, keyboard users cannot navigate the interface (WCAG 2.4.7)',
|
|
3444
|
-
'wcag-letter-spacing': 'Negative letter spacing
|
|
3445
|
-
'wcag-paragraph-spacing': '
|
|
3482
|
+
'wcag-letter-spacing': 'Negative letter spacing (tighter than default) harms readability — a best-practice hint, not a WCAG failure. WCAG 1.4.12 is about supporting user-overridden spacing without loss of content (verified in code), not the default tracking in the design.',
|
|
3483
|
+
'wcag-paragraph-spacing': 'Multi-paragraph text has paragraph spacing below 2x font size — a readability best practice (only flagged when a text node has 2+ paragraphs). NOT a WCAG failure: 1.4.12 requires content to survive a user overriding paragraph spacing to 2x without loss of content, verified in code, not by the default value in the design.',
|
|
3446
3484
|
'wcag-image-alt': 'Image or image fill has no description annotation for alternative text. All images need alt text; decorative images should be explicitly marked as decorative. Graphs and charts also need long descriptions (e.g., a data table) (WCAG 1.1.1)',
|
|
3447
3485
|
'wcag-heading-hierarchy': 'Heading levels skip a level (e.g., H1 followed by H3). Use H1 through H6 sequentially without skipping levels (WCAG 1.3.1)',
|
|
3448
3486
|
'wcag-reflow': 'Frame uses fixed positioning without auto-layout. Content must support 400% zoom on 1280px viewport (equivalent to 320px minimum width) without horizontal scrolling or loss of content (WCAG 1.4.10)',
|
|
@@ -3550,7 +3588,10 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3550
3588
|
// (checked after tree walk per-frame)
|
|
3551
3589
|
|
|
3552
3590
|
// ---- Resolve active rules ----
|
|
3553
|
-
|
|
3591
|
+
// Default audit = real WCAG conformance + design-system + layout. Best-practice
|
|
3592
|
+
// readability hints are opt-in (rules: ['best-practice'] or ['all']) so component
|
|
3593
|
+
// library audits aren't flooded with non-normative spacing/size noise.
|
|
3594
|
+
var requestedRules = msg.rules || ['wcag', 'design-system', 'layout'];
|
|
3554
3595
|
var activeRuleSet = {};
|
|
3555
3596
|
for (var ri = 0; ri < requestedRules.length; ri++) {
|
|
3556
3597
|
var ruleOrGroup = requestedRules[ri];
|
|
@@ -3737,7 +3778,7 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3737
3778
|
effectiveLh = fs * (lh.value / 100);
|
|
3738
3779
|
}
|
|
3739
3780
|
}
|
|
3740
|
-
if (effectiveLh !== null && effectiveLh < 1.5 * fs) {
|
|
3781
|
+
if (effectiveLh !== null && effectiveLh < 1.5 * fs && textRendersMultipleLines(node, effectiveLh)) {
|
|
3741
3782
|
if (totalFindings < maxFindings) {
|
|
3742
3783
|
findings['wcag-line-height'].push({
|
|
3743
3784
|
id: nodeId,
|
|
@@ -3940,7 +3981,7 @@ figma.ui.onmessage = async (msg) => {
|
|
|
3940
3981
|
var psFs = node.fontSize;
|
|
3941
3982
|
if (typeof ps === 'number' && typeof psFs === 'number' && ps > 0) {
|
|
3942
3983
|
var requiredPs = 2 * psFs;
|
|
3943
|
-
if (ps < requiredPs) {
|
|
3984
|
+
if (ps < requiredPs && textHasMultipleParagraphs(node)) {
|
|
3944
3985
|
if (totalFindings < maxFindings) {
|
|
3945
3986
|
findings['wcag-paragraph-spacing'].push({
|
|
3946
3987
|
id: nodeId,
|