@echothink-ui/accessibility 0.1.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 +5 -0
- package/dist/index.cjs +97 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/src/index.tsx +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# @echothink-ui/accessibility
|
|
2
|
+
|
|
3
|
+
Accessibility package for EchoThink app-domain websites.
|
|
4
|
+
|
|
5
|
+
This package is part of the EchoThink-UI app-domain library. It is designed for normal website app domains rendered inside EchoThink Studio's Chromium shell, not for implementing the studio browser chrome itself.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.tsx
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
VisuallyHidden: () => VisuallyHidden,
|
|
34
|
+
announce: () => announce,
|
|
35
|
+
getFocusableElements: () => getFocusableElements,
|
|
36
|
+
useReducedMotion: () => useReducedMotion
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
var React = __toESM(require("react"), 1);
|
|
40
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
41
|
+
function VisuallyHidden({ children }) {
|
|
42
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
43
|
+
"span",
|
|
44
|
+
{
|
|
45
|
+
style: {
|
|
46
|
+
border: 0,
|
|
47
|
+
clip: "rect(0 0 0 0)",
|
|
48
|
+
height: 1,
|
|
49
|
+
margin: -1,
|
|
50
|
+
overflow: "hidden",
|
|
51
|
+
padding: 0,
|
|
52
|
+
position: "absolute",
|
|
53
|
+
whiteSpace: "nowrap",
|
|
54
|
+
width: 1
|
|
55
|
+
},
|
|
56
|
+
children
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function useReducedMotion() {
|
|
61
|
+
const [reduced, setReduced] = React.useState(() => {
|
|
62
|
+
if (typeof window === "undefined") return false;
|
|
63
|
+
return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
64
|
+
});
|
|
65
|
+
React.useEffect(() => {
|
|
66
|
+
const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
67
|
+
if (!query) return;
|
|
68
|
+
const listener = () => setReduced(query.matches);
|
|
69
|
+
query.addEventListener("change", listener);
|
|
70
|
+
return () => query.removeEventListener("change", listener);
|
|
71
|
+
}, []);
|
|
72
|
+
return reduced;
|
|
73
|
+
}
|
|
74
|
+
function getFocusableElements(root) {
|
|
75
|
+
return Array.from(
|
|
76
|
+
root.querySelectorAll(
|
|
77
|
+
"a[href], button, input, textarea, select, details, [tabindex]:not([tabindex='-1'])"
|
|
78
|
+
)
|
|
79
|
+
).filter((element) => !element.hasAttribute("disabled"));
|
|
80
|
+
}
|
|
81
|
+
function announce(message, politeness = "polite") {
|
|
82
|
+
const region = document.createElement("div");
|
|
83
|
+
region.setAttribute("aria-live", politeness);
|
|
84
|
+
region.style.position = "absolute";
|
|
85
|
+
region.style.left = "-9999px";
|
|
86
|
+
region.textContent = message;
|
|
87
|
+
document.body.append(region);
|
|
88
|
+
window.setTimeout(() => region.remove(), 1e3);
|
|
89
|
+
}
|
|
90
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
91
|
+
0 && (module.exports = {
|
|
92
|
+
VisuallyHidden,
|
|
93
|
+
announce,
|
|
94
|
+
getFocusableElements,
|
|
95
|
+
useReducedMotion
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport function VisuallyHidden({ children }: { children: React.ReactNode }) {\n return (\n <span\n style={{\n border: 0,\n clip: \"rect(0 0 0 0)\",\n height: 1,\n margin: -1,\n overflow: \"hidden\",\n padding: 0,\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: 1\n }}\n >\n {children}\n </span>\n );\n}\n\nexport function useReducedMotion() {\n const [reduced, setReduced] = React.useState(() => {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches ?? false;\n });\n\n React.useEffect(() => {\n const query = window.matchMedia?.(\"(prefers-reduced-motion: reduce)\");\n if (!query) return;\n const listener = () => setReduced(query.matches);\n query.addEventListener(\"change\", listener);\n return () => query.removeEventListener(\"change\", listener);\n }, []);\n return reduced;\n}\n\nexport function getFocusableElements(root: HTMLElement) {\n return Array.from(\n root.querySelectorAll<HTMLElement>(\n \"a[href], button, input, textarea, select, details, [tabindex]:not([tabindex='-1'])\"\n )\n ).filter((element) => !element.hasAttribute(\"disabled\"));\n}\n\nexport function announce(message: string, politeness: \"polite\" | \"assertive\" = \"polite\") {\n const region = document.createElement(\"div\");\n region.setAttribute(\"aria-live\", politeness);\n region.style.position = \"absolute\";\n region.style.left = \"-9999px\";\n region.textContent = message;\n document.body.append(region);\n window.setTimeout(() => region.remove(), 1000);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAAuB;AAInB;AAFG,SAAS,eAAe,EAAE,SAAS,GAAkC;AAC1E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,OAAO;AAAA,MACT;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAEO,SAAS,mBAAmB;AACjC,QAAM,CAAC,SAAS,UAAU,IAAU,eAAS,MAAM;AACjD,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,WAAO,OAAO,aAAa,kCAAkC,EAAE,WAAW;AAAA,EAC5E,CAAC;AAED,EAAM,gBAAU,MAAM;AACpB,UAAM,QAAQ,OAAO,aAAa,kCAAkC;AACpE,QAAI,CAAC,MAAO;AACZ,UAAM,WAAW,MAAM,WAAW,MAAM,OAAO;AAC/C,UAAM,iBAAiB,UAAU,QAAQ;AACzC,WAAO,MAAM,MAAM,oBAAoB,UAAU,QAAQ;AAAA,EAC3D,GAAG,CAAC,CAAC;AACL,SAAO;AACT;AAEO,SAAS,qBAAqB,MAAmB;AACtD,SAAO,MAAM;AAAA,IACX,KAAK;AAAA,MACH;AAAA,IACF;AAAA,EACF,EAAE,OAAO,CAAC,YAAY,CAAC,QAAQ,aAAa,UAAU,CAAC;AACzD;AAEO,SAAS,SAAS,SAAiB,aAAqC,UAAU;AACvF,QAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,SAAO,aAAa,aAAa,UAAU;AAC3C,SAAO,MAAM,WAAW;AACxB,SAAO,MAAM,OAAO;AACpB,SAAO,cAAc;AACrB,WAAS,KAAK,OAAO,MAAM;AAC3B,SAAO,WAAW,MAAM,OAAO,OAAO,GAAG,GAAI;AAC/C;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export declare function VisuallyHidden({ children }: {
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function useReducedMotion(): boolean;
|
|
6
|
+
export declare function getFocusableElements(root: HTMLElement): HTMLElement[];
|
|
7
|
+
export declare function announce(message: string, politeness?: "polite" | "assertive"): void;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// src/index.tsx
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
function VisuallyHidden({ children }) {
|
|
5
|
+
return /* @__PURE__ */ jsx(
|
|
6
|
+
"span",
|
|
7
|
+
{
|
|
8
|
+
style: {
|
|
9
|
+
border: 0,
|
|
10
|
+
clip: "rect(0 0 0 0)",
|
|
11
|
+
height: 1,
|
|
12
|
+
margin: -1,
|
|
13
|
+
overflow: "hidden",
|
|
14
|
+
padding: 0,
|
|
15
|
+
position: "absolute",
|
|
16
|
+
whiteSpace: "nowrap",
|
|
17
|
+
width: 1
|
|
18
|
+
},
|
|
19
|
+
children
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
function useReducedMotion() {
|
|
24
|
+
const [reduced, setReduced] = React.useState(() => {
|
|
25
|
+
if (typeof window === "undefined") return false;
|
|
26
|
+
return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
27
|
+
});
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
30
|
+
if (!query) return;
|
|
31
|
+
const listener = () => setReduced(query.matches);
|
|
32
|
+
query.addEventListener("change", listener);
|
|
33
|
+
return () => query.removeEventListener("change", listener);
|
|
34
|
+
}, []);
|
|
35
|
+
return reduced;
|
|
36
|
+
}
|
|
37
|
+
function getFocusableElements(root) {
|
|
38
|
+
return Array.from(
|
|
39
|
+
root.querySelectorAll(
|
|
40
|
+
"a[href], button, input, textarea, select, details, [tabindex]:not([tabindex='-1'])"
|
|
41
|
+
)
|
|
42
|
+
).filter((element) => !element.hasAttribute("disabled"));
|
|
43
|
+
}
|
|
44
|
+
function announce(message, politeness = "polite") {
|
|
45
|
+
const region = document.createElement("div");
|
|
46
|
+
region.setAttribute("aria-live", politeness);
|
|
47
|
+
region.style.position = "absolute";
|
|
48
|
+
region.style.left = "-9999px";
|
|
49
|
+
region.textContent = message;
|
|
50
|
+
document.body.append(region);
|
|
51
|
+
window.setTimeout(() => region.remove(), 1e3);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
VisuallyHidden,
|
|
55
|
+
announce,
|
|
56
|
+
getFocusableElements,
|
|
57
|
+
useReducedMotion
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport function VisuallyHidden({ children }: { children: React.ReactNode }) {\n return (\n <span\n style={{\n border: 0,\n clip: \"rect(0 0 0 0)\",\n height: 1,\n margin: -1,\n overflow: \"hidden\",\n padding: 0,\n position: \"absolute\",\n whiteSpace: \"nowrap\",\n width: 1\n }}\n >\n {children}\n </span>\n );\n}\n\nexport function useReducedMotion() {\n const [reduced, setReduced] = React.useState(() => {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches ?? false;\n });\n\n React.useEffect(() => {\n const query = window.matchMedia?.(\"(prefers-reduced-motion: reduce)\");\n if (!query) return;\n const listener = () => setReduced(query.matches);\n query.addEventListener(\"change\", listener);\n return () => query.removeEventListener(\"change\", listener);\n }, []);\n return reduced;\n}\n\nexport function getFocusableElements(root: HTMLElement) {\n return Array.from(\n root.querySelectorAll<HTMLElement>(\n \"a[href], button, input, textarea, select, details, [tabindex]:not([tabindex='-1'])\"\n )\n ).filter((element) => !element.hasAttribute(\"disabled\"));\n}\n\nexport function announce(message: string, politeness: \"polite\" | \"assertive\" = \"polite\") {\n const region = document.createElement(\"div\");\n region.setAttribute(\"aria-live\", politeness);\n region.style.position = \"absolute\";\n region.style.left = \"-9999px\";\n region.textContent = message;\n document.body.append(region);\n window.setTimeout(() => region.remove(), 1000);\n}\n"],"mappings":";AAAA,YAAY,WAAW;AAInB;AAFG,SAAS,eAAe,EAAE,SAAS,GAAkC;AAC1E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,OAAO;AAAA,MACT;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAEO,SAAS,mBAAmB;AACjC,QAAM,CAAC,SAAS,UAAU,IAAU,eAAS,MAAM;AACjD,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,WAAO,OAAO,aAAa,kCAAkC,EAAE,WAAW;AAAA,EAC5E,CAAC;AAED,EAAM,gBAAU,MAAM;AACpB,UAAM,QAAQ,OAAO,aAAa,kCAAkC;AACpE,QAAI,CAAC,MAAO;AACZ,UAAM,WAAW,MAAM,WAAW,MAAM,OAAO;AAC/C,UAAM,iBAAiB,UAAU,QAAQ;AACzC,WAAO,MAAM,MAAM,oBAAoB,UAAU,QAAQ;AAAA,EAC3D,GAAG,CAAC,CAAC;AACL,SAAO;AACT;AAEO,SAAS,qBAAqB,MAAmB;AACtD,SAAO,MAAM;AAAA,IACX,KAAK;AAAA,MACH;AAAA,IACF;AAAA,EACF,EAAE,OAAO,CAAC,YAAY,CAAC,QAAQ,aAAa,UAAU,CAAC;AACzD;AAEO,SAAS,SAAS,SAAiB,aAAqC,UAAU;AACvF,QAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,SAAO,aAAa,aAAa,UAAU;AAC3C,SAAO,MAAM,WAAW;AACxB,SAAO,MAAM,OAAO;AACpB,SAAO,cAAc;AACrB,WAAS,KAAK,OAAO,MAAM;AAC3B,SAAO,WAAW,MAAM,OAAO,OAAO,GAAG,GAAI;AAC/C;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@echothink-ui/accessibility",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"react": ">=18.3.0",
|
|
24
|
+
"react-dom": ">=18.3.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@echothink-ui/core": "0.2.0"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup src/index.tsx --format esm,cjs --sourcemap --clean --external react --external react-dom && tsc -p tsconfig.json --declaration --emitDeclarationOnly --noEmit false --outDir dist",
|
|
34
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"test": "vitest run --config ../../vitest.config.ts --passWithNoTests",
|
|
36
|
+
"lint": "eslint src"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export function VisuallyHidden({ children }: { children: React.ReactNode }) {
|
|
4
|
+
return (
|
|
5
|
+
<span
|
|
6
|
+
style={{
|
|
7
|
+
border: 0,
|
|
8
|
+
clip: "rect(0 0 0 0)",
|
|
9
|
+
height: 1,
|
|
10
|
+
margin: -1,
|
|
11
|
+
overflow: "hidden",
|
|
12
|
+
padding: 0,
|
|
13
|
+
position: "absolute",
|
|
14
|
+
whiteSpace: "nowrap",
|
|
15
|
+
width: 1
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
{children}
|
|
19
|
+
</span>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useReducedMotion() {
|
|
24
|
+
const [reduced, setReduced] = React.useState(() => {
|
|
25
|
+
if (typeof window === "undefined") return false;
|
|
26
|
+
return window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
31
|
+
if (!query) return;
|
|
32
|
+
const listener = () => setReduced(query.matches);
|
|
33
|
+
query.addEventListener("change", listener);
|
|
34
|
+
return () => query.removeEventListener("change", listener);
|
|
35
|
+
}, []);
|
|
36
|
+
return reduced;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getFocusableElements(root: HTMLElement) {
|
|
40
|
+
return Array.from(
|
|
41
|
+
root.querySelectorAll<HTMLElement>(
|
|
42
|
+
"a[href], button, input, textarea, select, details, [tabindex]:not([tabindex='-1'])"
|
|
43
|
+
)
|
|
44
|
+
).filter((element) => !element.hasAttribute("disabled"));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function announce(message: string, politeness: "polite" | "assertive" = "polite") {
|
|
48
|
+
const region = document.createElement("div");
|
|
49
|
+
region.setAttribute("aria-live", politeness);
|
|
50
|
+
region.style.position = "absolute";
|
|
51
|
+
region.style.left = "-9999px";
|
|
52
|
+
region.textContent = message;
|
|
53
|
+
document.body.append(region);
|
|
54
|
+
window.setTimeout(() => region.remove(), 1000);
|
|
55
|
+
}
|