@bauer-group/accessibility-widget 1.0.3
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/LICENSE +21 -0
- package/README.md +259 -0
- package/dist/accessibility-widget-core.min.js +6 -0
- package/dist/accessibility-widget-core.min.js.map +7 -0
- package/dist/accessibility-widget-loader.min.js +14 -0
- package/dist/accessibility-widget-loader.min.js.map +7 -0
- package/dist/accessibility-widget.min.css +7 -0
- package/dist/accessibility-widget.min.css.map +7 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/core.d.ts +31 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/features/apply.d.ts +3 -0
- package/dist/features/apply.d.ts.map +1 -0
- package/dist/features/profile.d.ts +3 -0
- package/dist/features/profile.d.ts.map +1 -0
- package/dist/features/reading-guide.d.ts +2 -0
- package/dist/features/reading-guide.d.ts.map +1 -0
- package/dist/features/reading-mask.d.ts +2 -0
- package/dist/features/reading-mask.d.ts.map +1 -0
- package/dist/features/structure-nav.d.ts +2 -0
- package/dist/features/structure-nav.d.ts.map +1 -0
- package/dist/features/tts.d.ts +7 -0
- package/dist/features/tts.d.ts.map +1 -0
- package/dist/focus-trap.d.ts +6 -0
- package/dist/focus-trap.d.ts.map +1 -0
- package/dist/i18n/ar.d.ts +3 -0
- package/dist/i18n/ar.d.ts.map +1 -0
- package/dist/i18n/bn.d.ts +3 -0
- package/dist/i18n/bn.d.ts.map +1 -0
- package/dist/i18n/cs.d.ts +3 -0
- package/dist/i18n/cs.d.ts.map +1 -0
- package/dist/i18n/de.d.ts +3 -0
- package/dist/i18n/de.d.ts.map +1 -0
- package/dist/i18n/el.d.ts +3 -0
- package/dist/i18n/el.d.ts.map +1 -0
- package/dist/i18n/en.d.ts +3 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/es.d.ts +3 -0
- package/dist/i18n/es.d.ts.map +1 -0
- package/dist/i18n/fa.d.ts +3 -0
- package/dist/i18n/fa.d.ts.map +1 -0
- package/dist/i18n/fr.d.ts +3 -0
- package/dist/i18n/fr.d.ts.map +1 -0
- package/dist/i18n/he.d.ts +3 -0
- package/dist/i18n/he.d.ts.map +1 -0
- package/dist/i18n/hi.d.ts +3 -0
- package/dist/i18n/hi.d.ts.map +1 -0
- package/dist/i18n/hu.d.ts +3 -0
- package/dist/i18n/hu.d.ts.map +1 -0
- package/dist/i18n/id.d.ts +3 -0
- package/dist/i18n/id.d.ts.map +1 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/it.d.ts +3 -0
- package/dist/i18n/it.d.ts.map +1 -0
- package/dist/i18n/ja.d.ts +3 -0
- package/dist/i18n/ja.d.ts.map +1 -0
- package/dist/i18n/ko.d.ts +3 -0
- package/dist/i18n/ko.d.ts.map +1 -0
- package/dist/i18n/nl.d.ts +3 -0
- package/dist/i18n/nl.d.ts.map +1 -0
- package/dist/i18n/pl.d.ts +3 -0
- package/dist/i18n/pl.d.ts.map +1 -0
- package/dist/i18n/pt.d.ts +3 -0
- package/dist/i18n/pt.d.ts.map +1 -0
- package/dist/i18n/ro.d.ts +3 -0
- package/dist/i18n/ro.d.ts.map +1 -0
- package/dist/i18n/ru.d.ts +3 -0
- package/dist/i18n/ru.d.ts.map +1 -0
- package/dist/i18n/sv.d.ts +3 -0
- package/dist/i18n/sv.d.ts.map +1 -0
- package/dist/i18n/th.d.ts +3 -0
- package/dist/i18n/th.d.ts.map +1 -0
- package/dist/i18n/tr.d.ts +3 -0
- package/dist/i18n/tr.d.ts.map +1 -0
- package/dist/i18n/types.d.ts +44 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/uk.d.ts +3 -0
- package/dist/i18n/uk.d.ts.map +1 -0
- package/dist/i18n/ur.d.ts +3 -0
- package/dist/i18n/ur.d.ts.map +1 -0
- package/dist/i18n/vi.d.ts +3 -0
- package/dist/i18n/vi.d.ts.map +1 -0
- package/dist/i18n/zh.d.ts +3 -0
- package/dist/i18n/zh.d.ts.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/integrity.json +9 -0
- package/dist/integrity.txt +12 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/panel/drag.d.ts +34 -0
- package/dist/panel/drag.d.ts.map +1 -0
- package/dist/panel/panel.d.ts +23 -0
- package/dist/panel/panel.d.ts.map +1 -0
- package/dist/state.d.ts +18 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/styles/critical.d.ts +16 -0
- package/dist/styles/critical.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/locale.d.ts +11 -0
- package/dist/types/locale.d.ts.map +1 -0
- package/dist/types/widget.d.ts +207 -0
- package/dist/types/widget.d.ts.map +1 -0
- package/dist/util/debug.d.ts +8 -0
- package/dist/util/debug.d.ts.map +1 -0
- package/dist/util/dom.d.ts +19 -0
- package/dist/util/dom.d.ts.map +1 -0
- package/dist/util/events.d.ts +38 -0
- package/dist/util/events.d.ts.map +1 -0
- package/dist/util/feature-icons.d.ts +33 -0
- package/dist/util/feature-icons.d.ts.map +1 -0
- package/dist/util/language-names.d.ts +12 -0
- package/dist/util/language-names.d.ts.map +1 -0
- package/dist/util/svg.d.ts +38 -0
- package/dist/util/svg.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/config.ts +213 -0
- package/src/core.ts +173 -0
- package/src/features/apply.ts +37 -0
- package/src/features/profile.ts +18 -0
- package/src/features/reading-guide.ts +25 -0
- package/src/features/reading-mask.ts +25 -0
- package/src/features/structure-nav.ts +43 -0
- package/src/features/tts.ts +73 -0
- package/src/focus-trap.ts +35 -0
- package/src/globals.d.ts +63 -0
- package/src/i18n/ar.ts +48 -0
- package/src/i18n/bn.ts +48 -0
- package/src/i18n/cs.ts +48 -0
- package/src/i18n/de.ts +65 -0
- package/src/i18n/el.ts +48 -0
- package/src/i18n/en.ts +65 -0
- package/src/i18n/es.ts +48 -0
- package/src/i18n/fa.ts +48 -0
- package/src/i18n/fr.ts +48 -0
- package/src/i18n/he.ts +48 -0
- package/src/i18n/hi.ts +48 -0
- package/src/i18n/hu.ts +48 -0
- package/src/i18n/id.ts +48 -0
- package/src/i18n/index.ts +70 -0
- package/src/i18n/it.ts +48 -0
- package/src/i18n/ja.ts +48 -0
- package/src/i18n/ko.ts +48 -0
- package/src/i18n/nl.ts +48 -0
- package/src/i18n/pl.ts +48 -0
- package/src/i18n/pt.ts +48 -0
- package/src/i18n/ro.ts +48 -0
- package/src/i18n/ru.ts +48 -0
- package/src/i18n/sv.ts +48 -0
- package/src/i18n/th.ts +48 -0
- package/src/i18n/tr.ts +48 -0
- package/src/i18n/types.ts +36 -0
- package/src/i18n/uk.ts +48 -0
- package/src/i18n/ur.ts +48 -0
- package/src/i18n/vi.ts +48 -0
- package/src/i18n/zh.ts +48 -0
- package/src/index.ts +9 -0
- package/src/loader.ts +533 -0
- package/src/panel/drag.ts +210 -0
- package/src/panel/panel.ts +617 -0
- package/src/state.ts +91 -0
- package/src/styles/critical.ts +56 -0
- package/src/styles/widget.css +739 -0
- package/src/types/index.ts +2 -0
- package/src/types/locale.ts +55 -0
- package/src/types/widget.ts +300 -0
- package/src/util/debug.ts +12 -0
- package/src/util/dom.ts +68 -0
- package/src/util/events.ts +54 -0
- package/src/util/feature-icons.ts +163 -0
- package/src/util/language-names.ts +41 -0
- package/src/util/svg.ts +93 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panel drag-to-move — pointer-events based, with pointer capture so the drag
|
|
3
|
+
* survives the cursor leaving the panel. Position is persisted per device via
|
|
4
|
+
* a dedicated localStorage key, intentionally separate from WidgetState so the
|
|
5
|
+
* loader does not touch it before first paint.
|
|
6
|
+
*
|
|
7
|
+
* Keyboard users get an equivalent shortcut (Ctrl+Shift+Arrow) — a draggable
|
|
8
|
+
* accessibility widget with no keyboard path would be self-defeating.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { warnIfDebug } from '../util/debug.js';
|
|
12
|
+
|
|
13
|
+
export interface PanelPosition {
|
|
14
|
+
/** Left offset in pixels from the viewport edge. */
|
|
15
|
+
x: number;
|
|
16
|
+
/** Top offset in pixels from the viewport edge. */
|
|
17
|
+
y: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const KEYBOARD_STEP = 20;
|
|
21
|
+
const EDGE_MARGIN = 8;
|
|
22
|
+
|
|
23
|
+
export interface DraggableOptions {
|
|
24
|
+
root: HTMLElement;
|
|
25
|
+
handle: HTMLElement;
|
|
26
|
+
storageKey: string;
|
|
27
|
+
/** Called with null when the user resets, otherwise with the new position. */
|
|
28
|
+
onChange?: (pos: PanelPosition | null) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DraggableHandle {
|
|
32
|
+
/** Re-apply the saved position (call after rerender). */
|
|
33
|
+
restore(): void;
|
|
34
|
+
/** Remove listeners. */
|
|
35
|
+
destroy(): void;
|
|
36
|
+
/** Clear saved position. */
|
|
37
|
+
reset(): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function loadPanelPosition(storageKey: string): PanelPosition | null {
|
|
41
|
+
try {
|
|
42
|
+
const raw = localStorage.getItem(positionKey(storageKey));
|
|
43
|
+
if (!raw) return null;
|
|
44
|
+
const parsed = JSON.parse(raw) as Partial<PanelPosition>;
|
|
45
|
+
if (typeof parsed.x !== 'number' || typeof parsed.y !== 'number') return null;
|
|
46
|
+
return { x: parsed.x, y: parsed.y };
|
|
47
|
+
} catch (err) {
|
|
48
|
+
warnIfDebug('loadPanelPosition failed', err);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function savePanelPosition(storageKey: string, pos: PanelPosition | null): void {
|
|
54
|
+
try {
|
|
55
|
+
if (pos === null) localStorage.removeItem(positionKey(storageKey));
|
|
56
|
+
else localStorage.setItem(positionKey(storageKey), JSON.stringify(pos));
|
|
57
|
+
} catch (err) {
|
|
58
|
+
warnIfDebug('savePanelPosition failed', err);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function positionKey(storageKey: string): string {
|
|
63
|
+
return `${storageKey}-pos`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function makeDraggable(opts: DraggableOptions): DraggableHandle {
|
|
67
|
+
const { root, handle, storageKey, onChange } = opts;
|
|
68
|
+
|
|
69
|
+
let current: PanelPosition | null = loadPanelPosition(storageKey);
|
|
70
|
+
applyPosition(root, current);
|
|
71
|
+
|
|
72
|
+
// --- Pointer drag --------------------------------------------------------
|
|
73
|
+
let dragging = false;
|
|
74
|
+
let startX = 0;
|
|
75
|
+
let startY = 0;
|
|
76
|
+
let startLeft = 0;
|
|
77
|
+
let startTop = 0;
|
|
78
|
+
let pointerId = -1;
|
|
79
|
+
|
|
80
|
+
function onPointerDown(ev: PointerEvent): void {
|
|
81
|
+
// Only primary button / primary touch.
|
|
82
|
+
if (ev.button !== 0 && ev.pointerType === 'mouse') return;
|
|
83
|
+
// Don't steal clicks from interactive controls within the handle.
|
|
84
|
+
const target = ev.target as Element | null;
|
|
85
|
+
if (
|
|
86
|
+
target &&
|
|
87
|
+
target.closest('button, a, input, select, [role="button"]') &&
|
|
88
|
+
target !== handle
|
|
89
|
+
) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const rect = root.getBoundingClientRect();
|
|
93
|
+
dragging = true;
|
|
94
|
+
pointerId = ev.pointerId;
|
|
95
|
+
startX = ev.clientX;
|
|
96
|
+
startY = ev.clientY;
|
|
97
|
+
startLeft = rect.left;
|
|
98
|
+
startTop = rect.top;
|
|
99
|
+
handle.setPointerCapture(pointerId);
|
|
100
|
+
handle.classList.add('is-dragging');
|
|
101
|
+
ev.preventDefault();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function onPointerMove(ev: PointerEvent): void {
|
|
105
|
+
if (!dragging || ev.pointerId !== pointerId) return;
|
|
106
|
+
const dx = ev.clientX - startX;
|
|
107
|
+
const dy = ev.clientY - startY;
|
|
108
|
+
const next = clampToViewport({ x: startLeft + dx, y: startTop + dy }, root);
|
|
109
|
+
current = next;
|
|
110
|
+
applyPosition(root, next);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function onPointerUp(ev: PointerEvent): void {
|
|
114
|
+
if (!dragging || ev.pointerId !== pointerId) return;
|
|
115
|
+
dragging = false;
|
|
116
|
+
if (handle.hasPointerCapture(pointerId)) handle.releasePointerCapture(pointerId);
|
|
117
|
+
handle.classList.remove('is-dragging');
|
|
118
|
+
pointerId = -1;
|
|
119
|
+
if (current) {
|
|
120
|
+
savePanelPosition(storageKey, current);
|
|
121
|
+
onChange?.(current);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
handle.addEventListener('pointerdown', onPointerDown);
|
|
126
|
+
handle.addEventListener('pointermove', onPointerMove);
|
|
127
|
+
handle.addEventListener('pointerup', onPointerUp);
|
|
128
|
+
handle.addEventListener('pointercancel', onPointerUp);
|
|
129
|
+
|
|
130
|
+
// --- Keyboard fallback ---------------------------------------------------
|
|
131
|
+
function onKey(ev: KeyboardEvent): void {
|
|
132
|
+
if (!ev.ctrlKey || !ev.shiftKey) return;
|
|
133
|
+
const rect = root.getBoundingClientRect();
|
|
134
|
+
let { left, top } = rect;
|
|
135
|
+
let moved = false;
|
|
136
|
+
switch (ev.key) {
|
|
137
|
+
case 'ArrowLeft':
|
|
138
|
+
left -= KEYBOARD_STEP;
|
|
139
|
+
moved = true;
|
|
140
|
+
break;
|
|
141
|
+
case 'ArrowRight':
|
|
142
|
+
left += KEYBOARD_STEP;
|
|
143
|
+
moved = true;
|
|
144
|
+
break;
|
|
145
|
+
case 'ArrowUp':
|
|
146
|
+
top -= KEYBOARD_STEP;
|
|
147
|
+
moved = true;
|
|
148
|
+
break;
|
|
149
|
+
case 'ArrowDown':
|
|
150
|
+
top += KEYBOARD_STEP;
|
|
151
|
+
moved = true;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
if (!moved) return;
|
|
155
|
+
ev.preventDefault();
|
|
156
|
+
const next = clampToViewport({ x: left, y: top }, root);
|
|
157
|
+
current = next;
|
|
158
|
+
applyPosition(root, next);
|
|
159
|
+
savePanelPosition(storageKey, next);
|
|
160
|
+
onChange?.(next);
|
|
161
|
+
}
|
|
162
|
+
root.addEventListener('keydown', onKey);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
restore: () => applyPosition(root, current),
|
|
166
|
+
reset: () => {
|
|
167
|
+
current = null;
|
|
168
|
+
savePanelPosition(storageKey, null);
|
|
169
|
+
clearPosition(root);
|
|
170
|
+
onChange?.(null);
|
|
171
|
+
},
|
|
172
|
+
destroy: () => {
|
|
173
|
+
handle.removeEventListener('pointerdown', onPointerDown);
|
|
174
|
+
handle.removeEventListener('pointermove', onPointerMove);
|
|
175
|
+
handle.removeEventListener('pointerup', onPointerUp);
|
|
176
|
+
handle.removeEventListener('pointercancel', onPointerUp);
|
|
177
|
+
root.removeEventListener('keydown', onKey);
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function applyPosition(root: HTMLElement, pos: PanelPosition | null): void {
|
|
183
|
+
if (!pos) {
|
|
184
|
+
clearPosition(root);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
root.style.left = `${pos.x}px`;
|
|
188
|
+
root.style.top = `${pos.y}px`;
|
|
189
|
+
root.style.right = 'auto';
|
|
190
|
+
root.style.bottom = 'auto';
|
|
191
|
+
root.setAttribute('data-aw-moved', '1');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function clearPosition(root: HTMLElement): void {
|
|
195
|
+
root.style.left = '';
|
|
196
|
+
root.style.top = '';
|
|
197
|
+
root.style.right = '';
|
|
198
|
+
root.style.bottom = '';
|
|
199
|
+
root.removeAttribute('data-aw-moved');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function clampToViewport(pos: PanelPosition, root: HTMLElement): PanelPosition {
|
|
203
|
+
const rect = root.getBoundingClientRect();
|
|
204
|
+
const maxX = window.innerWidth - rect.width - EDGE_MARGIN;
|
|
205
|
+
const maxY = window.innerHeight - rect.height - EDGE_MARGIN;
|
|
206
|
+
return {
|
|
207
|
+
x: Math.max(EDGE_MARGIN, Math.min(pos.x, Math.max(EDGE_MARGIN, maxX))),
|
|
208
|
+
y: Math.max(EDGE_MARGIN, Math.min(pos.y, Math.max(EDGE_MARGIN, maxY))),
|
|
209
|
+
};
|
|
210
|
+
}
|