@pie-players/pie-tool-tts-inline 0.3.74 → 1.0.0-beta.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 CHANGED
@@ -15,7 +15,7 @@ focuses on the inline custom element API.
15
15
  - Play/pause trigger that opens the expanded panel when reading starts
16
16
  - Expanded controls: configurable Speed options, Rewind, Fast-forward, Stop
17
17
  - Play button switches to Pause while reading
18
- - Panel remains open while reading and closes on Stop
18
+ - Panel stays open while reading and after a read ends on its own; it closes on Stop or when the host calls `TTSService.stop()`
19
19
  - Arrow-key navigation within the controls toolbar
20
20
  - Takes its services from the toolkit runtime context and its reading scope from the enclosing item or passage shell
21
21
  - Integrates with `TTSService` for QTI 3.0 catalog-based TTS
@@ -31,13 +31,14 @@ bun add @pie-players/pie-tool-tts-inline
31
31
 
32
32
  ## Usage
33
33
 
34
- The element renders inside `<pie-item-shell>` or `<pie-passage-shell>` under
35
- `<pie-assessment-toolkit>`. The toolkit runtime context supplies the TTS
36
- service, the highlight coordinator and the toolkit coordinator, and the shell
37
- supplies the content to read; section players provide both. The packaged
34
+ The element renders inside `<pie-item-scope>` or `<pie-passage-shell>` under
35
+ `<pie-assessment-toolkit>`. The toolkit runtime context supplies the TTS service,
36
+ the highlight coordinator and the toolkit coordinator, and the shell supplies the
37
+ content to read. Section players provide both; around a plain item player, the
38
+ host writes the toolkit and the scope. The packaged
38
39
  `textToSpeech` capability in `@pie-players/pie-default-tool-loaders` creates
39
- this element in item and passage toolbars, takes `catalog-id`, `language` and
40
- `size` from the toolbar, and takes `layout-mode`, `speedOptions` and
40
+ this element in item and passage toolbars, takes `catalog-id` and `size` from
41
+ the toolbar, and takes `layout-mode`, `speedOptions` and
41
42
  `showSingleSpeedOption` from the toolkit's `textToSpeech` tool configuration.
42
43
 
43
44
  ```javascript
@@ -73,9 +74,8 @@ passageHeader.append(ttsButton);
73
74
  ### HTML Attributes
74
75
 
75
76
  - `catalog-id` - QTI 3.0 accessibility catalog ID for SSML lookup (default: `''`)
76
- - `language` - Language code for TTS (default: `'en-US'`)
77
77
  - `size` - Icon size: `'sm'` (1.5rem), `'md'` (2rem), or `'lg'` (2.5rem) (default: `'md'`)
78
- - `layout-mode` - Panel placement (default: `'expanding-row'`). `'reserved-row'`
78
+ - `layout-mode` - Panel placement (default: `'left-aligned'`). `'reserved-row'`
79
79
  and `'expanding-row'` drop the panel below the trigger; in the packaged toolbar
80
80
  the first keeps the controls row reserved and the second expands it while the
81
81
  panel is open. `'floating-overlay'` and `'left-aligned'` open the panel as an
@@ -132,21 +132,20 @@ Semantics:
132
132
 
133
133
  ## Behavior
134
134
 
135
- 1. **Services**: Reads `ttsService`, `highlightCoordinator` and `toolkitCoordinator` from the toolkit runtime context; the controls stay disabled until a `ttsService` arrives, and starting playback awaits `toolkitCoordinator.ensureTTSReady()`
136
- 2. **Text Extraction**: Reads the `textContent` of the scope element (the region scope, else the shell scope) when it is `[data-region='content']`, else of its first `[data-region='content']` descendant, else of the scope element itself
137
- 3. **TTS Trigger**: Calls `ttsService.speak(text, { catalogId, catalogContext, language, contentElement })`, where `contentElement` is that reading target and `catalogContext` names the owning item or passage
135
+ 1. **Services**: Reads `ttsService`, `highlightCoordinator` and `toolkitCoordinator` from the toolkit runtime context; the controls stay disabled until a `ttsService` arrives. A read started before the service is ready waits on the service's readiness gate, and a failure there announces that text-to-speech could not initialize
136
+ 2. **Text Extraction**: Reads the text of the scope element's content region (the region scope, else the shell scope, when it is `[data-region='content']`, else its first `[data-region='content']` descendant, else the scope element itself), including text rendered into open shadow roots
137
+ 3. **TTS Trigger**: Calls `ttsService.speak(readingTarget, { ownerId, rate, catalogId, catalogContext, language })`, where `ownerId` names this instance, `rate` is the selected speed, `catalogContext` names the owning item or passage and `language` is the toolkit's `content-language`. The service decides whether anything is speakable, cards included; a read that settles without playing closes the panel and announces that there is nothing to read. `speak` resolves the read's language from it as [TTS language](../../docs/architecture/internationalization.md#tts-language) sets out
138
138
  4. **Catalog Resolution**: TTSService checks for SSML in accessibility catalogs (priority order):
139
139
  - **Extracted catalogs** (from embedded SSML) - generated before render by hosts that run `SSMLExtractor`
140
140
  - **Item-level catalogs** (manually authored)
141
141
  - **Assessment-level catalogs** (manually authored)
142
- - **Plain text fallback** (browser TTS)
142
+ - **Generated speech** - MathML speech, else the visible text, on any backend
143
143
  5. **Expanded Controls**:
144
144
  - The trigger starts, pauses and resumes reading; starting opens the panel
145
- - Starting one instance stops playback another instance owns and closes that instance's panel
145
+ - The instance owns the service's run its read started (`getRunOwner()`); a read started by anything else, another instance or a selection read, closes its panel
146
146
  - Stop halts playback and closes the panel
147
147
  - Fast-forward/Rewind call `seekForward(1)` / `seekBackward(1)` on the TTS service, one sentence per press, and are enabled only while reading
148
- - Speed buttons call `ttsService.setPlaybackRate(rate)` when available,
149
- otherwise `ttsService.updateSettings({ rate })`
148
+ - Speed buttons call `ttsService.setPlaybackRate(rate)`
150
149
  - Speed choices render as a named `Playback speed` radio group with
151
150
  `aria-checked` state
152
151
  - Selecting another speed switches the active radio to that option
@@ -155,7 +154,7 @@ Semantics:
155
154
  reset to `1x` while rewind/forward/stop still render
156
155
  6. **Keyboard Interaction**: Arrow keys, Home and End move focus within one cluster, either the speed radio group or the Rewind/Fast-forward/Stop buttons, and skip disabled controls; arrowing onto a speed also selects it. Every control is a Tab stop except the speed radios, which share one Tab stop on the checked option
157
156
  7. **Active State**: Opening or closing the panel dispatches a bubbling, composed `pie-tool-active-change` event with `{ active }` and mirrors the state in the host's `data-active` attribute
158
- 8. **Cleanup**: Releases playback ownership and clears its highlight target resolver provider on unmount
157
+ 8. **Cleanup**: Clears its highlight target resolver provider on unmount
159
158
 
160
159
  ## SSML Extraction Integration
161
160
 
@@ -180,7 +179,7 @@ when a host/import pipeline runs `SSMLExtractor` before render:
180
179
  **Tool uses extracted catalog:**
181
180
 
182
181
  - User clicks TTS button in header
183
- - Tool calls `ttsService.speak(text, { catalogId: 'auto-prompt-q1-0' })`
182
+ - Tool calls `ttsService.speak(readingTarget, { catalogId: 'auto-prompt-q1-0' })`
184
183
  - TTSService finds SSML in extracted catalogs
185
184
  - Speaks with proper math pronunciation and pacing
186
185
 
@@ -205,10 +204,12 @@ component-scoped variables instead of overriding broad semantic tokens such as
205
204
  --pie-tool-trigger-active-border-color: Active/open trigger border
206
205
  ```
207
206
 
207
+ These three are registered `component-public` tokens.
208
+
208
209
  If unset, the trigger looks the same open as closed: each hook falls back to the
209
210
  value the control already resolves to — background through
210
211
  `--pie-button-background-color` / `--pie-button-bg` / `--pie-background`, border
211
- through `--pie-button-border-color` / `--pie-button-border` / `--pie-border`, and
212
+ through `--pie-button-border` / `--pie-border`, and
212
213
  foreground through `--pie-button-color` / `--pie-text`. Setting a hook is how a
213
214
  host opts into a distinct active/open appearance.
214
215
 
@@ -219,9 +220,9 @@ indication — so these defaults do not introduce one. Hosts remain responsible
219
220
  maintaining WCAG AA foreground/background contrast when overriding active trigger
220
221
  colors.
221
222
 
222
- ### Overlay panel colours
223
+ ### Overlay panel colors
223
224
 
224
- The floating and left-aligned panels take their colour from the active theme.
225
+ The floating and left-aligned panels take their color from the active theme.
225
226
  Each surface resolves a component-scoped hook first, then a canonical token,
226
227
  then a literal that only applies when no theme is loaded:
227
228
 
@@ -232,7 +233,7 @@ then a literal that only applies when no theme is loaded:
232
233
  --pie-selected-button-background /* selected speed chip → --pie-button-active-bg */
233
234
  --pie-selected-button-border /* selected speed chip border → --pie-button-border */
234
235
  --pie-tts-menu-shadow /* card elevation */
235
- --pie-tts-card-border /* card hairline; `transparent` for shadow-only */
236
+ --pie-tts-card-border /* card hairline */
236
237
  ```
237
238
 
238
239
  None of the seven is a registered host token. Each is read as
@@ -242,27 +243,21 @@ carries no compatibility guarantee — the panel's internals may move it.
242
243
  The card carries a hairline mixed from `--pie-text` because its shadow is black
243
244
  and disappears once the surface goes dark. It is deliberately not derived from
244
245
  `--pie-border`: a host that wants borderless controls sets that to transparent,
245
- which is the case where the shadow is the only edge. Set
246
- `--pie-tts-card-border: transparent` for the shadow-only card.
246
+ which is the case where the shadow is the only edge.
247
247
 
248
248
  A host that sets `--pie-button-border: transparent` also flattens the selected
249
- speed chip, which defaults through it — set `--pie-selected-button-border` to
250
- keep the chip outlined.
249
+ speed chip, which defaults through it.
251
250
 
252
251
  Foregrounds default through `--pie-button-color` (DaisyUI `base-content`) rather
253
252
  than `--pie-primary` or `--pie-tertiary`: those are direct mappings of DaisyUI
254
- slots chosen to pair with their own `-content` colour, so an accent glyph taken
253
+ slots chosen to pair with their own `-content` color, so an accent glyph taken
255
254
  from either falls under 3:1 against the card in 11 of the 35 shipped themes.
256
- Selection reads from the chip fill and the bolder weight instead of from hue. A
257
- host that wants a branded accent sets `--pie-tts-button-color` and owns the
258
- contrast, as with the active-trigger hooks above.
255
+ Selection reads from the chip fill and the bolder weight instead of from hue.
259
256
 
260
- Ordinary trigger and control button styling also preserves these legacy aliases:
261
- `--pie-button-background-color`, `--pie-button-border-color`, and
262
- `--pie-button-hover-background-color`. They remain supported for host
263
- compatibility, but fall back through the canonical `--pie-button-bg`,
264
- `--pie-button-border`, and `--pie-button-hover-bg` tokens before broad surface
265
- tokens.
257
+ Trigger and control backgrounds read `--pie-button-background-color` ahead of
258
+ the canonical `--pie-button-bg`; borders and hover backgrounds read
259
+ `--pie-button-border` and `--pie-button-hover-bg`. Each falls back to the broad
260
+ surface tokens.
266
261
 
267
262
  ## Architecture
268
263
 
@@ -275,10 +270,6 @@ This tool follows the PIE Assessment Toolkit tool pattern:
275
270
  - Panel state is announced with `pie-tool-active-change`, which the packaged
276
271
  toolbar registration subscribes to
277
272
 
278
- ## Example
279
-
280
- See active demos in `apps/section-demos`.
281
-
282
273
  ## License
283
274
 
284
275
  MIT
@@ -0,0 +1,144 @@
1
+ {
2
+ "schemaVersion": "2.1.0",
3
+ "modules": [
4
+ {
5
+ "kind": "javascript-module",
6
+ "path": "dist/tool-tts-inline.js",
7
+ "declarations": [
8
+ {
9
+ "kind": "class",
10
+ "description": "Read-aloud trigger for an item or passage header inside `<pie-item-scope>` or `<pie-passage-shell>`: play/pause opens a panel of speed, rewind, fast-forward and stop controls. It reads the shell's content region through the TTS service in the toolkit runtime context, passing `catalog-id` so the service can speak authored SSML from the accessibility catalogs. Its controls stay disabled until the runtime context supplies a TTS service.",
11
+ "name": "ToolTtsInline",
12
+ "tagName": "pie-tool-tts-inline",
13
+ "customElement": true,
14
+ "members": [
15
+ {
16
+ "kind": "field",
17
+ "name": "catalogId",
18
+ "type": {
19
+ "text": "string"
20
+ },
21
+ "default": "''",
22
+ "attribute": "catalog-id"
23
+ },
24
+ {
25
+ "kind": "field",
26
+ "name": "size",
27
+ "type": {
28
+ "text": "'sm' | 'md' | 'lg'"
29
+ },
30
+ "default": "'md'",
31
+ "attribute": "size"
32
+ },
33
+ {
34
+ "kind": "field",
35
+ "name": "speedOptions",
36
+ "type": {
37
+ "text": "TTSSpeedOption[]"
38
+ },
39
+ "attribute": "speed-options"
40
+ },
41
+ {
42
+ "kind": "field",
43
+ "name": "showSingleSpeedOption",
44
+ "type": {
45
+ "text": "boolean"
46
+ },
47
+ "default": "false",
48
+ "attribute": "show-single-speed-option"
49
+ },
50
+ {
51
+ "kind": "field",
52
+ "name": "layoutMode",
53
+ "type": {
54
+ "text": "TTSLayoutMode"
55
+ },
56
+ "default": "'left-aligned'",
57
+ "attribute": "layout-mode"
58
+ }
59
+ ],
60
+ "attributes": [
61
+ {
62
+ "name": "catalog-id",
63
+ "type": {
64
+ "text": "string"
65
+ },
66
+ "default": "''",
67
+ "fieldName": "catalogId"
68
+ },
69
+ {
70
+ "name": "size",
71
+ "type": {
72
+ "text": "string"
73
+ },
74
+ "default": "'md'",
75
+ "fieldName": "size"
76
+ },
77
+ {
78
+ "name": "speed-options",
79
+ "type": {
80
+ "text": "TTSSpeedOption[]"
81
+ },
82
+ "fieldName": "speedOptions"
83
+ },
84
+ {
85
+ "name": "show-single-speed-option",
86
+ "type": {
87
+ "text": "boolean"
88
+ },
89
+ "default": "false",
90
+ "fieldName": "showSingleSpeedOption"
91
+ },
92
+ {
93
+ "name": "layout-mode",
94
+ "type": {
95
+ "text": "string"
96
+ },
97
+ "default": "'left-aligned'",
98
+ "fieldName": "layoutMode"
99
+ }
100
+ ],
101
+ "events": [
102
+ {
103
+ "name": "pie-tool-active-change",
104
+ "type": {
105
+ "text": "CustomEvent<{ active: boolean }>"
106
+ },
107
+ "description": "When its panel opens or closes."
108
+ }
109
+ ],
110
+ "cssProperties": [
111
+ {
112
+ "name": "--pie-button-background-color",
113
+ "description": "Compatibility alias retained for TTS inline button backgrounds; implementations must fall back through canonical --pie-button-bg before broad surface tokens."
114
+ },
115
+ {
116
+ "name": "--pie-tool-trigger-active-background",
117
+ "description": "Component trigger active/open background hook; falls back through existing semantic tokens and must preserve WCAG contrast when overridden by hosts."
118
+ },
119
+ {
120
+ "name": "--pie-tool-trigger-active-border-color",
121
+ "description": "Component trigger active/open border hook; falls back through existing semantic tokens."
122
+ },
123
+ {
124
+ "name": "--pie-tool-trigger-active-color",
125
+ "description": "Component trigger active/open foreground hook; hosts are responsible for preserving contrast with the active trigger background."
126
+ }
127
+ ],
128
+ "x-pie": {
129
+ "shadow": "open"
130
+ }
131
+ }
132
+ ],
133
+ "exports": [
134
+ {
135
+ "kind": "custom-element-definition",
136
+ "name": "pie-tool-tts-inline",
137
+ "declaration": {
138
+ "name": "ToolTtsInline"
139
+ }
140
+ }
141
+ ]
142
+ }
143
+ ]
144
+ }