@pie-players/pie-assessment-toolkit 0.3.53 → 0.3.55
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 +12 -5
- package/dist/components/ItemToolBar.custom-element.js +97 -55
- package/dist/components/PieAssessmentToolkit.custom-element.js +58 -52
- package/dist/components/SectionToolBar.custom-element.js +97 -55
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/ToolRegistry.d.ts +11 -0
- package/dist/services/ToolRegistry.js.map +1 -1
- package/dist/services/tts-runtime-config.d.ts +8 -1
- package/dist/services/tts-runtime-config.js +87 -18
- package/dist/services/tts-runtime-config.js.map +1 -1
- package/dist/tools/registrations/calculator.js +4 -0
- package/dist/tools/registrations/calculator.js.map +1 -1
- package/dist/tools/registrations/tts.js +7 -3
- package/dist/tools/registrations/tts.js.map +1 -1
- package/package.json +7 -7
|
@@ -12,8 +12,13 @@ export const normalizeTTSLayoutMode = (value, fallback = "left-aligned") => type
|
|
|
12
12
|
VALID_TTS_LAYOUT_MODES.has(value)
|
|
13
13
|
? value
|
|
14
14
|
: fallback;
|
|
15
|
-
/**
|
|
15
|
+
/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */
|
|
16
16
|
export const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);
|
|
17
|
+
const DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([
|
|
18
|
+
{ rate: 0.8, label: "Slow", ariaLabel: "Slow speed" },
|
|
19
|
+
{ rate: 1, label: "Normal", ariaLabel: "Normal speed", default: true },
|
|
20
|
+
{ rate: 1.25, label: "Fast", ariaLabel: "Fast speed" },
|
|
21
|
+
]);
|
|
17
22
|
const normalizeSpeedRate = (entry) => {
|
|
18
23
|
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
19
24
|
return undefined;
|
|
@@ -21,6 +26,12 @@ const normalizeSpeedRate = (entry) => {
|
|
|
21
26
|
const rounded = Math.round(entry * 100) / 100;
|
|
22
27
|
return rounded === 1 ? undefined : rounded;
|
|
23
28
|
};
|
|
29
|
+
const normalizeControlSpeedRate = (entry) => {
|
|
30
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return Math.round(entry * 100) / 100;
|
|
34
|
+
};
|
|
24
35
|
const trimOptionalText = (value) => {
|
|
25
36
|
if (typeof value !== "string")
|
|
26
37
|
return undefined;
|
|
@@ -28,7 +39,11 @@ const trimOptionalText = (value) => {
|
|
|
28
39
|
return trimmed.length ? trimmed : undefined;
|
|
29
40
|
};
|
|
30
41
|
const formatSpeedLabel = (rate) => `${rate}x`;
|
|
31
|
-
const formatSpeedAriaLabel = (label, usedDefaultLabel) =>
|
|
42
|
+
const formatSpeedAriaLabel = (label, usedDefaultLabel) => label.toLowerCase() === "normal"
|
|
43
|
+
? "Normal speed"
|
|
44
|
+
: usedDefaultLabel
|
|
45
|
+
? `Speed ${label}`
|
|
46
|
+
: `${label} speed`;
|
|
32
47
|
const normalizeSpeedAriaLabel = (label, ariaLabel, usedDefaultLabel) => {
|
|
33
48
|
if (!ariaLabel)
|
|
34
49
|
return formatSpeedAriaLabel(label, usedDefaultLabel);
|
|
@@ -86,24 +101,69 @@ export const normalizeTTSSpeedOptions = (value) => {
|
|
|
86
101
|
return [];
|
|
87
102
|
return normalizeTTSSpeedOptionConfigs(value).map((option) => typeof option === "number" ? option : option.rate);
|
|
88
103
|
};
|
|
89
|
-
export const normalizeTTSSpeedControlOptions = (value) =>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
export const normalizeTTSSpeedControlOptions = (value) => {
|
|
105
|
+
const input = Array.isArray(value)
|
|
106
|
+
? value
|
|
107
|
+
: [...DEFAULT_TTS_SPEED_CONTROL_OPTIONS];
|
|
108
|
+
if (input.length === 0)
|
|
109
|
+
return [];
|
|
110
|
+
const dedupedRates = new Set();
|
|
111
|
+
const normalized = [];
|
|
112
|
+
for (const entry of input) {
|
|
113
|
+
const record = toRecord(entry);
|
|
114
|
+
const rate = typeof entry === "number"
|
|
115
|
+
? normalizeControlSpeedRate(entry)
|
|
116
|
+
: normalizeControlSpeedRate(record.rate);
|
|
117
|
+
if (rate === undefined || dedupedRates.has(rate))
|
|
118
|
+
continue;
|
|
119
|
+
dedupedRates.add(rate);
|
|
120
|
+
const defaultLabel = rate === 1 ? "Normal" : typeof entry === "number" ? formatSpeedLabel(rate) : formatSpeedLabel(rate);
|
|
121
|
+
const label = typeof entry === "number"
|
|
122
|
+
? defaultLabel
|
|
123
|
+
: trimOptionalText(record.label) || defaultLabel;
|
|
124
|
+
const ariaLabel = typeof entry === "number"
|
|
125
|
+
? rate === 1
|
|
126
|
+
? "Normal speed"
|
|
127
|
+
: formatSpeedAriaLabel(label, true)
|
|
128
|
+
: normalizeSpeedAriaLabel(label, trimOptionalText(record.ariaLabel), label === defaultLabel);
|
|
129
|
+
normalized.push({
|
|
130
|
+
rate,
|
|
94
131
|
label,
|
|
95
|
-
ariaLabel
|
|
132
|
+
ariaLabel,
|
|
133
|
+
isDefault: false,
|
|
134
|
+
requestedDefault: record.default === true || record.isDefault === true,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (!normalized.length) {
|
|
138
|
+
return normalizeTTSSpeedControlOptions(DEFAULT_TTS_SPEED_CONTROL_OPTIONS);
|
|
139
|
+
}
|
|
140
|
+
if (!dedupedRates.has(1)) {
|
|
141
|
+
const normalOption = {
|
|
142
|
+
rate: 1,
|
|
143
|
+
label: "Normal",
|
|
144
|
+
ariaLabel: "Normal speed",
|
|
145
|
+
isDefault: false,
|
|
146
|
+
requestedDefault: false,
|
|
96
147
|
};
|
|
148
|
+
const firstFasterIndex = normalized.findIndex((option) => option.rate > 1);
|
|
149
|
+
if (firstFasterIndex >= 0) {
|
|
150
|
+
normalized.splice(firstFasterIndex, 0, normalOption);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
normalized.push(normalOption);
|
|
154
|
+
}
|
|
97
155
|
}
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
156
|
+
const requestedDefaultIndex = normalized.findIndex((option) => option.requestedDefault);
|
|
157
|
+
const defaultIndex = requestedDefaultIndex >= 0
|
|
158
|
+
? requestedDefaultIndex
|
|
159
|
+
: normalized.findIndex((option) => option.rate === 1);
|
|
160
|
+
return normalized.map(({ requestedDefault: _requestedDefault, ...option }, index) => ({
|
|
161
|
+
...option,
|
|
162
|
+
isDefault: index === defaultIndex,
|
|
163
|
+
}));
|
|
164
|
+
};
|
|
106
165
|
export const formatTTSSpeedOptionsAsText = (values) => values.join(", ");
|
|
166
|
+
const DEFAULT_TTS_SPEED_CONTROL_RATES = Object.freeze([0.8, 1, 1.25]);
|
|
107
167
|
/**
|
|
108
168
|
* Parse comma/semicolon-separated multipliers from settings UI text.
|
|
109
169
|
* - Empty or whitespace-only string → hide speed buttons (`[]`).
|
|
@@ -121,8 +181,17 @@ export const parseTTSSpeedOptionsFromText = (text) => {
|
|
|
121
181
|
.map((p) => Number.parseFloat(p))
|
|
122
182
|
.filter((n) => Number.isFinite(n));
|
|
123
183
|
if (!candidates.length)
|
|
124
|
-
return [...
|
|
125
|
-
|
|
184
|
+
return [...DEFAULT_TTS_SPEED_CONTROL_RATES];
|
|
185
|
+
const dedupedRates = new Set();
|
|
186
|
+
const normalized = [];
|
|
187
|
+
for (const candidate of candidates) {
|
|
188
|
+
const rate = normalizeControlSpeedRate(candidate);
|
|
189
|
+
if (rate === undefined || dedupedRates.has(rate))
|
|
190
|
+
continue;
|
|
191
|
+
dedupedRates.add(rate);
|
|
192
|
+
normalized.push(rate);
|
|
193
|
+
}
|
|
194
|
+
return normalized.length ? normalized : [...DEFAULT_TTS_SPEED_CONTROL_RATES];
|
|
126
195
|
};
|
|
127
196
|
const applyRuntimeDefaults = (config) => {
|
|
128
197
|
const withLayoutDefaults = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tts-runtime-config.js","sourceRoot":"","sources":["../../src/services/tts-runtime-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TTSConfig } from \"./TTSService.js\";\nimport type { ToolProviderConfig } from \"./tools-config-normalizer.js\";\nimport {\n\tnormalizeSREMathSpeechOptions,\n\ttype SREMathSpeechOptions,\n} from \"./tts/math-speech.js\";\n\nexport type TTSLayoutMode =\n\t| \"reserved-row\"\n\t| \"expanding-row\"\n\t| \"floating-overlay\"\n\t| \"left-aligned\";\n\nconst VALID_TTS_LAYOUT_MODES = new Set<TTSLayoutMode>([\n\t\"reserved-row\",\n\t\"expanding-row\",\n\t\"floating-overlay\",\n\t\"left-aligned\",\n]);\n\nexport interface TTSHostToolbarLayout {\n\tmount: \"before-buttons\";\n\tcontrolsRow: {\n\t\treserveSpace: boolean;\n\t\texpandWhenToolActive: boolean;\n\t};\n}\n\nexport interface TTSSpeedOptionConfig {\n\trate: number;\n\tlabel?: string;\n\tariaLabel?: string;\n}\n\nexport type TTSSpeedOption = number | TTSSpeedOptionConfig;\n\nexport interface NormalizedTTSSpeedOption {\n\trate: number;\n\tlabel: string;\n\tariaLabel: string;\n}\n\nexport interface TTSRuntimeSettings {\n\tbackend?: \"browser\" | \"polly\" | \"google\" | \"server\";\n\tserverProvider?: \"polly\" | \"google\" | \"custom\";\n\tprovider?: \"polly\" | \"google\" | \"custom\";\n\tengine?: \"standard\" | \"neural\";\n\tsampleRate?: number;\n\tformat?: \"mp3\" | \"ogg\" | \"pcm\";\n\tspeechMarksMode?: \"word\" | \"word+sentence\";\n\tdefaultVoice?: string;\n\trate?: number;\n\tpitch?: number;\n\tapiEndpoint?: string;\n\tlanguage?: string;\n\ttransportMode?: \"pie\" | \"custom\";\n\tendpointMode?: \"synthesizePath\" | \"rootPost\";\n\tendpointValidationMode?: \"voices\" | \"endpoint\" | \"none\";\n\tincludeAuthOnAssetFetch?: boolean;\n\tvalidateEndpoint?: boolean;\n\tcache?: boolean;\n\tspeedRate?: \"slow\" | \"medium\" | \"fast\";\n\tlang_id?: string;\n\t/**\n\t * Optional inline TTS speed buttons.\n\t * - Omitted/non-array: default speed buttons are shown.\n\t * - Empty array: hide speed buttons.\n\t * - Arrays that sanitize to no valid values: default speed buttons are shown.\n\t * - Object entries can customize button text while preserving numeric rates.\n\t */\n\tspeedOptions?: TTSSpeedOption[];\n\tlayoutMode?: TTSLayoutMode;\n\t/**\n\t * Per-token highlighting of math expressions.\n\t * - `true` / omitted (default): when the spoken math aligns confidently to the\n\t * rendered MathML, the formula is highlighted glyph by glyph; otherwise it\n\t * safely falls back to a whole-formula block.\n\t * - `false`: every formula is highlighted as a single block (the fallback),\n\t * never broken into per-token highlights. Prose word tracking is unaffected.\n\t */\n\tmathTokenHighlighting?: boolean;\n\t/**\n\t * Speech Rule Engine options for generated MathML speech. Hosts can use these\n\t * to tune SRE itself (for example ClearSpeak ImpliedTimes/Paren preferences)\n\t * instead of relying on toolkit-specific speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n}\n\nconst toRecord = (value: unknown): Record<string, unknown> =>\n\tvalue && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\nconst isServerBackend = (\n\tbackend: TTSRuntimeSettings[\"backend\"],\n): backend is \"polly\" | \"google\" | \"server\" =>\n\tbackend === \"polly\" || backend === \"google\" || backend === \"server\";\n\nconst withDefault = <T>(value: T | undefined, fallback: T): T =>\n\tvalue === undefined ? fallback : value;\n\nexport const normalizeTTSLayoutMode = (\n\tvalue: unknown,\n\tfallback: TTSLayoutMode = \"left-aligned\",\n): TTSLayoutMode =>\n\ttypeof value === \"string\" &&\n\tVALID_TTS_LAYOUT_MODES.has(value as TTSLayoutMode)\n\t\t? (value as TTSLayoutMode)\n\t\t: fallback;\n\n/** Default inline TTS speed button multipliers (excluding 1.0×). */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\n\nconst normalizeSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\tconst rounded = Math.round(entry * 100) / 100;\n\treturn rounded === 1 ? undefined : rounded;\n};\n\nconst trimOptionalText = (value: unknown): string | undefined => {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed.length ? trimmed : undefined;\n};\n\nconst formatSpeedLabel = (rate: number): string => `${rate}x`;\n\nconst formatSpeedAriaLabel = (label: string, usedDefaultLabel: boolean): string =>\n\tusedDefaultLabel ? `Speed ${label}` : `${label} speed`;\n\nconst normalizeSpeedAriaLabel = (\n\tlabel: string,\n\tariaLabel: string | undefined,\n\tusedDefaultLabel: boolean,\n): string => {\n\tif (!ariaLabel) return formatSpeedAriaLabel(label, usedDefaultLabel);\n\tif (ariaLabel.toLowerCase().includes(label.toLowerCase())) return ariaLabel;\n\treturn `${label} ${ariaLabel}`;\n};\n\nconst normalizeTTSSpeedOptionConfig = (\n\tentry: unknown,\n): TTSSpeedOption | undefined => {\n\tif (typeof entry === \"number\") return normalizeSpeedRate(entry);\n\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\n\tconst record = entry as Record<string, unknown>;\n\tconst rate = normalizeSpeedRate(record.rate);\n\tif (rate === undefined) return undefined;\n\tconst label = trimOptionalText(record.label);\n\tconst ariaLabel = trimOptionalText(record.ariaLabel);\n\treturn {\n\t\trate,\n\t\t...(label ? { label } : {}),\n\t\t...(ariaLabel ? { ariaLabel } : {}),\n\t};\n};\n\nexport const normalizeTTSSpeedOptionConfigs = (\n\tvalue: unknown,\n): TTSSpeedOption[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: TTSSpeedOption[] = [];\n\tfor (const entry of value) {\n\t\tconst option = normalizeTTSSpeedOptionConfig(entry);\n\t\tif (option === undefined) continue;\n\t\tconst rate = typeof option === \"number\" ? option : option.rate;\n\t\tif (dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(option);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];\n};\n\n/**\n * Resolves inline toolbar speed options from host config.\n * - Omitted/non-array: default speed buttons.\n * - Empty array: hide speed buttons.\n * - Arrays that sanitize to no valid values: default speed buttons.\n * - 1.0× is never shown as a discrete speed button.\n */\nexport const normalizeTTSSpeedOptions = (value: unknown): number[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\treturn normalizeTTSSpeedOptionConfigs(value).map((option) =>\n\t\ttypeof option === \"number\" ? option : option.rate,\n\t);\n};\n\nexport const normalizeTTSSpeedControlOptions = (\n\tvalue: unknown,\n): NormalizedTTSSpeedOption[] =>\n\tnormalizeTTSSpeedOptionConfigs(value).map((option) => {\n\t\tif (typeof option === \"number\") {\n\t\t\tconst label = formatSpeedLabel(option);\n\t\t\treturn {\n\t\t\t\trate: option,\n\t\t\t\tlabel,\n\t\t\t\tariaLabel: formatSpeedAriaLabel(label, true),\n\t\t\t};\n\t\t}\n\t\tconst defaultLabel = formatSpeedLabel(option.rate);\n\t\tconst label = option.label || defaultLabel;\n\t\treturn {\n\t\t\trate: option.rate,\n\t\t\tlabel,\n\t\t\tariaLabel: normalizeSpeedAriaLabel(\n\t\t\t\tlabel,\n\t\t\t\toption.ariaLabel,\n\t\t\t\tlabel === defaultLabel,\n\t\t\t),\n\t\t};\n\t});\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\n\n/**\n * Parse comma/semicolon-separated multipliers from settings UI text.\n * - Empty or whitespace-only string → hide speed buttons (`[]`).\n * - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.\n */\nexport const parseTTSSpeedOptionsFromText = (text: string): number[] => {\n\tconst trimmed = text.trim();\n\tif (!trimmed) return [];\n\tconst parts = trimmed\n\t\t.split(/[,;]+/)\n\t\t.map((p) => p.trim())\n\t\t.filter(Boolean);\n\tconst candidates = parts\n\t\t.map((p) => Number.parseFloat(p))\n\t\t.filter((n) => Number.isFinite(n));\n\tif (!candidates.length) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\treturn normalizeTTSSpeedOptions(candidates);\n};\n\nconst applyRuntimeDefaults = (\n\tconfig: TTSRuntimeSettings,\n): TTSRuntimeSettings => {\n\tconst withLayoutDefaults: TTSRuntimeSettings = {\n\t\t...config,\n\t\tlayoutMode: normalizeTTSLayoutMode(config.layoutMode),\n\t};\n\tconst backend = config.backend || \"browser\";\n\tif (!isServerBackend(backend)) return withLayoutDefaults;\n\n\tconst withServerDefaults: TTSRuntimeSettings = {\n\t\t...withLayoutDefaults,\n\t\tapiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, \"/api/tts\"),\n\t\ttransportMode: withDefault(withLayoutDefaults.transportMode, \"pie\"),\n\t\tendpointValidationMode: withDefault(\n\t\t\twithLayoutDefaults.endpointValidationMode,\n\t\t\t\"voices\",\n\t\t),\n\t\tvalidateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),\n\t\tincludeAuthOnAssetFetch: withDefault(\n\t\t\twithLayoutDefaults.includeAuthOnAssetFetch,\n\t\t\tfalse,\n\t\t),\n\t\trate: withDefault(withLayoutDefaults.rate, 1.0),\n\t\tlanguage: withDefault(withLayoutDefaults.language, \"en-US\"),\n\t};\n\n\tif (backend === \"polly\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"Joanna\"),\n\t\t\tengine: withDefault(withServerDefaults.engine, \"neural\"),\n\t\t\tformat: withDefault(withServerDefaults.format, \"mp3\"),\n\t\t\tspeechMarksMode: withDefault(\n\t\t\t\twithServerDefaults.speechMarksMode,\n\t\t\t\t\"word+sentence\",\n\t\t\t),\n\t\t};\n\t}\n\n\tif (backend === \"google\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(\n\t\t\t\twithServerDefaults.defaultVoice,\n\t\t\t\t\"en-US-Wavenet-A\",\n\t\t\t),\n\t\t};\n\t}\n\n\treturn withServerDefaults;\n};\n\nexport const resolveTTSRuntimeSettings = (\n\tconfig: ToolProviderConfig | TTSRuntimeSettings | undefined,\n): TTSRuntimeSettings => {\n\tconst configRecord = toRecord(config);\n\tconst settingsRecord = toRecord(configRecord.settings);\n\treturn applyRuntimeDefaults({\n\t\t...configRecord,\n\t\t...settingsRecord,\n\t} as TTSRuntimeSettings);\n};\n\nexport const resolveTTSBackend = (\n\tconfig: TTSRuntimeSettings,\n): NonNullable<TTSRuntimeSettings[\"backend\"]> => config.backend || \"browser\";\n\nexport const resolveRuntimeProvider = (\n\tconfig: TTSRuntimeSettings,\n\tbackend: NonNullable<TTSRuntimeSettings[\"backend\"]>,\n): TTSRuntimeSettings[\"serverProvider\"] => {\n\tif (backend === \"polly\" || backend === \"google\") return backend;\n\tif (backend === \"server\") {\n\t\treturn config.serverProvider || config.provider;\n\t}\n\treturn config.serverProvider || config.provider;\n};\n\nexport const resolveTransportMode = (\n\tconfig: TTSRuntimeSettings,\n\truntimeProvider: TTSRuntimeSettings[\"serverProvider\"],\n): NonNullable<TTSRuntimeSettings[\"transportMode\"]> =>\n\tconfig.transportMode || (runtimeProvider === \"custom\" ? \"custom\" : \"pie\");\n\nexport const buildRuntimeTTSConfig = (\n\tconfig: TTSRuntimeSettings,\n): Partial<TTSConfig> => {\n\tconst backend = resolveTTSBackend(config);\n\tconst runtimeProvider = resolveRuntimeProvider(config, backend);\n\tconst transportMode = resolveTransportMode(config, runtimeProvider);\n\tconst mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);\n\treturn {\n\t\tvoice: config.defaultVoice,\n\t\trate: config.rate,\n\t\tpitch: config.pitch,\n\t\tproviderOptions: {\n\t\t\t...(config.language ? { locale: config.language } : {}),\n\t\t\t...(backend === \"polly\" && config.engine\n\t\t\t\t? { engine: config.engine }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && typeof config.sampleRate === \"number\"\n\t\t\t\t? { sampleRate: config.sampleRate }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && config.format\n\t\t\t\t? { format: config.format }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\"\n\t\t\t\t? {\n\t\t\t\t\t\tspeechMarkTypes:\n\t\t\t\t\t\t\tconfig.speechMarksMode === \"word+sentence\"\n\t\t\t\t\t\t\t\t? [\"word\", \"sentence\"]\n\t\t\t\t\t\t\t\t: [\"word\"],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && typeof config.cache === \"boolean\"\n\t\t\t\t? { cache: config.cache }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.speedRate\n\t\t\t\t? { speedRate: config.speedRate }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.lang_id\n\t\t\t\t? { lang_id: config.lang_id }\n\t\t\t\t: {}),\n\t\t\t...(mathSpeech ? { mathSpeech } : {}),\n\t\t},\n\t\tapiEndpoint: config.apiEndpoint,\n\t\tprovider: runtimeProvider,\n\t\tlanguage: config.language,\n\t\ttransportMode,\n\t\tendpointMode: config.endpointMode,\n\t\tendpointValidationMode: config.endpointValidationMode,\n\t\tincludeAuthOnAssetFetch: config.includeAuthOnAssetFetch,\n\t\tvalidateEndpoint: config.validateEndpoint,\n\t\t// Toolkit-level highlight setting carried through the config channel\n\t\t// (like apiEndpoint/transportMode); consumed by the highlight pipeline,\n\t\t// ignored by providers. Only forwarded when set so the pipeline default\n\t\t// (per-token enabled) applies otherwise.\n\t\t...(typeof config.mathTokenHighlighting === \"boolean\"\n\t\t\t? { mathTokenHighlighting: config.mathTokenHighlighting }\n\t\t\t: {}),\n\t} as Partial<TTSConfig>;\n};\n\nexport const resolveTTSLayoutMode = (\n\tconfig: TTSRuntimeSettings,\n): TTSLayoutMode => normalizeTTSLayoutMode(config.layoutMode);\n\nexport const resolveTTSHostToolbarLayout = (\n\tconfig: TTSRuntimeSettings,\n): TTSHostToolbarLayout => {\n\tconst layoutMode = resolveTTSLayoutMode(config);\n\tswitch (layoutMode) {\n\t\tcase \"reserved-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: true,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"expanding-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"floating-overlay\":\n\t\tcase \"left-aligned\":\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t}\n};\n"]}
|
|
1
|
+
{"version":3,"file":"tts-runtime-config.js","sourceRoot":"","sources":["../../src/services/tts-runtime-config.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TTSConfig } from \"./TTSService.js\";\nimport type { ToolProviderConfig } from \"./tools-config-normalizer.js\";\nimport {\n\tnormalizeSREMathSpeechOptions,\n\ttype SREMathSpeechOptions,\n} from \"./tts/math-speech.js\";\n\nexport type TTSLayoutMode =\n\t| \"reserved-row\"\n\t| \"expanding-row\"\n\t| \"floating-overlay\"\n\t| \"left-aligned\";\n\nconst VALID_TTS_LAYOUT_MODES = new Set<TTSLayoutMode>([\n\t\"reserved-row\",\n\t\"expanding-row\",\n\t\"floating-overlay\",\n\t\"left-aligned\",\n]);\n\nexport interface TTSHostToolbarLayout {\n\tmount: \"before-buttons\";\n\tcontrolsRow: {\n\t\treserveSpace: boolean;\n\t\texpandWhenToolActive: boolean;\n\t};\n}\n\nexport interface TTSSpeedOptionConfig {\n\trate: number;\n\tlabel?: string;\n\tariaLabel?: string;\n\tdefault?: boolean;\n}\n\nexport type TTSSpeedOption = number | TTSSpeedOptionConfig;\n\nexport interface NormalizedTTSSpeedOption {\n\trate: number;\n\tlabel: string;\n\tariaLabel: string;\n\tisDefault: boolean;\n}\n\nexport interface TTSRuntimeSettings {\n\tbackend?: \"browser\" | \"polly\" | \"google\" | \"server\";\n\tserverProvider?: \"polly\" | \"google\" | \"custom\";\n\tprovider?: \"polly\" | \"google\" | \"custom\";\n\tengine?: \"standard\" | \"neural\";\n\tsampleRate?: number;\n\tformat?: \"mp3\" | \"ogg\" | \"pcm\";\n\tspeechMarksMode?: \"word\" | \"word+sentence\";\n\tdefaultVoice?: string;\n\trate?: number;\n\tpitch?: number;\n\tapiEndpoint?: string;\n\tlanguage?: string;\n\ttransportMode?: \"pie\" | \"custom\";\n\tendpointMode?: \"synthesizePath\" | \"rootPost\";\n\tendpointValidationMode?: \"voices\" | \"endpoint\" | \"none\";\n\tincludeAuthOnAssetFetch?: boolean;\n\tvalidateEndpoint?: boolean;\n\tcache?: boolean;\n\tspeedRate?: \"slow\" | \"medium\" | \"fast\";\n\tlang_id?: string;\n\t/**\n\t * Optional inline TTS speed buttons.\n\t * - Omitted/non-array: default speed buttons are shown.\n\t * - Empty array: hide speed buttons.\n\t * - Arrays that sanitize to no valid values: default speed buttons are shown.\n\t * - Object entries can customize button text while preserving numeric rates.\n\t */\n\tspeedOptions?: TTSSpeedOption[];\n\t/**\n\t * Show a rendered speed group even when there is only one visible option.\n\t * Defaults to false because a one-option radio group has no meaningful choice.\n\t */\n\tshowSingleSpeedOption?: boolean;\n\tlayoutMode?: TTSLayoutMode;\n\t/**\n\t * Per-token highlighting of math expressions.\n\t * - `true` / omitted (default): when the spoken math aligns confidently to the\n\t * rendered MathML, the formula is highlighted glyph by glyph; otherwise it\n\t * safely falls back to a whole-formula block.\n\t * - `false`: every formula is highlighted as a single block (the fallback),\n\t * never broken into per-token highlights. Prose word tracking is unaffected.\n\t */\n\tmathTokenHighlighting?: boolean;\n\t/**\n\t * Speech Rule Engine options for generated MathML speech. Hosts can use these\n\t * to tune SRE itself (for example ClearSpeak ImpliedTimes/Paren preferences)\n\t * instead of relying on toolkit-specific speech rewrites.\n\t */\n\tmathSpeech?: SREMathSpeechOptions;\n}\n\nconst toRecord = (value: unknown): Record<string, unknown> =>\n\tvalue && typeof value === \"object\" ? (value as Record<string, unknown>) : {};\n\nconst isServerBackend = (\n\tbackend: TTSRuntimeSettings[\"backend\"],\n): backend is \"polly\" | \"google\" | \"server\" =>\n\tbackend === \"polly\" || backend === \"google\" || backend === \"server\";\n\nconst withDefault = <T>(value: T | undefined, fallback: T): T =>\n\tvalue === undefined ? fallback : value;\n\nexport const normalizeTTSLayoutMode = (\n\tvalue: unknown,\n\tfallback: TTSLayoutMode = \"left-aligned\",\n): TTSLayoutMode =>\n\ttypeof value === \"string\" &&\n\tVALID_TTS_LAYOUT_MODES.has(value as TTSLayoutMode)\n\t\t? (value as TTSLayoutMode)\n\t\t: fallback;\n\n/** Legacy numeric helper defaults. Rendered controls add visible Normal separately. */\nexport const DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);\n\nconst DEFAULT_TTS_SPEED_CONTROL_OPTIONS = Object.freeze([\n\t{ rate: 0.8, label: \"Slow\", ariaLabel: \"Slow speed\" },\n\t{ rate: 1, label: \"Normal\", ariaLabel: \"Normal speed\", default: true },\n\t{ rate: 1.25, label: \"Fast\", ariaLabel: \"Fast speed\" },\n] satisfies TTSSpeedOptionConfig[]);\n\nconst normalizeSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\tconst rounded = Math.round(entry * 100) / 100;\n\treturn rounded === 1 ? undefined : rounded;\n};\n\nconst normalizeControlSpeedRate = (entry: unknown): number | undefined => {\n\tif (typeof entry !== \"number\" || !Number.isFinite(entry) || entry <= 0) {\n\t\treturn undefined;\n\t}\n\treturn Math.round(entry * 100) / 100;\n};\n\nconst trimOptionalText = (value: unknown): string | undefined => {\n\tif (typeof value !== \"string\") return undefined;\n\tconst trimmed = value.trim();\n\treturn trimmed.length ? trimmed : undefined;\n};\n\nconst formatSpeedLabel = (rate: number): string => `${rate}x`;\n\nconst formatSpeedAriaLabel = (label: string, usedDefaultLabel: boolean): string =>\n\tlabel.toLowerCase() === \"normal\"\n\t\t? \"Normal speed\"\n\t\t: usedDefaultLabel\n\t\t\t? `Speed ${label}`\n\t\t\t: `${label} speed`;\n\nconst normalizeSpeedAriaLabel = (\n\tlabel: string,\n\tariaLabel: string | undefined,\n\tusedDefaultLabel: boolean,\n): string => {\n\tif (!ariaLabel) return formatSpeedAriaLabel(label, usedDefaultLabel);\n\tif (ariaLabel.toLowerCase().includes(label.toLowerCase())) return ariaLabel;\n\treturn `${label} ${ariaLabel}`;\n};\n\nconst normalizeTTSSpeedOptionConfig = (\n\tentry: unknown,\n): TTSSpeedOption | undefined => {\n\tif (typeof entry === \"number\") return normalizeSpeedRate(entry);\n\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return undefined;\n\tconst record = entry as Record<string, unknown>;\n\tconst rate = normalizeSpeedRate(record.rate);\n\tif (rate === undefined) return undefined;\n\tconst label = trimOptionalText(record.label);\n\tconst ariaLabel = trimOptionalText(record.ariaLabel);\n\treturn {\n\t\trate,\n\t\t...(label ? { label } : {}),\n\t\t...(ariaLabel ? { ariaLabel } : {}),\n\t};\n};\n\nexport const normalizeTTSSpeedOptionConfigs = (\n\tvalue: unknown,\n): TTSSpeedOption[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: TTSSpeedOption[] = [];\n\tfor (const entry of value) {\n\t\tconst option = normalizeTTSSpeedOptionConfig(entry);\n\t\tif (option === undefined) continue;\n\t\tconst rate = typeof option === \"number\" ? option : option.rate;\n\t\tif (dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(option);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];\n};\n\n/**\n * Resolves inline toolbar speed options from host config.\n * - Omitted/non-array: default speed buttons.\n * - Empty array: hide speed buttons.\n * - Arrays that sanitize to no valid values: default speed buttons.\n * - 1.0× is never shown as a discrete speed button.\n */\nexport const normalizeTTSSpeedOptions = (value: unknown): number[] => {\n\tif (!Array.isArray(value)) return [...DEFAULT_TTS_SPEED_OPTIONS];\n\tif (value.length === 0) return [];\n\treturn normalizeTTSSpeedOptionConfigs(value).map((option) =>\n\t\ttypeof option === \"number\" ? option : option.rate,\n\t);\n};\n\nexport const normalizeTTSSpeedControlOptions = (\n\tvalue: unknown,\n): NormalizedTTSSpeedOption[] => {\n\tconst input = Array.isArray(value)\n\t\t? value\n\t\t: [...DEFAULT_TTS_SPEED_CONTROL_OPTIONS];\n\tif (input.length === 0) return [];\n\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: Array<NormalizedTTSSpeedOption & { requestedDefault: boolean }> =\n\t\t[];\n\n\tfor (const entry of input) {\n\t\tconst record = toRecord(entry);\n\t\tconst rate =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? normalizeControlSpeedRate(entry)\n\t\t\t\t: normalizeControlSpeedRate(record.rate);\n\t\tif (rate === undefined || dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\n\t\tconst defaultLabel =\n\t\t\trate === 1 ? \"Normal\" : typeof entry === \"number\" ? formatSpeedLabel(rate) : formatSpeedLabel(rate);\n\t\tconst label =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? defaultLabel\n\t\t\t\t: trimOptionalText(record.label) || defaultLabel;\n\t\tconst ariaLabel =\n\t\t\ttypeof entry === \"number\"\n\t\t\t\t? rate === 1\n\t\t\t\t\t? \"Normal speed\"\n\t\t\t\t\t: formatSpeedAriaLabel(label, true)\n\t\t\t\t: normalizeSpeedAriaLabel(\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\ttrimOptionalText(record.ariaLabel),\n\t\t\t\t\t\tlabel === defaultLabel,\n\t\t\t\t\t);\n\t\tnormalized.push({\n\t\t\trate,\n\t\t\tlabel,\n\t\t\tariaLabel,\n\t\t\tisDefault: false,\n\t\t\trequestedDefault:\n\t\t\t\trecord.default === true || (record as { isDefault?: unknown }).isDefault === true,\n\t\t});\n\t}\n\n\tif (!normalized.length) {\n\t\treturn normalizeTTSSpeedControlOptions(DEFAULT_TTS_SPEED_CONTROL_OPTIONS);\n\t}\n\n\tif (!dedupedRates.has(1)) {\n\t\tconst normalOption = {\n\t\t\trate: 1,\n\t\t\tlabel: \"Normal\",\n\t\t\tariaLabel: \"Normal speed\",\n\t\t\tisDefault: false,\n\t\t\trequestedDefault: false,\n\t\t};\n\t\tconst firstFasterIndex = normalized.findIndex((option) => option.rate > 1);\n\t\tif (firstFasterIndex >= 0) {\n\t\t\tnormalized.splice(firstFasterIndex, 0, normalOption);\n\t\t} else {\n\t\t\tnormalized.push(normalOption);\n\t\t}\n\t}\n\n\tconst requestedDefaultIndex = normalized.findIndex(\n\t\t(option) => option.requestedDefault,\n\t);\n\tconst defaultIndex =\n\t\trequestedDefaultIndex >= 0\n\t\t\t? requestedDefaultIndex\n\t\t\t: normalized.findIndex((option) => option.rate === 1);\n\n\treturn normalized.map(({ requestedDefault: _requestedDefault, ...option }, index) => ({\n\t\t...option,\n\t\tisDefault: index === defaultIndex,\n\t}));\n};\n\nexport const formatTTSSpeedOptionsAsText = (values: number[]): string =>\n\tvalues.join(\", \");\n\nconst DEFAULT_TTS_SPEED_CONTROL_RATES = Object.freeze([0.8, 1, 1.25]);\n\n/**\n * Parse comma/semicolon-separated multipliers from settings UI text.\n * - Empty or whitespace-only string → hide speed buttons (`[]`).\n * - Non-empty text with no parseable finite numbers → same as invalid-only array config: defaults.\n */\nexport const parseTTSSpeedOptionsFromText = (text: string): number[] => {\n\tconst trimmed = text.trim();\n\tif (!trimmed) return [];\n\tconst parts = trimmed\n\t\t.split(/[,;]+/)\n\t\t.map((p) => p.trim())\n\t\t.filter(Boolean);\n\tconst candidates = parts\n\t\t.map((p) => Number.parseFloat(p))\n\t\t.filter((n) => Number.isFinite(n));\n\tif (!candidates.length) return [...DEFAULT_TTS_SPEED_CONTROL_RATES];\n\tconst dedupedRates = new Set<number>();\n\tconst normalized: number[] = [];\n\tfor (const candidate of candidates) {\n\t\tconst rate = normalizeControlSpeedRate(candidate);\n\t\tif (rate === undefined || dedupedRates.has(rate)) continue;\n\t\tdedupedRates.add(rate);\n\t\tnormalized.push(rate);\n\t}\n\treturn normalized.length ? normalized : [...DEFAULT_TTS_SPEED_CONTROL_RATES];\n};\n\nconst applyRuntimeDefaults = (\n\tconfig: TTSRuntimeSettings,\n): TTSRuntimeSettings => {\n\tconst withLayoutDefaults: TTSRuntimeSettings = {\n\t\t...config,\n\t\tlayoutMode: normalizeTTSLayoutMode(config.layoutMode),\n\t};\n\tconst backend = config.backend || \"browser\";\n\tif (!isServerBackend(backend)) return withLayoutDefaults;\n\n\tconst withServerDefaults: TTSRuntimeSettings = {\n\t\t...withLayoutDefaults,\n\t\tapiEndpoint: withDefault(withLayoutDefaults.apiEndpoint, \"/api/tts\"),\n\t\ttransportMode: withDefault(withLayoutDefaults.transportMode, \"pie\"),\n\t\tendpointValidationMode: withDefault(\n\t\t\twithLayoutDefaults.endpointValidationMode,\n\t\t\t\"voices\",\n\t\t),\n\t\tvalidateEndpoint: withDefault(withLayoutDefaults.validateEndpoint, true),\n\t\tincludeAuthOnAssetFetch: withDefault(\n\t\t\twithLayoutDefaults.includeAuthOnAssetFetch,\n\t\t\tfalse,\n\t\t),\n\t\trate: withDefault(withLayoutDefaults.rate, 1.0),\n\t\tlanguage: withDefault(withLayoutDefaults.language, \"en-US\"),\n\t};\n\n\tif (backend === \"polly\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(withServerDefaults.defaultVoice, \"Joanna\"),\n\t\t\tengine: withDefault(withServerDefaults.engine, \"neural\"),\n\t\t\tformat: withDefault(withServerDefaults.format, \"mp3\"),\n\t\t\tspeechMarksMode: withDefault(\n\t\t\t\twithServerDefaults.speechMarksMode,\n\t\t\t\t\"word+sentence\",\n\t\t\t),\n\t\t};\n\t}\n\n\tif (backend === \"google\") {\n\t\treturn {\n\t\t\t...withServerDefaults,\n\t\t\tdefaultVoice: withDefault(\n\t\t\t\twithServerDefaults.defaultVoice,\n\t\t\t\t\"en-US-Wavenet-A\",\n\t\t\t),\n\t\t};\n\t}\n\n\treturn withServerDefaults;\n};\n\nexport const resolveTTSRuntimeSettings = (\n\tconfig: ToolProviderConfig | TTSRuntimeSettings | undefined,\n): TTSRuntimeSettings => {\n\tconst configRecord = toRecord(config);\n\tconst settingsRecord = toRecord(configRecord.settings);\n\treturn applyRuntimeDefaults({\n\t\t...configRecord,\n\t\t...settingsRecord,\n\t} as TTSRuntimeSettings);\n};\n\nexport const resolveTTSBackend = (\n\tconfig: TTSRuntimeSettings,\n): NonNullable<TTSRuntimeSettings[\"backend\"]> => config.backend || \"browser\";\n\nexport const resolveRuntimeProvider = (\n\tconfig: TTSRuntimeSettings,\n\tbackend: NonNullable<TTSRuntimeSettings[\"backend\"]>,\n): TTSRuntimeSettings[\"serverProvider\"] => {\n\tif (backend === \"polly\" || backend === \"google\") return backend;\n\tif (backend === \"server\") {\n\t\treturn config.serverProvider || config.provider;\n\t}\n\treturn config.serverProvider || config.provider;\n};\n\nexport const resolveTransportMode = (\n\tconfig: TTSRuntimeSettings,\n\truntimeProvider: TTSRuntimeSettings[\"serverProvider\"],\n): NonNullable<TTSRuntimeSettings[\"transportMode\"]> =>\n\tconfig.transportMode || (runtimeProvider === \"custom\" ? \"custom\" : \"pie\");\n\nexport const buildRuntimeTTSConfig = (\n\tconfig: TTSRuntimeSettings,\n): Partial<TTSConfig> => {\n\tconst backend = resolveTTSBackend(config);\n\tconst runtimeProvider = resolveRuntimeProvider(config, backend);\n\tconst transportMode = resolveTransportMode(config, runtimeProvider);\n\tconst mathSpeech = normalizeSREMathSpeechOptions(config.mathSpeech);\n\treturn {\n\t\tvoice: config.defaultVoice,\n\t\trate: config.rate,\n\t\tpitch: config.pitch,\n\t\tproviderOptions: {\n\t\t\t...(config.language ? { locale: config.language } : {}),\n\t\t\t...(backend === \"polly\" && config.engine\n\t\t\t\t? { engine: config.engine }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && typeof config.sampleRate === \"number\"\n\t\t\t\t? { sampleRate: config.sampleRate }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\" && config.format\n\t\t\t\t? { format: config.format }\n\t\t\t\t: {}),\n\t\t\t...(backend === \"polly\"\n\t\t\t\t? {\n\t\t\t\t\t\tspeechMarkTypes:\n\t\t\t\t\t\t\tconfig.speechMarksMode === \"word+sentence\"\n\t\t\t\t\t\t\t\t? [\"word\", \"sentence\"]\n\t\t\t\t\t\t\t\t: [\"word\"],\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && typeof config.cache === \"boolean\"\n\t\t\t\t? { cache: config.cache }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.speedRate\n\t\t\t\t? { speedRate: config.speedRate }\n\t\t\t\t: {}),\n\t\t\t...(transportMode === \"custom\" && config.lang_id\n\t\t\t\t? { lang_id: config.lang_id }\n\t\t\t\t: {}),\n\t\t\t...(mathSpeech ? { mathSpeech } : {}),\n\t\t},\n\t\tapiEndpoint: config.apiEndpoint,\n\t\tprovider: runtimeProvider,\n\t\tlanguage: config.language,\n\t\ttransportMode,\n\t\tendpointMode: config.endpointMode,\n\t\tendpointValidationMode: config.endpointValidationMode,\n\t\tincludeAuthOnAssetFetch: config.includeAuthOnAssetFetch,\n\t\tvalidateEndpoint: config.validateEndpoint,\n\t\t// Toolkit-level highlight setting carried through the config channel\n\t\t// (like apiEndpoint/transportMode); consumed by the highlight pipeline,\n\t\t// ignored by providers. Only forwarded when set so the pipeline default\n\t\t// (per-token enabled) applies otherwise.\n\t\t...(typeof config.mathTokenHighlighting === \"boolean\"\n\t\t\t? { mathTokenHighlighting: config.mathTokenHighlighting }\n\t\t\t: {}),\n\t} as Partial<TTSConfig>;\n};\n\nexport const resolveTTSLayoutMode = (\n\tconfig: TTSRuntimeSettings,\n): TTSLayoutMode => normalizeTTSLayoutMode(config.layoutMode);\n\nexport const resolveTTSHostToolbarLayout = (\n\tconfig: TTSRuntimeSettings,\n): TTSHostToolbarLayout => {\n\tconst layoutMode = resolveTTSLayoutMode(config);\n\tswitch (layoutMode) {\n\t\tcase \"reserved-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: true,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"expanding-row\":\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: true,\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"floating-overlay\":\n\t\tcase \"left-aligned\":\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tmount: \"before-buttons\",\n\t\t\t\tcontrolsRow: {\n\t\t\t\t\treserveSpace: false,\n\t\t\t\t\texpandWhenToolActive: false,\n\t\t\t\t},\n\t\t\t};\n\t}\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calculator.js","sourceRoot":"","sources":["../../../src/tools/registrations/calculator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Calculator Tool Registration\n *\n * Registers the calculator tool with support for multiple calculator types\n * (basic, scientific, graphing) via Desmos provider.\n *\n * Maps to QTI 3.0 standard access features:\n * - calculator (cognitive support)\n * - graphingCalculator (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolCoordinatorApi } from \"../../services/interfaces.js\";\nimport type { ToolProviderConfig } from \"../../services/tools-config-normalizer.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport { DesmosToolProvider } from \"../../services/tool-providers/index.js\";\nimport { createToolElement } from \"../tool-tag-map.js\";\n\ntype CalculatorType = \"basic\" | \"scientific\";\n\n// The toolbar parent re-derives `renderedTools` whenever item state changes\n// (e.g. the learner answers a question and `effectiveItem`/`renderContext`\n// recompute). Calculator initialization is expensive (Desmos boot, container\n// mount), so we cache the overlay element by coordinator + scoped tool id.\n// Reusing the same element keeps `mountContent` a no-op and avoids tearing\n// down and re-initializing the calculator on every re-render.\nconst overlayElementCache = new WeakMap<\n\tToolCoordinatorApi,\n\tMap<string, HTMLElement>\n>();\n\nfunction getCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n): HTMLElement | null {\n\tif (!coordinator) return null;\n\tconst scoped = overlayElementCache.get(coordinator);\n\tconst element = scoped?.get(fullToolId);\n\tif (!element) return null;\n\t// Svelte custom elements destroy their component when disconnected.\n\t// A detached cached element is a dead instance — drop it and recreate.\n\tif (!element.isConnected) {\n\t\tscoped?.delete(fullToolId);\n\t\treturn null;\n\t}\n\treturn element;\n}\n\nfunction setCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n\telement: HTMLElement,\n): void {\n\tif (!coordinator) return;\n\tlet scoped = overlayElementCache.get(coordinator);\n\tif (!scoped) {\n\t\tscoped = new Map();\n\t\toverlayElementCache.set(coordinator, scoped);\n\t}\n\tscoped.set(fullToolId, element);\n}\n\nfunction normalizeCalculatorType(value: unknown): CalculatorType | null {\n\treturn value === \"basic\" || value === \"scientific\" ? value : null;\n}\n\nfunction getCalculatorRenderParams(toolbarContext: ToolbarContext): {\n\tcalculatorType: CalculatorType | null;\n\tavailableTypes: CalculatorType[] | null;\n\tdisplayName: string;\n} {\n\tconst params = toolbarContext.getToolRenderParams?.(\"calculator\") ?? {};\n\tconst calculatorType = normalizeCalculatorType(params.calculatorType);\n\tconst availableTypesRaw = params.availableTypes;\n\tconst availableTypes = Array.isArray(availableTypesRaw)\n\t\t? availableTypesRaw\n\t\t\t\t.map((value) => normalizeCalculatorType(value))\n\t\t\t\t.filter((value): value is CalculatorType => value !== null)\n\t\t: calculatorType\n\t\t\t? [calculatorType]\n\t\t\t: null;\n\n\treturn {\n\t\tcalculatorType,\n\t\tavailableTypes,\n\t\tdisplayName:\n\t\t\tcalculatorType === \"scientific\"\n\t\t\t\t? \"Scientific Calculator\"\n\t\t\t\t: calculatorType === \"basic\"\n\t\t\t\t\t? \"Basic Calculator\"\n\t\t\t\t\t: \"Calculator\",\n\t};\n}\n\nfunction applyCalculatorParamsToElement(\n\telement: HTMLElement,\n\tcalculatorType: CalculatorType | null,\n\tavailableTypes: CalculatorType[] | null,\n): void {\n\tconst calculatorElement = element as HTMLElement & {\n\t\tcalculatorType?: CalculatorType;\n\t\tavailableTypes?: CalculatorType[];\n\t};\n\n\tif (calculatorType) {\n\t\tcalculatorElement.calculatorType = calculatorType;\n\t\telement.setAttribute(\"calculator-type\", calculatorType);\n\t} else {\n\t\tdelete calculatorElement.calculatorType;\n\t\telement.removeAttribute(\"calculator-type\");\n\t}\n\n\tif (availableTypes && availableTypes.length > 0) {\n\t\tcalculatorElement.availableTypes = availableTypes;\n\t} else {\n\t\tdelete calculatorElement.availableTypes;\n\t}\n}\n\n/**\n * Calculator tool registration\n *\n * Supports:\n * - Basic, scientific, and graphing calculators via Desmos\n * - Context-aware visibility (shows only when math content is detected)\n * - Item level only\n */\nexport const calculatorToolRegistration: ToolRegistration = {\n\ttoolId: \"calculator\",\n\tname: \"Calculator\",\n\tdescription: \"Multi-type calculator (basic, scientific, graphing)\",\n\ticon: \"calculator\",\n\tprovider: {\n\t\tgetProviderId: (config: ToolProviderConfig | undefined) =>\n\t\t\ttypeof config?.provider?.id === \"string\" && config.provider.id.length > 0\n\t\t\t\t? config.provider.id\n\t\t\t\t: \"calculator-desmos\",\n\t\tcreateProvider: () => new DesmosToolProvider(),\n\t\tgetInitConfig: (config: ToolProviderConfig | undefined) =>\n\t\t\tconfig?.provider?.init ?? {},\n\t\tgetAuthFetcher: (config: ToolProviderConfig | undefined) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\tif (typeof runtimeAuthFetcher === \"function\") return runtimeAuthFetcher;\n\t\t\treturn async () => {\n\t\t\t\tconst response = await fetch(\"/api/tools/desmos/auth\", {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"same-origin\",\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch Desmos auth config (${response.status})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (await response.json()) as Record<string, unknown>;\n\t\t\t};\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// Calculator is item-level in this player architecture.\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: calculator, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"calculator\", // QTI 3.0 standard (cognitive.calculator)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"basicCalculator\", // Common variant\n\t\t\"scientificCalculator\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if calculator is relevant in this context\n\t *\n\t * Calculator is relevant when context contains mathematical content\n\t * (MathML, LaTeX, arithmetic markers).\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\t// Show only when math is present in item content.\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst { calculatorType, availableTypes, displayName } =\n\t\t\tgetCalculatorRenderParams(toolbarContext);\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst componentOverrides = toolbarContext.componentOverrides;\n\t\tconst cachedOverlay = getCachedOverlay(\n\t\t\ttoolbarContext.toolCoordinator,\n\t\t\tfullToolId,\n\t\t);\n\t\tconst overlay = (cachedOverlay ??\n\t\t\tcreateToolElement(\n\t\t\t\tthis.toolId,\n\t\t\t\tcontext,\n\t\t\t\ttoolbarContext,\n\t\t\t\tcomponentOverrides,\n\t\t\t)) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator?: unknown;\n\t\t};\n\t\tif (!cachedOverlay) {\n\t\t\tsetCachedOverlay(toolbarContext.toolCoordinator, fullToolId, overlay);\n\t\t}\n\t\toverlay.setAttribute(\"tool-id\", fullToolId);\n\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\tconst openLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Open scientific calculator\"\n\t\t\t\t: `Open ${displayName.toLowerCase()}`;\n\t\tconst closeLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Close scientific calculator\"\n\t\t\t\t: `Close ${displayName.toLowerCase()}`;\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: displayName,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: openLabel,\n\t\t\ttooltip: displayName,\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: toolbarContext.isToolVisible(fullToolId),\n\t\t};\n\t\tlet lastVisibleState: boolean | undefined = button.active;\n\t\tif (overlay.visible !== button.active) {\n\t\t\toverlay.visible = button.active;\n\t\t}\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 380,\n\t\t\t\t\t\tinitialHeight: 420,\n\t\t\t\t\t\tminWidth: 380,\n\t\t\t\t\t\tminHeight: 420,\n\t\t\t\t\t\tinitialAlign: \"bottom-right\",\n\t\t\t\t\t\tinitialMargin: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tbutton,\n\t\t\tsync: () => {\n\t\t\t\tconst active = toolbarContext.isToolVisible(fullToolId);\n\t\t\t\tbutton.active = active;\n\t\t\t\tbutton.label = displayName;\n\t\t\t\tbutton.ariaLabel = active ? closeLabel : openLabel;\n\t\t\t\tbutton.tooltip = active\n\t\t\t\t\t? `Close ${displayName.toLowerCase()}`\n\t\t\t\t\t: displayName;\n\t\t\t\tif (lastVisibleState !== active) {\n\t\t\t\t\toverlay.visible = active;\n\t\t\t\t\tlastVisibleState = active;\n\t\t\t\t}\n\t\t\t\tif (overlay.toolkitCoordinator !== toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\t\t},\n\t\t\tsubscribeActive: (callback: (active: boolean) => void) => {\n\t\t\t\tif (!toolbarContext.subscribeVisibility) return () => {};\n\t\t\t\treturn toolbarContext.subscribeVisibility(() => {\n\t\t\t\t\tcallback(toolbarContext.isToolVisible(fullToolId));\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"calculator.js","sourceRoot":"","sources":["../../../src/tools/registrations/calculator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Calculator Tool Registration\n *\n * Registers the calculator tool with support for multiple calculator types\n * (basic, scientific, graphing) via Desmos provider.\n *\n * Maps to QTI 3.0 standard access features:\n * - calculator (cognitive support)\n * - graphingCalculator (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolCoordinatorApi } from \"../../services/interfaces.js\";\nimport type { ToolProviderConfig } from \"../../services/tools-config-normalizer.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport { DesmosToolProvider } from \"../../services/tool-providers/index.js\";\nimport { createToolElement } from \"../tool-tag-map.js\";\n\ntype CalculatorType = \"basic\" | \"scientific\";\n\n// The toolbar parent re-derives `renderedTools` whenever item state changes\n// (e.g. the learner answers a question and `effectiveItem`/`renderContext`\n// recompute). Calculator initialization is expensive (Desmos boot, container\n// mount), so we cache the overlay element by coordinator + scoped tool id.\n// Reusing the same element keeps `mountContent` a no-op and avoids tearing\n// down and re-initializing the calculator on every re-render.\nconst overlayElementCache = new WeakMap<\n\tToolCoordinatorApi,\n\tMap<string, HTMLElement>\n>();\n\nfunction getCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n): HTMLElement | null {\n\tif (!coordinator) return null;\n\tconst scoped = overlayElementCache.get(coordinator);\n\tconst element = scoped?.get(fullToolId);\n\tif (!element) return null;\n\t// Svelte custom elements destroy their component when disconnected.\n\t// A detached cached element is a dead instance — drop it and recreate.\n\tif (!element.isConnected) {\n\t\tscoped?.delete(fullToolId);\n\t\treturn null;\n\t}\n\treturn element;\n}\n\nfunction setCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n\telement: HTMLElement,\n): void {\n\tif (!coordinator) return;\n\tlet scoped = overlayElementCache.get(coordinator);\n\tif (!scoped) {\n\t\tscoped = new Map();\n\t\toverlayElementCache.set(coordinator, scoped);\n\t}\n\tscoped.set(fullToolId, element);\n}\n\nfunction normalizeCalculatorType(value: unknown): CalculatorType | null {\n\treturn value === \"basic\" || value === \"scientific\" ? value : null;\n}\n\nfunction getCalculatorRenderParams(toolbarContext: ToolbarContext): {\n\tcalculatorType: CalculatorType | null;\n\tavailableTypes: CalculatorType[] | null;\n\tdisplayName: string;\n} {\n\tconst params = toolbarContext.getToolRenderParams?.(\"calculator\") ?? {};\n\tconst calculatorType = normalizeCalculatorType(params.calculatorType);\n\tconst availableTypesRaw = params.availableTypes;\n\tconst availableTypes = Array.isArray(availableTypesRaw)\n\t\t? availableTypesRaw\n\t\t\t\t.map((value) => normalizeCalculatorType(value))\n\t\t\t\t.filter((value): value is CalculatorType => value !== null)\n\t\t: calculatorType\n\t\t\t? [calculatorType]\n\t\t\t: null;\n\n\treturn {\n\t\tcalculatorType,\n\t\tavailableTypes,\n\t\tdisplayName:\n\t\t\tcalculatorType === \"scientific\"\n\t\t\t\t? \"Scientific Calculator\"\n\t\t\t\t: calculatorType === \"basic\"\n\t\t\t\t\t? \"Basic Calculator\"\n\t\t\t\t\t: \"Calculator\",\n\t};\n}\n\nfunction applyCalculatorParamsToElement(\n\telement: HTMLElement,\n\tcalculatorType: CalculatorType | null,\n\tavailableTypes: CalculatorType[] | null,\n): void {\n\tconst calculatorElement = element as HTMLElement & {\n\t\tcalculatorType?: CalculatorType;\n\t\tavailableTypes?: CalculatorType[];\n\t};\n\n\tif (calculatorType) {\n\t\tcalculatorElement.calculatorType = calculatorType;\n\t\telement.setAttribute(\"calculator-type\", calculatorType);\n\t} else {\n\t\tdelete calculatorElement.calculatorType;\n\t\telement.removeAttribute(\"calculator-type\");\n\t}\n\n\tif (availableTypes && availableTypes.length > 0) {\n\t\tcalculatorElement.availableTypes = availableTypes;\n\t} else {\n\t\tdelete calculatorElement.availableTypes;\n\t}\n}\n\n/**\n * Calculator tool registration\n *\n * Supports:\n * - Basic, scientific, and graphing calculators via Desmos\n * - Context-aware visibility (shows only when math content is detected)\n * - Item level only\n */\nexport const calculatorToolRegistration: ToolRegistration = {\n\ttoolId: \"calculator\",\n\tname: \"Calculator\",\n\tdescription: \"Multi-type calculator (basic, scientific, graphing)\",\n\ticon: \"calculator\",\n\tprovider: {\n\t\tgetProviderId: (config: ToolProviderConfig | undefined) =>\n\t\t\ttypeof config?.provider?.id === \"string\" && config.provider.id.length > 0\n\t\t\t\t? config.provider.id\n\t\t\t\t: \"calculator-desmos\",\n\t\tcreateProvider: () => new DesmosToolProvider(),\n\t\tgetInitConfig: (config: ToolProviderConfig | undefined) =>\n\t\t\tconfig?.provider?.init ?? {},\n\t\tgetAuthFetcher: (config: ToolProviderConfig | undefined) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\tif (typeof runtimeAuthFetcher === \"function\") return runtimeAuthFetcher;\n\t\t\treturn async () => {\n\t\t\t\tconst response = await fetch(\"/api/tools/desmos/auth\", {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"same-origin\",\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch Desmos auth config (${response.status})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (await response.json()) as Record<string, unknown>;\n\t\t\t};\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// Calculator is item-level in this player architecture.\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: calculator, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"calculator\", // QTI 3.0 standard (cognitive.calculator)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"basicCalculator\", // Common variant\n\t\t\"scientificCalculator\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if calculator is relevant in this context\n\t *\n\t * Calculator is relevant when context contains mathematical content\n\t * (MathML, LaTeX, arithmetic markers).\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\t// Show only when math is present in item content.\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst { calculatorType, availableTypes, displayName } =\n\t\t\tgetCalculatorRenderParams(toolbarContext);\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst componentOverrides = toolbarContext.componentOverrides;\n\t\tconst cachedOverlay = getCachedOverlay(\n\t\t\ttoolbarContext.toolCoordinator,\n\t\t\tfullToolId,\n\t\t);\n\t\tconst overlay = (cachedOverlay ??\n\t\t\tcreateToolElement(\n\t\t\t\tthis.toolId,\n\t\t\t\tcontext,\n\t\t\t\ttoolbarContext,\n\t\t\t\tcomponentOverrides,\n\t\t\t)) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator?: unknown;\n\t\t};\n\t\tif (!cachedOverlay) {\n\t\t\tsetCachedOverlay(toolbarContext.toolCoordinator, fullToolId, overlay);\n\t\t}\n\t\toverlay.setAttribute(\"tool-id\", fullToolId);\n\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\tconst openLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Open scientific calculator\"\n\t\t\t\t: `Open ${displayName.toLowerCase()}`;\n\t\tconst closeLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Close scientific calculator\"\n\t\t\t\t: `Close ${displayName.toLowerCase()}`;\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: displayName,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: openLabel,\n\t\t\ttooltip: displayName,\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: toolbarContext.isToolVisible(fullToolId),\n\t\t};\n\t\tlet lastVisibleState: boolean | undefined = button.active;\n\t\tif (overlay.visible !== button.active) {\n\t\t\toverlay.visible = button.active;\n\t\t}\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 380,\n\t\t\t\t\t\tinitialHeight: 420,\n\t\t\t\t\t\tminWidth: 380,\n\t\t\t\t\t\tminHeight: 420,\n\t\t\t\t\t\tinitialAlign: \"bottom-right\",\n\t\t\t\t\t\tinitialMargin: 16,\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\toverflowY: \"auto\",\n\t\t\t\t\t\t\tpreserveMinHeight: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tbutton,\n\t\t\tsync: () => {\n\t\t\t\tconst active = toolbarContext.isToolVisible(fullToolId);\n\t\t\t\tbutton.active = active;\n\t\t\t\tbutton.label = displayName;\n\t\t\t\tbutton.ariaLabel = active ? closeLabel : openLabel;\n\t\t\t\tbutton.tooltip = active\n\t\t\t\t\t? `Close ${displayName.toLowerCase()}`\n\t\t\t\t\t: displayName;\n\t\t\t\tif (lastVisibleState !== active) {\n\t\t\t\t\toverlay.visible = active;\n\t\t\t\t\tlastVisibleState = active;\n\t\t\t\t}\n\t\t\t\tif (overlay.toolkitCoordinator !== toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\t\t},\n\t\t\tsubscribeActive: (callback: (active: boolean) => void) => {\n\t\t\t\tif (!toolbarContext.subscribeVisibility) return () => {};\n\t\t\t\treturn toolbarContext.subscribeVisibility(() => {\n\t\t\t\t\tcallback(toolbarContext.isToolVisible(fullToolId));\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { hasReadableText } from "../../services/tool-context.js";
|
|
11
11
|
import { createScopedToolId } from "../../services/tool-instance-id.js";
|
|
12
|
-
import { buildRuntimeTTSConfig, normalizeTTSLayoutMode, normalizeTTSSpeedControlOptions,
|
|
12
|
+
import { buildRuntimeTTSConfig, normalizeTTSLayoutMode, normalizeTTSSpeedControlOptions, resolveTTSHostToolbarLayout, resolveTTSLayoutMode, resolveTTSBackend, resolveTTSRuntimeSettings, resolveRuntimeProvider, resolveTransportMode, } from "../../services/tts-runtime-config.js";
|
|
13
13
|
import { TTSToolProvider } from "../../services/tool-providers/index.js";
|
|
14
14
|
const inlineTTSControls = new Map();
|
|
15
15
|
export const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = "__pieToolElementUnmount";
|
|
@@ -59,7 +59,7 @@ export const ttsToolRegistration = {
|
|
|
59
59
|
settings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);
|
|
60
60
|
}
|
|
61
61
|
if (settings && "speedOptions" in settings) {
|
|
62
|
-
settings.speedOptions =
|
|
62
|
+
settings.speedOptions = normalizeTTSSpeedControlOptions(settings.speedOptions);
|
|
63
63
|
}
|
|
64
64
|
const normalizedConfig = {
|
|
65
65
|
...config,
|
|
@@ -68,7 +68,7 @@ export const ttsToolRegistration = {
|
|
|
68
68
|
normalizedConfig.layoutMode = normalizeTTSLayoutMode(normalizedConfig.layoutMode);
|
|
69
69
|
}
|
|
70
70
|
if ("speedOptions" in normalizedConfig) {
|
|
71
|
-
normalizedConfig.speedOptions =
|
|
71
|
+
normalizedConfig.speedOptions = normalizeTTSSpeedControlOptions(normalizedConfig.speedOptions);
|
|
72
72
|
}
|
|
73
73
|
if (settings) {
|
|
74
74
|
normalizedConfig.settings = settings;
|
|
@@ -134,6 +134,8 @@ export const ttsToolRegistration = {
|
|
|
134
134
|
element.setAttribute("size", resolveControlSize());
|
|
135
135
|
element.setAttribute("layout-mode", resolveLayoutMode());
|
|
136
136
|
element.speedOptions = resolveElementSpeedOptions();
|
|
137
|
+
element.showSingleSpeedOption =
|
|
138
|
+
resolveRuntimeSettings().showSingleSpeedOption === true;
|
|
137
139
|
return element;
|
|
138
140
|
};
|
|
139
141
|
const hostLayout = resolveHostLayout();
|
|
@@ -171,6 +173,8 @@ export const ttsToolRegistration = {
|
|
|
171
173
|
element.setAttribute("size", resolveControlSize());
|
|
172
174
|
element.setAttribute("layout-mode", resolveLayoutMode());
|
|
173
175
|
element.speedOptions = resolveElementSpeedOptions();
|
|
176
|
+
element.showSingleSpeedOption =
|
|
177
|
+
resolveRuntimeSettings().showSingleSpeedOption === true;
|
|
174
178
|
},
|
|
175
179
|
};
|
|
176
180
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/registrations/tts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text-to-Speech (TTS) Tool Registration\n *\n * Registers the TTS tool for reading content aloud.\n *\n * Maps to QTI 3.0 standard access features:\n * - textToSpeech (auditory support)\n * - readAloud (auditory support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport {\n\tbuildRuntimeTTSConfig,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedControlOptions,\n\tnormalizeTTSSpeedOptionConfigs,\n\ttype NormalizedTTSSpeedOption,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSBackend,\n\tresolveTTSRuntimeSettings,\n\tresolveRuntimeProvider,\n\tresolveTransportMode,\n} from \"../../services/tts-runtime-config.js\";\nimport { TTSToolProvider } from \"../../services/tool-providers/index.js\";\n\nconst inlineTTSControls = new Map<string, HTMLElement>();\nexport const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = \"__pieToolElementUnmount\";\nexport const TOOL_ACTIVE_CHANGE_EVENT = \"pie-tool-active-change\";\n\n/**\n * Text-to-Speech tool registration\n *\n * Supports:\n * - Reading content aloud using browser TTS or external providers\n * - Context-aware visibility (shows when readable text is available)\n * - All levels except assessment and element\n */\nexport const ttsToolRegistration: ToolRegistration = {\n\ttoolId: \"textToSpeech\",\n\tname: \"Text to Speech\",\n\tdescription: \"Read content aloud\",\n\ticon: \"volume-up\",\n\tprovider: {\n\t\tgetProviderId: () => \"tts\",\n\t\tcreateProvider: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\treturn new TTSToolProvider(resolveTTSBackend(settings));\n\t\t},\n\t\tgetInitConfig: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\tconst backend = resolveTTSBackend(settings);\n\t\t\tconst serverProvider = resolveRuntimeProvider(settings, backend);\n\t\t\tconst transportMode = resolveTransportMode(settings, serverProvider);\n\t\t\treturn {\n\t\t\t\tbackend,\n\t\t\t\tserverProvider,\n\t\t\t\ttransportMode,\n\t\t\t\t...buildRuntimeTTSConfig(settings),\n\t\t\t};\n\t\t},\n\t\tgetAuthFetcher: (config) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\treturn typeof runtimeAuthFetcher === \"function\"\n\t\t\t\t? runtimeAuthFetcher\n\t\t\t\t: undefined;\n\t\t},\n\t\tsanitizeConfig: (config) => {\n\t\t\tconst settings =\n\t\t\t\tconfig.settings && typeof config.settings === \"object\"\n\t\t\t\t\t? { ...(config.settings as Record<string, unknown>) }\n\t\t\t\t\t: undefined;\n\t\t\tif (settings && \"layoutMode\" in settings) {\n\t\t\t\tsettings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);\n\t\t\t}\n\t\t\tif (settings && \"speedOptions\" in settings) {\n\t\t\t\tsettings.speedOptions = normalizeTTSSpeedOptionConfigs(\n\t\t\t\t\tsettings.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst normalizedConfig: Record<string, unknown> = {\n\t\t\t\t...(config as Record<string, unknown>),\n\t\t\t};\n\t\t\tif (\"layoutMode\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.layoutMode = normalizeTTSLayoutMode(\n\t\t\t\t\tnormalizedConfig.layoutMode,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\"speedOptions\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.speedOptions = normalizeTTSSpeedOptionConfigs(\n\t\t\t\t\tnormalizedConfig.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (settings) {\n\t\t\t\tnormalizedConfig.settings = settings;\n\t\t\t}\n\t\t\treturn normalizedConfig as typeof config;\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// TTS is inline-only and scoped to item/passage contexts.\n\tsupportedLevels: [\"item\", \"passage\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: textToSpeech, readAloud\n\tpnpSupportIds: [\n\t\t\"textToSpeech\", // QTI 3.0 standard (auditory.textToSpeech)\n\t\t\"readAloud\", // QTI 3.0 standard (auditory.readAloud)\n\t\t\"tts\", // Common abbreviation\n\t\t\"speechOutput\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if TTS is relevant in this context\n\t *\n\t * TTS is relevant when:\n\t * - Context contains readable text (at least 10 characters)\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\t_context: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst resolveRuntimeSettings = () =>\n\t\t\tresolveTTSRuntimeSettings(\n\t\t\t\ttoolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||\n\t\t\t\t\tundefined,\n\t\t\t);\n\t\tconst resolveElementSpeedOptions = (): NormalizedTTSSpeedOption[] => {\n\t\t\tconst runtimeSettings = resolveRuntimeSettings();\n\t\t\treturn normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);\n\t\t};\n\t\tconst resolveLayoutMode = () =>\n\t\t\tresolveTTSLayoutMode(resolveRuntimeSettings());\n\t\tconst resolveHostLayout = () =>\n\t\t\tresolveTTSHostToolbarLayout(resolveRuntimeSettings());\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst resolveControlSize = (): \"sm\" | \"md\" | \"lg\" => {\n\t\t\tconst raw = toolbarContext.ui?.size;\n\t\t\treturn raw === \"sm\" || raw === \"lg\" ? raw : \"md\";\n\t\t};\n\t\tconst ensureElement = (): HTMLElement => {\n\t\t\tlet element = inlineTTSControls.get(fullToolId);\n\t\t\tif (\n\t\t\t\telement &&\n\t\t\t\ttypeof (element as { isConnected?: boolean }).isConnected ===\n\t\t\t\t\t\"boolean\" &&\n\t\t\t\t!(element as { isConnected?: boolean }).isConnected\n\t\t\t) {\n\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\telement = undefined;\n\t\t\t}\n\t\t\tif (!element) {\n\t\t\t\telement = document.createElement(\"pie-tool-tts-inline\");\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & {\n\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t}\n\t\t\t\t)[TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP] = () => {\n\t\t\t\t\tif (inlineTTSControls.get(fullToolId) === element) {\n\t\t\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tinlineTTSControls.set(fullToolId, element);\n\t\t\t}\n\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\telement.setAttribute(\n\t\t\t\t\"catalog-id\",\n\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t);\n\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t(\n\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\treturn element;\n\t\t};\n\t\tconst hostLayout = resolveHostLayout();\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton: null,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: ensureElement(),\n\t\t\t\t\tmount: hostLayout.mount,\n\t\t\t\t\tlayoutHints: {\n\t\t\t\t\t\tcontrolsRow: {\n\t\t\t\t\t\t\treserveSpace: hostLayout.controlsRow.reserveSpace,\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsubscribeActive: (callback) => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\tconst handler = (event: Event) => {\n\t\t\t\t\tconst detail = (event as CustomEvent<{ active?: boolean }>).detail;\n\t\t\t\t\tcallback(detail?.active === true);\n\t\t\t\t};\n\t\t\t\telement.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\treturn () => {\n\t\t\t\t\telement.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\t};\n\t\t\t},\n\t\t\tsync: () => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\t\telement.setAttribute(\n\t\t\t\t\t\"catalog-id\",\n\t\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t\t);\n\t\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/registrations/tts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text-to-Speech (TTS) Tool Registration\n *\n * Registers the TTS tool for reading content aloud.\n *\n * Maps to QTI 3.0 standard access features:\n * - textToSpeech (auditory support)\n * - readAloud (auditory support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport {\n\tbuildRuntimeTTSConfig,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedControlOptions,\n\ttype NormalizedTTSSpeedOption,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSBackend,\n\tresolveTTSRuntimeSettings,\n\tresolveRuntimeProvider,\n\tresolveTransportMode,\n} from \"../../services/tts-runtime-config.js\";\nimport { TTSToolProvider } from \"../../services/tool-providers/index.js\";\n\nconst inlineTTSControls = new Map<string, HTMLElement>();\nexport const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = \"__pieToolElementUnmount\";\nexport const TOOL_ACTIVE_CHANGE_EVENT = \"pie-tool-active-change\";\n\n/**\n * Text-to-Speech tool registration\n *\n * Supports:\n * - Reading content aloud using browser TTS or external providers\n * - Context-aware visibility (shows when readable text is available)\n * - All levels except assessment and element\n */\nexport const ttsToolRegistration: ToolRegistration = {\n\ttoolId: \"textToSpeech\",\n\tname: \"Text to Speech\",\n\tdescription: \"Read content aloud\",\n\ticon: \"volume-up\",\n\tprovider: {\n\t\tgetProviderId: () => \"tts\",\n\t\tcreateProvider: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\treturn new TTSToolProvider(resolveTTSBackend(settings));\n\t\t},\n\t\tgetInitConfig: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\tconst backend = resolveTTSBackend(settings);\n\t\t\tconst serverProvider = resolveRuntimeProvider(settings, backend);\n\t\t\tconst transportMode = resolveTransportMode(settings, serverProvider);\n\t\t\treturn {\n\t\t\t\tbackend,\n\t\t\t\tserverProvider,\n\t\t\t\ttransportMode,\n\t\t\t\t...buildRuntimeTTSConfig(settings),\n\t\t\t};\n\t\t},\n\t\tgetAuthFetcher: (config) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\treturn typeof runtimeAuthFetcher === \"function\"\n\t\t\t\t? runtimeAuthFetcher\n\t\t\t\t: undefined;\n\t\t},\n\t\tsanitizeConfig: (config) => {\n\t\t\tconst settings =\n\t\t\t\tconfig.settings && typeof config.settings === \"object\"\n\t\t\t\t\t? { ...(config.settings as Record<string, unknown>) }\n\t\t\t\t\t: undefined;\n\t\t\tif (settings && \"layoutMode\" in settings) {\n\t\t\t\tsettings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);\n\t\t\t}\n\t\t\tif (settings && \"speedOptions\" in settings) {\n\t\t\t\tsettings.speedOptions = normalizeTTSSpeedControlOptions(\n\t\t\t\t\tsettings.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst normalizedConfig: Record<string, unknown> = {\n\t\t\t\t...(config as Record<string, unknown>),\n\t\t\t};\n\t\t\tif (\"layoutMode\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.layoutMode = normalizeTTSLayoutMode(\n\t\t\t\t\tnormalizedConfig.layoutMode,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\"speedOptions\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.speedOptions = normalizeTTSSpeedControlOptions(\n\t\t\t\t\tnormalizedConfig.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (settings) {\n\t\t\t\tnormalizedConfig.settings = settings;\n\t\t\t}\n\t\t\treturn normalizedConfig as typeof config;\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// TTS is inline-only and scoped to item/passage contexts.\n\tsupportedLevels: [\"item\", \"passage\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: textToSpeech, readAloud\n\tpnpSupportIds: [\n\t\t\"textToSpeech\", // QTI 3.0 standard (auditory.textToSpeech)\n\t\t\"readAloud\", // QTI 3.0 standard (auditory.readAloud)\n\t\t\"tts\", // Common abbreviation\n\t\t\"speechOutput\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if TTS is relevant in this context\n\t *\n\t * TTS is relevant when:\n\t * - Context contains readable text (at least 10 characters)\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\t_context: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst resolveRuntimeSettings = () =>\n\t\t\tresolveTTSRuntimeSettings(\n\t\t\t\ttoolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||\n\t\t\t\t\tundefined,\n\t\t\t);\n\t\tconst resolveElementSpeedOptions = (): NormalizedTTSSpeedOption[] => {\n\t\t\tconst runtimeSettings = resolveRuntimeSettings();\n\t\t\treturn normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);\n\t\t};\n\t\tconst resolveLayoutMode = () =>\n\t\t\tresolveTTSLayoutMode(resolveRuntimeSettings());\n\t\tconst resolveHostLayout = () =>\n\t\t\tresolveTTSHostToolbarLayout(resolveRuntimeSettings());\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst resolveControlSize = (): \"sm\" | \"md\" | \"lg\" => {\n\t\t\tconst raw = toolbarContext.ui?.size;\n\t\t\treturn raw === \"sm\" || raw === \"lg\" ? raw : \"md\";\n\t\t};\n\t\tconst ensureElement = (): HTMLElement => {\n\t\t\tlet element = inlineTTSControls.get(fullToolId);\n\t\t\tif (\n\t\t\t\telement &&\n\t\t\t\ttypeof (element as { isConnected?: boolean }).isConnected ===\n\t\t\t\t\t\"boolean\" &&\n\t\t\t\t!(element as { isConnected?: boolean }).isConnected\n\t\t\t) {\n\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\telement = undefined;\n\t\t\t}\n\t\t\tif (!element) {\n\t\t\t\telement = document.createElement(\"pie-tool-tts-inline\");\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & {\n\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t}\n\t\t\t\t)[TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP] = () => {\n\t\t\t\t\tif (inlineTTSControls.get(fullToolId) === element) {\n\t\t\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tinlineTTSControls.set(fullToolId, element);\n\t\t\t}\n\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\telement.setAttribute(\n\t\t\t\t\"catalog-id\",\n\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t);\n\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t(\n\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t(\n\t\t\t\telement as HTMLElement & { showSingleSpeedOption?: boolean }\n\t\t\t).showSingleSpeedOption =\n\t\t\t\tresolveRuntimeSettings().showSingleSpeedOption === true;\n\t\t\treturn element;\n\t\t};\n\t\tconst hostLayout = resolveHostLayout();\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton: null,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: ensureElement(),\n\t\t\t\t\tmount: hostLayout.mount,\n\t\t\t\t\tlayoutHints: {\n\t\t\t\t\t\tcontrolsRow: {\n\t\t\t\t\t\t\treserveSpace: hostLayout.controlsRow.reserveSpace,\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsubscribeActive: (callback) => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\tconst handler = (event: Event) => {\n\t\t\t\t\tconst detail = (event as CustomEvent<{ active?: boolean }>).detail;\n\t\t\t\t\tcallback(detail?.active === true);\n\t\t\t\t};\n\t\t\t\telement.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\treturn () => {\n\t\t\t\t\telement.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\t};\n\t\t\t},\n\t\t\tsync: () => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\t\telement.setAttribute(\n\t\t\t\t\t\"catalog-id\",\n\t\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t\t);\n\t\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & { speedOptions?: NormalizedTTSSpeedOption[] }\n\t\t\t\t).speedOptions = resolveElementSpeedOptions();\n\t\t\t(\n\t\t\t\telement as HTMLElement & { showSingleSpeedOption?: boolean }\n\t\t\t).showSingleSpeedOption =\n\t\t\t\tresolveRuntimeSettings().showSingleSpeedOption === true;\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-players/pie-assessment-toolkit",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.55",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "PIE assessment toolkit: composable services + reference implementation for assessment players and tool coordination",
|
|
6
6
|
"license": "MIT",
|
|
@@ -75,15 +75,15 @@
|
|
|
75
75
|
"test": "bun test"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@pie-players/pie-calculator": "0.3.
|
|
79
|
-
"@pie-players/pie-context": "0.3.
|
|
80
|
-
"@pie-players/pie-players-shared": "0.3.
|
|
81
|
-
"@pie-players/pie-tts": "0.3.
|
|
78
|
+
"@pie-players/pie-calculator": "0.3.55",
|
|
79
|
+
"@pie-players/pie-context": "0.3.55",
|
|
80
|
+
"@pie-players/pie-players-shared": "0.3.55",
|
|
81
|
+
"@pie-players/pie-tts": "0.3.55",
|
|
82
82
|
"speech-rule-engine": "^5.0.0-rc.1"
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
|
-
"@pie-players/pie-calculator-desmos": "0.3.
|
|
86
|
-
"@pie-players/tts-client-server": "0.3.
|
|
85
|
+
"@pie-players/pie-calculator-desmos": "0.3.55",
|
|
86
|
+
"@pie-players/tts-client-server": "0.3.55"
|
|
87
87
|
},
|
|
88
88
|
"peerDependenciesMeta": {
|
|
89
89
|
"@pie-players/pie-calculator-desmos": {
|