diff --git a/test/proof-badge.test.js b/test/proof-badge.test.js index ca870a8..9146461 100644 --- a/test/proof-badge.test.js +++ b/test/proof-badge.test.js @@ -1,7 +1,7 @@ import { createElement } from 'react'; import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; -import { ProofBadge, SimpleProofBadge } from '../widgets/verify-gate/dist/ProofBadge.js'; +import { ProofBadge, SimpleProofBadge, ProofablePillLink } from '../widgets/verify-gate/dist/ProofBadge.js'; const render = (Component, props) => renderToStaticMarkup(createElement(Component, props)); @@ -40,4 +40,30 @@ describe('ProofBadge evidence', () => { expect(render(ProofBadge, { qHash: 'example', uiLinkBase: 'https://proofable.me' })) .not.toContain('href="https://proofable.me/proof/example"'); }); + + // WCAG 2.2 AA Target Size (Minimum) is 24x24 CSS px. The `sm` pill computed to + // 16px tall (10px text x line-height 1, plus 2px padding and a 1px border per + // side), which axe flags as `target-size` (serious) wherever two of these stack + // in a list — measured on neus `/` and `/connect` at mobile width. Pinned here + // because the widget ships to every consumer, so the fix has to live in the + // widget rather than in one consumer's override. + it('meets the 24x24 target-size minimum at every size', () => { + for (const props of [ + { proof: { status: 'verified' } }, + { proof: { status: 'verified' }, size: 'md' }, + ]) { + const style = (render(ProofBadge, props).match(/style="([^"]*)"/) || [])[1] || ''; + expect(style).toContain('min-height:24px'); + expect(style).toContain('min-width:24px'); + // border-box keeps the pill at exactly 24px instead of padding it past the floor. + expect(style).toContain('box-sizing:border-box'); + } + }); + + it('carries the same target-size floor on the pill link', () => { + const style = (render(ProofablePillLink, { label: 'View' }).match(/style="([^"]*)"/) || [])[1] || ''; + expect(style).toContain('min-height:24px'); + expect(style).toContain('min-width:24px'); + expect(style).toContain('box-sizing:border-box'); + }); }); diff --git a/widgets/verify-gate/ProofBadge.jsx b/widgets/verify-gate/ProofBadge.jsx index 7acc21d..462ac16 100644 --- a/widgets/verify-gate/ProofBadge.jsx +++ b/widgets/verify-gate/ProofBadge.jsx @@ -107,6 +107,7 @@ export function ProofBadge({ const style = { display: 'inline-flex', alignItems: 'center', + justifyContent: 'center', gap, textDecoration: 'none', padding: `${padY}px ${padX}px`, @@ -120,7 +121,15 @@ export function ProofBadge({ whiteSpace: 'nowrap', lineHeight: 1, cursor: 'pointer', - transition: 'opacity 0.15s ease' + transition: 'opacity 0.15s ease', + // WCAG 2.2 AA Target Size (Minimum). The `sm` pill computed to 16px tall + // (10px text x line-height 1, plus 2px padding and a 1px border per side), which + // is under the 24x24 CSS px minimum and is flagged as an axe `target-size` + // violation wherever two of these stack in a list. border-box keeps the pill at + // exactly 24px rather than growing it beyond what the rule requires. + minHeight: 24, + minWidth: 24, + boxSizing: 'border-box' }; const handleClick = (e) => { @@ -184,6 +193,7 @@ export function ProofablePillLink({ const style = { display: 'inline-flex', alignItems: 'center', + justifyContent: 'center', gap: 4, textDecoration: 'none', padding: '2px 6px', @@ -197,7 +207,12 @@ export function ProofablePillLink({ whiteSpace: 'nowrap', lineHeight: 1, cursor: 'pointer', - transition: 'opacity 0.15s ease' + transition: 'opacity 0.15s ease', + // Same WCAG 2.2 AA Target Size floor as ProofBadge: the 16px `sm` pill is under + // the 24x24 CSS px minimum. + minHeight: 24, + minWidth: 24, + boxSizing: 'border-box' }; const handleClick = (e) => {