@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 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":[]}
@@ -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
+ }