@wcag-checkr/ci 1.0.0-rc.71 → 1.0.0-rc.72
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/dist/assets/App-CWTgG7P6.js +4 -0
- package/dist/assets/ErrorBoundary-WCBiDb3V.js +519 -0
- package/dist/assets/{devtools-panel-DywDeibE.js → devtools-panel-BTQzCvYa.js} +1 -1
- package/dist/assets/{forensic-log-IPQGyBrY.js → forensic-log-VcNR3Xcq.js} +1 -1
- package/dist/assets/{service-worker.ts-DNXd83Q-.js → service-worker.ts-BE3GStv1.js} +1 -1
- package/dist/assets/{side-panel-BdFcHzTw.js → side-panel-fpGu79zZ.js} +1 -1
- package/dist/assets/{site-report-renderer-BuPjYXyY.js → site-report-renderer-CXRggal1.js} +1 -1
- package/dist/axe.min.js +12 -0
- package/dist/devtools/panel.html +3 -3
- package/dist/manifest.json +3 -2
- package/dist/service-worker-loader.js +1 -1
- package/dist/side-panel/App.tsx +18 -8
- package/dist/side-panel/side-panel.html +3 -3
- package/package.json +1 -1
- package/dist/assets/ErrorBoundary-CQaSAxe1.js +0 -524
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{j as n,r as u}from"./styles-D2VxXLiY.js";import{c as g}from"./ErrorBoundary-WCBiDb3V.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./crash-reporter-Dc5lvxvY.js";import"./state-BIsozXtc.js";import"./preload-helper-D7HrI6pR.js";import"./forensic-log-VcNR3Xcq.js";const d=g(e=>({status:"idle",result:null,beginScan:()=>e({status:"scanning"}),setResult:t=>e({status:"done",result:t}),clear:()=>e({status:"idle",result:null})})),h=[{ruleId:"color-contrast",wcagCriterion:"1.4.3",wcagLevel:"AA",ownerLabel:"Text is too light to read",ownerFix:"Make the text color darker (or background lighter) until the contrast ratio is at least 4.5:1 for normal text or 3:1 for large/bold text. WebAIM's free contrast checker (webaim.org/resources/contrastchecker) verifies any pair."},{ruleId:"image-alt",wcagCriterion:"1.1.1",wcagLevel:"A",ownerLabel:"Image is missing alt text",ownerFix:'Add an `alt` attribute to every `<img>` tag describing what the image shows or its purpose. Decorative images that add nothing semantically get `alt=""` (empty but present).'},{ruleId:"input-image-alt",wcagCriterion:"1.1.1",wcagLevel:"A",ownerLabel:"Image button is missing a label",ownerFix:'Add an `alt` attribute to every `<input type="image">` describing what the button does ("Search", "Submit", etc.).'},{ruleId:"label",wcagCriterion:"3.3.2",wcagLevel:"A",ownerLabel:"Form field is missing a label",ownerFix:"Every text input, select, and textarea needs an associated `<label>` (via `for=...` matching the input's `id`) or an `aria-label`/`aria-labelledby`. Placeholder text alone is not a label."},{ruleId:"button-name",wcagCriterion:"4.1.2",wcagLevel:"A",ownerLabel:"Button has no accessible name",ownerFix:'Every `<button>` needs visible text content OR an `aria-label` describing what it does. Icon-only buttons (like a close ✕) need `aria-label="Close"`.'},{ruleId:"input-button-name",wcagCriterion:"4.1.2",wcagLevel:"A",ownerLabel:"Submit/reset button has no label",ownerFix:'Every `<input type="submit">` and `<input type="button">` needs a `value` attribute (which is also its visible label) or an `aria-label`.'},{ruleId:"link-name",wcagCriterion:"2.4.4",wcagLevel:"A",ownerLabel:"Link has no readable text",ownerFix:"Every `<a>` needs visible text content OR `aria-label`/`aria-labelledby`. Icon-only or image-only links need either alt text on the image or aria-label on the link itself."},{ruleId:"empty-button",wcagCriterion:"4.1.2",wcagLevel:"A",ownerLabel:"Empty button on the page",ownerFix:"A `<button>` with no text and no `aria-label` is invisible to assistive tech. Add visible text or an aria-label describing the button's action."},{ruleId:"empty-link",wcagCriterion:"2.4.4",wcagLevel:"A",ownerLabel:"Empty link on the page",ownerFix:"A link with no text and no aria-label is unreachable by screen readers. Add visible text or `aria-label` describing where the link goes."},{ruleId:"empty-heading",wcagCriterion:"2.4.6",wcagLevel:"AA",ownerLabel:"Empty heading element",ownerFix:"Every heading (`<h1>`–`<h6>`) needs visible text. Empty headings confuse screen readers and break page outline."},{ruleId:"document-title",wcagCriterion:"2.4.2",wcagLevel:"A",ownerLabel:"Page is missing a title",ownerFix:"Add a descriptive `<title>` element inside `<head>`. The title should briefly describe what this page is about — it shows in browser tabs, bookmarks, and is the first thing screen readers announce."},{ruleId:"html-has-lang",wcagCriterion:"3.1.1",wcagLevel:"A",ownerLabel:"Page language not declared",ownerFix:'Add a `lang` attribute to your `<html>` element (e.g., `<html lang="en">`). Screen readers use this to pick the correct pronunciation engine.'},{ruleId:"landmark-one-main",wcagCriterion:"1.3.1",wcagLevel:"A",ownerLabel:"No main content area defined",ownerFix:'Wrap your primary page content in `<main>` (or `<div role="main">`). Screen-reader users have a built-in shortcut to skip directly to main content — without this, every page-load starts at the top with the menu.'},{ruleId:"frame-title",wcagCriterion:"4.1.2",wcagLevel:"A",ownerLabel:"Iframe is missing a title",ownerFix:'Every `<iframe>` needs a `title` attribute describing what it contains (e.g., `title="Sign-up form"`, `title="Embedded video"`). Without this, screen readers announce it as just "frame."'}],b=h.map(e=>e.ruleId);function f(e){return h.find(t=>t.ruleId===e)??null}async function x(){const[e]=await chrome.tabs.query({active:!0,currentWindow:!0});return e??null}function w(e){return e?/^https?:\/\//i.test(e)||e.startsWith("file://"):!1}function v(e){const t=window;return t.axe?t.axe.run(document,{runOnly:{type:"rule",values:e},resultTypes:["violations"]}):Promise.reject(new Error("axe-core not loaded in target tab"))}function y(e){var i;const t=new Map;for(const a of e){const s=f(a.id);if(s)for(const c of a.nodes){const o=c.target.join(" "),p=((i=/[.#]([\w-]+)/.exec(o))==null?void 0:i[1])??o,m=`${a.id}::${p}`;let l=t.get(m);l||(l={rule:s,samples:[],count:0},t.set(m,l)),l.count++,l.samples.length<20&&l.samples.push({selector:o,textSnippet:""})}}const r=[];for(const a of t.values())a.rule&&r.push({ruleId:a.rule.ruleId,wcagCriterion:a.rule.wcagCriterion,wcagLevel:a.rule.wcagLevel,ownerLabel:a.rule.ownerLabel,ownerFix:a.rule.ownerFix,affectedSamples:a.samples,affectedCount:a.count});return r.sort((a,s)=>a.wcagLevel!==s.wcagLevel?a.wcagLevel==="A"?-1:1:s.affectedCount-a.affectedCount),r}async function j(){var c;const e=performance.now(),t=await x();if(!t||!t.id)return{url:"",title:"",scannedAt:new Date().toISOString(),durationMs:0,verdict:"unscannable",findings:[],unscannableReason:"No active tab found. Open the page you want to scan and try again."};if(!w(t.url))return{url:t.url??"",title:t.title??"",scannedAt:new Date().toISOString(),durationMs:performance.now()-e,verdict:"unscannable",findings:[],unscannableReason:"This is a browser internal page (chrome://, about:, etc.) and cannot be scanned. Navigate to your website and try again."};try{await chrome.scripting.executeScript({target:{tabId:t.id},files:["axe.min.js"]})}catch(o){return{url:t.url??"",title:t.title??"",scannedAt:new Date().toISOString(),durationMs:performance.now()-e,verdict:"unscannable",findings:[],unscannableReason:"Could not inject the scanner into this page (likely a strict Content-Security-Policy). Try a different page or contact support."+(o instanceof Error?` (${o.message})`:"")}}let r;try{r=(c=(await chrome.scripting.executeScript({target:{tabId:t.id},func:v,args:[b]}))[0])==null?void 0:c.result}catch(o){return{url:t.url??"",title:t.title??"",scannedAt:new Date().toISOString(),durationMs:performance.now()-e,verdict:"unscannable",findings:[],unscannableReason:"Scanner crashed while reading this page."+(o instanceof Error?` (${o.message})`:"")}}const i=(r==null?void 0:r.violations)??[],a=y(i),s=a.length===0?"safe":"at-risk";return{url:t.url??"",title:t.title??"",scannedAt:new Date().toISOString(),durationMs:performance.now()-e,verdict:s,findings:a}}function A({status:e,onClick:t}){const r=e==="scanning",i=e==="done";return n.jsx("button",{type:"button","data-normal-scan-button":!0,onClick:t,disabled:r,className:"w-full py-4 rounded-lg bg-brand-500 text-white text-base font-semibold shadow-sm hover:bg-brand-600 disabled:opacity-60 disabled:cursor-wait transition",children:r?"Checking page…":i?"Re-check this page":"Check this page"})}function C({finding:e,index:t,expanded:r,onToggle:i}){return n.jsxs("li",{className:"rounded-lg border border-slate-200 bg-white",children:[n.jsxs("button",{type:"button",onClick:i,"aria-expanded":r,className:"w-full px-3 py-2 text-left flex items-start gap-2 hover:bg-slate-50 rounded-lg",children:[n.jsxs("span",{className:"text-[11px] font-mono text-slate-400 mt-0.5",children:[t,"."]}),n.jsxs("span",{className:"flex-1 min-w-0",children:[n.jsx("span",{className:"block text-sm font-medium text-slate-900 leading-snug",children:e.ownerLabel}),n.jsxs("span",{className:"block text-[11px] text-slate-500 mt-0.5",children:["WCAG ",e.wcagCriterion," (",e.wcagLevel,") ·"," ",e.affectedCount===1?"1 element":`${e.affectedCount} elements`]})]}),n.jsx("span",{className:"text-slate-400 text-sm shrink-0","aria-hidden":"true",children:r?"−":"+"})]}),r&&n.jsxs("div",{className:"px-3 pb-3 pt-1 border-t border-slate-100 space-y-2 text-[12px]",children:[n.jsx("p",{className:"text-slate-700 leading-snug",children:e.ownerFix}),e.affectedSamples.length>0&&n.jsxs("div",{children:[n.jsxs("p",{className:"text-[10px] uppercase tracking-wide text-slate-400 mb-1",children:["Affected",e.affectedCount>e.affectedSamples.length?` (first ${e.affectedSamples.length} of ${e.affectedCount})`:""]}),n.jsx("ul",{className:"bg-slate-50 rounded p-2 max-h-32 overflow-y-auto space-y-0.5",children:e.affectedSamples.map((a,s)=>n.jsx("li",{className:"font-mono text-[10px] text-slate-700 truncate",children:a.selector},s))})]})]})]})}function S(e){const t=[];if(t.push(`# Accessibility issues on ${e.url}`),t.push(""),t.push(`Scanned: ${e.scannedAt}`),t.push(""),e.verdict==="safe")return t.push("**Good news.** Automated accessibility scan caught no issues on this page. This means the page passes the same checks demand-letter mills use to identify lawsuit targets. It does NOT mean the page is fully WCAG 2.1 AA conformant — full conformance requires manual verification by a human evaluator, which automation alone cannot replace. But you're off the easy-target list."),t.join(`
|
|
2
|
+
`);if(e.verdict==="unscannable")return t.push(`Scan could not run: ${e.unscannableReason??"unknown reason"}`),t.join(`
|
|
3
|
+
`);t.push(`An automated accessibility scan found **${e.findings.length} ${e.findings.length===1?"issue":"issues"}** on this page. These are the same kinds of issues demand-letter mills look for when they identify lawsuit targets — please fix them as soon as possible.`),t.push(""),t.push("---"),t.push("");for(let r=0;r<e.findings.length;r++){const i=e.findings[r];t.push(`## ${r+1}. ${i.ownerLabel} — WCAG ${i.wcagCriterion} (Level ${i.wcagLevel})`),t.push(""),t.push(i.ownerFix),t.push(""),t.push(`**Affected** ${i.affectedCount===1?"element":`${i.affectedCount} elements`}`+(i.affectedCount>i.affectedSamples.length?` (showing first ${i.affectedSamples.length}):`:":")),t.push(""),t.push("```");for(const a of i.affectedSamples)t.push(a.selector);t.push("```"),t.push(""),t.push(`Reference: https://www.w3.org/WAI/WCAG21/Understanding/${k(i.wcagCriterion)}.html`),t.push(""),t.push("---"),t.push("")}return t.push('Once these are fixed, re-run the scan to confirm. The scan tool is at wcagcheckr.com — install the Chrome extension, navigate to this page, click "Check this page."'),t.join(`
|
|
4
|
+
`)}function k(e){return{"1.1.1":"non-text-content","1.3.1":"info-and-relationships","1.4.3":"contrast-minimum","2.4.2":"page-titled","2.4.4":"link-purpose-in-context","2.4.6":"headings-and-labels","3.1.1":"language-of-page","3.3.2":"labels-or-instructions","4.1.2":"name-role-value"}[e]??""}function L({result:e}){const[t,r]=u.useState(!1);async function i(){const a=S(e);try{await navigator.clipboard.writeText(a),r(!0),setTimeout(()=>r(!1),2400)}catch{const s=document.createElement("textarea");s.value=a,s.style.position="fixed",s.style.opacity="0",document.body.appendChild(s),s.select(),document.execCommand("copy"),document.body.removeChild(s),r(!0),setTimeout(()=>r(!1),2400)}}return n.jsx("button",{type:"button",onClick:()=>void i(),className:"w-full py-2 rounded-lg border border-slate-300 bg-white text-sm font-medium hover:bg-slate-50",children:t?"✓ Copied — paste into email":"✉ Copy fix list for my developer"})}function N({result:e}){const[t,r]=u.useState(null);return e.verdict==="unscannable"?n.jsxs("div",{className:"rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-900",children:[n.jsx("p",{className:"font-semibold",children:"Couldn't scan this page"}),n.jsx("p",{className:"mt-1 text-[12px]",children:e.unscannableReason??"Unknown reason."})]}):e.verdict==="safe"?n.jsxs("div",{className:"rounded-lg border border-emerald-200 bg-emerald-50 p-4",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx("span",{className:"text-3xl","aria-hidden":"true",children:"✓"}),n.jsx("p",{className:"text-base font-semibold text-emerald-900",children:"Off the radar"})]}),n.jsx("p",{className:"text-[12px] text-emerald-900 mt-2 leading-snug",children:"Automated scan caught no issues. This page passes the same checks demand-letter mills use to identify lawsuit targets. Note: full WCAG 2.1 AA conformance still requires human verification — switch to Advanced mode for that."}),n.jsxs("p",{className:"text-[10px] text-emerald-700 mt-2",children:["Scanned ",e.url," in ",Math.round(e.durationMs)," ms."]})]}):n.jsxs("div",{className:"space-y-3",children:[n.jsxs("div",{className:"rounded-lg border border-rose-200 bg-rose-50 p-4",children:[n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx("span",{className:"text-3xl","aria-hidden":"true",children:"⚠"}),n.jsxs("p",{className:"text-base font-semibold text-rose-900",children:[e.findings.length," ",e.findings.length===1?"issue":"issues"," to fix"]})]}),n.jsx("p",{className:"text-[12px] text-rose-900 mt-2 leading-snug",children:"These are the issues demand-letter mills look for. Until they're fixed, this page is at risk of being flagged as a lawsuit target."}),n.jsxs("p",{className:"text-[10px] text-rose-700 mt-2",children:["Scanned ",e.url," in ",Math.round(e.durationMs)," ms."]})]}),n.jsx("ul",{className:"space-y-2",children:e.findings.map((i,a)=>n.jsx(C,{finding:i,index:a+1,expanded:t===a,onToggle:()=>r(t===a?null:a)},`${i.ruleId}-${a}`))}),n.jsx(L,{result:e})]})}function I(){async function e(){await chrome.storage.local.set({userMode:"developer"}),window.location.reload()}return n.jsxs("footer",{className:"px-4 py-2 bg-slate-100 border-t border-slate-200 text-[11px] text-slate-500 flex items-center justify-between",children:[n.jsx("span",{children:"Normal mode"}),n.jsx("button",{type:"button",onClick:()=>void e(),className:"underline hover:text-slate-800",children:"Switch to Advanced mode →"})]})}function W(){const e=d(s=>s.status),t=d(s=>s.result),r=d(s=>s.beginScan),i=d(s=>s.setResult);async function a(){r();const s=await j();i(s)}return u.useEffect(()=>{const s=document.querySelector("[data-normal-scan-button]");s==null||s.focus()},[]),n.jsxs("div",{className:"min-h-screen bg-slate-50 text-slate-900 flex flex-col",children:[n.jsxs("header",{className:"px-4 py-3 bg-white border-b border-slate-200",children:[n.jsx("h1",{className:"text-base font-semibold",children:"wcagcheckr"}),n.jsx("p",{className:"text-[11px] text-slate-500",children:"Off the lawsuit-mill radar in one click."})]}),n.jsxs("main",{className:"flex-1 px-4 py-4 space-y-4",children:[n.jsx(A,{status:e,onClick:()=>void a()}),t&&n.jsx(N,{result:t})]}),n.jsx(I,{})]})}export{W as NormalApp};
|