@contractspec/lib.accessibility 3.7.15 → 3.7.17

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.
@@ -1,132 +1 @@
1
- // src/preferences.tsx
2
- import React from "react";
3
- import { jsxDEV } from "react/jsx-dev-runtime";
4
- "use client";
5
- var DEFAULT_PREFERENCES = {
6
- textSize: "m",
7
- textSpacing: "normal",
8
- lineHeight: "normal",
9
- underlineLinks: false,
10
- focusRing: "normal",
11
- reduceMotion: "system",
12
- highContrast: false,
13
- dyslexiaFont: false
14
- };
15
- var STORAGE_KEY = "a11y:preferences:v1";
16
- function getStoredPreferences() {
17
- try {
18
- const raw = typeof window !== "undefined" ? window.localStorage.getItem(STORAGE_KEY) : null;
19
- if (!raw)
20
- return null;
21
- const parsed = JSON.parse(raw);
22
- return { ...DEFAULT_PREFERENCES, ...parsed };
23
- } catch {
24
- return null;
25
- }
26
- }
27
- function savePreferences(prefs) {
28
- try {
29
- if (typeof window !== "undefined") {
30
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
31
- }
32
- } catch {}
33
- }
34
- function applyCssVariables(prefs) {
35
- if (typeof document === "undefined")
36
- return;
37
- const root = document.documentElement;
38
- const body = document.body;
39
- const sizeMap = {
40
- s: "0.95",
41
- m: "1",
42
- l: "1.1",
43
- xl: "1.25"
44
- };
45
- root.style.setProperty("--a11y-text-scale", sizeMap[prefs.textSize]);
46
- const targetMin = prefs.textSize === "l" || prefs.textSize === "xl" ? "44px" : "0px";
47
- root.style.setProperty("--a11y-target-min", targetMin);
48
- root.style.setProperty("--a11y-letter-spacing", prefs.textSpacing === "increased" ? "0.12em" : "normal");
49
- root.style.setProperty("--a11y-word-spacing", prefs.textSpacing === "increased" ? "0.16em" : "normal");
50
- root.style.setProperty("--a11y-line-height", prefs.lineHeight === "increased" ? "1.6" : "1.5");
51
- root.style.setProperty("--a11y-underline-links", prefs.underlineLinks ? "underline" : "revert");
52
- root.style.setProperty("--a11y-focus-ring-width", prefs.focusRing === "thick" ? "4px" : "2px");
53
- root.style.setProperty("--a11y-reduce-motion", prefs.reduceMotion);
54
- root.style.setProperty("--a11y-contrast-mode", prefs.highContrast ? "high" : "normal");
55
- if (prefs.highContrast) {
56
- root.setAttribute("data-contrast", "high");
57
- } else {
58
- root.removeAttribute("data-contrast");
59
- }
60
- root.style.setProperty("--a11y-font-family-alt-enabled", prefs.dyslexiaFont ? "1" : "0");
61
- if (body) {
62
- if (prefs.textSpacing === "increased") {
63
- body.style.letterSpacing = "0.12em";
64
- body.style.wordSpacing = "0.16em";
65
- } else {
66
- body.style.letterSpacing = "";
67
- body.style.wordSpacing = "";
68
- }
69
- body.style.lineHeight = prefs.lineHeight === "increased" ? "1.6" : "";
70
- }
71
- }
72
- var PreferencesContext = React.createContext(null);
73
- function useA11YPreferences() {
74
- const ctx = React.useContext(PreferencesContext);
75
- if (!ctx)
76
- throw new Error("useA11YPreferences must be used within A11YPreferencesProvider");
77
- return ctx;
78
- }
79
- function A11YPreferencesProvider({
80
- children
81
- }) {
82
- const [preferences, setPreferencesState] = React.useState(DEFAULT_PREFERENCES);
83
- const [hydrated, setHydrated] = React.useState(false);
84
- React.useEffect(() => {
85
- const stored = getStoredPreferences();
86
- const next = stored ?? DEFAULT_PREFERENCES;
87
- setPreferencesState(next);
88
- setHydrated(true);
89
- applyCssVariables(next);
90
- }, []);
91
- const setPreferences = React.useCallback((updater) => {
92
- setPreferencesState((prev) => {
93
- const next = typeof updater === "function" ? updater(prev) : { ...prev, ...updater };
94
- savePreferences(next);
95
- applyCssVariables(next);
96
- try {
97
- if (typeof window !== "undefined") {
98
- const changed = {};
99
- for (const key of Object.keys(next)) {
100
- if (next[key] !== prev[key]) {
101
- changed[key] = next[key];
102
- }
103
- }
104
- window.dispatchEvent(new CustomEvent("a11y:pref_changed", {
105
- detail: {
106
- previous: prev,
107
- current: next,
108
- changed
109
- }
110
- }));
111
- }
112
- } catch {}
113
- return next;
114
- });
115
- }, []);
116
- const value = React.useMemo(() => ({ preferences, setPreferences }), [preferences, setPreferences]);
117
- return /* @__PURE__ */ jsxDEV(PreferencesContext, {
118
- value,
119
- children: [
120
- children,
121
- !hydrated ? null : null
122
- ]
123
- }, undefined, true, undefined, this);
124
- }
125
- function a11yRootClassName() {
126
- return "a11y-root";
127
- }
128
- export {
129
- useA11YPreferences,
130
- a11yRootClassName,
131
- A11YPreferencesProvider
132
- };
1
+ import W from"react";import{jsxs as m}from"react/jsx-runtime";var j={textSize:"m",textSpacing:"normal",lineHeight:"normal",underlineLinks:!1,focusRing:"normal",reduceMotion:"system",highContrast:!1,dyslexiaFont:!1},K="a11y:preferences:v1";function V(){try{let q=typeof window<"u"?window.localStorage.getItem(K):null;if(!q)return null;let B=JSON.parse(q);return{...j,...B}}catch{return null}}function Y(q){try{if(typeof window<"u")window.localStorage.setItem(K,JSON.stringify(q))}catch{}}function H(q){if(typeof document>"u")return;let{documentElement:B,body:I}=document,$={s:"0.95",m:"1",l:"1.1",xl:"1.25"};B.style.setProperty("--a11y-text-scale",$[q.textSize]);let z=q.textSize==="l"||q.textSize==="xl"?"44px":"0px";if(B.style.setProperty("--a11y-target-min",z),B.style.setProperty("--a11y-letter-spacing",q.textSpacing==="increased"?"0.12em":"normal"),B.style.setProperty("--a11y-word-spacing",q.textSpacing==="increased"?"0.16em":"normal"),B.style.setProperty("--a11y-line-height",q.lineHeight==="increased"?"1.6":"1.5"),B.style.setProperty("--a11y-underline-links",q.underlineLinks?"underline":"revert"),B.style.setProperty("--a11y-focus-ring-width",q.focusRing==="thick"?"4px":"2px"),B.style.setProperty("--a11y-reduce-motion",q.reduceMotion),B.style.setProperty("--a11y-contrast-mode",q.highContrast?"high":"normal"),q.highContrast)B.setAttribute("data-contrast","high");else B.removeAttribute("data-contrast");if(B.style.setProperty("--a11y-font-family-alt-enabled",q.dyslexiaFont?"1":"0"),I){if(q.textSpacing==="increased")I.style.letterSpacing="0.12em",I.style.wordSpacing="0.16em";else I.style.letterSpacing="",I.style.wordSpacing="";I.style.lineHeight=q.lineHeight==="increased"?"1.6":""}}var M=W.createContext(null);function L(){let q=W.useContext(M);if(!q)throw Error("useA11YPreferences must be used within A11YPreferencesProvider");return q}function U({children:q}){let[B,I]=W.useState(j),[$,z]=W.useState(!1);W.useEffect(()=>{let J=V()??j;I(J),z(!0),H(J)},[]);let w=W.useCallback((X)=>{I((J)=>{let Q=typeof X==="function"?X(J):{...J,...X};Y(Q),H(Q);try{if(typeof window<"u"){let G={};for(let Z of Object.keys(Q))if(Q[Z]!==J[Z])G[Z]=Q[Z];window.dispatchEvent(new CustomEvent("a11y:pref_changed",{detail:{previous:J,current:Q,changed:G}}))}}catch{}return Q})},[]),O=W.useMemo(()=>({preferences:B,setPreferences:w}),[B,w]);return m(M,{value:O,children:[q,!$?null:null]})}function g(){return"a11y-root"}export{L as useA11YPreferences,g as a11yRootClassName,U as A11YPreferencesProvider};
package/dist/index.css CHANGED
@@ -1,60 +1 @@
1
- /* src/styles.css */
2
- :root {
3
- --a11y-text-scale: 1;
4
- --a11y-letter-spacing: normal;
5
- --a11y-word-spacing: normal;
6
- --a11y-line-height: 1.5;
7
- --a11y-underline-links: auto;
8
- --a11y-focus-ring-width: 2px;
9
- --a11y-reduce-motion: system;
10
- --a11y-contrast-mode: normal;
11
- --a11y-font-family-alt-enabled: 0;
12
- }
13
-
14
- html, body {
15
- font-size: calc(16px * var(--a11y-text-scale));
16
- }
17
-
18
- body, p, li {
19
- letter-spacing: var(--a11y-letter-spacing);
20
- word-spacing: var(--a11y-word-spacing);
21
- line-height: var(--a11y-line-height);
22
- }
23
-
24
- a {
25
- text-decoration: var(--a11y-underline-links);
26
- }
27
-
28
- :where(button, [role="button"], a, input, select, textarea) {
29
- outline-offset: 2px;
30
- min-height: var(--a11y-target-min, 0);
31
- min-width: var(--a11y-target-min, 0);
32
- }
33
-
34
- :where(:focus-visible) {
35
- outline: var(--a11y-focus-ring-width) solid currentColor;
36
- }
37
-
38
- :root[style*="--a11y-font-family-alt-enabled: 1"] body {
39
- font-family: var(--font-dyslexia, system-ui, sans-serif);
40
- }
41
-
42
- @media (prefers-reduced-motion: reduce) {
43
- :root[style*="--a11y-reduce-motion: system"] * {
44
- animation: none !important;
45
- scroll-behavior: auto !important;
46
- transition: none !important;
47
- }
48
- }
49
-
50
- :root[style*="--a11y-reduce-motion: reduce"] * {
51
- animation: none !important;
52
- scroll-behavior: auto !important;
53
- transition: none !important;
54
- }
55
-
56
- body {
57
- letter-spacing: var(--a11y-letter-spacing, normal);
58
- word-spacing: var(--a11y-word-spacing, normal);
59
- line-height: var(--a11y-line-height, 1.5);
60
- }
1
+ :root{--a11y-text-scale:1;--a11y-letter-spacing:normal;--a11y-word-spacing:normal;--a11y-line-height:1.5;--a11y-underline-links:auto;--a11y-focus-ring-width:2px;--a11y-reduce-motion:system;--a11y-contrast-mode:normal;--a11y-font-family-alt-enabled:0}html,body{font-size:calc(16px*var(--a11y-text-scale))}body,p,li{letter-spacing:var(--a11y-letter-spacing);word-spacing:var(--a11y-word-spacing);line-height:var(--a11y-line-height)}a{text-decoration:var(--a11y-underline-links)}:where(button,[role=button],a,input,select,textarea){outline-offset:2px;min-height:var(--a11y-target-min,0);min-width:var(--a11y-target-min,0)}:where(:focus-visible){outline:var(--a11y-focus-ring-width)solid currentColor}:root[style*="--a11y-font-family-alt-enabled: 1"] body{font-family:var(--font-dyslexia,system-ui,sans-serif)}@media (prefers-reduced-motion:reduce){:root[style*="--a11y-reduce-motion: system"] *{animation:none!important;scroll-behavior:auto!important;transition:none!important}}:root[style*="--a11y-reduce-motion: reduce"] *{animation:none!important;scroll-behavior:auto!important;transition:none!important}body{letter-spacing:var(--a11y-letter-spacing,normal);word-spacing:var(--a11y-word-spacing,normal);line-height:var(--a11y-line-height,1.5)}
package/dist/index.js CHANGED
@@ -1,15 +1,2 @@
1
1
  // @bun
2
- export {
3
- useSRLiveRegion,
4
- useReducedMotion,
5
- useA11YPreferences,
6
- VisuallyHidden,
7
- SkipLink,
8
- SRLiveRegionProvider,
9
- RouteAnnouncer,
10
- NextRouteAnnouncer,
11
- FocusOnRouteChange,
12
- AccessibilityProvider,
13
- AccessibilityPanel,
14
- A11YPreferencesProvider
15
- };
2
+ export{B as useSRLiveRegion,H as useReducedMotion,M as useA11YPreferences,J as VisuallyHidden,F as SkipLink,z as SRLiveRegionProvider,D as RouteAnnouncer,T as NextRouteAnnouncer,m as FocusOnRouteChange,R as AccessibilityProvider,O as AccessibilityPanel,L as A11YPreferencesProvider};
@@ -1,24 +1,2 @@
1
1
  // @bun
2
- // src/next-route-announcer.tsx
3
- import { usePathname } from "next/navigation";
4
- import * as React from "react";
5
- import { jsxDEV } from "react/jsx-dev-runtime";
6
- "use client";
7
- function NextRouteAnnouncer() {
8
- const pathname = usePathname();
9
- const [message, setMessage] = React.useState("");
10
- React.useEffect(() => {
11
- if (typeof document !== "undefined") {
12
- setMessage(document.title || pathname || "");
13
- }
14
- }, [pathname]);
15
- return /* @__PURE__ */ jsxDEV("div", {
16
- "aria-live": "polite",
17
- "aria-atomic": "true",
18
- className: "sr-only",
19
- children: message
20
- }, undefined, false, undefined, this);
21
- }
22
- export {
23
- NextRouteAnnouncer
24
- };
2
+ import{usePathname as y}from"next/navigation";import*as b from"react";import{jsx as z}from"react/jsx-runtime";function B(){let f=y(),[k,q]=b.useState("");return b.useEffect(()=>{if(typeof document<"u")q(document.title||f||"")},[f]),z("div",{"aria-live":"polite","aria-atomic":"true",className:"sr-only",children:k})}export{B as NextRouteAnnouncer};
@@ -1,133 +1,2 @@
1
1
  // @bun
2
- // src/preferences.tsx
3
- import React from "react";
4
- import { jsxDEV } from "react/jsx-dev-runtime";
5
- "use client";
6
- var DEFAULT_PREFERENCES = {
7
- textSize: "m",
8
- textSpacing: "normal",
9
- lineHeight: "normal",
10
- underlineLinks: false,
11
- focusRing: "normal",
12
- reduceMotion: "system",
13
- highContrast: false,
14
- dyslexiaFont: false
15
- };
16
- var STORAGE_KEY = "a11y:preferences:v1";
17
- function getStoredPreferences() {
18
- try {
19
- const raw = typeof window !== "undefined" ? window.localStorage.getItem(STORAGE_KEY) : null;
20
- if (!raw)
21
- return null;
22
- const parsed = JSON.parse(raw);
23
- return { ...DEFAULT_PREFERENCES, ...parsed };
24
- } catch {
25
- return null;
26
- }
27
- }
28
- function savePreferences(prefs) {
29
- try {
30
- if (typeof window !== "undefined") {
31
- window.localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
32
- }
33
- } catch {}
34
- }
35
- function applyCssVariables(prefs) {
36
- if (typeof document === "undefined")
37
- return;
38
- const root = document.documentElement;
39
- const body = document.body;
40
- const sizeMap = {
41
- s: "0.95",
42
- m: "1",
43
- l: "1.1",
44
- xl: "1.25"
45
- };
46
- root.style.setProperty("--a11y-text-scale", sizeMap[prefs.textSize]);
47
- const targetMin = prefs.textSize === "l" || prefs.textSize === "xl" ? "44px" : "0px";
48
- root.style.setProperty("--a11y-target-min", targetMin);
49
- root.style.setProperty("--a11y-letter-spacing", prefs.textSpacing === "increased" ? "0.12em" : "normal");
50
- root.style.setProperty("--a11y-word-spacing", prefs.textSpacing === "increased" ? "0.16em" : "normal");
51
- root.style.setProperty("--a11y-line-height", prefs.lineHeight === "increased" ? "1.6" : "1.5");
52
- root.style.setProperty("--a11y-underline-links", prefs.underlineLinks ? "underline" : "revert");
53
- root.style.setProperty("--a11y-focus-ring-width", prefs.focusRing === "thick" ? "4px" : "2px");
54
- root.style.setProperty("--a11y-reduce-motion", prefs.reduceMotion);
55
- root.style.setProperty("--a11y-contrast-mode", prefs.highContrast ? "high" : "normal");
56
- if (prefs.highContrast) {
57
- root.setAttribute("data-contrast", "high");
58
- } else {
59
- root.removeAttribute("data-contrast");
60
- }
61
- root.style.setProperty("--a11y-font-family-alt-enabled", prefs.dyslexiaFont ? "1" : "0");
62
- if (body) {
63
- if (prefs.textSpacing === "increased") {
64
- body.style.letterSpacing = "0.12em";
65
- body.style.wordSpacing = "0.16em";
66
- } else {
67
- body.style.letterSpacing = "";
68
- body.style.wordSpacing = "";
69
- }
70
- body.style.lineHeight = prefs.lineHeight === "increased" ? "1.6" : "";
71
- }
72
- }
73
- var PreferencesContext = React.createContext(null);
74
- function useA11YPreferences() {
75
- const ctx = React.useContext(PreferencesContext);
76
- if (!ctx)
77
- throw new Error("useA11YPreferences must be used within A11YPreferencesProvider");
78
- return ctx;
79
- }
80
- function A11YPreferencesProvider({
81
- children
82
- }) {
83
- const [preferences, setPreferencesState] = React.useState(DEFAULT_PREFERENCES);
84
- const [hydrated, setHydrated] = React.useState(false);
85
- React.useEffect(() => {
86
- const stored = getStoredPreferences();
87
- const next = stored ?? DEFAULT_PREFERENCES;
88
- setPreferencesState(next);
89
- setHydrated(true);
90
- applyCssVariables(next);
91
- }, []);
92
- const setPreferences = React.useCallback((updater) => {
93
- setPreferencesState((prev) => {
94
- const next = typeof updater === "function" ? updater(prev) : { ...prev, ...updater };
95
- savePreferences(next);
96
- applyCssVariables(next);
97
- try {
98
- if (typeof window !== "undefined") {
99
- const changed = {};
100
- for (const key of Object.keys(next)) {
101
- if (next[key] !== prev[key]) {
102
- changed[key] = next[key];
103
- }
104
- }
105
- window.dispatchEvent(new CustomEvent("a11y:pref_changed", {
106
- detail: {
107
- previous: prev,
108
- current: next,
109
- changed
110
- }
111
- }));
112
- }
113
- } catch {}
114
- return next;
115
- });
116
- }, []);
117
- const value = React.useMemo(() => ({ preferences, setPreferences }), [preferences, setPreferences]);
118
- return /* @__PURE__ */ jsxDEV(PreferencesContext, {
119
- value,
120
- children: [
121
- children,
122
- !hydrated ? null : null
123
- ]
124
- }, undefined, true, undefined, this);
125
- }
126
- function a11yRootClassName() {
127
- return "a11y-root";
128
- }
129
- export {
130
- useA11YPreferences,
131
- a11yRootClassName,
132
- A11YPreferencesProvider
133
- };
2
+ import W from"react";import{jsxs as m}from"react/jsx-runtime";var j={textSize:"m",textSpacing:"normal",lineHeight:"normal",underlineLinks:!1,focusRing:"normal",reduceMotion:"system",highContrast:!1,dyslexiaFont:!1},K="a11y:preferences:v1";function V(){try{let q=typeof window<"u"?window.localStorage.getItem(K):null;if(!q)return null;let B=JSON.parse(q);return{...j,...B}}catch{return null}}function Y(q){try{if(typeof window<"u")window.localStorage.setItem(K,JSON.stringify(q))}catch{}}function H(q){if(typeof document>"u")return;let{documentElement:B,body:I}=document,$={s:"0.95",m:"1",l:"1.1",xl:"1.25"};B.style.setProperty("--a11y-text-scale",$[q.textSize]);let z=q.textSize==="l"||q.textSize==="xl"?"44px":"0px";if(B.style.setProperty("--a11y-target-min",z),B.style.setProperty("--a11y-letter-spacing",q.textSpacing==="increased"?"0.12em":"normal"),B.style.setProperty("--a11y-word-spacing",q.textSpacing==="increased"?"0.16em":"normal"),B.style.setProperty("--a11y-line-height",q.lineHeight==="increased"?"1.6":"1.5"),B.style.setProperty("--a11y-underline-links",q.underlineLinks?"underline":"revert"),B.style.setProperty("--a11y-focus-ring-width",q.focusRing==="thick"?"4px":"2px"),B.style.setProperty("--a11y-reduce-motion",q.reduceMotion),B.style.setProperty("--a11y-contrast-mode",q.highContrast?"high":"normal"),q.highContrast)B.setAttribute("data-contrast","high");else B.removeAttribute("data-contrast");if(B.style.setProperty("--a11y-font-family-alt-enabled",q.dyslexiaFont?"1":"0"),I){if(q.textSpacing==="increased")I.style.letterSpacing="0.12em",I.style.wordSpacing="0.16em";else I.style.letterSpacing="",I.style.wordSpacing="";I.style.lineHeight=q.lineHeight==="increased"?"1.6":""}}var M=W.createContext(null);function L(){let q=W.useContext(M);if(!q)throw Error("useA11YPreferences must be used within A11YPreferencesProvider");return q}function U({children:q}){let[B,I]=W.useState(j),[$,z]=W.useState(!1);W.useEffect(()=>{let J=V()??j;I(J),z(!0),H(J)},[]);let w=W.useCallback((X)=>{I((J)=>{let Q=typeof X==="function"?X(J):{...J,...X};Y(Q),H(Q);try{if(typeof window<"u"){let G={};for(let Z of Object.keys(Q))if(Q[Z]!==J[Z])G[Z]=Q[Z];window.dispatchEvent(new CustomEvent("a11y:pref_changed",{detail:{previous:J,current:Q,changed:G}}))}}catch{}return Q})},[]),O=W.useMemo(()=>({preferences:B,setPreferences:w}),[B,w]);return m(M,{value:O,children:[q,!$?null:null]})}function g(){return"a11y-root"}export{L as useA11YPreferences,g as a11yRootClassName,U as A11YPreferencesProvider};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.accessibility",
3
- "version": "3.7.15",
3
+ "version": "3.7.17",
4
4
  "description": "WCAG compliance utilities and validators",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -19,25 +19,25 @@
19
19
  "dev": "contractspec-bun-build dev",
20
20
  "clean": "rimraf dist .turbo",
21
21
  "lint": "bun lint:fix",
22
- "lint:fix": "biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .",
23
- "lint:check": "biome check .",
22
+ "lint:fix": "node ../../../scripts/biome.cjs check --write --unsafe --only=nursery/useSortedClasses . && node ../../../scripts/biome.cjs check --write .",
23
+ "lint:check": "node ../../../scripts/biome.cjs check .",
24
24
  "prebuild": "contractspec-bun-build prebuild",
25
25
  "typecheck": "tsc --noEmit"
26
26
  },
27
27
  "dependencies": {
28
- "@contractspec/lib.design-system": "3.8.9",
29
- "@contractspec/lib.ui-kit": "3.8.8",
30
- "@contractspec/lib.ui-kit-web": "3.9.8"
28
+ "@contractspec/lib.design-system": "3.8.11",
29
+ "@contractspec/lib.ui-kit": "3.8.10",
30
+ "@contractspec/lib.ui-kit-web": "3.9.10"
31
31
  },
32
32
  "devDependencies": {
33
- "@contractspec/tool.typescript": "3.7.12",
33
+ "@contractspec/tool.typescript": "3.7.13",
34
34
  "react-native-css": "^3.0.4",
35
35
  "typescript": "^5.9.3",
36
- "@contractspec/tool.bun": "3.7.12"
36
+ "@contractspec/tool.bun": "3.7.14"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "react": "19.2.4",
40
- "next": "16.2.1"
40
+ "next": "16.2.3"
41
41
  },
42
42
  "type": "module",
43
43
  "types": "./dist/index.d.ts",