@yuktishaalaa/a11y 0.0.0-stage → 6.0.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 CHANGED
@@ -1,3 +1,77 @@
1
- # Temporary Holding Version
1
+ # @yuktishaalaa/a11y
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Web accessibility for any page, in the browser. Safe ARIA, WCAG AA/AAA contrast, `lang` for every part found automatically, read aloud in the right voice, and the visitor's own preferences. One attribute. No server, no key, nothing sent anywhere.
4
+
5
+ Part of **YuktAI 6.0** by Sandeep Miriyala.
6
+
7
+ ## No code: one attribute + one script
8
+
9
+ ```html
10
+ <body data-yuktai-a11y="auto" data-yuktai-level="AA">
11
+ ...
12
+ <script src="https://cdn.jsdelivr.net/npm/@yuktishaalaa/a11y@6/dist/a11y.global.js" defer></script>
13
+ </body>
14
+ ```
15
+
16
+ | Attribute | Values | Default |
17
+ |---|---|---|
18
+ | `data-yuktai-a11y` | `auto` (safe fixes + report) · `check` (report only) · `off` | `auto` |
19
+ | `data-yuktai-level` | `AA` · `AAA` · `off` | `AA` |
20
+ | `data-yuktai-contrast` | `check` · `fix` | `check` |
21
+ | `data-yuktai-lang` | `auto` · `off` | `auto` |
22
+ | `data-yuktai-speak` | `on` · `off` (🔊 button after h1–h3) | `off` |
23
+
24
+ Any element can opt out with `data-yuktai-a11y="off"` (and `data-yuktai-speak="off"` for reading).
25
+ There is no `lang` setting: the page language is found from the text.
26
+
27
+ ## npm
28
+
29
+ ```ts
30
+ import { createA11y } from "@yuktishaalaa/a11y"
31
+
32
+ const a11y = createA11y({ level: "AA", contrast: "check" })
33
+ const report = a11y.run() // { fixed, check, unknown }
34
+ a11y.setPrefs({ textSize: 130, dark: "device" })
35
+ a11y.destroy() // removes every change
36
+ ```
37
+
38
+ In Next.js, call it in a client component after mount (`useEffect`), never during render.
39
+
40
+ ## Do no harm
41
+
42
+ - **Native elements are checked, never relabelled.** No made-up "Button", "Image" or "Interactive element" labels, no `alt=""` on pictures that may matter, no `role="grid"` on tables. A wrong label is worse than none.
43
+ - **Your `lang` and ARIA are never changed.** Only missing `lang` is added.
44
+ - **The only structural fix:** an element with an inline `onclick` that is not a control, and that has a name, gets `role="button"`, `tabindex="0"` and Enter/Space.
45
+ - **"Not checked" is never "pass".** Text over an image, closed web components and iframes from other sites are listed as *unknown*.
46
+ - **Everything can be undone** (`undo()` / `destroy()`): every change carries a `data-yuktai-*` mark.
47
+ - **Typing areas, passwords and code are never read.**
48
+
49
+ ## Language, automatically
50
+
51
+ The script of the text tells the language in every browser (Telugu, Tamil, Kannada, Malayalam, Gujarati, Punjabi, Odia, Bengali, Devanagari, Arabic, Latin and more). Scripts several languages share (Devanagari: Hindi or Marathi?) can be refined with Chrome's on-device `LanguageDetector` (`refineWithDetector`). Missing `<html lang>` is added (WCAG 3.1.1), and parts in another language get their own `lang` (3.1.2), with `dir="rtl"` for Urdu and Arabic. Screen readers then switch voice correctly too.
52
+
53
+ ## Read aloud
54
+
55
+ `speak(element)` uses the browser's own Web Speech. Text is cut where the language changes and each part is read with a voice for its language (`te-IN`, `en-IN`…). A part whose language has no voice on the device is skipped and reported (`onMissingVoice`), never read with a wrong voice. Long text is read sentence by sentence. Reading starts only on a click.
56
+
57
+ ## Report
58
+
59
+ | Group | Meaning |
60
+ |---|---|
61
+ | `fixed` | Changed safely by YuktAI (and undoable) |
62
+ | `check` | A person should look; the message says how |
63
+ | `unknown` | Could not be checked; never counted as a pass |
64
+
65
+ Each finding has the WCAG 2.2 criterion (`1.4.3`, `3.1.2`…), a short path, and messages in English and Telugu (`message(finding, "te")`).
66
+
67
+ ## Visitor preferences
68
+
69
+ `setPrefs({ textSize, spacing, reduceMotion, focusRing, theme, custom, dark })`: one `<style>` element, removed by `destroy()`. `theme: "custom"` darkens or lightens the chosen text colour until it passes the level.
70
+
71
+ ## Browsers
72
+
73
+ All modern browsers on desktop and phones (Chrome, Edge, Firefox, Safari, Samsung Internet). Read aloud depends on the voices the device has; `LanguageDetector` is Chrome only (others keep the script guess).
74
+
75
+ ## License
76
+
77
+ GPL-3.0-only. © Sandeep Miriyala — Yuktishaalaa AI Lab.
@@ -0,0 +1,2 @@
1
+ "use strict";var YuktaiA11yBundle=(()=>{var Ct=Object.defineProperty;var Rt=(t,e)=>{for(var n in e)Ct(t,n,{get:e[n],enumerable:!0})};var dt={};Rt(dt,{DEFAULT_PREFS:()=>M,DEFAULT_SETTINGS:()=>O,MESSAGES:()=>_,VERSION:()=>ct,WCAG:()=>A,accessibleName:()=>T,addSpeakButtons:()=>W,annotateLanguages:()=>J,applyPrefs:()=>ot,auditAria:()=>I,blend:()=>et,canSpeak:()=>$,checkElementContrast:()=>nt,clearPrefs:()=>at,contrastRatio:()=>S,createA11y:()=>ut,describe:()=>k,detectText:()=>N,effectiveBackground:()=>kt,findAll:()=>H,getVoices:()=>st,hasAttributes:()=>Z,inheritedLang:()=>v,isLargeText:()=>yt,isRtl:()=>mt,isSkipped:()=>x,loadPrefs:()=>_t,luminance:()=>q,message:()=>ft,nearestPassingColor:()=>F,pageLanguage:()=>z,pageText:()=>Y,parseColor:()=>E,pickVoice:()=>At,prefsCss:()=>xt,primary:()=>y,readAttributes:()=>Q,readableText:()=>wt,refineWithDetector:()=>Bt,requiredRatio:()=>V,savePrefs:()=>Kt,scriptOf:()=>K,sentences:()=>St,speak:()=>lt,speakableLanguages:()=>Ut,splitByLanguage:()=>U,toHex:()=>w,toJSON:()=>gt,undoAria:()=>B,undoLanguages:()=>X});var A={"page-lang-missing":"3.1.1","page-lang-mismatch":"3.1.1","part-lang-missing":"3.1.2",contrast:"1.4.3","contrast-unknown":"1.4.3","img-alt-missing":"1.1.1","control-name-missing":"4.1.2","fake-button":"4.1.2","clickable-not-focusable":"2.1.1","field-label-missing":"3.3.2","heading-skip":"1.3.1","h1-count":"1.3.1","link-text-vague":"2.4.4","iframe-title-missing":"4.1.2","iframe-cross-origin":"","table-headers-missing":"1.3.1","media-autoplay":"1.4.2","tabindex-positive":"2.4.3","aria-hidden-focusable":"4.1.2","main-landmark-missing":"2.4.1","closed-shadow-root":""},_={en:{"page-lang-missing":"The page has no lang. Detected: {lang}.","page-lang-mismatch":'<html lang="{declared}"> but the text is {detected}.',"part-lang-missing":"A part in {lang} had no lang.",contrast:"Text contrast {ratio}:1, needs {required}:1.","contrast-unknown":"Contrast not checked: {reason}.","img-alt-missing":'Image has no alt text. Describe it, or use alt="" if it is decoration.',"control-name-missing":"A {tag} has no name a screen reader can say.","fake-button":"A clickable {tag} was not a button. Added role, focus and Enter/Space. A real <button> is better.","clickable-not-focusable":"Something clickable ({tag}) cannot be reached by keyboard.","field-label-missing":"A form field has no label.","heading-skip":"Heading jumps from h{from} to h{to}.","h1-count":"The page has {count} h1 headings; one is expected.","link-text-vague":'Link text "{text}" does not say where it goes.',"iframe-title-missing":"An iframe has no title.","iframe-cross-origin":"Content from another site (iframe) cannot be checked from here.","table-headers-missing":"A data table has no header cells (th).","media-autoplay":"Media plays by itself. Give a way to pause it.","tabindex-positive":'tabindex="{value}" changes the Tab order.',"aria-hidden-focusable":"A hidden (aria-hidden) element can still take focus.","main-landmark-missing":"The page has no <main>.","closed-shadow-root":"A closed component cannot be checked from outside."},te:{"page-lang-missing":"\u0C2A\u0C47\u0C1C\u0C40\u0C15\u0C3F lang \u0C32\u0C47\u0C26\u0C41. \u0C17\u0C41\u0C30\u0C4D\u0C24\u0C3F\u0C02\u0C1A\u0C3F\u0C28 \u0C2D\u0C3E\u0C37: {lang}.","page-lang-mismatch":'<html lang="{declared}"> \u0C09\u0C02\u0C26\u0C3F, \u0C15\u0C3E\u0C28\u0C40 text {detected} \u0C32\u0C4B \u0C09\u0C02\u0C26\u0C3F.',"part-lang-missing":"{lang} \u0C2D\u0C3E\u0C17\u0C3E\u0C28\u0C3F\u0C15\u0C3F lang \u0C32\u0C47\u0C26\u0C41.",contrast:"Text contrast {ratio}:1, \u0C15\u0C28\u0C40\u0C38\u0C02 {required}:1 \u0C15\u0C3E\u0C35\u0C3E\u0C32\u0C3F.","contrast-unknown":"Contrast check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C15\u0C2A\u0C4B\u0C2F\u0C3E\u0C02: {reason}.","img-alt-missing":'Image \u0C15\u0C3F alt \u0C32\u0C47\u0C26\u0C41. \u0C35\u0C3F\u0C35\u0C30\u0C23 \u0C30\u0C3E\u0C2F\u0C02\u0C21\u0C3F, \u0C05\u0C32\u0C02\u0C15\u0C3E\u0C30\u0C2E\u0C48\u0C24\u0C47 alt="" \u0C2A\u0C46\u0C1F\u0C4D\u0C1F\u0C02\u0C21\u0C3F.',"control-name-missing":"{tag} \u0C15\u0C3F screen reader \u0C1A\u0C46\u0C2A\u0C4D\u0C2A\u0C17\u0C32\u0C3F\u0C17\u0C47 \u0C2A\u0C47\u0C30\u0C41 \u0C32\u0C47\u0C26\u0C41.","fake-button":"Click \u0C1A\u0C47\u0C38\u0C47 {tag} button \u0C15\u0C3E\u0C26\u0C41. Role, focus, Enter/Space \u0C1C\u0C4B\u0C21\u0C3F\u0C02\u0C1A\u0C3E\u0C02. \u0C28\u0C3F\u0C1C\u0C2E\u0C48\u0C28 <button> \u0C07\u0C02\u0C15\u0C3E \u0C2E\u0C02\u0C1A\u0C3F\u0C26\u0C3F.","clickable-not-focusable":"Click \u0C1A\u0C47\u0C38\u0C47 {tag} \u0C28\u0C3F keyboard \u0C24\u0C4B \u0C1A\u0C47\u0C30\u0C32\u0C47\u0C2E\u0C41.","field-label-missing":"Form field \u0C15\u0C3F label \u0C32\u0C47\u0C26\u0C41.","heading-skip":"Heading h{from} \u0C28\u0C41\u0C02\u0C21\u0C3F h{to} \u0C15\u0C3F \u0C26\u0C42\u0C15\u0C3F\u0C02\u0C26\u0C3F.","h1-count":"\u0C2A\u0C47\u0C1C\u0C40\u0C32\u0C4B {count} h1 \u0C32\u0C41 \u0C09\u0C28\u0C4D\u0C28\u0C3E\u0C2F\u0C3F; \u0C12\u0C15\u0C1F\u0C3F \u0C09\u0C02\u0C21\u0C3E\u0C32\u0C3F.","link-text-vague":'Link text "{text}" \u0C0E\u0C15\u0C4D\u0C15\u0C21\u0C3F\u0C15\u0C3F \u0C35\u0C46\u0C33\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C4B \u0C1A\u0C46\u0C2A\u0C4D\u0C2A\u0C26\u0C41.',"iframe-title-missing":"iframe \u0C15\u0C3F title \u0C32\u0C47\u0C26\u0C41.","iframe-cross-origin":"\u0C35\u0C47\u0C30\u0C47 site content (iframe) \u0C28\u0C3F \u0C07\u0C15\u0C4D\u0C15\u0C21\u0C3F \u0C28\u0C41\u0C02\u0C21\u0C3F check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C2E\u0C41.","table-headers-missing":"Data table \u0C15\u0C3F header cells (th) \u0C32\u0C47\u0C35\u0C41.","media-autoplay":"Media \u0C24\u0C28\u0C02\u0C24\u0C1F \u0C24\u0C3E\u0C28\u0C47 play \u0C05\u0C35\u0C41\u0C24\u0C41\u0C02\u0C26\u0C3F. \u0C06\u0C2A\u0C47 \u0C2E\u0C3E\u0C30\u0C4D\u0C17\u0C02 \u0C07\u0C35\u0C4D\u0C35\u0C02\u0C21\u0C3F.","tabindex-positive":'tabindex="{value}" Tab \u0C15\u0C4D\u0C30\u0C2E\u0C3E\u0C28\u0C4D\u0C28\u0C3F \u0C2E\u0C3E\u0C30\u0C41\u0C38\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C3F.',"aria-hidden-focusable":"\u0C26\u0C3E\u0C1A\u0C3F\u0C28 (aria-hidden) element \u0C15\u0C3F focus \u0C35\u0C38\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C3F.","main-landmark-missing":"\u0C2A\u0C47\u0C1C\u0C40\u0C32\u0C4B <main> \u0C32\u0C47\u0C26\u0C41.","closed-shadow-root":"\u0C2E\u0C42\u0C38\u0C3F \u0C09\u0C28\u0C4D\u0C28 component \u0C28\u0C3F \u0C2C\u0C2F\u0C1F\u0C3F \u0C28\u0C41\u0C02\u0C21\u0C3F check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C2E\u0C41."}};function ft(t,e="en"){return(_[e][t.rule]??t.rule).replace(/\{(\w+)\}/g,(o,a)=>String(t.data?.[a]??""))}function k(t){let e=a=>{let i=a.tagName.toLowerCase();if(a.id)return i+"#"+a.id;let r=(a.getAttribute("class")??"").trim().split(/\s+/).filter(Boolean).slice(0,2);return r.length&&(i+="."+r.join(".")),i},n=[],o=t;for(;o&&n.length<3&&o.tagName.toLowerCase()!=="body"&&o.tagName.toLowerCase()!=="html"&&(n.unshift(e(o)),!o.id);)o=o.parentElement;return n.join(" > ")||t.tagName.toLowerCase()}function gt(t){let e=n=>n.map(({el:o,...a})=>a);return{...t,fixed:e(t.fixed),check:e(t.check),unknown:e(t.unknown)}}var Ft=[{script:"Telugu",lang:"te",shared:!1,from:3072,to:3199},{script:"Kannada",lang:"kn",shared:!1,from:3200,to:3327},{script:"Tamil",lang:"ta",shared:!1,from:2944,to:3071},{script:"Malayalam",lang:"ml",shared:!1,from:3328,to:3455},{script:"Devanagari",lang:"hi",shared:!0,from:2304,to:2431},{script:"Bengali",lang:"bn",shared:!0,from:2432,to:2559},{script:"Gurmukhi",lang:"pa",shared:!1,from:2560,to:2687},{script:"Gujarati",lang:"gu",shared:!1,from:2688,to:2815},{script:"Oriya",lang:"or",shared:!1,from:2816,to:2943},{script:"Sinhala",lang:"si",shared:!1,from:3456,to:3583},{script:"Arabic",lang:"ar",shared:!0,from:1536,to:1791},{script:"Hebrew",lang:"he",shared:!0,from:1424,to:1535},{script:"Thai",lang:"th",shared:!1,from:3584,to:3711},{script:"Greek",lang:"el",shared:!1,from:880,to:1023},{script:"Cyrillic",lang:"ru",shared:!0,from:1024,to:1279},{script:"Hangul",lang:"ko",shared:!1,from:44032,to:55215},{script:"Kana",lang:"ja",shared:!1,from:12352,to:12543},{script:"Han",lang:"zh",shared:!0,from:19968,to:40959},{script:"Latin",lang:"en",shared:!0,from:65,to:591}],Mt=new Set(["ar","ur","fa","he","sd","ks","ps","yi","dv","ug"]),mt=t=>Mt.has(y(t)),y=t=>(t||"").toLowerCase().split(/[-_]/)[0];function K(t){let e=t.codePointAt(0);if(e<128&&!/[A-Za-z]/.test(t)||e>=128&&e<192)return null;for(let n of Ft)if(e>=n.from&&e<=n.to)return{script:n.script,lang:n.lang,shared:n.shared};return null}function N(t,e=3){let n=new Map,o=0;for(let i of t){let r=K(i);if(!r)continue;o++;let s=n.get(r.script);s?s.n++:n.set(r.script,{n:1,info:r})}if(o<e)return null;let a=null;for(let i of n.values())(!a||i.n>a.n)&&(a=i);return a?{lang:a.info.lang,script:a.info.script,confidence:a.n/o,letters:o,shared:a.info.shared}:null}function U(t,e){let n=[],o="",a=null;for(let i of t){let r=K(i),s=r?Pt(r,e):null;s&&a&&s!==a&&(n.push({text:o,lang:a}),o=""),s&&(a=s),o+=i}return o&&n.push({text:o,lang:a??e}),n.filter(i=>i.text.trim()).reduce((i,r)=>{let s=i[i.length-1];return s&&s.lang===r.lang?s.text+=r.text:i.push({...r}),i},[])}function Pt(t,e){let n={lang:t.lang,script:t.script,confidence:1,letters:1,shared:t.shared};return e&&D(e,n)?e:t.lang}var pt=new Set(["en","fr","de","es","pt","it","nl","sv","da","no","nb","fi","pl","cs","ro","hu","tr","id","ms","vi","sw","tl"]),Nt=t=>pt.has(y(t));function v(t){let e=t;for(;e;){let n=e.getAttribute("lang");if(n!==null&&n!=="")return n;e=e.parentElement??e.getRootNode().host??null}return""}var Dt="script,style,noscript,template,code,pre,kbd,samp,var,textarea,input,select,option,[contenteditable=''],[contenteditable='true'],[data-yuktai-a11y='off'],svg,math";function x(t){try{return!!t.closest(Dt)}catch{return!1}}function ht(t){let e="";for(let n of Array.from(t.childNodes))if(n.nodeType===3)e+=n.textContent??"";else if(n.nodeType===1){let o=n;if(bt.has(o.tagName.toLowerCase())||o.hasAttribute("lang")||x(o))continue;e+=ht(o)}return e}var bt=new Set(["p","h1","h2","h3","h4","h5","h6","li","dt","dd","td","th","caption","figcaption","blockquote","q","label","legend","button","a","summary","div","section","article","aside","header","footer","nav","main","span","em","strong","b","i","small","cite","title"]);function Y(t,e=2e4){let n=t.body;if(!n)return"";let o=t.createTreeWalker(n,4),a="";for(;o.nextNode()&&a.length<e;){let i=o.currentNode.parentElement;i&&!x(i)&&(a+=o.currentNode.textContent+" ")}return a}function z(t){let e=t.documentElement.getAttribute("lang")??"",n=N(Y(t),20),o=!!(e&&n&&n.confidence>=.7&&!D(e,n));return{declared:e,detected:n,mismatch:o}}function D(t,e){let n=y(t);return n===e.lang?!0:({Devanagari:["hi","mr","ne","sa","kok","mai","doi","brx","bho"],Bengali:["bn","as","mni"],Arabic:["ar","ur","fa","sd","ks","ps"],Latin:Array.from(pt),Cyrillic:["ru","uk","bg","sr","be","kk"],Han:["zh","ja"],Hebrew:["he","yi"]}[e.script]??[]).includes(n)}function J(t,e={apply:!0}){let n=[],o=t.documentElement;if(!o.getAttribute("lang")){let r=N(Y(t),20);r&&(n.push({el:o,lang:r.lang,scope:"page"}),e.apply&&(o.setAttribute("lang",r.lang),o.setAttribute("data-yuktai-lang","added")))}let a=e.root??t.body;if(!a)return n;let i=Array.from(a.querySelectorAll("*"));for(let r of i){let s=r.tagName.toLowerCase();if(!bt.has(s)||r.hasAttribute("lang")||x(r))continue;let l=N(ht(r),3);if(!l||l.confidence<.6)continue;let d=e.apply?v(r):It(r,n);if(!d||!D(d,l)){if(l.script==="Latin"&&d&&Nt(d))continue;n.push({el:r,lang:l.lang,scope:"part"}),e.apply&&(r.setAttribute("lang",l.lang),r.setAttribute("data-yuktai-lang","added"),mt(l.lang)&&!r.hasAttribute("dir")&&(r.setAttribute("dir","rtl"),r.setAttribute("data-yuktai-lang","added-dir")))}}return n}function It(t,e){let n=t.parentElement;for(;n;){let o=e.find(i=>i.el===n);if(o)return o.lang;let a=n.getAttribute("lang");if(a)return a;n=n.parentElement}return""}function X(t){let e=0;return t.querySelectorAll("[data-yuktai-lang]").forEach(n=>{n.getAttribute("data-yuktai-lang")==="added-dir"&&n.removeAttribute("dir"),n.removeAttribute("lang"),n.removeAttribute("data-yuktai-lang"),e++}),e}async function Bt(t,e){if(!e.shared)return e.lang;let n=globalThis.LanguageDetector;if(!n)return e.lang;try{if(n.availability&&await n.availability()==="unavailable")return e.lang;let o=await n.create(),[a]=await o.detect(t.slice(0,2e3));if(a&&a.confidence>=.6&&a.detectedLanguage!=="und")return D(a.detectedLanguage,e)?a.detectedLanguage:e.lang}catch{}return e.lang}var Ot=new Set(["a","button","input","select","textarea","summary","details","option","label","video","audio"]),Gt=new Set(["click here","here","read more","more","link","this","click","\u0C07\u0C15\u0C4D\u0C15\u0C21","\u0C07\u0C15\u0C4D\u0C15\u0C21 \u0C15\u0C4D\u0C32\u0C3F\u0C15\u0C4D \u0C1A\u0C47\u0C2F\u0C02\u0C21\u0C3F","\u0C2E\u0C30\u0C3F\u0C02\u0C24","\u092F\u0939\u093E\u0901","\u092F\u0939\u093E\u0902 \u0915\u094D\u0932\u093F\u0915 \u0915\u0930\u0947\u0902","\u0914\u0930 \u092A\u0922\u093C\u0947\u0902"]),b=(t,e,n,o)=>({rule:t,status:e,wcag:A[t],where:k(n),data:o,el:n});function T(t){let e=t.ownerDocument,n=t.getAttribute("aria-labelledby");if(n){let r=n.split(/\s+/).map(s=>e.getElementById(s)?.textContent?.trim()??"").join(" ").trim();if(r)return r}let o=t.getAttribute("aria-label")?.trim();if(o)return o;let a=t.tagName.toLowerCase();if(a==="input"||a==="select"||a==="textarea"){let r=t.getAttribute("id");if(r){let d=e.querySelector(`label[for="${qt(r)}"]`);if(d?.textContent?.trim())return d.textContent.trim()}let s=t.closest("label");if(s?.textContent?.trim())return s.textContent.trim();let l=(t.getAttribute("type")||"").toLowerCase();return(l==="submit"||l==="button"||l==="reset")&&t.value?t.value:l==="image"&&t.getAttribute("alt")?t.getAttribute("alt"):t.getAttribute("title")?.trim()||""}if(a==="img")return t.getAttribute("alt")??"";let i=(t.textContent??"").replace(/\s+/g," ").trim();if(i)return i;for(let r of Array.from(t.querySelectorAll("img[alt], [aria-label], svg title"))){let s=r.tagName.toLowerCase()==="title"?r.textContent:r.getAttribute("alt")??r.getAttribute("aria-label");if(s&&s.trim())return s.trim()}return t.getAttribute("title")?.trim()||""}function qt(t){let e=globalThis.CSS;return e?.escape?e.escape(t):t.replace(/["\\]/g,"\\$&")}function Vt(t){if(t.closest("[hidden],[aria-hidden='true']"))return!0;let e=t.ownerDocument.defaultView;if(!e)return!1;let n=e.getComputedStyle(t);return n.display==="none"||n.visibility==="hidden"}var Ht=t=>{let e=t.tagName.toLowerCase();return t.hasAttribute("disabled")?!1:t.hasAttribute("tabindex")?Number(t.getAttribute("tabindex"))>=0:e==="a"?t.hasAttribute("href"):["button","input","select","textarea","summary","iframe"].includes(e)||t.getAttribute("contenteditable")==="true"};function I(t,e,n){let o=[],a=0,i=0;for(let r of e){if(r.closest("[data-yuktai-a11y='off'],[data-yuktai-ui]"))continue;let s=r.tagName.toLowerCase(),l=Vt(r);if(/^h[1-6]$/.test(s)&&!l){let c=Number(s[1]);c===1&&i++,a&&c>a+1&&o.push(b("heading-skip","check",r,{from:a,to:c})),a=c}if(l){r.getAttribute("aria-hidden")==="true"&&Ht(r)&&o.push(b("aria-hidden-focusable","check",r));continue}if(s==="img"&&!r.hasAttribute("alt")&&r.getAttribute("role")!=="presentation"&&r.getAttribute("role")!=="none"&&!r.getAttribute("aria-label")&&!r.getAttribute("aria-labelledby")&&o.push(b("img-alt-missing","check",r)),(s==="button"||s==="a"&&r.hasAttribute("href")||r.getAttribute("role")==="button"||r.getAttribute("role")==="link")&&!T(r)&&o.push(b("control-name-missing","check",r,{tag:r.getAttribute("role")||s})),s==="a"&&r.hasAttribute("href")){let c=(r.textContent??"").replace(/\s+/g," ").trim().toLowerCase();c&&Gt.has(c)&&!r.getAttribute("aria-label")&&!r.getAttribute("aria-labelledby")&&o.push(b("link-text-vague","check",r,{text:c}))}if(["input","select","textarea"].includes(s)){let c=(r.getAttribute("type")||"").toLowerCase();!["hidden","submit","button","reset","image"].includes(c)&&!T(r)&&o.push(b("field-label-missing","check",r))}s==="iframe"&&!r.getAttribute("title")&&!r.getAttribute("aria-label")&&o.push(b("iframe-title-missing","check",r)),s==="table"&&r.getAttribute("role")!=="presentation"&&r.querySelectorAll("tr").length>1&&!r.querySelector("th,[role='columnheader'],[role='rowheader']")&&o.push(b("table-headers-missing","check",r)),(s==="video"||s==="audio")&&r.hasAttribute("autoplay")&&!r.hasAttribute("muted")&&!r.hasAttribute("controls")&&o.push(b("media-autoplay","check",r));let d=r.getAttribute("tabindex");if(d!==null&&Number(d)>0&&o.push(b("tabindex-positive","check",r,{value:d})),!Ot.has(s)&&!r.getAttribute("role")&&r.hasAttribute("onclick")&&!x(r)){let c=T(r);if(n.fix&&c){r.setAttribute("role","button");let g=!r.hasAttribute("tabindex");g&&r.setAttribute("tabindex","0"),$t(r),r.setAttribute("data-yuktai-fix",g?"fake-button tabindex":"fake-button"),o.push(b("fake-button","fixed",r,{tag:s}))}else o.push(b(c?"clickable-not-focusable":"control-name-missing","check",r,{tag:s}))}}return i!==1&&e.length&&o.push(b("h1-count","check",t.body??t.documentElement,{count:i})),t.body&&!t.querySelector("main,[role='main']")&&o.push(b("main-landmark-missing","check",t.body)),o}var C=Symbol.for("yuktai.keys");function $t(t){let e=t;if(e[C])return;let n=o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),e.click())};e[C]=n,e.addEventListener("keydown",n)}function B(t){let e=0;return t.querySelectorAll("[data-yuktai-fix~='fake-button']").forEach(n=>{n.removeAttribute("role"),(n.getAttribute("data-yuktai-fix")??"").includes("tabindex")&&n.removeAttribute("tabindex");let o=n;o[C]&&(o.removeEventListener("keydown",o[C]),delete o[C]),n.removeAttribute("data-yuktai-fix"),e++}),e}var O={mode:"auto",level:"AA",contrast:"check",lang:"auto",speak:"off"};function R(t,e,n){let o=(t??"").trim();return e.find(i=>i.toLowerCase()===o.toLowerCase())??n}function Z(t){return[t.body,t.documentElement].some(e=>e&&Array.from(e.attributes).some(n=>n.name.startsWith("data-yuktai-")))}function Q(t,e={}){let n=a=>t.body?.getAttribute(a)??t.documentElement.getAttribute(a),o={...O,...e};return{mode:R(n("data-yuktai-a11y"),["auto","check","off"],o.mode),level:R(n("data-yuktai-level"),["AA","AAA","off"],o.level),contrast:R(n("data-yuktai-contrast"),["check","fix"],o.contrast),lang:R(n("data-yuktai-lang"),["auto","off"],o.lang),speak:R(n("data-yuktai-speak"),["on","off"],o.speak)}}function E(t){if(!t)return null;let e=t.trim().toLowerCase();if(e==="transparent")return{r:0,g:0,b:0,a:0};let n=e.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/);if(n){let a=1;return n[4]!==void 0&&(a=n[4].endsWith("%")?parseFloat(n[4])/100:parseFloat(n[4])),{r:+n[1],g:+n[2],b:+n[3],a}}let o=e.match(/^#([0-9a-f]{3,8})$/);if(o){let a=o[1];return(a.length===3||a.length===4)&&(a=a.split("").map(i=>i+i).join("")),a.length!==6&&a.length!==8?null:{r:parseInt(a.slice(0,2),16),g:parseInt(a.slice(2,4),16),b:parseInt(a.slice(4,6),16),a:a.length===8?parseInt(a.slice(6,8),16)/255:1}}return null}var tt=t=>{let e=t/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)};function q(t){return .2126*tt(t.r)+.7152*tt(t.g)+.0722*tt(t.b)}function S(t,e){let n=q(t),o=q(e),[a,i]=n>o?[n,o]:[o,n];return(a+.05)/(i+.05)}function et(t,e){let n=t.a;return{r:Math.round(t.r*n+e.r*(1-n)),g:Math.round(t.g*n+e.g*(1-n)),b:Math.round(t.b*n+e.b*(1-n)),a:1}}function yt(t,e){return t>=24||t>=18.66&&e>=700}function V(t,e){return t==="AAA"?e?4.5:7:e?3:4.5}var G={r:255,g:255,b:255,a:1};function kt(t){let e=[],n=t,o=t.ownerDocument?.defaultView;if(!o)return{color:null,reason:"no-window"};for(;n;){let i=o.getComputedStyle(n),r=i.backgroundImage;if(r&&r!=="none"&&r!=="initial")return{color:null,reason:"background-image"};let s=i.backgroundColor,l=s&&s!=="initial"?E(s):null;if(l===null&&s&&s!=="initial")return{color:null,reason:"colour-format"};if(l&&l.a>0&&(e.push(l),l.a>=1))break;n=jt(n)}let a=G;e.length&&e[e.length-1].a>=1&&(a=e.pop());for(let i=e.length-1;i>=0;i--)a=et(e[i],a);return{color:a}}function jt(t){if(t.parentElement)return t.parentElement;let e=t.getRootNode();return e&&e.host?e.host:null}function nt(t,e){if(e==="off")return{status:"pass"};let n=t.ownerDocument?.defaultView;if(!n)return{status:"unknown",reason:"no-window"};let o=n.getComputedStyle(t),a=o.color;for(let f=t.parentElement;!a&&f;f=f.parentElement)a=n.getComputedStyle(f).color;let i=a?E(a):{r:0,g:0,b:0,a:1};if(!i)return{status:"unknown",reason:"colour-format"};let r=kt(t);if(!r.color)return{status:"unknown",reason:r.reason};let s=i.a<1?et(i,r.color):i,l=parseFloat(o.fontSize)||16,d=parseInt(o.fontWeight,10)||(o.fontWeight==="bold"?700:400),c=yt(l,d),g=V(e,c),p=Math.round(S(s,r.color)*100)/100;return{status:p+1e-9>=g?"pass":"fail",ratio:p,required:g,large:c,fg:s,bg:r.color}}var w=t=>"#"+[t.r,t.g,t.b].map(e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0")).join("");function F(t,e,n){if(S(t,e)>=n)return{...t,a:1};let a=q(e)>.18?{r:0,g:0,b:0,a:1}:G;for(let i=.05;i<=1.0001;i+=.05){let r={r:t.r+(a.r-t.r)*i,g:t.g+(a.g-t.g)*i,b:t.b+(a.b-t.b)*i,a:1},s={r:Math.round(r.r),g:Math.round(r.g),b:Math.round(r.b),a:1};if(S(s,e)>=n)return s}return S({r:0,g:0,b:0,a:1},e)>=S(G,e)?{r:0,g:0,b:0,a:1}:G}var Wt=t=>t.tagName.includes("-");function H(t,e=5e4){let n={elements:[],closed:[],crossOrigin:[]},o=a=>{let i=a.querySelectorAll("*");for(let r of Array.from(i)){if(n.elements.length>=e)return;if(r.closest("[data-yuktai-ui]"))continue;n.elements.push(r);let s=r.shadowRoot;if(s?o(s):Wt(r)&&!r.children.length&&!(r.textContent??"").trim()&&r.ownerDocument.defaultView?.customElements?.get(r.tagName.toLowerCase())&&n.closed.push(r),r.tagName==="IFRAME"){let l=r,d=null;try{d=l.contentDocument}catch{d=null}!d&&l.getAttribute("src")&&!/^(about:|javascript:)/i.test(l.getAttribute("src")||"")&&n.crossOrigin.push(l)}}};return o(t),n}var M={textSize:100,spacing:!1,reduceMotion:"device",focusRing:!1,theme:"default",dark:"off",level:"AA"},rt="yuktai-a11y-prefs";function xt(t){let e=[],n=Math.min(200,Math.max(100,Math.round(t.textSize||100)));n!==100&&e.push(`html{font-size:${n}% !important}`),t.spacing&&e.push("body *:not([data-yuktai-ui]):not([data-yuktai-ui] *){line-height:1.5 !important;letter-spacing:.12em !important;word-spacing:.16em !important}","body p:not([data-yuktai-ui] *){margin-bottom:2em !important}");let o="*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}";t.reduceMotion==="on"&&e.push(o),t.reduceMotion==="device"&&e.push(`@media (prefers-reduced-motion: reduce){${o}}`),t.focusRing&&e.push(":focus-visible{outline:3px solid #2F43C4 !important;outline-offset:2px !important;box-shadow:0 0 0 5px #FFFFFF !important}");let a=":not([data-yuktai-ui]):not([data-yuktai-ui] *)";if(t.theme==="high-contrast")e.push("html,body{background:#000 !important}",`body *${a}{background-color:#000 !important;color:#FFF !important;border-color:#FFF !important}`,`body a${a},body a${a} *{color:#FFFF00 !important}`,`body button${a},body [role=button]${a}{color:#00FFFF !important}`);else if(t.theme==="soft")e.push("html,body{background:#F4ECD8 !important}",`body *${a}{background-color:transparent !important;color:#3B2F1E !important}`,`body a${a}{color:#1F4E9E !important}`);else if(t.theme==="custom"&&t.custom){let r=E(t.custom.background),s=E(t.custom.text);if(r&&s){let l=V(t.level==="off"?"AA":t.level,!1),d=S(s,r)>=l?s:F(s,r,l);e.push(`html,body{background:${w(r)} !important}`,`body *${a}{background-color:transparent !important;color:${w(d)} !important;border-color:${w(d)} !important}`)}}let i='html{filter:invert(1) hue-rotate(180deg) !important;background:#FFF}img,video,picture,canvas,iframe,svg image,[style*="background-image"],[data-yuktai-ui]{filter:invert(1) hue-rotate(180deg) !important}';return t.theme==="default"&&(t.dark==="on"&&e.push(i),t.dark==="device"&&e.push(`@media (prefers-color-scheme: dark){${i}}`)),e.join(`
2
+ `)}function ot(t,e){let n=xt(e),o=t.getElementById(rt);if(!n){o?.remove();return}o||(o=t.createElement("style"),o.id=rt,o.setAttribute("data-yuktai-ui",""),(t.head??t.documentElement).appendChild(o)),o.textContent=n}function at(t){t.getElementById(rt)?.remove()}function _t(t="yuktai-a11y-prefs"){try{let e=globalThis.localStorage?.getItem(t);if(e)return{...M,...JSON.parse(e)}}catch{}return{...M}}function Kt(t,e="yuktai-a11y-prefs"){try{globalThis.localStorage?.setItem(e,JSON.stringify(t))}catch{}}var it=()=>typeof globalThis<"u"&&globalThis.speechSynthesis||null,$=()=>!!it()&&typeof globalThis.SpeechSynthesisUtterance=="function";function st(t=1500){let e=it();if(!e)return Promise.resolve([]);let n=e.getVoices();return n.length?Promise.resolve(n):new Promise(o=>{let a=()=>{clearTimeout(i),e.removeEventListener?.("voiceschanged",a),o(e.getVoices())},i=setTimeout(a,t);e.addEventListener?.("voiceschanged",a)})}function At(t,e){let n=t.toLowerCase().replace("_","-"),o=y(n),a=l=>l.lang.toLowerCase().replace("_","-"),i=l=>l.localService?0:1,r=e.filter(l=>a(l)===n).sort((l,d)=>i(l)-i(d));return r.length?r[0]:e.filter(l=>y(a(l))===o).sort((l,d)=>{let c=a(l).endsWith("-in")?0:1,g=a(d).endsWith("-in")?0:1;return c-g||i(l)-i(d)})[0]??null}async function Ut(){let t=await st();return Array.from(new Set(t.map(e=>y(e.lang)))).sort()}function St(t,e=220){let n=t.replace(/\s+/g," ").trim().split(/(?<=[.!?।॥\n])\s+/),o=[];for(let a of n){if(!a)continue;if(a.length<=e){o.push(a);continue}let i=a;for(;i.length>e;){let r=i.lastIndexOf(",",e);r<e/2&&(r=i.lastIndexOf(" ",e)),r<e/3&&(r=e),o.push(i.slice(0,r+1).trim()),i=i.slice(r+1)}i.trim()&&o.push(i.trim())}return o}function wt(t){let n=t.ownerDocument.createTreeWalker(t,4),o="";for(;n.nextNode();){let a=n.currentNode.parentElement;!a||x(a)||a.closest("[data-yuktai-speak='off'],[aria-hidden='true']")||(o+=n.currentNode.textContent+" ")}return o.replace(/\s+/g," ").trim()}function lt(t,e={}){let n=it(),a=(e.lang??(typeof t=="string"?"":v(t))??"")||(typeof document<"u"?document.documentElement.lang:"")||"en",i=typeof t=="string"?t:wt(t),r=U(i,a),s=!1,l={parts:r,pause:()=>n?.pause(),resume:()=>n?.resume(),stop:()=>{s=!0,n?.cancel(),e.onEnd?.()}};return!n||!$()||!r.length?(queueMicrotask(()=>e.onEnd?.()),l):(n.cancel(),st().then(d=>{if(s)return;let c=new Set,g=[];if(r.forEach((f,u)=>{let m=At(f.lang,d);if(!m){c.has(y(f.lang))||(c.add(y(f.lang)),e.onMissingVoice?.(f.lang));return}for(let h of St(f.text))g.push({text:h,voice:m,part:f,index:u})}),!g.length){e.onEnd?.();return}let p=-1;g.forEach((f,u)=>{let m=globalThis.SpeechSynthesisUtterance,h=new m(f.text);h.voice=f.voice,h.lang=f.voice.lang,h.rate=Math.min(2,Math.max(.5,e.rate??1)),h.onstart=()=>{f.index!==p&&(p=f.index,e.onPart?.(f.part,f.index,r.length))},u===g.length-1&&(h.onend=()=>!s&&e.onEnd?.()),n.speak(h)})}),l)}var j={en:{read:"Read aloud",stop:"Stop reading",noVoice:"This device has no voice for"},te:{read:"\u0C1A\u0C26\u0C3F\u0C35\u0C3F \u0C35\u0C3F\u0C28\u0C3F\u0C2A\u0C3F\u0C02\u0C1A\u0C41",stop:"\u0C1A\u0C26\u0C35\u0C21\u0C02 \u0C06\u0C2A\u0C41",noVoice:"\u0C08 device \u0C32\u0C4B voice \u0C32\u0C47\u0C26\u0C41:"},hi:{read:"\u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u090F\u0901",stop:"\u092A\u0922\u093C\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",noVoice:"\u0907\u0938 \u0921\u093F\u0935\u093E\u0907\u0938 \u092E\u0947\u0902 \u0906\u0935\u093E\u091C\u093C \u0928\u0939\u0940\u0902 \u0939\u0948:"}},Yt='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M11 5 6 9H3v6h3l5 4z"></path><path d="M15.5 8.5a5 5 0 0 1 0 7"></path><path d="M18.5 5.5a9 9 0 0 1 0 13"></path></svg>';function zt(t){let e=Number(t.tagName[1]),n=[t],o=t.nextElementSibling;for(;o&&!(/^H[1-6]$/.test(o.tagName)&&Number(o.tagName[1])<=e);)o.hasAttribute("data-yuktai-ui")||n.push(o),o=o.nextElementSibling;return n}function W(t,e={}){if(!$())return()=>{};let n=null,o=[],a=()=>{if(!n)return;let{speaker:r,button:s}=n;n=null,r.stop(),i(s,!1)},i=(r,s)=>{let l=j[y(r.dataset.lang??"en")]??j.en;r.setAttribute("aria-pressed",s?"true":"false"),r.setAttribute("aria-label",`${s?l.stop:l.read}: ${r.dataset.title}`)};return t.querySelectorAll("h1,h2,h3").forEach(r=>{if(r.closest("[data-yuktai-speak='off'],[data-yuktai-a11y='off'],[data-yuktai-ui],[hidden]")||r.nextElementSibling?.hasAttribute("data-yuktai-speak-button"))return;let s=(r.textContent??"").replace(/\s+/g," ").trim();if(!s)return;let l=t.createElement("button");l.type="button",l.innerHTML=Yt,l.setAttribute("data-yuktai-ui",""),l.setAttribute("data-yuktai-speak-button",""),l.dataset.title=s.slice(0,80),l.dataset.lang=v(r)||"en",l.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;margin:4px 0;border-radius:999px;border:1px solid #C9CBD3;background:#FFFFFF;color:#2F43C4;cursor:pointer;vertical-align:middle",i(l,!1),l.addEventListener("click",()=>{if(n?.button===l)return a();a();let d=zt(r),c=t.createElement("div");for(let p of d)c.appendChild(p.cloneNode(!0));c.setAttribute("lang",v(r)||t.documentElement.lang||"en"),n={speaker:lt(c,{lang:c.getAttribute("lang")??void 0,onMissingVoice:p=>{let f=j[y(l.dataset.lang??"en")]??j.en;e.onMissingVoice?.(p,`${f.noVoice} ${p}`)},onEnd:()=>{n?.button===l&&(n=null,i(l,!1))}}),button:l},i(l,!0)}),r.insertAdjacentElement("afterend",l),o.push(l)}),()=>{a(),o.forEach(r=>r.remove())}}var ct="6.0.0",Jt="p,h1,h2,h3,h4,h5,h6,li,td,th,dt,dd,a,button,label,span,small,strong,em,b,figcaption,caption,blockquote,summary,legend";function Xt(t){for(let e of Array.from(t.childNodes))if(e.nodeType===3&&(e.textContent??"").trim())return!0;return!1}function ut(t={}){let e=t.document??document,n=t.attributes===!1?{...O,...vt(t)}:Q(e,vt(t)),o={...M,level:n.level},a=null,i=null,r=null,s=!1,l=()=>{s=!0;let c={level:n.level,mode:n.mode,fixed:[],check:[],unknown:[],scanned:0,at:new Date().toISOString()};try{if(n.mode==="off")return a=c;let g=n.mode==="auto",p=H(e);c.scanned=p.elements.length;let f=u=>c[u.status].push(u);if(n.lang==="auto"){let u=z(e);u.mismatch&&u.detected&&f({rule:"page-lang-mismatch",status:"check",wcag:A["page-lang-mismatch"],where:"html",data:{declared:u.declared,detected:u.detected.lang},el:e.documentElement});for(let m of J(e,{apply:g})){let h=m.scope==="page"?"page-lang-missing":"part-lang-missing";f({rule:h,status:g?"fixed":"check",wcag:A[h],where:m.scope==="page"?"html":k(m.el),data:{lang:m.lang},el:m.el})}}for(let u of I(e,p.elements,{fix:g}))f(u);if(n.level!=="off")for(let u of p.elements){if(!u.matches(Jt)||!Xt(u)||x(u)||u.closest("[data-yuktai-ui],[data-yuktai-a11y='off'],[hidden],[aria-hidden='true']"))continue;let m=nt(u,n.level);if(m.status!=="pass"){if(m.status==="unknown"){f({rule:"contrast-unknown",status:"unknown",wcag:A["contrast-unknown"],where:k(u),data:{reason:m.reason??""},el:u});continue}if(g&&n.contrast==="fix"&&m.fg&&m.bg&&m.required){let h=F(m.fg,m.bg,m.required),P=u;P.hasAttribute("data-yuktai-color")||P.setAttribute("data-yuktai-color",P.style.getPropertyValue("color")||"-"),P.style.setProperty("color",w(h),"important"),f({rule:"contrast",status:"fixed",wcag:n.level==="AAA"?"1.4.6":"1.4.3",where:k(u),data:{ratio:m.ratio??0,required:m.required,to:w(h)},el:u})}else f({rule:"contrast",status:"check",wcag:n.level==="AAA"?"1.4.6":"1.4.3",where:k(u),data:{ratio:m.ratio??0,required:m.required??0},el:u})}}for(let u of p.closed)f({rule:"closed-shadow-root",status:"unknown",wcag:"",where:k(u),el:u});for(let u of p.crossOrigin)f({rule:"iframe-cross-origin",status:"unknown",wcag:"",where:k(u),data:{src:u.getAttribute("src")??""},el:u})}finally{i?.takeRecords(),s=!1}return a=c,t.onReport?.(c),c},d=()=>{X(e),B(e),e.querySelectorAll("[data-yuktai-color]").forEach(c=>{let g=c,p=g.getAttribute("data-yuktai-color");g.style.removeProperty("color"),p&&p!=="-"&&g.style.setProperty("color",p),g.removeAttribute("data-yuktai-color")}),at(e),a=null};return t.observe!==!1&&typeof MutationObserver<"u"&&n.mode!=="off"&&(i=new MutationObserver(c=>{s||c.some(g=>g.type==="childList"&&g.addedNodes.length)&&(r&&clearTimeout(r),r=setTimeout(l,400))}),queueMicrotask(()=>e.body&&i?.observe(e.body,{childList:!0,subtree:!0}))),{settings:n,run:l,get report(){return a},setPrefs(c){return o={...o,...c},ot(e,o),o},get prefs(){return o},undo:d,destroy(){i?.disconnect(),i=null,r&&clearTimeout(r),d()}}}function vt(t){let e={};for(let n of["mode","level","contrast","lang","speak"]){let o=t[n];o!==void 0&&(e[n]=o)}return e}var L=null,Et=null;function Tt(t={}){return L?.destroy(),Et?.(),L=ut({...window.YuktaiA11yConfig,...t}),L.run(),L.settings.speak==="on"&&(Et=W(document)),window.YuktaiA11y&&(window.YuktaiA11y.instance=L),L}window.YuktaiA11y={instance:null,version:ct,api:dt,start:Tt};var Lt=()=>{(window.YuktaiA11yConfig||Z(document))&&Tt()};document.readyState==="complete"?requestAnimationFrame(Lt):window.addEventListener("load",()=>requestAnimationFrame(Lt),{once:!0});})();
package/dist/aria.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { type Finding } from "./report";
2
+ /** A simple accessible name: aria-labelledby, aria-label, labels, alt/title, text, child images. */
3
+ export declare function accessibleName(el: Element): string;
4
+ export interface AriaOptions {
5
+ /** true: apply the safe fix (fake buttons). false: report only. */
6
+ fix: boolean;
7
+ }
8
+ /** Runs the structure and name rules over `elements`. */
9
+ export declare function auditAria(doc: Document, elements: Element[], opts: AriaOptions): Finding[];
10
+ /** Removes every attribute and key handler auditAria added. */
11
+ export declare function undoAria(doc: Document): number;
@@ -0,0 +1,12 @@
1
+ import type { Level } from "./contrast";
2
+ export interface A11ySettings {
3
+ mode: "auto" | "check" | "off";
4
+ level: Level;
5
+ contrast: "check" | "fix";
6
+ lang: "auto" | "off";
7
+ speak: "on" | "off";
8
+ }
9
+ export declare const DEFAULT_SETTINGS: A11ySettings;
10
+ /** True when the page asks for YuktAI accessibility through attributes. */
11
+ export declare function hasAttributes(doc: Document): boolean;
12
+ export declare function readAttributes(doc: Document, base?: Partial<A11ySettings>): A11ySettings;
@@ -0,0 +1,49 @@
1
+ export type Level = "off" | "AA" | "AAA";
2
+ export interface RGBA {
3
+ r: number;
4
+ g: number;
5
+ b: number;
6
+ a: number;
7
+ }
8
+ export interface ContrastResult {
9
+ status: "pass" | "fail" | "unknown";
10
+ /** Contrast ratio, 1–21, when known. */
11
+ ratio?: number;
12
+ /** Ratio the text needs at this level and size. */
13
+ required?: number;
14
+ large?: boolean;
15
+ /** Why the result is unknown. */
16
+ reason?: string;
17
+ fg?: RGBA;
18
+ bg?: RGBA;
19
+ }
20
+ /** Parses rgb()/rgba() (as getComputedStyle returns), #rgb, #rrggbb, #rrggbbaa and "transparent". */
21
+ export declare function parseColor(value: string | null | undefined): RGBA | null;
22
+ /** WCAG relative luminance. */
23
+ export declare function luminance(c: RGBA): number;
24
+ export declare function contrastRatio(a: RGBA, b: RGBA): number;
25
+ /** Puts `top` (with alpha) over an opaque `bottom`. */
26
+ export declare function blend(top: RGBA, bottom: RGBA): RGBA;
27
+ /** WCAG "large text": 24 px and up, or 18.66 px (14 pt) and up when bold. */
28
+ export declare function isLargeText(fontSizePx: number, fontWeight: number): boolean;
29
+ /** The ratio text must reach: AA 4.5 (large 3), AAA 7 (large 4.5). */
30
+ export declare function requiredRatio(level: Level, large: boolean): number;
31
+ /**
32
+ * The colour actually behind an element: walks up the ancestors, blending
33
+ * translucent backgrounds, until one is opaque. Returns null (unknown) when a
34
+ * background image or gradient is on the way, because the pixels behind the
35
+ * text then cannot be known from styles alone.
36
+ */
37
+ export declare function effectiveBackground(el: Element): {
38
+ color: RGBA | null;
39
+ reason?: string;
40
+ };
41
+ /** Checks one element's text colour against its background. */
42
+ export declare function checkElementContrast(el: Element, level: Level): ContrastResult;
43
+ export declare const toHex: (c: RGBA) => string;
44
+ /**
45
+ * The closest colour to `fg` (same hue, darker or lighter) that reaches
46
+ * `required` on `bg`. Moves towards black on light backgrounds and towards
47
+ * white on dark ones; falls back to pure black or white.
48
+ */
49
+ export declare function nearestPassingColor(fg: RGBA, bg: RGBA, required: number): RGBA;
@@ -0,0 +1,8 @@
1
+ export interface FoundTree {
2
+ elements: Element[];
3
+ /** Custom elements whose inside we cannot see (closed shadow root, or not upgraded). */
4
+ closed: Element[];
5
+ /** Iframes we cannot read (another site, or blocked). */
6
+ crossOrigin: HTMLIFrameElement[];
7
+ }
8
+ export declare function findAll(root: Document | Element | ShadowRoot, limit?: number): FoundTree;
@@ -0,0 +1,13 @@
1
+ import { type A11y, type A11yOptions } from "./index";
2
+ import * as api from "./index";
3
+ declare global {
4
+ interface Window {
5
+ YuktaiA11yConfig?: A11yOptions;
6
+ YuktaiA11y?: {
7
+ instance: A11y | null;
8
+ version: string;
9
+ api: typeof api;
10
+ start: (o?: A11yOptions) => A11y;
11
+ };
12
+ }
13
+ }
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var j=Object.defineProperty;var At=Object.getOwnPropertyDescriptor;var St=Object.getOwnPropertyNames;var wt=Object.prototype.hasOwnProperty;var vt=(t,e)=>{for(var n in e)j(t,n,{get:e[n],enumerable:!0})},Et=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of St(e))!wt.call(t,a)&&a!==n&&j(t,a,{get:()=>e[a],enumerable:!(o=At(e,a))||o.enumerable});return t};var Lt=t=>Et(j({},"__esModule",{value:!0}),t);var Zt={};vt(Zt,{DEFAULT_PREFS:()=>F,DEFAULT_SETTINGS:()=>B,MESSAGES:()=>W,VERSION:()=>zt,WCAG:()=>A,accessibleName:()=>L,addSpeakButtons:()=>xt,annotateLanguages:()=>J,applyPrefs:()=>nt,auditAria:()=>D,blend:()=>Q,canSpeak:()=>V,checkElementContrast:()=>tt,clearPrefs:()=>rt,contrastRatio:()=>S,createA11y:()=>Xt,describe:()=>x,detectText:()=>P,effectiveBackground:()=>mt,findAll:()=>H,getVoices:()=>at,hasAttributes:()=>Ht,inheritedLang:()=>v,isLargeText:()=>gt,isRtl:()=>ct,isSkipped:()=>k,loadPrefs:()=>jt,luminance:()=>G,message:()=>st,nearestPassingColor:()=>R,pageLanguage:()=>z,pageText:()=>U,parseColor:()=>E,pickVoice:()=>ht,prefsCss:()=>pt,primary:()=>y,readAttributes:()=>X,readableText:()=>yt,refineWithDetector:()=>Nt,requiredRatio:()=>q,savePrefs:()=>Wt,scriptOf:()=>_,sentences:()=>bt,speak:()=>it,speakableLanguages:()=>_t,splitByLanguage:()=>K,toHex:()=>w,toJSON:()=>lt,undoAria:()=>I,undoLanguages:()=>Y});module.exports=Lt(Zt);var A={"page-lang-missing":"3.1.1","page-lang-mismatch":"3.1.1","part-lang-missing":"3.1.2",contrast:"1.4.3","contrast-unknown":"1.4.3","img-alt-missing":"1.1.1","control-name-missing":"4.1.2","fake-button":"4.1.2","clickable-not-focusable":"2.1.1","field-label-missing":"3.3.2","heading-skip":"1.3.1","h1-count":"1.3.1","link-text-vague":"2.4.4","iframe-title-missing":"4.1.2","iframe-cross-origin":"","table-headers-missing":"1.3.1","media-autoplay":"1.4.2","tabindex-positive":"2.4.3","aria-hidden-focusable":"4.1.2","main-landmark-missing":"2.4.1","closed-shadow-root":""},W={en:{"page-lang-missing":"The page has no lang. Detected: {lang}.","page-lang-mismatch":'<html lang="{declared}"> but the text is {detected}.',"part-lang-missing":"A part in {lang} had no lang.",contrast:"Text contrast {ratio}:1, needs {required}:1.","contrast-unknown":"Contrast not checked: {reason}.","img-alt-missing":'Image has no alt text. Describe it, or use alt="" if it is decoration.',"control-name-missing":"A {tag} has no name a screen reader can say.","fake-button":"A clickable {tag} was not a button. Added role, focus and Enter/Space. A real <button> is better.","clickable-not-focusable":"Something clickable ({tag}) cannot be reached by keyboard.","field-label-missing":"A form field has no label.","heading-skip":"Heading jumps from h{from} to h{to}.","h1-count":"The page has {count} h1 headings; one is expected.","link-text-vague":'Link text "{text}" does not say where it goes.',"iframe-title-missing":"An iframe has no title.","iframe-cross-origin":"Content from another site (iframe) cannot be checked from here.","table-headers-missing":"A data table has no header cells (th).","media-autoplay":"Media plays by itself. Give a way to pause it.","tabindex-positive":'tabindex="{value}" changes the Tab order.',"aria-hidden-focusable":"A hidden (aria-hidden) element can still take focus.","main-landmark-missing":"The page has no <main>.","closed-shadow-root":"A closed component cannot be checked from outside."},te:{"page-lang-missing":"\u0C2A\u0C47\u0C1C\u0C40\u0C15\u0C3F lang \u0C32\u0C47\u0C26\u0C41. \u0C17\u0C41\u0C30\u0C4D\u0C24\u0C3F\u0C02\u0C1A\u0C3F\u0C28 \u0C2D\u0C3E\u0C37: {lang}.","page-lang-mismatch":'<html lang="{declared}"> \u0C09\u0C02\u0C26\u0C3F, \u0C15\u0C3E\u0C28\u0C40 text {detected} \u0C32\u0C4B \u0C09\u0C02\u0C26\u0C3F.',"part-lang-missing":"{lang} \u0C2D\u0C3E\u0C17\u0C3E\u0C28\u0C3F\u0C15\u0C3F lang \u0C32\u0C47\u0C26\u0C41.",contrast:"Text contrast {ratio}:1, \u0C15\u0C28\u0C40\u0C38\u0C02 {required}:1 \u0C15\u0C3E\u0C35\u0C3E\u0C32\u0C3F.","contrast-unknown":"Contrast check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C15\u0C2A\u0C4B\u0C2F\u0C3E\u0C02: {reason}.","img-alt-missing":'Image \u0C15\u0C3F alt \u0C32\u0C47\u0C26\u0C41. \u0C35\u0C3F\u0C35\u0C30\u0C23 \u0C30\u0C3E\u0C2F\u0C02\u0C21\u0C3F, \u0C05\u0C32\u0C02\u0C15\u0C3E\u0C30\u0C2E\u0C48\u0C24\u0C47 alt="" \u0C2A\u0C46\u0C1F\u0C4D\u0C1F\u0C02\u0C21\u0C3F.',"control-name-missing":"{tag} \u0C15\u0C3F screen reader \u0C1A\u0C46\u0C2A\u0C4D\u0C2A\u0C17\u0C32\u0C3F\u0C17\u0C47 \u0C2A\u0C47\u0C30\u0C41 \u0C32\u0C47\u0C26\u0C41.","fake-button":"Click \u0C1A\u0C47\u0C38\u0C47 {tag} button \u0C15\u0C3E\u0C26\u0C41. Role, focus, Enter/Space \u0C1C\u0C4B\u0C21\u0C3F\u0C02\u0C1A\u0C3E\u0C02. \u0C28\u0C3F\u0C1C\u0C2E\u0C48\u0C28 <button> \u0C07\u0C02\u0C15\u0C3E \u0C2E\u0C02\u0C1A\u0C3F\u0C26\u0C3F.","clickable-not-focusable":"Click \u0C1A\u0C47\u0C38\u0C47 {tag} \u0C28\u0C3F keyboard \u0C24\u0C4B \u0C1A\u0C47\u0C30\u0C32\u0C47\u0C2E\u0C41.","field-label-missing":"Form field \u0C15\u0C3F label \u0C32\u0C47\u0C26\u0C41.","heading-skip":"Heading h{from} \u0C28\u0C41\u0C02\u0C21\u0C3F h{to} \u0C15\u0C3F \u0C26\u0C42\u0C15\u0C3F\u0C02\u0C26\u0C3F.","h1-count":"\u0C2A\u0C47\u0C1C\u0C40\u0C32\u0C4B {count} h1 \u0C32\u0C41 \u0C09\u0C28\u0C4D\u0C28\u0C3E\u0C2F\u0C3F; \u0C12\u0C15\u0C1F\u0C3F \u0C09\u0C02\u0C21\u0C3E\u0C32\u0C3F.","link-text-vague":'Link text "{text}" \u0C0E\u0C15\u0C4D\u0C15\u0C21\u0C3F\u0C15\u0C3F \u0C35\u0C46\u0C33\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C4B \u0C1A\u0C46\u0C2A\u0C4D\u0C2A\u0C26\u0C41.',"iframe-title-missing":"iframe \u0C15\u0C3F title \u0C32\u0C47\u0C26\u0C41.","iframe-cross-origin":"\u0C35\u0C47\u0C30\u0C47 site content (iframe) \u0C28\u0C3F \u0C07\u0C15\u0C4D\u0C15\u0C21\u0C3F \u0C28\u0C41\u0C02\u0C21\u0C3F check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C2E\u0C41.","table-headers-missing":"Data table \u0C15\u0C3F header cells (th) \u0C32\u0C47\u0C35\u0C41.","media-autoplay":"Media \u0C24\u0C28\u0C02\u0C24\u0C1F \u0C24\u0C3E\u0C28\u0C47 play \u0C05\u0C35\u0C41\u0C24\u0C41\u0C02\u0C26\u0C3F. \u0C06\u0C2A\u0C47 \u0C2E\u0C3E\u0C30\u0C4D\u0C17\u0C02 \u0C07\u0C35\u0C4D\u0C35\u0C02\u0C21\u0C3F.","tabindex-positive":'tabindex="{value}" Tab \u0C15\u0C4D\u0C30\u0C2E\u0C3E\u0C28\u0C4D\u0C28\u0C3F \u0C2E\u0C3E\u0C30\u0C41\u0C38\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C3F.',"aria-hidden-focusable":"\u0C26\u0C3E\u0C1A\u0C3F\u0C28 (aria-hidden) element \u0C15\u0C3F focus \u0C35\u0C38\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C3F.","main-landmark-missing":"\u0C2A\u0C47\u0C1C\u0C40\u0C32\u0C4B <main> \u0C32\u0C47\u0C26\u0C41.","closed-shadow-root":"\u0C2E\u0C42\u0C38\u0C3F \u0C09\u0C28\u0C4D\u0C28 component \u0C28\u0C3F \u0C2C\u0C2F\u0C1F\u0C3F \u0C28\u0C41\u0C02\u0C21\u0C3F check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C2E\u0C41."}};function st(t,e="en"){return(W[e][t.rule]??t.rule).replace(/\{(\w+)\}/g,(o,a)=>String(t.data?.[a]??""))}function x(t){let e=a=>{let i=a.tagName.toLowerCase();if(a.id)return i+"#"+a.id;let r=(a.getAttribute("class")??"").trim().split(/\s+/).filter(Boolean).slice(0,2);return r.length&&(i+="."+r.join(".")),i},n=[],o=t;for(;o&&n.length<3&&o.tagName.toLowerCase()!=="body"&&o.tagName.toLowerCase()!=="html"&&(n.unshift(e(o)),!o.id);)o=o.parentElement;return n.join(" > ")||t.tagName.toLowerCase()}function lt(t){let e=n=>n.map(({el:o,...a})=>a);return{...t,fixed:e(t.fixed),check:e(t.check),unknown:e(t.unknown)}}var Tt=[{script:"Telugu",lang:"te",shared:!1,from:3072,to:3199},{script:"Kannada",lang:"kn",shared:!1,from:3200,to:3327},{script:"Tamil",lang:"ta",shared:!1,from:2944,to:3071},{script:"Malayalam",lang:"ml",shared:!1,from:3328,to:3455},{script:"Devanagari",lang:"hi",shared:!0,from:2304,to:2431},{script:"Bengali",lang:"bn",shared:!0,from:2432,to:2559},{script:"Gurmukhi",lang:"pa",shared:!1,from:2560,to:2687},{script:"Gujarati",lang:"gu",shared:!1,from:2688,to:2815},{script:"Oriya",lang:"or",shared:!1,from:2816,to:2943},{script:"Sinhala",lang:"si",shared:!1,from:3456,to:3583},{script:"Arabic",lang:"ar",shared:!0,from:1536,to:1791},{script:"Hebrew",lang:"he",shared:!0,from:1424,to:1535},{script:"Thai",lang:"th",shared:!1,from:3584,to:3711},{script:"Greek",lang:"el",shared:!1,from:880,to:1023},{script:"Cyrillic",lang:"ru",shared:!0,from:1024,to:1279},{script:"Hangul",lang:"ko",shared:!1,from:44032,to:55215},{script:"Kana",lang:"ja",shared:!1,from:12352,to:12543},{script:"Han",lang:"zh",shared:!0,from:19968,to:40959},{script:"Latin",lang:"en",shared:!0,from:65,to:591}],Ct=new Set(["ar","ur","fa","he","sd","ks","ps","yi","dv","ug"]),ct=t=>Ct.has(y(t)),y=t=>(t||"").toLowerCase().split(/[-_]/)[0];function _(t){let e=t.codePointAt(0);if(e<128&&!/[A-Za-z]/.test(t)||e>=128&&e<192)return null;for(let n of Tt)if(e>=n.from&&e<=n.to)return{script:n.script,lang:n.lang,shared:n.shared};return null}function P(t,e=3){let n=new Map,o=0;for(let i of t){let r=_(i);if(!r)continue;o++;let s=n.get(r.script);s?s.n++:n.set(r.script,{n:1,info:r})}if(o<e)return null;let a=null;for(let i of n.values())(!a||i.n>a.n)&&(a=i);return a?{lang:a.info.lang,script:a.info.script,confidence:a.n/o,letters:o,shared:a.info.shared}:null}function K(t,e){let n=[],o="",a=null;for(let i of t){let r=_(i),s=r?Rt(r,e):null;s&&a&&s!==a&&(n.push({text:o,lang:a}),o=""),s&&(a=s),o+=i}return o&&n.push({text:o,lang:a??e}),n.filter(i=>i.text.trim()).reduce((i,r)=>{let s=i[i.length-1];return s&&s.lang===r.lang?s.text+=r.text:i.push({...r}),i},[])}function Rt(t,e){let n={lang:t.lang,script:t.script,confidence:1,letters:1,shared:t.shared};return e&&N(e,n)?e:t.lang}var ut=new Set(["en","fr","de","es","pt","it","nl","sv","da","no","nb","fi","pl","cs","ro","hu","tr","id","ms","vi","sw","tl"]),Ft=t=>ut.has(y(t));function v(t){let e=t;for(;e;){let n=e.getAttribute("lang");if(n!==null&&n!=="")return n;e=e.parentElement??e.getRootNode().host??null}return""}var Mt="script,style,noscript,template,code,pre,kbd,samp,var,textarea,input,select,option,[contenteditable=''],[contenteditable='true'],[data-yuktai-a11y='off'],svg,math";function k(t){try{return!!t.closest(Mt)}catch{return!1}}function dt(t){let e="";for(let n of Array.from(t.childNodes))if(n.nodeType===3)e+=n.textContent??"";else if(n.nodeType===1){let o=n;if(ft.has(o.tagName.toLowerCase())||o.hasAttribute("lang")||k(o))continue;e+=dt(o)}return e}var ft=new Set(["p","h1","h2","h3","h4","h5","h6","li","dt","dd","td","th","caption","figcaption","blockquote","q","label","legend","button","a","summary","div","section","article","aside","header","footer","nav","main","span","em","strong","b","i","small","cite","title"]);function U(t,e=2e4){let n=t.body;if(!n)return"";let o=t.createTreeWalker(n,4),a="";for(;o.nextNode()&&a.length<e;){let i=o.currentNode.parentElement;i&&!k(i)&&(a+=o.currentNode.textContent+" ")}return a}function z(t){let e=t.documentElement.getAttribute("lang")??"",n=P(U(t),20),o=!!(e&&n&&n.confidence>=.7&&!N(e,n));return{declared:e,detected:n,mismatch:o}}function N(t,e){let n=y(t);return n===e.lang?!0:({Devanagari:["hi","mr","ne","sa","kok","mai","doi","brx","bho"],Bengali:["bn","as","mni"],Arabic:["ar","ur","fa","sd","ks","ps"],Latin:Array.from(ut),Cyrillic:["ru","uk","bg","sr","be","kk"],Han:["zh","ja"],Hebrew:["he","yi"]}[e.script]??[]).includes(n)}function J(t,e={apply:!0}){let n=[],o=t.documentElement;if(!o.getAttribute("lang")){let r=P(U(t),20);r&&(n.push({el:o,lang:r.lang,scope:"page"}),e.apply&&(o.setAttribute("lang",r.lang),o.setAttribute("data-yuktai-lang","added")))}let a=e.root??t.body;if(!a)return n;let i=Array.from(a.querySelectorAll("*"));for(let r of i){let s=r.tagName.toLowerCase();if(!ft.has(s)||r.hasAttribute("lang")||k(r))continue;let l=P(dt(r),3);if(!l||l.confidence<.6)continue;let d=e.apply?v(r):Pt(r,n);if(!d||!N(d,l)){if(l.script==="Latin"&&d&&Ft(d))continue;n.push({el:r,lang:l.lang,scope:"part"}),e.apply&&(r.setAttribute("lang",l.lang),r.setAttribute("data-yuktai-lang","added"),ct(l.lang)&&!r.hasAttribute("dir")&&(r.setAttribute("dir","rtl"),r.setAttribute("data-yuktai-lang","added-dir")))}}return n}function Pt(t,e){let n=t.parentElement;for(;n;){let o=e.find(i=>i.el===n);if(o)return o.lang;let a=n.getAttribute("lang");if(a)return a;n=n.parentElement}return""}function Y(t){let e=0;return t.querySelectorAll("[data-yuktai-lang]").forEach(n=>{n.getAttribute("data-yuktai-lang")==="added-dir"&&n.removeAttribute("dir"),n.removeAttribute("lang"),n.removeAttribute("data-yuktai-lang"),e++}),e}async function Nt(t,e){if(!e.shared)return e.lang;let n=globalThis.LanguageDetector;if(!n)return e.lang;try{if(n.availability&&await n.availability()==="unavailable")return e.lang;let o=await n.create(),[a]=await o.detect(t.slice(0,2e3));if(a&&a.confidence>=.6&&a.detectedLanguage!=="und")return N(a.detectedLanguage,e)?a.detectedLanguage:e.lang}catch{}return e.lang}var Dt=new Set(["a","button","input","select","textarea","summary","details","option","label","video","audio"]),It=new Set(["click here","here","read more","more","link","this","click","\u0C07\u0C15\u0C4D\u0C15\u0C21","\u0C07\u0C15\u0C4D\u0C15\u0C21 \u0C15\u0C4D\u0C32\u0C3F\u0C15\u0C4D \u0C1A\u0C47\u0C2F\u0C02\u0C21\u0C3F","\u0C2E\u0C30\u0C3F\u0C02\u0C24","\u092F\u0939\u093E\u0901","\u092F\u0939\u093E\u0902 \u0915\u094D\u0932\u093F\u0915 \u0915\u0930\u0947\u0902","\u0914\u0930 \u092A\u0922\u093C\u0947\u0902"]),b=(t,e,n,o)=>({rule:t,status:e,wcag:A[t],where:x(n),data:o,el:n});function L(t){let e=t.ownerDocument,n=t.getAttribute("aria-labelledby");if(n){let r=n.split(/\s+/).map(s=>e.getElementById(s)?.textContent?.trim()??"").join(" ").trim();if(r)return r}let o=t.getAttribute("aria-label")?.trim();if(o)return o;let a=t.tagName.toLowerCase();if(a==="input"||a==="select"||a==="textarea"){let r=t.getAttribute("id");if(r){let d=e.querySelector(`label[for="${Bt(r)}"]`);if(d?.textContent?.trim())return d.textContent.trim()}let s=t.closest("label");if(s?.textContent?.trim())return s.textContent.trim();let l=(t.getAttribute("type")||"").toLowerCase();return(l==="submit"||l==="button"||l==="reset")&&t.value?t.value:l==="image"&&t.getAttribute("alt")?t.getAttribute("alt"):t.getAttribute("title")?.trim()||""}if(a==="img")return t.getAttribute("alt")??"";let i=(t.textContent??"").replace(/\s+/g," ").trim();if(i)return i;for(let r of Array.from(t.querySelectorAll("img[alt], [aria-label], svg title"))){let s=r.tagName.toLowerCase()==="title"?r.textContent:r.getAttribute("alt")??r.getAttribute("aria-label");if(s&&s.trim())return s.trim()}return t.getAttribute("title")?.trim()||""}function Bt(t){let e=globalThis.CSS;return e?.escape?e.escape(t):t.replace(/["\\]/g,"\\$&")}function Ot(t){if(t.closest("[hidden],[aria-hidden='true']"))return!0;let e=t.ownerDocument.defaultView;if(!e)return!1;let n=e.getComputedStyle(t);return n.display==="none"||n.visibility==="hidden"}var Gt=t=>{let e=t.tagName.toLowerCase();return t.hasAttribute("disabled")?!1:t.hasAttribute("tabindex")?Number(t.getAttribute("tabindex"))>=0:e==="a"?t.hasAttribute("href"):["button","input","select","textarea","summary","iframe"].includes(e)||t.getAttribute("contenteditable")==="true"};function D(t,e,n){let o=[],a=0,i=0;for(let r of e){if(r.closest("[data-yuktai-a11y='off'],[data-yuktai-ui]"))continue;let s=r.tagName.toLowerCase(),l=Ot(r);if(/^h[1-6]$/.test(s)&&!l){let c=Number(s[1]);c===1&&i++,a&&c>a+1&&o.push(b("heading-skip","check",r,{from:a,to:c})),a=c}if(l){r.getAttribute("aria-hidden")==="true"&&Gt(r)&&o.push(b("aria-hidden-focusable","check",r));continue}if(s==="img"&&!r.hasAttribute("alt")&&r.getAttribute("role")!=="presentation"&&r.getAttribute("role")!=="none"&&!r.getAttribute("aria-label")&&!r.getAttribute("aria-labelledby")&&o.push(b("img-alt-missing","check",r)),(s==="button"||s==="a"&&r.hasAttribute("href")||r.getAttribute("role")==="button"||r.getAttribute("role")==="link")&&!L(r)&&o.push(b("control-name-missing","check",r,{tag:r.getAttribute("role")||s})),s==="a"&&r.hasAttribute("href")){let c=(r.textContent??"").replace(/\s+/g," ").trim().toLowerCase();c&&It.has(c)&&!r.getAttribute("aria-label")&&!r.getAttribute("aria-labelledby")&&o.push(b("link-text-vague","check",r,{text:c}))}if(["input","select","textarea"].includes(s)){let c=(r.getAttribute("type")||"").toLowerCase();!["hidden","submit","button","reset","image"].includes(c)&&!L(r)&&o.push(b("field-label-missing","check",r))}s==="iframe"&&!r.getAttribute("title")&&!r.getAttribute("aria-label")&&o.push(b("iframe-title-missing","check",r)),s==="table"&&r.getAttribute("role")!=="presentation"&&r.querySelectorAll("tr").length>1&&!r.querySelector("th,[role='columnheader'],[role='rowheader']")&&o.push(b("table-headers-missing","check",r)),(s==="video"||s==="audio")&&r.hasAttribute("autoplay")&&!r.hasAttribute("muted")&&!r.hasAttribute("controls")&&o.push(b("media-autoplay","check",r));let d=r.getAttribute("tabindex");if(d!==null&&Number(d)>0&&o.push(b("tabindex-positive","check",r,{value:d})),!Dt.has(s)&&!r.getAttribute("role")&&r.hasAttribute("onclick")&&!k(r)){let c=L(r);if(n.fix&&c){r.setAttribute("role","button");let g=!r.hasAttribute("tabindex");g&&r.setAttribute("tabindex","0"),qt(r),r.setAttribute("data-yuktai-fix",g?"fake-button tabindex":"fake-button"),o.push(b("fake-button","fixed",r,{tag:s}))}else o.push(b(c?"clickable-not-focusable":"control-name-missing","check",r,{tag:s}))}}return i!==1&&e.length&&o.push(b("h1-count","check",t.body??t.documentElement,{count:i})),t.body&&!t.querySelector("main,[role='main']")&&o.push(b("main-landmark-missing","check",t.body)),o}var T=Symbol.for("yuktai.keys");function qt(t){let e=t;if(e[T])return;let n=o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),e.click())};e[T]=n,e.addEventListener("keydown",n)}function I(t){let e=0;return t.querySelectorAll("[data-yuktai-fix~='fake-button']").forEach(n=>{n.removeAttribute("role"),(n.getAttribute("data-yuktai-fix")??"").includes("tabindex")&&n.removeAttribute("tabindex");let o=n;o[T]&&(o.removeEventListener("keydown",o[T]),delete o[T]),n.removeAttribute("data-yuktai-fix"),e++}),e}var B={mode:"auto",level:"AA",contrast:"check",lang:"auto",speak:"off"};function C(t,e,n){let o=(t??"").trim();return e.find(i=>i.toLowerCase()===o.toLowerCase())??n}function Ht(t){return[t.body,t.documentElement].some(e=>e&&Array.from(e.attributes).some(n=>n.name.startsWith("data-yuktai-")))}function X(t,e={}){let n=a=>t.body?.getAttribute(a)??t.documentElement.getAttribute(a),o={...B,...e};return{mode:C(n("data-yuktai-a11y"),["auto","check","off"],o.mode),level:C(n("data-yuktai-level"),["AA","AAA","off"],o.level),contrast:C(n("data-yuktai-contrast"),["check","fix"],o.contrast),lang:C(n("data-yuktai-lang"),["auto","off"],o.lang),speak:C(n("data-yuktai-speak"),["on","off"],o.speak)}}function E(t){if(!t)return null;let e=t.trim().toLowerCase();if(e==="transparent")return{r:0,g:0,b:0,a:0};let n=e.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/);if(n){let a=1;return n[4]!==void 0&&(a=n[4].endsWith("%")?parseFloat(n[4])/100:parseFloat(n[4])),{r:+n[1],g:+n[2],b:+n[3],a}}let o=e.match(/^#([0-9a-f]{3,8})$/);if(o){let a=o[1];return(a.length===3||a.length===4)&&(a=a.split("").map(i=>i+i).join("")),a.length!==6&&a.length!==8?null:{r:parseInt(a.slice(0,2),16),g:parseInt(a.slice(2,4),16),b:parseInt(a.slice(4,6),16),a:a.length===8?parseInt(a.slice(6,8),16)/255:1}}return null}var Z=t=>{let e=t/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)};function G(t){return .2126*Z(t.r)+.7152*Z(t.g)+.0722*Z(t.b)}function S(t,e){let n=G(t),o=G(e),[a,i]=n>o?[n,o]:[o,n];return(a+.05)/(i+.05)}function Q(t,e){let n=t.a;return{r:Math.round(t.r*n+e.r*(1-n)),g:Math.round(t.g*n+e.g*(1-n)),b:Math.round(t.b*n+e.b*(1-n)),a:1}}function gt(t,e){return t>=24||t>=18.66&&e>=700}function q(t,e){return t==="AAA"?e?4.5:7:e?3:4.5}var O={r:255,g:255,b:255,a:1};function mt(t){let e=[],n=t,o=t.ownerDocument?.defaultView;if(!o)return{color:null,reason:"no-window"};for(;n;){let i=o.getComputedStyle(n),r=i.backgroundImage;if(r&&r!=="none"&&r!=="initial")return{color:null,reason:"background-image"};let s=i.backgroundColor,l=s&&s!=="initial"?E(s):null;if(l===null&&s&&s!=="initial")return{color:null,reason:"colour-format"};if(l&&l.a>0&&(e.push(l),l.a>=1))break;n=Vt(n)}let a=O;e.length&&e[e.length-1].a>=1&&(a=e.pop());for(let i=e.length-1;i>=0;i--)a=Q(e[i],a);return{color:a}}function Vt(t){if(t.parentElement)return t.parentElement;let e=t.getRootNode();return e&&e.host?e.host:null}function tt(t,e){if(e==="off")return{status:"pass"};let n=t.ownerDocument?.defaultView;if(!n)return{status:"unknown",reason:"no-window"};let o=n.getComputedStyle(t),a=o.color;for(let f=t.parentElement;!a&&f;f=f.parentElement)a=n.getComputedStyle(f).color;let i=a?E(a):{r:0,g:0,b:0,a:1};if(!i)return{status:"unknown",reason:"colour-format"};let r=mt(t);if(!r.color)return{status:"unknown",reason:r.reason};let s=i.a<1?Q(i,r.color):i,l=parseFloat(o.fontSize)||16,d=parseInt(o.fontWeight,10)||(o.fontWeight==="bold"?700:400),c=gt(l,d),g=q(e,c),p=Math.round(S(s,r.color)*100)/100;return{status:p+1e-9>=g?"pass":"fail",ratio:p,required:g,large:c,fg:s,bg:r.color}}var w=t=>"#"+[t.r,t.g,t.b].map(e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0")).join("");function R(t,e,n){if(S(t,e)>=n)return{...t,a:1};let a=G(e)>.18?{r:0,g:0,b:0,a:1}:O;for(let i=.05;i<=1.0001;i+=.05){let r={r:t.r+(a.r-t.r)*i,g:t.g+(a.g-t.g)*i,b:t.b+(a.b-t.b)*i,a:1},s={r:Math.round(r.r),g:Math.round(r.g),b:Math.round(r.b),a:1};if(S(s,e)>=n)return s}return S({r:0,g:0,b:0,a:1},e)>=S(O,e)?{r:0,g:0,b:0,a:1}:O}var $t=t=>t.tagName.includes("-");function H(t,e=5e4){let n={elements:[],closed:[],crossOrigin:[]},o=a=>{let i=a.querySelectorAll("*");for(let r of Array.from(i)){if(n.elements.length>=e)return;if(r.closest("[data-yuktai-ui]"))continue;n.elements.push(r);let s=r.shadowRoot;if(s?o(s):$t(r)&&!r.children.length&&!(r.textContent??"").trim()&&r.ownerDocument.defaultView?.customElements?.get(r.tagName.toLowerCase())&&n.closed.push(r),r.tagName==="IFRAME"){let l=r,d=null;try{d=l.contentDocument}catch{d=null}!d&&l.getAttribute("src")&&!/^(about:|javascript:)/i.test(l.getAttribute("src")||"")&&n.crossOrigin.push(l)}}};return o(t),n}var F={textSize:100,spacing:!1,reduceMotion:"device",focusRing:!1,theme:"default",dark:"off",level:"AA"},et="yuktai-a11y-prefs";function pt(t){let e=[],n=Math.min(200,Math.max(100,Math.round(t.textSize||100)));n!==100&&e.push(`html{font-size:${n}% !important}`),t.spacing&&e.push("body *:not([data-yuktai-ui]):not([data-yuktai-ui] *){line-height:1.5 !important;letter-spacing:.12em !important;word-spacing:.16em !important}","body p:not([data-yuktai-ui] *){margin-bottom:2em !important}");let o="*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}";t.reduceMotion==="on"&&e.push(o),t.reduceMotion==="device"&&e.push(`@media (prefers-reduced-motion: reduce){${o}}`),t.focusRing&&e.push(":focus-visible{outline:3px solid #2F43C4 !important;outline-offset:2px !important;box-shadow:0 0 0 5px #FFFFFF !important}");let a=":not([data-yuktai-ui]):not([data-yuktai-ui] *)";if(t.theme==="high-contrast")e.push("html,body{background:#000 !important}",`body *${a}{background-color:#000 !important;color:#FFF !important;border-color:#FFF !important}`,`body a${a},body a${a} *{color:#FFFF00 !important}`,`body button${a},body [role=button]${a}{color:#00FFFF !important}`);else if(t.theme==="soft")e.push("html,body{background:#F4ECD8 !important}",`body *${a}{background-color:transparent !important;color:#3B2F1E !important}`,`body a${a}{color:#1F4E9E !important}`);else if(t.theme==="custom"&&t.custom){let r=E(t.custom.background),s=E(t.custom.text);if(r&&s){let l=q(t.level==="off"?"AA":t.level,!1),d=S(s,r)>=l?s:R(s,r,l);e.push(`html,body{background:${w(r)} !important}`,`body *${a}{background-color:transparent !important;color:${w(d)} !important;border-color:${w(d)} !important}`)}}let i='html{filter:invert(1) hue-rotate(180deg) !important;background:#FFF}img,video,picture,canvas,iframe,svg image,[style*="background-image"],[data-yuktai-ui]{filter:invert(1) hue-rotate(180deg) !important}';return t.theme==="default"&&(t.dark==="on"&&e.push(i),t.dark==="device"&&e.push(`@media (prefers-color-scheme: dark){${i}}`)),e.join(`
2
+ `)}function nt(t,e){let n=pt(e),o=t.getElementById(et);if(!n){o?.remove();return}o||(o=t.createElement("style"),o.id=et,o.setAttribute("data-yuktai-ui",""),(t.head??t.documentElement).appendChild(o)),o.textContent=n}function rt(t){t.getElementById(et)?.remove()}function jt(t="yuktai-a11y-prefs"){try{let e=globalThis.localStorage?.getItem(t);if(e)return{...F,...JSON.parse(e)}}catch{}return{...F}}function Wt(t,e="yuktai-a11y-prefs"){try{globalThis.localStorage?.setItem(e,JSON.stringify(t))}catch{}}var ot=()=>typeof globalThis<"u"&&globalThis.speechSynthesis||null,V=()=>!!ot()&&typeof globalThis.SpeechSynthesisUtterance=="function";function at(t=1500){let e=ot();if(!e)return Promise.resolve([]);let n=e.getVoices();return n.length?Promise.resolve(n):new Promise(o=>{let a=()=>{clearTimeout(i),e.removeEventListener?.("voiceschanged",a),o(e.getVoices())},i=setTimeout(a,t);e.addEventListener?.("voiceschanged",a)})}function ht(t,e){let n=t.toLowerCase().replace("_","-"),o=y(n),a=l=>l.lang.toLowerCase().replace("_","-"),i=l=>l.localService?0:1,r=e.filter(l=>a(l)===n).sort((l,d)=>i(l)-i(d));return r.length?r[0]:e.filter(l=>y(a(l))===o).sort((l,d)=>{let c=a(l).endsWith("-in")?0:1,g=a(d).endsWith("-in")?0:1;return c-g||i(l)-i(d)})[0]??null}async function _t(){let t=await at();return Array.from(new Set(t.map(e=>y(e.lang)))).sort()}function bt(t,e=220){let n=t.replace(/\s+/g," ").trim().split(/(?<=[.!?।॥\n])\s+/),o=[];for(let a of n){if(!a)continue;if(a.length<=e){o.push(a);continue}let i=a;for(;i.length>e;){let r=i.lastIndexOf(",",e);r<e/2&&(r=i.lastIndexOf(" ",e)),r<e/3&&(r=e),o.push(i.slice(0,r+1).trim()),i=i.slice(r+1)}i.trim()&&o.push(i.trim())}return o}function yt(t){let n=t.ownerDocument.createTreeWalker(t,4),o="";for(;n.nextNode();){let a=n.currentNode.parentElement;!a||k(a)||a.closest("[data-yuktai-speak='off'],[aria-hidden='true']")||(o+=n.currentNode.textContent+" ")}return o.replace(/\s+/g," ").trim()}function it(t,e={}){let n=ot(),a=(e.lang??(typeof t=="string"?"":v(t))??"")||(typeof document<"u"?document.documentElement.lang:"")||"en",i=typeof t=="string"?t:yt(t),r=K(i,a),s=!1,l={parts:r,pause:()=>n?.pause(),resume:()=>n?.resume(),stop:()=>{s=!0,n?.cancel(),e.onEnd?.()}};return!n||!V()||!r.length?(queueMicrotask(()=>e.onEnd?.()),l):(n.cancel(),at().then(d=>{if(s)return;let c=new Set,g=[];if(r.forEach((f,u)=>{let m=ht(f.lang,d);if(!m){c.has(y(f.lang))||(c.add(y(f.lang)),e.onMissingVoice?.(f.lang));return}for(let h of bt(f.text))g.push({text:h,voice:m,part:f,index:u})}),!g.length){e.onEnd?.();return}let p=-1;g.forEach((f,u)=>{let m=globalThis.SpeechSynthesisUtterance,h=new m(f.text);h.voice=f.voice,h.lang=f.voice.lang,h.rate=Math.min(2,Math.max(.5,e.rate??1)),h.onstart=()=>{f.index!==p&&(p=f.index,e.onPart?.(f.part,f.index,r.length))},u===g.length-1&&(h.onend=()=>!s&&e.onEnd?.()),n.speak(h)})}),l)}var $={en:{read:"Read aloud",stop:"Stop reading",noVoice:"This device has no voice for"},te:{read:"\u0C1A\u0C26\u0C3F\u0C35\u0C3F \u0C35\u0C3F\u0C28\u0C3F\u0C2A\u0C3F\u0C02\u0C1A\u0C41",stop:"\u0C1A\u0C26\u0C35\u0C21\u0C02 \u0C06\u0C2A\u0C41",noVoice:"\u0C08 device \u0C32\u0C4B voice \u0C32\u0C47\u0C26\u0C41:"},hi:{read:"\u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u090F\u0901",stop:"\u092A\u0922\u093C\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",noVoice:"\u0907\u0938 \u0921\u093F\u0935\u093E\u0907\u0938 \u092E\u0947\u0902 \u0906\u0935\u093E\u091C\u093C \u0928\u0939\u0940\u0902 \u0939\u0948:"}},Kt='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M11 5 6 9H3v6h3l5 4z"></path><path d="M15.5 8.5a5 5 0 0 1 0 7"></path><path d="M18.5 5.5a9 9 0 0 1 0 13"></path></svg>';function Ut(t){let e=Number(t.tagName[1]),n=[t],o=t.nextElementSibling;for(;o&&!(/^H[1-6]$/.test(o.tagName)&&Number(o.tagName[1])<=e);)o.hasAttribute("data-yuktai-ui")||n.push(o),o=o.nextElementSibling;return n}function xt(t,e={}){if(!V())return()=>{};let n=null,o=[],a=()=>{if(!n)return;let{speaker:r,button:s}=n;n=null,r.stop(),i(s,!1)},i=(r,s)=>{let l=$[y(r.dataset.lang??"en")]??$.en;r.setAttribute("aria-pressed",s?"true":"false"),r.setAttribute("aria-label",`${s?l.stop:l.read}: ${r.dataset.title}`)};return t.querySelectorAll("h1,h2,h3").forEach(r=>{if(r.closest("[data-yuktai-speak='off'],[data-yuktai-a11y='off'],[data-yuktai-ui],[hidden]")||r.nextElementSibling?.hasAttribute("data-yuktai-speak-button"))return;let s=(r.textContent??"").replace(/\s+/g," ").trim();if(!s)return;let l=t.createElement("button");l.type="button",l.innerHTML=Kt,l.setAttribute("data-yuktai-ui",""),l.setAttribute("data-yuktai-speak-button",""),l.dataset.title=s.slice(0,80),l.dataset.lang=v(r)||"en",l.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;margin:4px 0;border-radius:999px;border:1px solid #C9CBD3;background:#FFFFFF;color:#2F43C4;cursor:pointer;vertical-align:middle",i(l,!1),l.addEventListener("click",()=>{if(n?.button===l)return a();a();let d=Ut(r),c=t.createElement("div");for(let p of d)c.appendChild(p.cloneNode(!0));c.setAttribute("lang",v(r)||t.documentElement.lang||"en"),n={speaker:it(c,{lang:c.getAttribute("lang")??void 0,onMissingVoice:p=>{let f=$[y(l.dataset.lang??"en")]??$.en;e.onMissingVoice?.(p,`${f.noVoice} ${p}`)},onEnd:()=>{n?.button===l&&(n=null,i(l,!1))}}),button:l},i(l,!0)}),r.insertAdjacentElement("afterend",l),o.push(l)}),()=>{a(),o.forEach(r=>r.remove())}}var zt="6.0.0",Jt="p,h1,h2,h3,h4,h5,h6,li,td,th,dt,dd,a,button,label,span,small,strong,em,b,figcaption,caption,blockquote,summary,legend";function Yt(t){for(let e of Array.from(t.childNodes))if(e.nodeType===3&&(e.textContent??"").trim())return!0;return!1}function Xt(t={}){let e=t.document??document,n=t.attributes===!1?{...B,...kt(t)}:X(e,kt(t)),o={...F,level:n.level},a=null,i=null,r=null,s=!1,l=()=>{s=!0;let c={level:n.level,mode:n.mode,fixed:[],check:[],unknown:[],scanned:0,at:new Date().toISOString()};try{if(n.mode==="off")return a=c;let g=n.mode==="auto",p=H(e);c.scanned=p.elements.length;let f=u=>c[u.status].push(u);if(n.lang==="auto"){let u=z(e);u.mismatch&&u.detected&&f({rule:"page-lang-mismatch",status:"check",wcag:A["page-lang-mismatch"],where:"html",data:{declared:u.declared,detected:u.detected.lang},el:e.documentElement});for(let m of J(e,{apply:g})){let h=m.scope==="page"?"page-lang-missing":"part-lang-missing";f({rule:h,status:g?"fixed":"check",wcag:A[h],where:m.scope==="page"?"html":x(m.el),data:{lang:m.lang},el:m.el})}}for(let u of D(e,p.elements,{fix:g}))f(u);if(n.level!=="off")for(let u of p.elements){if(!u.matches(Jt)||!Yt(u)||k(u)||u.closest("[data-yuktai-ui],[data-yuktai-a11y='off'],[hidden],[aria-hidden='true']"))continue;let m=tt(u,n.level);if(m.status!=="pass"){if(m.status==="unknown"){f({rule:"contrast-unknown",status:"unknown",wcag:A["contrast-unknown"],where:x(u),data:{reason:m.reason??""},el:u});continue}if(g&&n.contrast==="fix"&&m.fg&&m.bg&&m.required){let h=R(m.fg,m.bg,m.required),M=u;M.hasAttribute("data-yuktai-color")||M.setAttribute("data-yuktai-color",M.style.getPropertyValue("color")||"-"),M.style.setProperty("color",w(h),"important"),f({rule:"contrast",status:"fixed",wcag:n.level==="AAA"?"1.4.6":"1.4.3",where:x(u),data:{ratio:m.ratio??0,required:m.required,to:w(h)},el:u})}else f({rule:"contrast",status:"check",wcag:n.level==="AAA"?"1.4.6":"1.4.3",where:x(u),data:{ratio:m.ratio??0,required:m.required??0},el:u})}}for(let u of p.closed)f({rule:"closed-shadow-root",status:"unknown",wcag:"",where:x(u),el:u});for(let u of p.crossOrigin)f({rule:"iframe-cross-origin",status:"unknown",wcag:"",where:x(u),data:{src:u.getAttribute("src")??""},el:u})}finally{i?.takeRecords(),s=!1}return a=c,t.onReport?.(c),c},d=()=>{Y(e),I(e),e.querySelectorAll("[data-yuktai-color]").forEach(c=>{let g=c,p=g.getAttribute("data-yuktai-color");g.style.removeProperty("color"),p&&p!=="-"&&g.style.setProperty("color",p),g.removeAttribute("data-yuktai-color")}),rt(e),a=null};return t.observe!==!1&&typeof MutationObserver<"u"&&n.mode!=="off"&&(i=new MutationObserver(c=>{s||c.some(g=>g.type==="childList"&&g.addedNodes.length)&&(r&&clearTimeout(r),r=setTimeout(l,400))}),queueMicrotask(()=>e.body&&i?.observe(e.body,{childList:!0,subtree:!0}))),{settings:n,run:l,get report(){return a},setPrefs(c){return o={...o,...c},nt(e,o),o},get prefs(){return o},undo:d,destroy(){i?.disconnect(),i=null,r&&clearTimeout(r),d()}}}function kt(t){let e={};for(let n of["mode","level","contrast","lang","speak"]){let o=t[n];o!==void 0&&(e[n]=o)}return e}
@@ -0,0 +1,37 @@
1
+ import { type A11ySettings } from "./attributes";
2
+ import { type Prefs } from "./prefs";
3
+ import { type Report } from "./report";
4
+ export * from "./contrast";
5
+ export * from "./language";
6
+ export * from "./speak";
7
+ export * from "./prefs";
8
+ export * from "./attributes";
9
+ export { accessibleName, auditAria, undoAria } from "./aria";
10
+ export { findAll, type FoundTree } from "./finder";
11
+ export { addSpeakButtons, type SpeakButtonsOptions } from "./speakButtons";
12
+ export { message, describe, toJSON, MESSAGES, WCAG, type Finding, type Report, type RuleId, type FindingStatus } from "./report";
13
+ export declare const VERSION = "6.0.0";
14
+ export interface A11yOptions extends Partial<A11ySettings> {
15
+ /** Document to work on. Default: the current document. */
16
+ document?: Document;
17
+ /** Read data-yuktai-* attributes from <body>/<html> (they win over options). Default true. */
18
+ attributes?: boolean;
19
+ /** Re-run on content added later (React, Next.js, infinite lists). Default true. */
20
+ observe?: boolean;
21
+ /** Called after each run. */
22
+ onReport?: (report: Report) => void;
23
+ }
24
+ export interface A11y {
25
+ readonly settings: A11ySettings;
26
+ /** Checks the page and applies the safe fixes allowed by `mode`. */
27
+ run(): Report;
28
+ /** The last report. */
29
+ readonly report: Report | null;
30
+ setPrefs(p: Partial<Prefs>): Prefs;
31
+ readonly prefs: Prefs;
32
+ /** Removes every change YuktAI made (lang, roles, colours, preferences). */
33
+ undo(): void;
34
+ /** undo() and stop watching the page. */
35
+ destroy(): void;
36
+ }
37
+ export declare function createA11y(options?: A11yOptions): A11y;
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var A={"page-lang-missing":"3.1.1","page-lang-mismatch":"3.1.1","part-lang-missing":"3.1.2",contrast:"1.4.3","contrast-unknown":"1.4.3","img-alt-missing":"1.1.1","control-name-missing":"4.1.2","fake-button":"4.1.2","clickable-not-focusable":"2.1.1","field-label-missing":"3.3.2","heading-skip":"1.3.1","h1-count":"1.3.1","link-text-vague":"2.4.4","iframe-title-missing":"4.1.2","iframe-cross-origin":"","table-headers-missing":"1.3.1","media-autoplay":"1.4.2","tabindex-positive":"2.4.3","aria-hidden-focusable":"4.1.2","main-landmark-missing":"2.4.1","closed-shadow-root":""},K={en:{"page-lang-missing":"The page has no lang. Detected: {lang}.","page-lang-mismatch":'<html lang="{declared}"> but the text is {detected}.',"part-lang-missing":"A part in {lang} had no lang.",contrast:"Text contrast {ratio}:1, needs {required}:1.","contrast-unknown":"Contrast not checked: {reason}.","img-alt-missing":'Image has no alt text. Describe it, or use alt="" if it is decoration.',"control-name-missing":"A {tag} has no name a screen reader can say.","fake-button":"A clickable {tag} was not a button. Added role, focus and Enter/Space. A real <button> is better.","clickable-not-focusable":"Something clickable ({tag}) cannot be reached by keyboard.","field-label-missing":"A form field has no label.","heading-skip":"Heading jumps from h{from} to h{to}.","h1-count":"The page has {count} h1 headings; one is expected.","link-text-vague":'Link text "{text}" does not say where it goes.',"iframe-title-missing":"An iframe has no title.","iframe-cross-origin":"Content from another site (iframe) cannot be checked from here.","table-headers-missing":"A data table has no header cells (th).","media-autoplay":"Media plays by itself. Give a way to pause it.","tabindex-positive":'tabindex="{value}" changes the Tab order.',"aria-hidden-focusable":"A hidden (aria-hidden) element can still take focus.","main-landmark-missing":"The page has no <main>.","closed-shadow-root":"A closed component cannot be checked from outside."},te:{"page-lang-missing":"\u0C2A\u0C47\u0C1C\u0C40\u0C15\u0C3F lang \u0C32\u0C47\u0C26\u0C41. \u0C17\u0C41\u0C30\u0C4D\u0C24\u0C3F\u0C02\u0C1A\u0C3F\u0C28 \u0C2D\u0C3E\u0C37: {lang}.","page-lang-mismatch":'<html lang="{declared}"> \u0C09\u0C02\u0C26\u0C3F, \u0C15\u0C3E\u0C28\u0C40 text {detected} \u0C32\u0C4B \u0C09\u0C02\u0C26\u0C3F.',"part-lang-missing":"{lang} \u0C2D\u0C3E\u0C17\u0C3E\u0C28\u0C3F\u0C15\u0C3F lang \u0C32\u0C47\u0C26\u0C41.",contrast:"Text contrast {ratio}:1, \u0C15\u0C28\u0C40\u0C38\u0C02 {required}:1 \u0C15\u0C3E\u0C35\u0C3E\u0C32\u0C3F.","contrast-unknown":"Contrast check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C15\u0C2A\u0C4B\u0C2F\u0C3E\u0C02: {reason}.","img-alt-missing":'Image \u0C15\u0C3F alt \u0C32\u0C47\u0C26\u0C41. \u0C35\u0C3F\u0C35\u0C30\u0C23 \u0C30\u0C3E\u0C2F\u0C02\u0C21\u0C3F, \u0C05\u0C32\u0C02\u0C15\u0C3E\u0C30\u0C2E\u0C48\u0C24\u0C47 alt="" \u0C2A\u0C46\u0C1F\u0C4D\u0C1F\u0C02\u0C21\u0C3F.',"control-name-missing":"{tag} \u0C15\u0C3F screen reader \u0C1A\u0C46\u0C2A\u0C4D\u0C2A\u0C17\u0C32\u0C3F\u0C17\u0C47 \u0C2A\u0C47\u0C30\u0C41 \u0C32\u0C47\u0C26\u0C41.","fake-button":"Click \u0C1A\u0C47\u0C38\u0C47 {tag} button \u0C15\u0C3E\u0C26\u0C41. Role, focus, Enter/Space \u0C1C\u0C4B\u0C21\u0C3F\u0C02\u0C1A\u0C3E\u0C02. \u0C28\u0C3F\u0C1C\u0C2E\u0C48\u0C28 <button> \u0C07\u0C02\u0C15\u0C3E \u0C2E\u0C02\u0C1A\u0C3F\u0C26\u0C3F.","clickable-not-focusable":"Click \u0C1A\u0C47\u0C38\u0C47 {tag} \u0C28\u0C3F keyboard \u0C24\u0C4B \u0C1A\u0C47\u0C30\u0C32\u0C47\u0C2E\u0C41.","field-label-missing":"Form field \u0C15\u0C3F label \u0C32\u0C47\u0C26\u0C41.","heading-skip":"Heading h{from} \u0C28\u0C41\u0C02\u0C21\u0C3F h{to} \u0C15\u0C3F \u0C26\u0C42\u0C15\u0C3F\u0C02\u0C26\u0C3F.","h1-count":"\u0C2A\u0C47\u0C1C\u0C40\u0C32\u0C4B {count} h1 \u0C32\u0C41 \u0C09\u0C28\u0C4D\u0C28\u0C3E\u0C2F\u0C3F; \u0C12\u0C15\u0C1F\u0C3F \u0C09\u0C02\u0C21\u0C3E\u0C32\u0C3F.","link-text-vague":'Link text "{text}" \u0C0E\u0C15\u0C4D\u0C15\u0C21\u0C3F\u0C15\u0C3F \u0C35\u0C46\u0C33\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C4B \u0C1A\u0C46\u0C2A\u0C4D\u0C2A\u0C26\u0C41.',"iframe-title-missing":"iframe \u0C15\u0C3F title \u0C32\u0C47\u0C26\u0C41.","iframe-cross-origin":"\u0C35\u0C47\u0C30\u0C47 site content (iframe) \u0C28\u0C3F \u0C07\u0C15\u0C4D\u0C15\u0C21\u0C3F \u0C28\u0C41\u0C02\u0C21\u0C3F check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C2E\u0C41.","table-headers-missing":"Data table \u0C15\u0C3F header cells (th) \u0C32\u0C47\u0C35\u0C41.","media-autoplay":"Media \u0C24\u0C28\u0C02\u0C24\u0C1F \u0C24\u0C3E\u0C28\u0C47 play \u0C05\u0C35\u0C41\u0C24\u0C41\u0C02\u0C26\u0C3F. \u0C06\u0C2A\u0C47 \u0C2E\u0C3E\u0C30\u0C4D\u0C17\u0C02 \u0C07\u0C35\u0C4D\u0C35\u0C02\u0C21\u0C3F.","tabindex-positive":'tabindex="{value}" Tab \u0C15\u0C4D\u0C30\u0C2E\u0C3E\u0C28\u0C4D\u0C28\u0C3F \u0C2E\u0C3E\u0C30\u0C41\u0C38\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C3F.',"aria-hidden-focusable":"\u0C26\u0C3E\u0C1A\u0C3F\u0C28 (aria-hidden) element \u0C15\u0C3F focus \u0C35\u0C38\u0C4D\u0C24\u0C41\u0C02\u0C26\u0C3F.","main-landmark-missing":"\u0C2A\u0C47\u0C1C\u0C40\u0C32\u0C4B <main> \u0C32\u0C47\u0C26\u0C41.","closed-shadow-root":"\u0C2E\u0C42\u0C38\u0C3F \u0C09\u0C28\u0C4D\u0C28 component \u0C28\u0C3F \u0C2C\u0C2F\u0C1F\u0C3F \u0C28\u0C41\u0C02\u0C21\u0C3F check \u0C1A\u0C47\u0C2F\u0C32\u0C47\u0C2E\u0C41."}};function ut(t,e="en"){return(K[e][t.rule]??t.rule).replace(/\{(\w+)\}/g,(o,a)=>String(t.data?.[a]??""))}function x(t){let e=a=>{let i=a.tagName.toLowerCase();if(a.id)return i+"#"+a.id;let r=(a.getAttribute("class")??"").trim().split(/\s+/).filter(Boolean).slice(0,2);return r.length&&(i+="."+r.join(".")),i},n=[],o=t;for(;o&&n.length<3&&o.tagName.toLowerCase()!=="body"&&o.tagName.toLowerCase()!=="html"&&(n.unshift(e(o)),!o.id);)o=o.parentElement;return n.join(" > ")||t.tagName.toLowerCase()}function dt(t){let e=n=>n.map(({el:o,...a})=>a);return{...t,fixed:e(t.fixed),check:e(t.check),unknown:e(t.unknown)}}var ft=[{script:"Telugu",lang:"te",shared:!1,from:3072,to:3199},{script:"Kannada",lang:"kn",shared:!1,from:3200,to:3327},{script:"Tamil",lang:"ta",shared:!1,from:2944,to:3071},{script:"Malayalam",lang:"ml",shared:!1,from:3328,to:3455},{script:"Devanagari",lang:"hi",shared:!0,from:2304,to:2431},{script:"Bengali",lang:"bn",shared:!0,from:2432,to:2559},{script:"Gurmukhi",lang:"pa",shared:!1,from:2560,to:2687},{script:"Gujarati",lang:"gu",shared:!1,from:2688,to:2815},{script:"Oriya",lang:"or",shared:!1,from:2816,to:2943},{script:"Sinhala",lang:"si",shared:!1,from:3456,to:3583},{script:"Arabic",lang:"ar",shared:!0,from:1536,to:1791},{script:"Hebrew",lang:"he",shared:!0,from:1424,to:1535},{script:"Thai",lang:"th",shared:!1,from:3584,to:3711},{script:"Greek",lang:"el",shared:!1,from:880,to:1023},{script:"Cyrillic",lang:"ru",shared:!0,from:1024,to:1279},{script:"Hangul",lang:"ko",shared:!1,from:44032,to:55215},{script:"Kana",lang:"ja",shared:!1,from:12352,to:12543},{script:"Han",lang:"zh",shared:!0,from:19968,to:40959},{script:"Latin",lang:"en",shared:!0,from:65,to:591}],gt=new Set(["ar","ur","fa","he","sd","ks","ps","yi","dv","ug"]),mt=t=>gt.has(y(t)),y=t=>(t||"").toLowerCase().split(/[-_]/)[0];function U(t){let e=t.codePointAt(0);if(e<128&&!/[A-Za-z]/.test(t)||e>=128&&e<192)return null;for(let n of ft)if(e>=n.from&&e<=n.to)return{script:n.script,lang:n.lang,shared:n.shared};return null}function I(t,e=3){let n=new Map,o=0;for(let i of t){let r=U(i);if(!r)continue;o++;let s=n.get(r.script);s?s.n++:n.set(r.script,{n:1,info:r})}if(o<e)return null;let a=null;for(let i of n.values())(!a||i.n>a.n)&&(a=i);return a?{lang:a.info.lang,script:a.info.script,confidence:a.n/o,letters:o,shared:a.info.shared}:null}function z(t,e){let n=[],o="",a=null;for(let i of t){let r=U(i),s=r?pt(r,e):null;s&&a&&s!==a&&(n.push({text:o,lang:a}),o=""),s&&(a=s),o+=i}return o&&n.push({text:o,lang:a??e}),n.filter(i=>i.text.trim()).reduce((i,r)=>{let s=i[i.length-1];return s&&s.lang===r.lang?s.text+=r.text:i.push({...r}),i},[])}function pt(t,e){let n={lang:t.lang,script:t.script,confidence:1,letters:1,shared:t.shared};return e&&R(e,n)?e:t.lang}var J=new Set(["en","fr","de","es","pt","it","nl","sv","da","no","nb","fi","pl","cs","ro","hu","tr","id","ms","vi","sw","tl"]),ht=t=>J.has(y(t));function v(t){let e=t;for(;e;){let n=e.getAttribute("lang");if(n!==null&&n!=="")return n;e=e.parentElement??e.getRootNode().host??null}return""}var bt="script,style,noscript,template,code,pre,kbd,samp,var,textarea,input,select,option,[contenteditable=''],[contenteditable='true'],[data-yuktai-a11y='off'],svg,math";function k(t){try{return!!t.closest(bt)}catch{return!1}}function Y(t){let e="";for(let n of Array.from(t.childNodes))if(n.nodeType===3)e+=n.textContent??"";else if(n.nodeType===1){let o=n;if(X.has(o.tagName.toLowerCase())||o.hasAttribute("lang")||k(o))continue;e+=Y(o)}return e}var X=new Set(["p","h1","h2","h3","h4","h5","h6","li","dt","dd","td","th","caption","figcaption","blockquote","q","label","legend","button","a","summary","div","section","article","aside","header","footer","nav","main","span","em","strong","b","i","small","cite","title"]);function Z(t,e=2e4){let n=t.body;if(!n)return"";let o=t.createTreeWalker(n,4),a="";for(;o.nextNode()&&a.length<e;){let i=o.currentNode.parentElement;i&&!k(i)&&(a+=o.currentNode.textContent+" ")}return a}function Q(t){let e=t.documentElement.getAttribute("lang")??"",n=I(Z(t),20),o=!!(e&&n&&n.confidence>=.7&&!R(e,n));return{declared:e,detected:n,mismatch:o}}function R(t,e){let n=y(t);return n===e.lang?!0:({Devanagari:["hi","mr","ne","sa","kok","mai","doi","brx","bho"],Bengali:["bn","as","mni"],Arabic:["ar","ur","fa","sd","ks","ps"],Latin:Array.from(J),Cyrillic:["ru","uk","bg","sr","be","kk"],Han:["zh","ja"],Hebrew:["he","yi"]}[e.script]??[]).includes(n)}function tt(t,e={apply:!0}){let n=[],o=t.documentElement;if(!o.getAttribute("lang")){let r=I(Z(t),20);r&&(n.push({el:o,lang:r.lang,scope:"page"}),e.apply&&(o.setAttribute("lang",r.lang),o.setAttribute("data-yuktai-lang","added")))}let a=e.root??t.body;if(!a)return n;let i=Array.from(a.querySelectorAll("*"));for(let r of i){let s=r.tagName.toLowerCase();if(!X.has(s)||r.hasAttribute("lang")||k(r))continue;let l=I(Y(r),3);if(!l||l.confidence<.6)continue;let d=e.apply?v(r):yt(r,n);if(!d||!R(d,l)){if(l.script==="Latin"&&d&&ht(d))continue;n.push({el:r,lang:l.lang,scope:"part"}),e.apply&&(r.setAttribute("lang",l.lang),r.setAttribute("data-yuktai-lang","added"),mt(l.lang)&&!r.hasAttribute("dir")&&(r.setAttribute("dir","rtl"),r.setAttribute("data-yuktai-lang","added-dir")))}}return n}function yt(t,e){let n=t.parentElement;for(;n;){let o=e.find(i=>i.el===n);if(o)return o.lang;let a=n.getAttribute("lang");if(a)return a;n=n.parentElement}return""}function et(t){let e=0;return t.querySelectorAll("[data-yuktai-lang]").forEach(n=>{n.getAttribute("data-yuktai-lang")==="added-dir"&&n.removeAttribute("dir"),n.removeAttribute("lang"),n.removeAttribute("data-yuktai-lang"),e++}),e}async function qt(t,e){if(!e.shared)return e.lang;let n=globalThis.LanguageDetector;if(!n)return e.lang;try{if(n.availability&&await n.availability()==="unavailable")return e.lang;let o=await n.create(),[a]=await o.detect(t.slice(0,2e3));if(a&&a.confidence>=.6&&a.detectedLanguage!=="und")return R(a.detectedLanguage,e)?a.detectedLanguage:e.lang}catch{}return e.lang}var xt=new Set(["a","button","input","select","textarea","summary","details","option","label","video","audio"]),kt=new Set(["click here","here","read more","more","link","this","click","\u0C07\u0C15\u0C4D\u0C15\u0C21","\u0C07\u0C15\u0C4D\u0C15\u0C21 \u0C15\u0C4D\u0C32\u0C3F\u0C15\u0C4D \u0C1A\u0C47\u0C2F\u0C02\u0C21\u0C3F","\u0C2E\u0C30\u0C3F\u0C02\u0C24","\u092F\u0939\u093E\u0901","\u092F\u0939\u093E\u0902 \u0915\u094D\u0932\u093F\u0915 \u0915\u0930\u0947\u0902","\u0914\u0930 \u092A\u0922\u093C\u0947\u0902"]),b=(t,e,n,o)=>({rule:t,status:e,wcag:A[t],where:x(n),data:o,el:n});function F(t){let e=t.ownerDocument,n=t.getAttribute("aria-labelledby");if(n){let r=n.split(/\s+/).map(s=>e.getElementById(s)?.textContent?.trim()??"").join(" ").trim();if(r)return r}let o=t.getAttribute("aria-label")?.trim();if(o)return o;let a=t.tagName.toLowerCase();if(a==="input"||a==="select"||a==="textarea"){let r=t.getAttribute("id");if(r){let d=e.querySelector(`label[for="${At(r)}"]`);if(d?.textContent?.trim())return d.textContent.trim()}let s=t.closest("label");if(s?.textContent?.trim())return s.textContent.trim();let l=(t.getAttribute("type")||"").toLowerCase();return(l==="submit"||l==="button"||l==="reset")&&t.value?t.value:l==="image"&&t.getAttribute("alt")?t.getAttribute("alt"):t.getAttribute("title")?.trim()||""}if(a==="img")return t.getAttribute("alt")??"";let i=(t.textContent??"").replace(/\s+/g," ").trim();if(i)return i;for(let r of Array.from(t.querySelectorAll("img[alt], [aria-label], svg title"))){let s=r.tagName.toLowerCase()==="title"?r.textContent:r.getAttribute("alt")??r.getAttribute("aria-label");if(s&&s.trim())return s.trim()}return t.getAttribute("title")?.trim()||""}function At(t){let e=globalThis.CSS;return e?.escape?e.escape(t):t.replace(/["\\]/g,"\\$&")}function St(t){if(t.closest("[hidden],[aria-hidden='true']"))return!0;let e=t.ownerDocument.defaultView;if(!e)return!1;let n=e.getComputedStyle(t);return n.display==="none"||n.visibility==="hidden"}var wt=t=>{let e=t.tagName.toLowerCase();return t.hasAttribute("disabled")?!1:t.hasAttribute("tabindex")?Number(t.getAttribute("tabindex"))>=0:e==="a"?t.hasAttribute("href"):["button","input","select","textarea","summary","iframe"].includes(e)||t.getAttribute("contenteditable")==="true"};function B(t,e,n){let o=[],a=0,i=0;for(let r of e){if(r.closest("[data-yuktai-a11y='off'],[data-yuktai-ui]"))continue;let s=r.tagName.toLowerCase(),l=St(r);if(/^h[1-6]$/.test(s)&&!l){let c=Number(s[1]);c===1&&i++,a&&c>a+1&&o.push(b("heading-skip","check",r,{from:a,to:c})),a=c}if(l){r.getAttribute("aria-hidden")==="true"&&wt(r)&&o.push(b("aria-hidden-focusable","check",r));continue}if(s==="img"&&!r.hasAttribute("alt")&&r.getAttribute("role")!=="presentation"&&r.getAttribute("role")!=="none"&&!r.getAttribute("aria-label")&&!r.getAttribute("aria-labelledby")&&o.push(b("img-alt-missing","check",r)),(s==="button"||s==="a"&&r.hasAttribute("href")||r.getAttribute("role")==="button"||r.getAttribute("role")==="link")&&!F(r)&&o.push(b("control-name-missing","check",r,{tag:r.getAttribute("role")||s})),s==="a"&&r.hasAttribute("href")){let c=(r.textContent??"").replace(/\s+/g," ").trim().toLowerCase();c&&kt.has(c)&&!r.getAttribute("aria-label")&&!r.getAttribute("aria-labelledby")&&o.push(b("link-text-vague","check",r,{text:c}))}if(["input","select","textarea"].includes(s)){let c=(r.getAttribute("type")||"").toLowerCase();!["hidden","submit","button","reset","image"].includes(c)&&!F(r)&&o.push(b("field-label-missing","check",r))}s==="iframe"&&!r.getAttribute("title")&&!r.getAttribute("aria-label")&&o.push(b("iframe-title-missing","check",r)),s==="table"&&r.getAttribute("role")!=="presentation"&&r.querySelectorAll("tr").length>1&&!r.querySelector("th,[role='columnheader'],[role='rowheader']")&&o.push(b("table-headers-missing","check",r)),(s==="video"||s==="audio")&&r.hasAttribute("autoplay")&&!r.hasAttribute("muted")&&!r.hasAttribute("controls")&&o.push(b("media-autoplay","check",r));let d=r.getAttribute("tabindex");if(d!==null&&Number(d)>0&&o.push(b("tabindex-positive","check",r,{value:d})),!xt.has(s)&&!r.getAttribute("role")&&r.hasAttribute("onclick")&&!k(r)){let c=F(r);if(n.fix&&c){r.setAttribute("role","button");let g=!r.hasAttribute("tabindex");g&&r.setAttribute("tabindex","0"),vt(r),r.setAttribute("data-yuktai-fix",g?"fake-button tabindex":"fake-button"),o.push(b("fake-button","fixed",r,{tag:s}))}else o.push(b(c?"clickable-not-focusable":"control-name-missing","check",r,{tag:s}))}}return i!==1&&e.length&&o.push(b("h1-count","check",t.body??t.documentElement,{count:i})),t.body&&!t.querySelector("main,[role='main']")&&o.push(b("main-landmark-missing","check",t.body)),o}var E=Symbol.for("yuktai.keys");function vt(t){let e=t;if(e[E])return;let n=o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),e.click())};e[E]=n,e.addEventListener("keydown",n)}function O(t){let e=0;return t.querySelectorAll("[data-yuktai-fix~='fake-button']").forEach(n=>{n.removeAttribute("role"),(n.getAttribute("data-yuktai-fix")??"").includes("tabindex")&&n.removeAttribute("tabindex");let o=n;o[E]&&(o.removeEventListener("keydown",o[E]),delete o[E]),n.removeAttribute("data-yuktai-fix"),e++}),e}var G={mode:"auto",level:"AA",contrast:"check",lang:"auto",speak:"off"};function L(t,e,n){let o=(t??"").trim();return e.find(i=>i.toLowerCase()===o.toLowerCase())??n}function Wt(t){return[t.body,t.documentElement].some(e=>e&&Array.from(e.attributes).some(n=>n.name.startsWith("data-yuktai-")))}function nt(t,e={}){let n=a=>t.body?.getAttribute(a)??t.documentElement.getAttribute(a),o={...G,...e};return{mode:L(n("data-yuktai-a11y"),["auto","check","off"],o.mode),level:L(n("data-yuktai-level"),["AA","AAA","off"],o.level),contrast:L(n("data-yuktai-contrast"),["check","fix"],o.contrast),lang:L(n("data-yuktai-lang"),["auto","off"],o.lang),speak:L(n("data-yuktai-speak"),["on","off"],o.speak)}}function T(t){if(!t)return null;let e=t.trim().toLowerCase();if(e==="transparent")return{r:0,g:0,b:0,a:0};let n=e.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/);if(n){let a=1;return n[4]!==void 0&&(a=n[4].endsWith("%")?parseFloat(n[4])/100:parseFloat(n[4])),{r:+n[1],g:+n[2],b:+n[3],a}}let o=e.match(/^#([0-9a-f]{3,8})$/);if(o){let a=o[1];return(a.length===3||a.length===4)&&(a=a.split("").map(i=>i+i).join("")),a.length!==6&&a.length!==8?null:{r:parseInt(a.slice(0,2),16),g:parseInt(a.slice(2,4),16),b:parseInt(a.slice(4,6),16),a:a.length===8?parseInt(a.slice(6,8),16)/255:1}}return null}var q=t=>{let e=t/255;return e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4)};function H(t){return .2126*q(t.r)+.7152*q(t.g)+.0722*q(t.b)}function S(t,e){let n=H(t),o=H(e),[a,i]=n>o?[n,o]:[o,n];return(a+.05)/(i+.05)}function rt(t,e){let n=t.a;return{r:Math.round(t.r*n+e.r*(1-n)),g:Math.round(t.g*n+e.g*(1-n)),b:Math.round(t.b*n+e.b*(1-n)),a:1}}function Et(t,e){return t>=24||t>=18.66&&e>=700}function V(t,e){return t==="AAA"?e?4.5:7:e?3:4.5}var M={r:255,g:255,b:255,a:1};function Lt(t){let e=[],n=t,o=t.ownerDocument?.defaultView;if(!o)return{color:null,reason:"no-window"};for(;n;){let i=o.getComputedStyle(n),r=i.backgroundImage;if(r&&r!=="none"&&r!=="initial")return{color:null,reason:"background-image"};let s=i.backgroundColor,l=s&&s!=="initial"?T(s):null;if(l===null&&s&&s!=="initial")return{color:null,reason:"colour-format"};if(l&&l.a>0&&(e.push(l),l.a>=1))break;n=Tt(n)}let a=M;e.length&&e[e.length-1].a>=1&&(a=e.pop());for(let i=e.length-1;i>=0;i--)a=rt(e[i],a);return{color:a}}function Tt(t){if(t.parentElement)return t.parentElement;let e=t.getRootNode();return e&&e.host?e.host:null}function ot(t,e){if(e==="off")return{status:"pass"};let n=t.ownerDocument?.defaultView;if(!n)return{status:"unknown",reason:"no-window"};let o=n.getComputedStyle(t),a=o.color;for(let f=t.parentElement;!a&&f;f=f.parentElement)a=n.getComputedStyle(f).color;let i=a?T(a):{r:0,g:0,b:0,a:1};if(!i)return{status:"unknown",reason:"colour-format"};let r=Lt(t);if(!r.color)return{status:"unknown",reason:r.reason};let s=i.a<1?rt(i,r.color):i,l=parseFloat(o.fontSize)||16,d=parseInt(o.fontWeight,10)||(o.fontWeight==="bold"?700:400),c=Et(l,d),g=V(e,c),p=Math.round(S(s,r.color)*100)/100;return{status:p+1e-9>=g?"pass":"fail",ratio:p,required:g,large:c,fg:s,bg:r.color}}var w=t=>"#"+[t.r,t.g,t.b].map(e=>Math.max(0,Math.min(255,Math.round(e))).toString(16).padStart(2,"0")).join("");function P(t,e,n){if(S(t,e)>=n)return{...t,a:1};let a=H(e)>.18?{r:0,g:0,b:0,a:1}:M;for(let i=.05;i<=1.0001;i+=.05){let r={r:t.r+(a.r-t.r)*i,g:t.g+(a.g-t.g)*i,b:t.b+(a.b-t.b)*i,a:1},s={r:Math.round(r.r),g:Math.round(r.g),b:Math.round(r.b),a:1};if(S(s,e)>=n)return s}return S({r:0,g:0,b:0,a:1},e)>=S(M,e)?{r:0,g:0,b:0,a:1}:M}var Ct=t=>t.tagName.includes("-");function $(t,e=5e4){let n={elements:[],closed:[],crossOrigin:[]},o=a=>{let i=a.querySelectorAll("*");for(let r of Array.from(i)){if(n.elements.length>=e)return;if(r.closest("[data-yuktai-ui]"))continue;n.elements.push(r);let s=r.shadowRoot;if(s?o(s):Ct(r)&&!r.children.length&&!(r.textContent??"").trim()&&r.ownerDocument.defaultView?.customElements?.get(r.tagName.toLowerCase())&&n.closed.push(r),r.tagName==="IFRAME"){let l=r,d=null;try{d=l.contentDocument}catch{d=null}!d&&l.getAttribute("src")&&!/^(about:|javascript:)/i.test(l.getAttribute("src")||"")&&n.crossOrigin.push(l)}}};return o(t),n}var N={textSize:100,spacing:!1,reduceMotion:"device",focusRing:!1,theme:"default",dark:"off",level:"AA"},j="yuktai-a11y-prefs";function Rt(t){let e=[],n=Math.min(200,Math.max(100,Math.round(t.textSize||100)));n!==100&&e.push(`html{font-size:${n}% !important}`),t.spacing&&e.push("body *:not([data-yuktai-ui]):not([data-yuktai-ui] *){line-height:1.5 !important;letter-spacing:.12em !important;word-spacing:.16em !important}","body p:not([data-yuktai-ui] *){margin-bottom:2em !important}");let o="*,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;scroll-behavior:auto !important}";t.reduceMotion==="on"&&e.push(o),t.reduceMotion==="device"&&e.push(`@media (prefers-reduced-motion: reduce){${o}}`),t.focusRing&&e.push(":focus-visible{outline:3px solid #2F43C4 !important;outline-offset:2px !important;box-shadow:0 0 0 5px #FFFFFF !important}");let a=":not([data-yuktai-ui]):not([data-yuktai-ui] *)";if(t.theme==="high-contrast")e.push("html,body{background:#000 !important}",`body *${a}{background-color:#000 !important;color:#FFF !important;border-color:#FFF !important}`,`body a${a},body a${a} *{color:#FFFF00 !important}`,`body button${a},body [role=button]${a}{color:#00FFFF !important}`);else if(t.theme==="soft")e.push("html,body{background:#F4ECD8 !important}",`body *${a}{background-color:transparent !important;color:#3B2F1E !important}`,`body a${a}{color:#1F4E9E !important}`);else if(t.theme==="custom"&&t.custom){let r=T(t.custom.background),s=T(t.custom.text);if(r&&s){let l=V(t.level==="off"?"AA":t.level,!1),d=S(s,r)>=l?s:P(s,r,l);e.push(`html,body{background:${w(r)} !important}`,`body *${a}{background-color:transparent !important;color:${w(d)} !important;border-color:${w(d)} !important}`)}}let i='html{filter:invert(1) hue-rotate(180deg) !important;background:#FFF}img,video,picture,canvas,iframe,svg image,[style*="background-image"],[data-yuktai-ui]{filter:invert(1) hue-rotate(180deg) !important}';return t.theme==="default"&&(t.dark==="on"&&e.push(i),t.dark==="device"&&e.push(`@media (prefers-color-scheme: dark){${i}}`)),e.join(`
2
+ `)}function at(t,e){let n=Rt(e),o=t.getElementById(j);if(!n){o?.remove();return}o||(o=t.createElement("style"),o.id=j,o.setAttribute("data-yuktai-ui",""),(t.head??t.documentElement).appendChild(o)),o.textContent=n}function it(t){t.getElementById(j)?.remove()}function Jt(t="yuktai-a11y-prefs"){try{let e=globalThis.localStorage?.getItem(t);if(e)return{...N,...JSON.parse(e)}}catch{}return{...N}}function Yt(t,e="yuktai-a11y-prefs"){try{globalThis.localStorage?.setItem(e,JSON.stringify(t))}catch{}}var W=()=>typeof globalThis<"u"&&globalThis.speechSynthesis||null,_=()=>!!W()&&typeof globalThis.SpeechSynthesisUtterance=="function";function st(t=1500){let e=W();if(!e)return Promise.resolve([]);let n=e.getVoices();return n.length?Promise.resolve(n):new Promise(o=>{let a=()=>{clearTimeout(i),e.removeEventListener?.("voiceschanged",a),o(e.getVoices())},i=setTimeout(a,t);e.addEventListener?.("voiceschanged",a)})}function Ft(t,e){let n=t.toLowerCase().replace("_","-"),o=y(n),a=l=>l.lang.toLowerCase().replace("_","-"),i=l=>l.localService?0:1,r=e.filter(l=>a(l)===n).sort((l,d)=>i(l)-i(d));return r.length?r[0]:e.filter(l=>y(a(l))===o).sort((l,d)=>{let c=a(l).endsWith("-in")?0:1,g=a(d).endsWith("-in")?0:1;return c-g||i(l)-i(d)})[0]??null}async function Qt(){let t=await st();return Array.from(new Set(t.map(e=>y(e.lang)))).sort()}function Mt(t,e=220){let n=t.replace(/\s+/g," ").trim().split(/(?<=[.!?।॥\n])\s+/),o=[];for(let a of n){if(!a)continue;if(a.length<=e){o.push(a);continue}let i=a;for(;i.length>e;){let r=i.lastIndexOf(",",e);r<e/2&&(r=i.lastIndexOf(" ",e)),r<e/3&&(r=e),o.push(i.slice(0,r+1).trim()),i=i.slice(r+1)}i.trim()&&o.push(i.trim())}return o}function Pt(t){let n=t.ownerDocument.createTreeWalker(t,4),o="";for(;n.nextNode();){let a=n.currentNode.parentElement;!a||k(a)||a.closest("[data-yuktai-speak='off'],[aria-hidden='true']")||(o+=n.currentNode.textContent+" ")}return o.replace(/\s+/g," ").trim()}function lt(t,e={}){let n=W(),a=(e.lang??(typeof t=="string"?"":v(t))??"")||(typeof document<"u"?document.documentElement.lang:"")||"en",i=typeof t=="string"?t:Pt(t),r=z(i,a),s=!1,l={parts:r,pause:()=>n?.pause(),resume:()=>n?.resume(),stop:()=>{s=!0,n?.cancel(),e.onEnd?.()}};return!n||!_()||!r.length?(queueMicrotask(()=>e.onEnd?.()),l):(n.cancel(),st().then(d=>{if(s)return;let c=new Set,g=[];if(r.forEach((f,u)=>{let m=Ft(f.lang,d);if(!m){c.has(y(f.lang))||(c.add(y(f.lang)),e.onMissingVoice?.(f.lang));return}for(let h of Mt(f.text))g.push({text:h,voice:m,part:f,index:u})}),!g.length){e.onEnd?.();return}let p=-1;g.forEach((f,u)=>{let m=globalThis.SpeechSynthesisUtterance,h=new m(f.text);h.voice=f.voice,h.lang=f.voice.lang,h.rate=Math.min(2,Math.max(.5,e.rate??1)),h.onstart=()=>{f.index!==p&&(p=f.index,e.onPart?.(f.part,f.index,r.length))},u===g.length-1&&(h.onend=()=>!s&&e.onEnd?.()),n.speak(h)})}),l)}var D={en:{read:"Read aloud",stop:"Stop reading",noVoice:"This device has no voice for"},te:{read:"\u0C1A\u0C26\u0C3F\u0C35\u0C3F \u0C35\u0C3F\u0C28\u0C3F\u0C2A\u0C3F\u0C02\u0C1A\u0C41",stop:"\u0C1A\u0C26\u0C35\u0C21\u0C02 \u0C06\u0C2A\u0C41",noVoice:"\u0C08 device \u0C32\u0C4B voice \u0C32\u0C47\u0C26\u0C41:"},hi:{read:"\u092A\u0922\u093C\u0915\u0930 \u0938\u0941\u0928\u093E\u090F\u0901",stop:"\u092A\u0922\u093C\u0928\u093E \u092C\u0902\u0926 \u0915\u0930\u0947\u0902",noVoice:"\u0907\u0938 \u0921\u093F\u0935\u093E\u0907\u0938 \u092E\u0947\u0902 \u0906\u0935\u093E\u091C\u093C \u0928\u0939\u0940\u0902 \u0939\u0948:"}},Nt='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M11 5 6 9H3v6h3l5 4z"></path><path d="M15.5 8.5a5 5 0 0 1 0 7"></path><path d="M18.5 5.5a9 9 0 0 1 0 13"></path></svg>';function Dt(t){let e=Number(t.tagName[1]),n=[t],o=t.nextElementSibling;for(;o&&!(/^H[1-6]$/.test(o.tagName)&&Number(o.tagName[1])<=e);)o.hasAttribute("data-yuktai-ui")||n.push(o),o=o.nextElementSibling;return n}function It(t,e={}){if(!_())return()=>{};let n=null,o=[],a=()=>{if(!n)return;let{speaker:r,button:s}=n;n=null,r.stop(),i(s,!1)},i=(r,s)=>{let l=D[y(r.dataset.lang??"en")]??D.en;r.setAttribute("aria-pressed",s?"true":"false"),r.setAttribute("aria-label",`${s?l.stop:l.read}: ${r.dataset.title}`)};return t.querySelectorAll("h1,h2,h3").forEach(r=>{if(r.closest("[data-yuktai-speak='off'],[data-yuktai-a11y='off'],[data-yuktai-ui],[hidden]")||r.nextElementSibling?.hasAttribute("data-yuktai-speak-button"))return;let s=(r.textContent??"").replace(/\s+/g," ").trim();if(!s)return;let l=t.createElement("button");l.type="button",l.innerHTML=Nt,l.setAttribute("data-yuktai-ui",""),l.setAttribute("data-yuktai-speak-button",""),l.dataset.title=s.slice(0,80),l.dataset.lang=v(r)||"en",l.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;margin:4px 0;border-radius:999px;border:1px solid #C9CBD3;background:#FFFFFF;color:#2F43C4;cursor:pointer;vertical-align:middle",i(l,!1),l.addEventListener("click",()=>{if(n?.button===l)return a();a();let d=Dt(r),c=t.createElement("div");for(let p of d)c.appendChild(p.cloneNode(!0));c.setAttribute("lang",v(r)||t.documentElement.lang||"en"),n={speaker:lt(c,{lang:c.getAttribute("lang")??void 0,onMissingVoice:p=>{let f=D[y(l.dataset.lang??"en")]??D.en;e.onMissingVoice?.(p,`${f.noVoice} ${p}`)},onEnd:()=>{n?.button===l&&(n=null,i(l,!1))}}),button:l},i(l,!0)}),r.insertAdjacentElement("afterend",l),o.push(l)}),()=>{a(),o.forEach(r=>r.remove())}}var de="6.0.0",Bt="p,h1,h2,h3,h4,h5,h6,li,td,th,dt,dd,a,button,label,span,small,strong,em,b,figcaption,caption,blockquote,summary,legend";function Ot(t){for(let e of Array.from(t.childNodes))if(e.nodeType===3&&(e.textContent??"").trim())return!0;return!1}function fe(t={}){let e=t.document??document,n=t.attributes===!1?{...G,...ct(t)}:nt(e,ct(t)),o={...N,level:n.level},a=null,i=null,r=null,s=!1,l=()=>{s=!0;let c={level:n.level,mode:n.mode,fixed:[],check:[],unknown:[],scanned:0,at:new Date().toISOString()};try{if(n.mode==="off")return a=c;let g=n.mode==="auto",p=$(e);c.scanned=p.elements.length;let f=u=>c[u.status].push(u);if(n.lang==="auto"){let u=Q(e);u.mismatch&&u.detected&&f({rule:"page-lang-mismatch",status:"check",wcag:A["page-lang-mismatch"],where:"html",data:{declared:u.declared,detected:u.detected.lang},el:e.documentElement});for(let m of tt(e,{apply:g})){let h=m.scope==="page"?"page-lang-missing":"part-lang-missing";f({rule:h,status:g?"fixed":"check",wcag:A[h],where:m.scope==="page"?"html":x(m.el),data:{lang:m.lang},el:m.el})}}for(let u of B(e,p.elements,{fix:g}))f(u);if(n.level!=="off")for(let u of p.elements){if(!u.matches(Bt)||!Ot(u)||k(u)||u.closest("[data-yuktai-ui],[data-yuktai-a11y='off'],[hidden],[aria-hidden='true']"))continue;let m=ot(u,n.level);if(m.status!=="pass"){if(m.status==="unknown"){f({rule:"contrast-unknown",status:"unknown",wcag:A["contrast-unknown"],where:x(u),data:{reason:m.reason??""},el:u});continue}if(g&&n.contrast==="fix"&&m.fg&&m.bg&&m.required){let h=P(m.fg,m.bg,m.required),C=u;C.hasAttribute("data-yuktai-color")||C.setAttribute("data-yuktai-color",C.style.getPropertyValue("color")||"-"),C.style.setProperty("color",w(h),"important"),f({rule:"contrast",status:"fixed",wcag:n.level==="AAA"?"1.4.6":"1.4.3",where:x(u),data:{ratio:m.ratio??0,required:m.required,to:w(h)},el:u})}else f({rule:"contrast",status:"check",wcag:n.level==="AAA"?"1.4.6":"1.4.3",where:x(u),data:{ratio:m.ratio??0,required:m.required??0},el:u})}}for(let u of p.closed)f({rule:"closed-shadow-root",status:"unknown",wcag:"",where:x(u),el:u});for(let u of p.crossOrigin)f({rule:"iframe-cross-origin",status:"unknown",wcag:"",where:x(u),data:{src:u.getAttribute("src")??""},el:u})}finally{i?.takeRecords(),s=!1}return a=c,t.onReport?.(c),c},d=()=>{et(e),O(e),e.querySelectorAll("[data-yuktai-color]").forEach(c=>{let g=c,p=g.getAttribute("data-yuktai-color");g.style.removeProperty("color"),p&&p!=="-"&&g.style.setProperty("color",p),g.removeAttribute("data-yuktai-color")}),it(e),a=null};return t.observe!==!1&&typeof MutationObserver<"u"&&n.mode!=="off"&&(i=new MutationObserver(c=>{s||c.some(g=>g.type==="childList"&&g.addedNodes.length)&&(r&&clearTimeout(r),r=setTimeout(l,400))}),queueMicrotask(()=>e.body&&i?.observe(e.body,{childList:!0,subtree:!0}))),{settings:n,run:l,get report(){return a},setPrefs(c){return o={...o,...c},at(e,o),o},get prefs(){return o},undo:d,destroy(){i?.disconnect(),i=null,r&&clearTimeout(r),d()}}}function ct(t){let e={};for(let n of["mode","level","contrast","lang","speak"]){let o=t[n];o!==void 0&&(e[n]=o)}return e}export{N as DEFAULT_PREFS,G as DEFAULT_SETTINGS,K as MESSAGES,de as VERSION,A as WCAG,F as accessibleName,It as addSpeakButtons,tt as annotateLanguages,at as applyPrefs,B as auditAria,rt as blend,_ as canSpeak,ot as checkElementContrast,it as clearPrefs,S as contrastRatio,fe as createA11y,x as describe,I as detectText,Lt as effectiveBackground,$ as findAll,st as getVoices,Wt as hasAttributes,v as inheritedLang,Et as isLargeText,mt as isRtl,k as isSkipped,Jt as loadPrefs,H as luminance,ut as message,P as nearestPassingColor,Q as pageLanguage,Z as pageText,T as parseColor,Ft as pickVoice,Rt as prefsCss,y as primary,nt as readAttributes,Pt as readableText,qt as refineWithDetector,V as requiredRatio,Yt as savePrefs,U as scriptOf,Mt as sentences,lt as speak,Qt as speakableLanguages,z as splitByLanguage,w as toHex,dt as toJSON,O as undoAria,et as undoLanguages};
@@ -0,0 +1,70 @@
1
+ export interface ScriptInfo {
2
+ script: string;
3
+ /** BCP 47 language used when this script is all we know. */
4
+ lang: string;
5
+ /** True when other languages share the script (the guess may be wrong). */
6
+ shared: boolean;
7
+ }
8
+ /** True for languages written right to left. */
9
+ export declare const isRtl: (lang: string) => boolean;
10
+ /** "te-IN" → "te". */
11
+ export declare const primary: (lang: string) => string;
12
+ /** The script of one character, or null for digits, spaces and punctuation. */
13
+ export declare function scriptOf(ch: string): ScriptInfo | null;
14
+ export interface Detection {
15
+ lang: string;
16
+ script: string;
17
+ /** Share of letters in the winning script, 0–1. */
18
+ confidence: number;
19
+ letters: number;
20
+ shared: boolean;
21
+ }
22
+ /** Language of a piece of text from its letters. Null when it has (almost) no letters. */
23
+ export declare function detectText(text: string, minLetters?: number): Detection | null;
24
+ export interface Segment {
25
+ text: string;
26
+ lang: string;
27
+ }
28
+ /**
29
+ * Splits text where the script changes, so each part can be read with the
30
+ * right voice. Digits, spaces and punctuation stay with the part around them.
31
+ */
32
+ export declare function splitByLanguage(text: string, fallback: string): Segment[];
33
+ /** The language an element inherits: its own or the closest ancestor's `lang` (crossing shadow roots). */
34
+ export declare function inheritedLang(el: Element): string;
35
+ /** True when the element is a typing area, code, or switched off for YuktAI. */
36
+ export declare function isSkipped(el: Element): boolean;
37
+ /** Body text of a document, without typing areas, code or switched-off parts. */
38
+ export declare function pageText(doc: Document, limit?: number): string;
39
+ export interface PageLanguage {
40
+ /** What <html lang> says ("" when missing). */
41
+ declared: string;
42
+ /** What the text says, or null when there is too little text. */
43
+ detected: Detection | null;
44
+ /** True when the declared language and the text clearly disagree. */
45
+ mismatch: boolean;
46
+ }
47
+ export declare function pageLanguage(doc: Document): PageLanguage;
48
+ export interface LangChange {
49
+ el: Element;
50
+ lang: string;
51
+ /** "page" for <html>, "part" for an element. */
52
+ scope: "page" | "part";
53
+ }
54
+ /**
55
+ * Adds `lang` where it is missing: on <html> when the page has none, and on
56
+ * elements whose text is in another language than they inherit. Returns what
57
+ * it set (or would set, with apply=false). Never overwrites an existing `lang`.
58
+ */
59
+ export declare function annotateLanguages(doc: Document, opts?: {
60
+ apply: boolean;
61
+ root?: Element | ShadowRoot;
62
+ }): LangChange[];
63
+ /** Removes every `lang` (and `dir`) this file added. */
64
+ export declare function undoLanguages(doc: Document): number;
65
+ /**
66
+ * Refines a guess for a shared script (Devanagari → Hindi or Marathi?) with
67
+ * Chrome's on-device LanguageDetector. Returns the guess unchanged when the
68
+ * browser has no detector or is not sure.
69
+ */
70
+ export declare function refineWithDetector(text: string, guess: Detection): Promise<string>;
@@ -0,0 +1,29 @@
1
+ import { type Level } from "./contrast";
2
+ export type Tristate = "off" | "on" | "device";
3
+ export type Theme = "default" | "high-contrast" | "soft" | "custom";
4
+ export interface Prefs {
5
+ /** 100–200 (%). */
6
+ textSize: number;
7
+ /** WCAG 1.4.12 spacing: line 1.5, paragraphs 2×, letters 0.12em, words 0.16em. */
8
+ spacing: boolean;
9
+ reduceMotion: Tristate;
10
+ focusRing: boolean;
11
+ theme: Theme;
12
+ /** For theme "custom": text and background (any CSS hex). The text is adjusted until it passes `level`. */
13
+ custom?: {
14
+ text: string;
15
+ background: string;
16
+ };
17
+ dark: Tristate;
18
+ level: Level;
19
+ }
20
+ export declare const DEFAULT_PREFS: Prefs;
21
+ /** The CSS for a set of preferences (exported for tests). */
22
+ export declare function prefsCss(p: Prefs): string;
23
+ /** Applies preferences to the page (replacing earlier ones). */
24
+ export declare function applyPrefs(doc: Document, p: Prefs): void;
25
+ /** Takes every preference off the page. */
26
+ export declare function clearPrefs(doc: Document): void;
27
+ /** Reads saved preferences; storage may be blocked, so this never throws. */
28
+ export declare function loadPrefs(key?: string): Prefs;
29
+ export declare function savePrefs(p: Prefs, key?: string): void;