@pie-players/pie-tool-annotation-toolbar 0.1.1
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 +147 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/tool-annotation-toolbar.js +2638 -0
- package/dist/tool-annotation-toolbar.js.map +1 -0
- package/index.ts +8 -0
- package/package.json +63 -0
- package/tool-annotation-toolbar.svelte +129 -0
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Annotation Toolbar
|
|
2
|
+
|
|
3
|
+
A text selection toolbar for highlighting and annotating text in the PIEoneer assessment player. Uses modern CSS Custom Highlight API for zero DOM mutation and optimal performance.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **4-Color Highlighting**: Yellow, pink, blue, and green highlight swatches
|
|
8
|
+
- **Underline Annotation**: Underline selected text
|
|
9
|
+
- **Persistent Annotations**: Saved to sessionStorage and restored on page load
|
|
10
|
+
- **Clear Annotations**: Remove annotations from selected text or clear all
|
|
11
|
+
- **Dictionary Lookup**: Look up selected words in dictionary
|
|
12
|
+
- **Translation**: Translate selected text
|
|
13
|
+
- **Picture Dictionary**: Visual dictionary for selected words
|
|
14
|
+
- **Text-to-Speech (Read Aloud)**: Read selected text aloud with word-level highlighting
|
|
15
|
+
- **Modern CSS Custom Highlight API**:
|
|
16
|
+
- Zero DOM mutation (no `<span>` wrappers)
|
|
17
|
+
- 10-50x faster than traditional approaches
|
|
18
|
+
- 5-10x less memory usage
|
|
19
|
+
- Framework-compatible (works with React, Vue, Svelte)
|
|
20
|
+
- **Accessibility**:
|
|
21
|
+
- Full ARIA labels and screen reader support
|
|
22
|
+
- Keyboard navigation (Escape to close)
|
|
23
|
+
- Focus-visible outlines
|
|
24
|
+
- WCAG 2.2 compliant
|
|
25
|
+
- **Dark Mode**: Automatic adaptation to system color scheme
|
|
26
|
+
- **High Contrast Mode**: Enhanced visibility in high contrast settings
|
|
27
|
+
- **Responsive Design**: Optimized for mobile and desktop viewports
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```svelte
|
|
32
|
+
<script>
|
|
33
|
+
import ToolAnnotationToolbar from '$lib/tags/tool-annotation-toolbar/tool-annotation-toolbar.svelte';
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<!-- Toolbar appears automatically when text is selected -->
|
|
37
|
+
<ToolAnnotationToolbar />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Props
|
|
41
|
+
|
|
42
|
+
This component doesn't take props - it automatically shows when text is selected and hides when selection is cleared or Escape is pressed.
|
|
43
|
+
|
|
44
|
+
## Events
|
|
45
|
+
|
|
46
|
+
- `dictionarylookup`: Dispatched when dictionary button is clicked
|
|
47
|
+
- `detail: { text: string }` - The selected text
|
|
48
|
+
- `translationrequest`: Dispatched when translation button is clicked
|
|
49
|
+
- `detail: { text: string }` - The selected text
|
|
50
|
+
- `picturedictionarylookup`: Dispatched when picture dictionary button is clicked
|
|
51
|
+
- `detail: { text: string }` - The selected text
|
|
52
|
+
|
|
53
|
+
**Note**: Text-to-Speech (Read Aloud) button does not emit an event - it directly uses the TTS service to read the selected text.
|
|
54
|
+
|
|
55
|
+
## Architecture
|
|
56
|
+
|
|
57
|
+
The annotation toolbar integrates with PIE's shared highlight infrastructure:
|
|
58
|
+
|
|
59
|
+
- **HighlightCoordinator**: Singleton managing both TTS and annotation highlights
|
|
60
|
+
- **RangeSerializer**: Serializes/deserializes DOM ranges for persistence
|
|
61
|
+
- **CSS Custom Highlight API**: Modern browser API for non-invasive highlighting
|
|
62
|
+
|
|
63
|
+
### Browser Support
|
|
64
|
+
|
|
65
|
+
Requires CSS Custom Highlight API support:
|
|
66
|
+
- Chrome/Edge 105+
|
|
67
|
+
- Safari 17.2+
|
|
68
|
+
- Firefox 128+
|
|
69
|
+
|
|
70
|
+
For unsupported browsers, the component gracefully degrades (no highlights shown).
|
|
71
|
+
|
|
72
|
+
## Annotation Persistence
|
|
73
|
+
|
|
74
|
+
Annotations are automatically saved to `sessionStorage` and restored on page load. The storage key includes the current URL path to scope annotations to specific content.
|
|
75
|
+
|
|
76
|
+
Storage format:
|
|
77
|
+
```typescript
|
|
78
|
+
{
|
|
79
|
+
"annotation-highlight-yellow-1234567890": {
|
|
80
|
+
startContainer: ["body", "div", "p", "#text"],
|
|
81
|
+
startOffset: 10,
|
|
82
|
+
endContainer: ["body", "div", "p", "#text"],
|
|
83
|
+
endOffset: 20,
|
|
84
|
+
text: "highlighted text"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Annotations are automatically cleared when:
|
|
90
|
+
- User explicitly clicks "Clear" button
|
|
91
|
+
- User navigates to different content
|
|
92
|
+
- sessionStorage is cleared
|
|
93
|
+
|
|
94
|
+
## Text-to-Speech Integration
|
|
95
|
+
|
|
96
|
+
The annotation toolbar includes a "Read" button that uses the TTS service to read selected text aloud with word-level highlighting.
|
|
97
|
+
|
|
98
|
+
### How It Works
|
|
99
|
+
|
|
100
|
+
1. **User selects text** in the assessment content
|
|
101
|
+
2. **Annotation toolbar appears** with highlight, dictionary, translate, and read buttons
|
|
102
|
+
3. **User clicks "Read"** button (speaker icon)
|
|
103
|
+
4. **TTS service speaks the selected text** using Web Speech API
|
|
104
|
+
5. **Words are highlighted** in sync with speech using CSS Custom Highlight API
|
|
105
|
+
|
|
106
|
+
### Technical Implementation
|
|
107
|
+
|
|
108
|
+
The toolbar uses `ttsService.speakRange()` instead of `ttsService.speak()` to ensure accurate word highlighting:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// speakRange() calculates text offset for accurate highlighting
|
|
112
|
+
await ttsService.speakRange(selectedRange, {
|
|
113
|
+
rate: 1.0,
|
|
114
|
+
highlightWords: true
|
|
115
|
+
}, {
|
|
116
|
+
onEnd: () => ttsSpeaking = false,
|
|
117
|
+
onError: (err) => ttsSpeaking = false
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Why this matters:**
|
|
122
|
+
- User selects text in the middle of a paragraph
|
|
123
|
+
- `speak(text)` would highlight from the beginning of the container (wrong)
|
|
124
|
+
- `speakRange(range)` highlights the exact selected text (correct)
|
|
125
|
+
|
|
126
|
+
### UX Details
|
|
127
|
+
|
|
128
|
+
- **Read button is disabled** while TTS is speaking
|
|
129
|
+
- **Active state** shown with visual feedback
|
|
130
|
+
- **TTS stops automatically** when toolbar is hidden (user clicks away)
|
|
131
|
+
- **No conflicts** with annotation highlights (different highlight layers)
|
|
132
|
+
|
|
133
|
+
### Browser Support
|
|
134
|
+
|
|
135
|
+
- **TTS (Web Speech API)**: 97%+ browser support
|
|
136
|
+
- **Word Highlighting**: 85-90% browser support (CSS Custom Highlight API)
|
|
137
|
+
- **Graceful degradation**: TTS works without highlighting in older browsers
|
|
138
|
+
|
|
139
|
+
## Based On
|
|
140
|
+
|
|
141
|
+
This implementation is inspired by production annotation toolbar patterns but uses modern 2025 web standards:
|
|
142
|
+
|
|
143
|
+
- CSS Custom Highlight API instead of DOM mutation
|
|
144
|
+
- Svelte 5 patterns and best practices
|
|
145
|
+
- Modern accessibility (WCAG 2.2)
|
|
146
|
+
- Dark mode and high contrast support
|
|
147
|
+
- Responsive design for mobile devices
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|