Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ All exports are named from `accessibility-plugin-react`. JavaScript consumers re
| DictionaryController | Optional `className?: string`, `label?: string`, `description?: string`, `provider?: DictionaryProvider | null`, `defaultOpen?: boolean`, `initialTerm?: string`. Accessible dictionary lookup dialog with zero network requests by default, local glossaries, and sanitization. See docs/DICTIONARY.md. |
| VoiceNavigationController | Optional `className?: string`, `label?: string`, `description?: string`. Opt-in research prototype controller enabling browser-native speech commands with inactivity watchdog and keyboard fallback buttons. See docs/VOICE_NAVIGATION.md. |
| TranslationController | Optional `className?: string`, `label?: string`, `description?: string`, `provider?: TranslationAdapter`, `defaultTargetLanguage?: string`. Host-content translation adapter prototype with explicit consent, privacy boundaries, sensitive element exclusion, and DOM restoration. See docs/TRANSLATION.md. |
| SmartContrastController | Optional `className?: string`, `label?: string`, `description?: string`, `options?: SmartContrastOptions`. Measured smart contrast research prototype with relative luminance, alpha compositing, live statistics, and non-destructive restoration. See docs/SMART_CONTRAST.md. |
| DiagnosticsHarness | Optional `config?: DiagnosticsConfig`, `visible?: boolean`, `className?: string`. Development-only integration diagnostics harness inspecting containing-block traps, CSP, host CSS, and accessibility landmarks. See docs/DIAGNOSTICS.md. |
| SmartContrastController | Optional `className?: string`, `label?: string`, `description?: string`, `options?: SmartContrastOptions`. Measured smart contrast research prototype with relative luminance, alpha compositing, live statistics, and non-destructive restoration. See docs/SMART_CONTRAST.md. |
| DiagnosticsHarness | Optional `config?: DiagnosticsConfig`, `visible?: boolean`, `className?: string`. Development-only integration diagnostics harness inspecting containing-block traps, CSP, host CSS, and accessibility landmarks. See docs/DIAGNOSTICS.md. |
| All other controllers in FEATURES.md | Pick/omit in JSX. For custom labels or behavior, compose a control with useAccessibility or the modular control primitives. |

Use one button/list pair per provider and one provider per document. UI IDs use React `useId`; do not target the old fixed `arap-panel` ID. Plugin children can include ordinary app content, but mounting the widget as a sibling makes intent clearer. Persistence configuration is fixed at mount; use `<AccessibilityPlugin key={newKey} persistenceKey={newKey}>` when switching storage identity.
Expand Down
43 changes: 26 additions & 17 deletions docs/PERFORMANCE_PROFILING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,31 @@ This document records empirical performance profiling, bundle size analysis, lis
## 1. Bundle and chunk size analysis

### Library Distribution Assets (`dist/`)

Built with `tsup` targeting ES2020:

| Asset | Description | Raw Size | Gzip Size | Brotli Size |
| :--- | :--- | :--- | :--- | :--- |
| `dist/index.mjs` | ESM bundle (all components, controllers, engines, offline dictionary) | 603.27 KB | 111.48 KB | 86.04 KB |
| `dist/index.js` | CommonJS bundle | 636.96 KB | 114.52 KB | 87.33 KB |
| `dist/style.css` | Scoped CSS stylesheet | 71.31 KB | 11.31 KB | 9.57 KB |
| `dist/index.d.mts` | TypeScript ESM declarations | 83.58 KB | 22.07 KB | 18.48 KB |
| `dist/index.d.ts` | TypeScript CommonJS declarations | 83.58 KB | 22.07 KB | 18.48 KB |
| Asset | Description | Raw Size | Gzip Size | Brotli Size |
| :----------------- | :-------------------------------------------------------------------- | :-------- | :-------- | :---------- |
| `dist/index.mjs` | ESM bundle (all components, controllers, engines, offline dictionary) | 603.27 KB | 111.48 KB | 86.04 KB |
| `dist/index.js` | CommonJS bundle | 636.96 KB | 114.52 KB | 87.33 KB |
| `dist/style.css` | Scoped CSS stylesheet | 71.31 KB | 11.31 KB | 9.57 KB |
| `dist/index.d.mts` | TypeScript ESM declarations | 83.58 KB | 22.07 KB | 18.48 KB |
| `dist/index.d.ts` | TypeScript CommonJS declarations | 83.58 KB | 22.07 KB | 18.48 KB |

### Module Composition & Offline Guarantees

- **Offline Glossary & Dictionaries**: Contains built-in glossaries (English, Sinhala, Tamil) allowing instantaneous client-side definitions without external API latency, rate limits, or network tracking.
- **Zero Runtime Dependencies**: The package relies exclusively on React and React DOM as peer dependencies. Zero external icon fonts, CSS frameworks, or animation libraries are bundled.

### Real Consumer Application Production Builds

Measured in clean consumer testbeds with minification and tree-shaking:

| Consumer Application | Framework / Bundler | Packed Archive Asset | Production Gzip Size |
| :--- | :--- | :--- | :--- |
| **React 18 Consumer** | React 18.3.1 + Vite 7 (Rollup) | Application bundle (React + React DOM + Plugin) | **127.36 KB** gzipped |
| **Next.js 16 App Router** | Next.js 16.2.10 (Webpack 5) | Page Route Chunks (`app/page.js`, `app/route-test/page.js`) | **1.85 KB** gzipped |
| **Next.js 16 App Router** | Next.js 16.2.10 (Webpack 5) | Shared Vendor Chunks | **59.37 KB – 79.42 KB** gzipped |
| Consumer Application | Framework / Bundler | Packed Archive Asset | Production Gzip Size |
| :------------------------ | :----------------------------- | :---------------------------------------------------------- | :------------------------------ |
| **React 18 Consumer** | React 18.3.1 + Vite 7 (Rollup) | Application bundle (React + React DOM + Plugin) | **127.36 KB** gzipped |
| **Next.js 16 App Router** | Next.js 16.2.10 (Webpack 5) | Page Route Chunks (`app/page.js`, `app/route-test/page.js`) | **1.85 KB** gzipped |
| **Next.js 16 App Router** | Next.js 16.2.10 (Webpack 5) | Shared Vendor Chunks | **59.37 KB – 79.42 KB** gzipped |

---

Expand All @@ -39,6 +42,7 @@ Measured in clean consumer testbeds with minification and tree-shaking:
When the accessibility widget is mounted in a host application with the panel closed (the standard idle state), its runtime footprint is strictly constrained:

### Event Listener Footprint (Closed State)

- **Window Listeners**:
- `pagehide`: 1 handler attached to synchronously flush any debounced state to storage prior to navigation.
- `resize`: 1 throttled listener for viewport boundary clamping during repositioning.
Expand All @@ -51,7 +55,9 @@ When the accessibility widget is mounted in a host application with the panel cl
- `0` persistent audio/microphone streams.

### Feature-Specific Listener Isolation

Listeners for features with dynamic tracking are registered **only while that specific feature is active**:

- **Reading Guide / Reading Mask**: Pointer tracking listeners (`pointermove`, `touchmove`, `scroll`) are attached only when either guide or mask is toggled ON, and are removed immediately upon toggle OFF or reset.
- **Accessible Tooltips**: Global hover/focus listeners are active only when tooltips are enabled.
- **Speech & Voice**: Recognition and synthesis listeners attach only during active listening or playback sessions, and disconnect immediately on stop, timeout, visibility change, or unmount.
Expand All @@ -64,13 +70,14 @@ To verify that display preferences do not induce perceptible UI lag (jank) or bl

### Benchmark Results (Automated Vitest / JSDOM Suite)

| Operation | Scope | Target Budget | Measured Duration | Status |
| :--- | :--- | :--- | :--- | :--- |
| **Multi-Feature Apply** | 1,000 DOM elements (Text Scale, Line Height, Font Family, Contrast Mode, Hide Images) | < 3,000 ms (JSDOM non-JIT) | **~1,770 ms** | **PASS** |
| **Full Reset Teardown** | 1,000 DOM elements (Complete style restoration across all nodes) | < 1,500 ms (JSDOM non-JIT) | **~420 ms** | **PASS** |
| **Real Browser Main Thread** | Chrome 120+ / WebKit (Playwright runtime execution) | < 100 ms | **< 45 ms** | **PASS** |
| Operation | Scope | Target Budget | Measured Duration | Status |
| :--------------------------- | :------------------------------------------------------------------------------------ | :------------------------- | :---------------- | :------- |
| **Multi-Feature Apply** | 1,000 DOM elements (Text Scale, Line Height, Font Family, Contrast Mode, Hide Images) | < 3,000 ms (JSDOM non-JIT) | **~1,770 ms** | **PASS** |
| **Full Reset Teardown** | 1,000 DOM elements (Complete style restoration across all nodes) | < 1,500 ms (JSDOM non-JIT) | **~420 ms** | **PASS** |
| **Real Browser Main Thread** | Chrome 120+ / WebKit (Playwright runtime execution) | < 100 ms | **< 45 ms** | **PASS** |

### Style Application Efficiency

- Features modify inline styles using direct property assignment or scoped CSS class toggling rather than DOM tree rebuilds.
- Protected elements (such as `<code>`, `<pre>`, form buttons, meaningful images, and CAPTCHAs) are identified via cached selector filters, avoiding redundant style computation.

Expand All @@ -79,12 +86,14 @@ To verify that display preferences do not induce perceptible UI lag (jank) or bl
## 4. 100 Mount/Unmount and toggle leak stress-testing

### Mount/Unmount Cycle Verification

- Executed **100 consecutive mount and unmount cycles** of `<AccessibilityPlugin>`:
- Verified `0` orphaned `.arap-root` or `.arap-panel` DOM nodes remaining in `document.body`.
- Verified `0` residual `<style id="arap-*">` tags in `document.head`.
- Verified `0` detached DOM nodes retained in memory.

### 100 Consecutive Toggle Cycles

- Executed **100 rapid consecutive toggles** across text scale, letter spacing, line height, and image hiding:
- Asserted that element inline styles return precisely to authored baseline values without compounding drift or rounding errors.
- Asserted zero residual CSS properties after triggering `Reset All`.
Expand Down
22 changes: 13 additions & 9 deletions docs/PUBLISH_REHEARSAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ This document records the exact archive inspection, tarball packaging rehearsal,

The package archive was built, packed, and inspected via `scripts/check-package.mjs`:

| Inspection Item | Requirement | Measured Result | Status |
| :--- | :--- | :--- | :--- |
| **Tarball Location** | Local disposable archive | `.consumers/package.tgz` | **PASS** |
| **Total Files** | Required bundle, types, CSS, legal, and docs | **61 files** | **PASS** |
| **Archive Size** | Uncompressed package content | **1,186,512 bytes** (~1.18 MB) | **PASS** |
| **Client Directives** | Leading `"use client";` on entrypoints | Present in `dist/index.mjs` and `dist/index.js` | **PASS** |
| **CSS Injection** | Self-contained automatic injection | `styleInject` with `.arap-root` present in bundles | **PASS** |
| **CSS Isolation** | Zero global element resets | No un-scoped resets on `html`, `body`, `:root`, or `*` | **PASS** |
| **Legal Files** | Permissive license and attribution | `LICENSE` and `NOTICE` verified in tarball | **PASS** |
| Inspection Item | Requirement | Measured Result | Status |
| :-------------------- | :------------------------------------------- | :----------------------------------------------------- | :------- |
| **Tarball Location** | Local disposable archive | `.consumers/package.tgz` | **PASS** |
| **Total Files** | Required bundle, types, CSS, legal, and docs | **61 files** | **PASS** |
| **Archive Size** | Uncompressed package content | **1,186,512 bytes** (~1.18 MB) | **PASS** |
| **Client Directives** | Leading `"use client";` on entrypoints | Present in `dist/index.mjs` and `dist/index.js` | **PASS** |
| **CSS Injection** | Self-contained automatic injection | `styleInject` with `.arap-root` present in bundles | **PASS** |
| **CSS Isolation** | Zero global element resets | No un-scoped resets on `html`, `body`, `:root`, or `*` | **PASS** |
| **Legal Files** | Permissive license and attribution | `LICENSE` and `NOTICE` verified in tarball | **PASS** |

### Packed Files Breakdown

- `dist/index.mjs` (ESM build)
- `dist/index.js` (CommonJS build)
- `dist/index.d.mts` (ESM TypeScript declarations)
Expand All @@ -37,13 +38,15 @@ The package archive was built, packed, and inspected via `scripts/check-package.
The exact archive (`.consumers/package.tgz`) was installed in isolated consumer testbeds across supported framework versions:

### React 18 Consumer (`.consumers/react18`)

- **Environment**: React 18.3.1, React DOM 18.3.1, Vite 7.3.7.
- **Verification**:
- NodeNext ESM import and SSR hydration: **PASS**
- CommonJS `require()` resolution: **PASS**
- Production Vite rollup build: **PASS** (`dist/assets/index-RXyyFYxY.js` 487.73 KB raw / 130.42 KB gzip).

### React 19 Consumer (`.consumers/react19`)

- **Environment**: React 19.2.0, React DOM 19.2.0, Tailwind CSS 3.4.19, Vite 7.3.7.
- **Verification**:
- NodeNext ESM import and SSR hydration: **PASS**
Expand All @@ -52,6 +55,7 @@ The exact archive (`.consumers/package.tgz`) was installed in isolated consumer
- Tailwind CSS co-existence: Scoped `.arap-*` classes operate without interference from host Tailwind utilities.

### Next.js 16 Consumer (`.consumers/next`)

- **Environment**: Next.js 16.2.10 (Webpack), React 19.2.0.
- **Verification**:
- Server Component layouts: **PASS**
Expand Down
Loading
Loading