@pie-players/pie-assessment-toolkit 0.3.49 → 0.3.51
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 +25 -0
- package/dist/components/ItemToolBar.custom-element.js +99 -30
- package/dist/components/PieAssessmentToolkit.custom-element.js +120 -30
- package/dist/components/SectionToolBar.custom-element.js +99 -28
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/TTSService.d.ts +4 -0
- package/dist/services/TTSService.js +54 -20
- package/dist/services/TTSService.js.map +1 -1
- package/dist/services/ToolkitCoordinator.d.ts +3 -2
- package/dist/services/ToolkitCoordinator.js.map +1 -1
- package/dist/services/interfaces.d.ts +4 -0
- package/dist/services/interfaces.js.map +1 -1
- package/dist/services/tts-runtime-config.d.ts +15 -1
- package/dist/services/tts-runtime-config.js +76 -10
- package/dist/services/tts-runtime-config.js.map +1 -1
- package/dist/tools/registrations/tts.js +6 -8
- package/dist/tools/registrations/tts.js.map +1 -1
- package/package.json +7 -7
- package/dist/tools/default-tool-module-loaders.d.ts +0 -2
- package/dist/tools/default-tool-module-loaders.js +0 -28
- package/dist/tools/default-tool-module-loaders.js.map +0 -1
package/README.md
CHANGED
|
@@ -616,12 +616,37 @@ tools: {
|
|
|
616
616
|
}
|
|
617
617
|
```
|
|
618
618
|
|
|
619
|
+
Hosts that need semantic UI copy can use object-form options. The `rate` still
|
|
620
|
+
drives playback and provider mapping; `label` / `ariaLabel` only change visible
|
|
621
|
+
and accessible button text.
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
tools: {
|
|
625
|
+
providers: {
|
|
626
|
+
textToSpeech: {
|
|
627
|
+
enabled: true,
|
|
628
|
+
backend: "server",
|
|
629
|
+
serverProvider: "custom",
|
|
630
|
+
settings: {
|
|
631
|
+
speedOptions: [
|
|
632
|
+
{ rate: 0.8, label: "Slow", ariaLabel: "Slow speed" },
|
|
633
|
+
{ rate: 1.5, label: "Fast", ariaLabel: "Fast speed" }
|
|
634
|
+
]
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
619
641
|
`speedOptions` semantics:
|
|
620
642
|
|
|
621
643
|
- Omitted or non-array: default speed buttons are shown (`0.8x`, `1.25x`).
|
|
622
644
|
- Explicit empty array (`[]`): hide all speed buttons.
|
|
623
645
|
- Invalid-only arrays (for example `["fast", -1, 1]`): fall back to defaults.
|
|
624
646
|
- Valid numeric values are deduplicated and keep first-seen order.
|
|
647
|
+
- Object-form entries use the same numeric validation/deduping by `rate`.
|
|
648
|
+
- Missing labels fall back to numeric text like `1.5x`; missing `ariaLabel`
|
|
649
|
+
falls back to a matching accessible name like `Fast speed`.
|
|
625
650
|
- `1` is excluded (normal speed is already available by toggling active speed off).
|
|
626
651
|
|
|
627
652
|
### Runtime Fallback: Server TTS -> Browser TTS
|
|
@@ -6871,22 +6871,81 @@ var isServerBackend = (backend) => backend === "polly" || backend === "google" |
|
|
|
6871
6871
|
var withDefault = (value, fallback2) => value === undefined ? fallback2 : value;
|
|
6872
6872
|
var normalizeTTSLayoutMode = (value, fallback2 = "left-aligned") => typeof value === "string" && VALID_TTS_LAYOUT_MODES.has(value) ? value : fallback2;
|
|
6873
6873
|
var DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);
|
|
6874
|
-
var
|
|
6874
|
+
var normalizeSpeedRate = (entry) => {
|
|
6875
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
6876
|
+
return;
|
|
6877
|
+
}
|
|
6878
|
+
const rounded = Math.round(entry * 100) / 100;
|
|
6879
|
+
return rounded === 1 ? undefined : rounded;
|
|
6880
|
+
};
|
|
6881
|
+
var trimOptionalText = (value) => {
|
|
6882
|
+
if (typeof value !== "string")
|
|
6883
|
+
return;
|
|
6884
|
+
const trimmed = value.trim();
|
|
6885
|
+
return trimmed.length ? trimmed : undefined;
|
|
6886
|
+
};
|
|
6887
|
+
var formatSpeedLabel = (rate) => `${rate}x`;
|
|
6888
|
+
var formatSpeedAriaLabel = (label, usedDefaultLabel) => usedDefaultLabel ? `Speed ${label}` : `${label} speed`;
|
|
6889
|
+
var normalizeSpeedAriaLabel = (label, ariaLabel, usedDefaultLabel) => {
|
|
6890
|
+
if (!ariaLabel)
|
|
6891
|
+
return formatSpeedAriaLabel(label, usedDefaultLabel);
|
|
6892
|
+
if (ariaLabel.toLowerCase().includes(label.toLowerCase()))
|
|
6893
|
+
return ariaLabel;
|
|
6894
|
+
return `${label} ${ariaLabel}`;
|
|
6895
|
+
};
|
|
6896
|
+
var normalizeTTSSpeedOptionConfig = (entry) => {
|
|
6897
|
+
if (typeof entry === "number")
|
|
6898
|
+
return normalizeSpeedRate(entry);
|
|
6899
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
6900
|
+
return;
|
|
6901
|
+
const record = entry;
|
|
6902
|
+
const rate = normalizeSpeedRate(record.rate);
|
|
6903
|
+
if (rate === undefined)
|
|
6904
|
+
return;
|
|
6905
|
+
const label = trimOptionalText(record.label);
|
|
6906
|
+
const ariaLabel = trimOptionalText(record.ariaLabel);
|
|
6907
|
+
return {
|
|
6908
|
+
rate,
|
|
6909
|
+
...label ? { label } : {},
|
|
6910
|
+
...ariaLabel ? { ariaLabel } : {}
|
|
6911
|
+
};
|
|
6912
|
+
};
|
|
6913
|
+
var normalizeTTSSpeedOptionConfigs = (value) => {
|
|
6875
6914
|
if (!Array.isArray(value))
|
|
6876
6915
|
return [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
6877
6916
|
if (value.length === 0)
|
|
6878
6917
|
return [];
|
|
6879
|
-
const
|
|
6918
|
+
const dedupedRates = new Set;
|
|
6919
|
+
const normalized = [];
|
|
6880
6920
|
for (const entry of value) {
|
|
6881
|
-
|
|
6921
|
+
const option = normalizeTTSSpeedOptionConfig(entry);
|
|
6922
|
+
if (option === undefined)
|
|
6882
6923
|
continue;
|
|
6883
|
-
const
|
|
6884
|
-
if (
|
|
6924
|
+
const rate = typeof option === "number" ? option : option.rate;
|
|
6925
|
+
if (dedupedRates.has(rate))
|
|
6885
6926
|
continue;
|
|
6886
|
-
|
|
6927
|
+
dedupedRates.add(rate);
|
|
6928
|
+
normalized.push(option);
|
|
6887
6929
|
}
|
|
6888
|
-
return
|
|
6930
|
+
return normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
6889
6931
|
};
|
|
6932
|
+
var normalizeTTSSpeedControlOptions = (value) => normalizeTTSSpeedOptionConfigs(value).map((option) => {
|
|
6933
|
+
if (typeof option === "number") {
|
|
6934
|
+
const label2 = formatSpeedLabel(option);
|
|
6935
|
+
return {
|
|
6936
|
+
rate: option,
|
|
6937
|
+
label: label2,
|
|
6938
|
+
ariaLabel: formatSpeedAriaLabel(label2, true)
|
|
6939
|
+
};
|
|
6940
|
+
}
|
|
6941
|
+
const defaultLabel = formatSpeedLabel(option.rate);
|
|
6942
|
+
const label = option.label || defaultLabel;
|
|
6943
|
+
return {
|
|
6944
|
+
rate: option.rate,
|
|
6945
|
+
label,
|
|
6946
|
+
ariaLabel: normalizeSpeedAriaLabel(label, option.ariaLabel, label === defaultLabel)
|
|
6947
|
+
};
|
|
6948
|
+
});
|
|
6890
6949
|
var applyRuntimeDefaults = (config) => {
|
|
6891
6950
|
const withLayoutDefaults = {
|
|
6892
6951
|
...config,
|
|
@@ -7043,7 +7102,7 @@ var ttsToolRegistration = {
|
|
|
7043
7102
|
settings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);
|
|
7044
7103
|
}
|
|
7045
7104
|
if (settings && "speedOptions" in settings) {
|
|
7046
|
-
settings.speedOptions =
|
|
7105
|
+
settings.speedOptions = normalizeTTSSpeedOptionConfigs(settings.speedOptions);
|
|
7047
7106
|
}
|
|
7048
7107
|
const normalizedConfig = {
|
|
7049
7108
|
...config
|
|
@@ -7052,7 +7111,7 @@ var ttsToolRegistration = {
|
|
|
7052
7111
|
normalizedConfig.layoutMode = normalizeTTSLayoutMode(normalizedConfig.layoutMode);
|
|
7053
7112
|
}
|
|
7054
7113
|
if ("speedOptions" in normalizedConfig) {
|
|
7055
|
-
normalizedConfig.speedOptions =
|
|
7114
|
+
normalizedConfig.speedOptions = normalizeTTSSpeedOptionConfigs(normalizedConfig.speedOptions);
|
|
7056
7115
|
}
|
|
7057
7116
|
if (settings) {
|
|
7058
7117
|
normalizedConfig.settings = settings;
|
|
@@ -7075,7 +7134,7 @@ var ttsToolRegistration = {
|
|
|
7075
7134
|
const resolveRuntimeSettings = () => resolveTTSRuntimeSettings(toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) || undefined);
|
|
7076
7135
|
const resolveElementSpeedOptions = () => {
|
|
7077
7136
|
const runtimeSettings = resolveRuntimeSettings();
|
|
7078
|
-
return
|
|
7137
|
+
return normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);
|
|
7079
7138
|
};
|
|
7080
7139
|
const resolveLayoutMode = () => resolveTTSLayoutMode(resolveRuntimeSettings());
|
|
7081
7140
|
const resolveHostLayout = () => resolveTTSHostToolbarLayout(resolveRuntimeSettings());
|
|
@@ -7718,21 +7777,6 @@ function createPackagedToolRegistry(options = {}) {
|
|
|
7718
7777
|
});
|
|
7719
7778
|
}
|
|
7720
7779
|
|
|
7721
|
-
// dist/tools/default-tool-module-loaders.js
|
|
7722
|
-
var loadSideEffectModule = (load) => load().then(() => {
|
|
7723
|
-
return;
|
|
7724
|
-
});
|
|
7725
|
-
function loadCalculatorModule() {
|
|
7726
|
-
if (typeof globalThis !== "undefined" && "customElements" in globalThis && globalThis.customElements?.get("pie-tool-calculator")) {
|
|
7727
|
-
return Promise.resolve();
|
|
7728
|
-
}
|
|
7729
|
-
return loadSideEffectModule(() => import("@pie-players/pie-tool-calculator-desmos"));
|
|
7730
|
-
}
|
|
7731
|
-
var DEFAULT_TOOL_MODULE_LOADERS = {
|
|
7732
|
-
calculator: loadCalculatorModule,
|
|
7733
|
-
textToSpeech: () => loadSideEffectModule(() => import("@pie-players/pie-tool-tts-inline"))
|
|
7734
|
-
};
|
|
7735
|
-
|
|
7736
7780
|
// dist/components/vendor/nds/nds-icon-button.js
|
|
7737
7781
|
var H = globalThis;
|
|
7738
7782
|
var D = H.ShadowRoot && (H.ShadyCSS === undefined || H.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype;
|
|
@@ -8707,7 +8751,7 @@ function ItemToolBar($$anchor, $$props) {
|
|
|
8707
8751
|
installFaInToolbarShadow(node);
|
|
8708
8752
|
return {};
|
|
8709
8753
|
};
|
|
8710
|
-
const fallbackToolRegistry = createPackagedToolRegistry(
|
|
8754
|
+
const fallbackToolRegistry = createPackagedToolRegistry();
|
|
8711
8755
|
let activeToolState = state(proxy({}));
|
|
8712
8756
|
let level = prop($$props, "level", 7, "item"), scopeId = prop($$props, "scopeId", 7, ""), itemId = prop($$props, "itemId", 7, ""), sectionId = prop($$props, "sectionId", 7, ""), catalogId = prop($$props, "catalogId", 7, ""), tools = prop($$props, "tools", 7, "calculator,textToSpeech,answerEliminator"), contentKind = prop($$props, "contentKind", 7, "assessment-item"), position = prop($$props, "position", 7, "bottom"), scopeElement = prop($$props, "scopeElement", 7, null), toolRegistry = prop($$props, "toolRegistry", 7, null), item = prop($$props, "item", 7, null), hostButtons = prop($$props, "hostButtons", 23, () => []), className = prop($$props, "class", 7, ""), size = prop($$props, "size", 7, "md"), language = prop($$props, "language", 7, "en-US");
|
|
8713
8757
|
let toolbarRootElement = state(null);
|
|
@@ -9349,13 +9393,34 @@ function ItemToolBar($$anchor, $$props) {
|
|
|
9349
9393
|
const maxHeight = shellConfig?.maxHeight ?? window.innerHeight;
|
|
9350
9394
|
return { minWidth, minHeight, maxWidth, maxHeight };
|
|
9351
9395
|
};
|
|
9396
|
+
const applyContentMinWidth = () => {
|
|
9397
|
+
const configuredMinWidth = currentArgs.mounted.entry.shell?.minWidth;
|
|
9398
|
+
const shouldScroll = typeof configuredMinWidth === "number" && configuredMinWidth > 0 && width < configuredMinWidth;
|
|
9399
|
+
const minWidthValue = shouldScroll ? `${configuredMinWidth}px` : "";
|
|
9400
|
+
if (mountedContentElement) {
|
|
9401
|
+
mountedContentElement.style.minWidth = minWidthValue;
|
|
9402
|
+
}
|
|
9403
|
+
if (headerEl) {
|
|
9404
|
+
headerEl.style.minWidth = minWidthValue;
|
|
9405
|
+
}
|
|
9406
|
+
if (contentEl) {
|
|
9407
|
+
contentEl.style.minWidth = minWidthValue;
|
|
9408
|
+
}
|
|
9409
|
+
if (shellEl) {
|
|
9410
|
+
shellEl.style.overflowX = shouldScroll ? "auto" : "visible";
|
|
9411
|
+
shellEl.style.overflowY = "visible";
|
|
9412
|
+
}
|
|
9413
|
+
};
|
|
9352
9414
|
const applyPositionAndSize = () => {
|
|
9353
9415
|
const { minWidth, minHeight, maxWidth, maxHeight } = getShellBounds();
|
|
9354
|
-
|
|
9355
|
-
|
|
9416
|
+
const effectiveMinWidth = Math.min(minWidth, window.innerWidth);
|
|
9417
|
+
const effectiveMinHeight = Math.min(minHeight, window.innerHeight);
|
|
9418
|
+
width = clamp(width, effectiveMinWidth, Math.max(effectiveMinWidth, Math.min(maxWidth, window.innerWidth)));
|
|
9419
|
+
height = clamp(height, effectiveMinHeight, Math.max(effectiveMinHeight, Math.min(maxHeight, window.innerHeight)));
|
|
9356
9420
|
x2 = clamp(x2, 0, Math.max(0, window.innerWidth - width));
|
|
9357
9421
|
y2 = clamp(y2, 0, Math.max(0, window.innerHeight - height));
|
|
9358
9422
|
applyShellStyle();
|
|
9423
|
+
applyContentMinWidth();
|
|
9359
9424
|
notifyHostedResize();
|
|
9360
9425
|
};
|
|
9361
9426
|
const moveBy = (dx, dy) => {
|
|
@@ -9456,6 +9521,7 @@ function ItemToolBar($$anchor, $$props) {
|
|
|
9456
9521
|
element2.style.height = "100%";
|
|
9457
9522
|
element2.style.flex = "1 1 auto";
|
|
9458
9523
|
element2.style.minHeight = "0";
|
|
9524
|
+
applyContentMinWidth();
|
|
9459
9525
|
if (mountedContentElement && mountedContentElement !== element2) {
|
|
9460
9526
|
if (mountedContentElement.parentNode === contentEl) {
|
|
9461
9527
|
invokeElementUnmount(mountedContentElement);
|
|
@@ -9704,8 +9770,10 @@ function ItemToolBar($$anchor, $$props) {
|
|
|
9704
9770
|
if (resizePointerId === event2.pointerId) {
|
|
9705
9771
|
event2.preventDefault();
|
|
9706
9772
|
const shellConfig = currentArgs.mounted.entry.shell;
|
|
9707
|
-
const
|
|
9708
|
-
const
|
|
9773
|
+
const configuredMinWidth = shellConfig?.minWidth ?? 320;
|
|
9774
|
+
const configuredMinHeight = shellConfig?.minHeight ?? 240;
|
|
9775
|
+
const minWidth = Math.min(configuredMinWidth, window.innerWidth);
|
|
9776
|
+
const minHeight = Math.min(configuredMinHeight, window.innerHeight);
|
|
9709
9777
|
const maxWidth = shellConfig?.maxWidth ?? window.innerWidth;
|
|
9710
9778
|
const maxHeight = shellConfig?.maxHeight ?? window.innerHeight;
|
|
9711
9779
|
const dx = event2.clientX - resizeStartX;
|
|
@@ -9736,6 +9804,7 @@ function ItemToolBar($$anchor, $$props) {
|
|
|
9736
9804
|
height = newHeight;
|
|
9737
9805
|
}
|
|
9738
9806
|
applyShellStyle();
|
|
9807
|
+
applyContentMinWidth();
|
|
9739
9808
|
notifyHostedResize();
|
|
9740
9809
|
}
|
|
9741
9810
|
};
|
|
@@ -39,7 +39,7 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
39
39
|
|
|
40
40
|
// ../../node_modules/.bun/speech-rule-engine@5.0.0-rc.1/node_modules/speech-rule-engine/lib/sre.js
|
|
41
41
|
var require_sre = __commonJS((exports, module) => {
|
|
42
|
-
var __dirname = "/
|
|
42
|
+
var __dirname = "/home/runner/work/pie-players/pie-players/node_modules/.bun/speech-rule-engine@5.0.0-rc.1/node_modules/speech-rule-engine/lib";
|
|
43
43
|
(function(t, e) {
|
|
44
44
|
typeof exports == "object" && typeof module == "object" ? module.exports = e() : typeof define == "function" && define.amd ? define([], e) : typeof exports == "object" ? exports.SRE = e() : t.SRE = e();
|
|
45
45
|
})(exports, () => (() => {
|
|
@@ -18971,22 +18971,81 @@ var isServerBackend = (backend) => backend === "polly" || backend === "google" |
|
|
|
18971
18971
|
var withDefault = (value, fallback2) => value === undefined ? fallback2 : value;
|
|
18972
18972
|
var normalizeTTSLayoutMode = (value, fallback2 = "left-aligned") => typeof value === "string" && VALID_TTS_LAYOUT_MODES.has(value) ? value : fallback2;
|
|
18973
18973
|
var DEFAULT_TTS_SPEED_OPTIONS = Object.freeze([0.8, 1.25]);
|
|
18974
|
-
var
|
|
18974
|
+
var normalizeSpeedRate = (entry) => {
|
|
18975
|
+
if (typeof entry !== "number" || !Number.isFinite(entry) || entry <= 0) {
|
|
18976
|
+
return;
|
|
18977
|
+
}
|
|
18978
|
+
const rounded = Math.round(entry * 100) / 100;
|
|
18979
|
+
return rounded === 1 ? undefined : rounded;
|
|
18980
|
+
};
|
|
18981
|
+
var trimOptionalText = (value) => {
|
|
18982
|
+
if (typeof value !== "string")
|
|
18983
|
+
return;
|
|
18984
|
+
const trimmed = value.trim();
|
|
18985
|
+
return trimmed.length ? trimmed : undefined;
|
|
18986
|
+
};
|
|
18987
|
+
var formatSpeedLabel = (rate) => `${rate}x`;
|
|
18988
|
+
var formatSpeedAriaLabel = (label, usedDefaultLabel) => usedDefaultLabel ? `Speed ${label}` : `${label} speed`;
|
|
18989
|
+
var normalizeSpeedAriaLabel = (label, ariaLabel, usedDefaultLabel) => {
|
|
18990
|
+
if (!ariaLabel)
|
|
18991
|
+
return formatSpeedAriaLabel(label, usedDefaultLabel);
|
|
18992
|
+
if (ariaLabel.toLowerCase().includes(label.toLowerCase()))
|
|
18993
|
+
return ariaLabel;
|
|
18994
|
+
return `${label} ${ariaLabel}`;
|
|
18995
|
+
};
|
|
18996
|
+
var normalizeTTSSpeedOptionConfig = (entry) => {
|
|
18997
|
+
if (typeof entry === "number")
|
|
18998
|
+
return normalizeSpeedRate(entry);
|
|
18999
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
19000
|
+
return;
|
|
19001
|
+
const record = entry;
|
|
19002
|
+
const rate = normalizeSpeedRate(record.rate);
|
|
19003
|
+
if (rate === undefined)
|
|
19004
|
+
return;
|
|
19005
|
+
const label = trimOptionalText(record.label);
|
|
19006
|
+
const ariaLabel = trimOptionalText(record.ariaLabel);
|
|
19007
|
+
return {
|
|
19008
|
+
rate,
|
|
19009
|
+
...label ? { label } : {},
|
|
19010
|
+
...ariaLabel ? { ariaLabel } : {}
|
|
19011
|
+
};
|
|
19012
|
+
};
|
|
19013
|
+
var normalizeTTSSpeedOptionConfigs = (value) => {
|
|
18975
19014
|
if (!Array.isArray(value))
|
|
18976
19015
|
return [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
18977
19016
|
if (value.length === 0)
|
|
18978
19017
|
return [];
|
|
18979
|
-
const
|
|
19018
|
+
const dedupedRates = new Set;
|
|
19019
|
+
const normalized = [];
|
|
18980
19020
|
for (const entry of value) {
|
|
18981
|
-
|
|
19021
|
+
const option = normalizeTTSSpeedOptionConfig(entry);
|
|
19022
|
+
if (option === undefined)
|
|
18982
19023
|
continue;
|
|
18983
|
-
const
|
|
18984
|
-
if (
|
|
19024
|
+
const rate = typeof option === "number" ? option : option.rate;
|
|
19025
|
+
if (dedupedRates.has(rate))
|
|
18985
19026
|
continue;
|
|
18986
|
-
|
|
19027
|
+
dedupedRates.add(rate);
|
|
19028
|
+
normalized.push(option);
|
|
18987
19029
|
}
|
|
18988
|
-
return
|
|
19030
|
+
return normalized.length ? normalized : [...DEFAULT_TTS_SPEED_OPTIONS];
|
|
18989
19031
|
};
|
|
19032
|
+
var normalizeTTSSpeedControlOptions = (value) => normalizeTTSSpeedOptionConfigs(value).map((option) => {
|
|
19033
|
+
if (typeof option === "number") {
|
|
19034
|
+
const label2 = formatSpeedLabel(option);
|
|
19035
|
+
return {
|
|
19036
|
+
rate: option,
|
|
19037
|
+
label: label2,
|
|
19038
|
+
ariaLabel: formatSpeedAriaLabel(label2, true)
|
|
19039
|
+
};
|
|
19040
|
+
}
|
|
19041
|
+
const defaultLabel = formatSpeedLabel(option.rate);
|
|
19042
|
+
const label = option.label || defaultLabel;
|
|
19043
|
+
return {
|
|
19044
|
+
rate: option.rate,
|
|
19045
|
+
label,
|
|
19046
|
+
ariaLabel: normalizeSpeedAriaLabel(label, option.ariaLabel, label === defaultLabel)
|
|
19047
|
+
};
|
|
19048
|
+
});
|
|
18990
19049
|
var applyRuntimeDefaults = (config) => {
|
|
18991
19050
|
const withLayoutDefaults = {
|
|
18992
19051
|
...config,
|
|
@@ -19143,7 +19202,7 @@ var ttsToolRegistration = {
|
|
|
19143
19202
|
settings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);
|
|
19144
19203
|
}
|
|
19145
19204
|
if (settings && "speedOptions" in settings) {
|
|
19146
|
-
settings.speedOptions =
|
|
19205
|
+
settings.speedOptions = normalizeTTSSpeedOptionConfigs(settings.speedOptions);
|
|
19147
19206
|
}
|
|
19148
19207
|
const normalizedConfig = {
|
|
19149
19208
|
...config
|
|
@@ -19152,7 +19211,7 @@ var ttsToolRegistration = {
|
|
|
19152
19211
|
normalizedConfig.layoutMode = normalizeTTSLayoutMode(normalizedConfig.layoutMode);
|
|
19153
19212
|
}
|
|
19154
19213
|
if ("speedOptions" in normalizedConfig) {
|
|
19155
|
-
normalizedConfig.speedOptions =
|
|
19214
|
+
normalizedConfig.speedOptions = normalizeTTSSpeedOptionConfigs(normalizedConfig.speedOptions);
|
|
19156
19215
|
}
|
|
19157
19216
|
if (settings) {
|
|
19158
19217
|
normalizedConfig.settings = settings;
|
|
@@ -19175,7 +19234,7 @@ var ttsToolRegistration = {
|
|
|
19175
19234
|
const resolveRuntimeSettings = () => resolveTTSRuntimeSettings(toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) || undefined);
|
|
19176
19235
|
const resolveElementSpeedOptions = () => {
|
|
19177
19236
|
const runtimeSettings = resolveRuntimeSettings();
|
|
19178
|
-
return
|
|
19237
|
+
return normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);
|
|
19179
19238
|
};
|
|
19180
19239
|
const resolveLayoutMode = () => resolveTTSLayoutMode(resolveRuntimeSettings());
|
|
19181
19240
|
const resolveHostLayout = () => resolveTTSHostToolbarLayout(resolveRuntimeSettings());
|
|
@@ -23839,6 +23898,7 @@ class TTSService {
|
|
|
23839
23898
|
lastError = null;
|
|
23840
23899
|
speakRunId = 0;
|
|
23841
23900
|
currentBoundaryOffset = 0;
|
|
23901
|
+
activeWordBoundaryOffset = 0;
|
|
23842
23902
|
seekSegments = [];
|
|
23843
23903
|
sentenceHighlightSegments = [];
|
|
23844
23904
|
currentSeekSegmentIndex = 0;
|
|
@@ -24232,11 +24292,11 @@ class TTSService {
|
|
|
24232
24292
|
this.currentBoundaryOffset = 0;
|
|
24233
24293
|
const originalOnWordBoundary = this.provider.onWordBoundary;
|
|
24234
24294
|
this.provider.onWordBoundary = (word, position, length) => {
|
|
24295
|
+
originalOnWordBoundary?.(word, position, length);
|
|
24235
24296
|
if (Number.isFinite(position)) {
|
|
24236
24297
|
this.currentBoundaryOffset = position;
|
|
24237
24298
|
this.currentSeekSegmentIndex = this.getCurrentSeekSegmentIndex();
|
|
24238
24299
|
}
|
|
24239
|
-
originalOnWordBoundary?.(word, position, length);
|
|
24240
24300
|
};
|
|
24241
24301
|
try {
|
|
24242
24302
|
await providerWithPlan.speakSegments(segments);
|
|
@@ -24247,6 +24307,10 @@ class TTSService {
|
|
|
24247
24307
|
}
|
|
24248
24308
|
return;
|
|
24249
24309
|
}
|
|
24310
|
+
this.configureWordBoundaryHighlighting({
|
|
24311
|
+
highlightMode: options?.highlightMode || "word",
|
|
24312
|
+
wordBoundaryOffset: this.activeWordBoundaryOffset
|
|
24313
|
+
});
|
|
24250
24314
|
for (const segment of segments) {
|
|
24251
24315
|
if (runId !== this.speakRunId)
|
|
24252
24316
|
return;
|
|
@@ -24366,6 +24430,7 @@ class TTSService {
|
|
|
24366
24430
|
this.initializeSpeakTracking(highlightText, options);
|
|
24367
24431
|
const highlightMode = options?.highlightModeOverride || (speechMatchesVisibleText ? this.resolveHighlightMode() : "sentence");
|
|
24368
24432
|
this.activeHighlightMode = highlightMode;
|
|
24433
|
+
this.activeWordBoundaryOffset = options?.wordBoundaryOffset || 0;
|
|
24369
24434
|
const hasExplicitBreaks = this.hasExplicitBreakSemantics(contentToSpeak);
|
|
24370
24435
|
const shouldUsePlan = !!this.currentContentElement && !usedCatalogSpoken && !hasExplicitBreaks && speechMatchesVisibleText;
|
|
24371
24436
|
this.seekSegments = hasExplicitBreaks || !speechMatchesVisibleText ? [] : shouldUsePlan && this.currentContentElement ? this.createSpeechPlan(this.currentContentElement, normalizedText) : this.createSeekSegmentsFromText(highlightText);
|
|
@@ -24951,6 +25016,7 @@ class TTSService {
|
|
|
24951
25016
|
this.currentContentElement = null;
|
|
24952
25017
|
this.normalizedToDOM.clear();
|
|
24953
25018
|
this.currentBoundaryOffset = 0;
|
|
25019
|
+
this.activeWordBoundaryOffset = 0;
|
|
24954
25020
|
this.seekSegments = [];
|
|
24955
25021
|
this.sentenceHighlightSegments = [];
|
|
24956
25022
|
this.currentSeekSegmentIndex = 0;
|
|
@@ -25005,31 +25071,27 @@ class TTSService {
|
|
|
25005
25071
|
this.setState(PlaybackState.PLAYING);
|
|
25006
25072
|
}
|
|
25007
25073
|
}
|
|
25008
|
-
|
|
25009
|
-
if (!
|
|
25010
|
-
return;
|
|
25011
|
-
|
|
25012
|
-
|
|
25013
|
-
|
|
25014
|
-
if (this.
|
|
25015
|
-
return;
|
|
25016
|
-
if (this.seekSegments.length === 0)
|
|
25017
|
-
return;
|
|
25018
|
-
const delta = Number.isFinite(units) ? Math.trunc(units) : 0;
|
|
25019
|
-
if (delta === 0)
|
|
25020
|
-
return;
|
|
25021
|
-
const currentIndex = this.getCurrentSeekSegmentIndex();
|
|
25022
|
-
const targetIndex = Math.max(0, Math.min(this.seekSegments.length - 1, currentIndex + delta));
|
|
25023
|
-
if (targetIndex === currentIndex)
|
|
25074
|
+
normalizePlaybackRate(rate) {
|
|
25075
|
+
if (!Number.isFinite(rate))
|
|
25076
|
+
return 1;
|
|
25077
|
+
return Math.max(0.25, Math.min(4, rate));
|
|
25078
|
+
}
|
|
25079
|
+
async restartFromSeekIndex(targetIndex) {
|
|
25080
|
+
if (!this.provider || this.seekSegments.length === 0)
|
|
25024
25081
|
return;
|
|
25082
|
+
const safeTargetIndex = Math.max(0, Math.min(this.seekSegments.length - 1, targetIndex));
|
|
25025
25083
|
this.speakRunId += 1;
|
|
25026
25084
|
this.provider.onWordBoundary = undefined;
|
|
25027
25085
|
this.provider.stop();
|
|
25028
|
-
this.currentSeekSegmentIndex =
|
|
25086
|
+
this.currentSeekSegmentIndex = safeTargetIndex;
|
|
25029
25087
|
const runId = ++this.speakRunId;
|
|
25030
|
-
const restartSegments = this.seekSegments.slice(
|
|
25088
|
+
const restartSegments = this.seekSegments.slice(safeTargetIndex);
|
|
25031
25089
|
this.setState(PlaybackState.PLAYING);
|
|
25032
25090
|
try {
|
|
25091
|
+
this.configureWordBoundaryHighlighting({
|
|
25092
|
+
highlightMode: this.activeHighlightMode,
|
|
25093
|
+
wordBoundaryOffset: this.activeWordBoundaryOffset
|
|
25094
|
+
});
|
|
25033
25095
|
await this.speakWithPlan(restartSegments, runId, {
|
|
25034
25096
|
highlightMode: this.activeHighlightMode
|
|
25035
25097
|
});
|
|
@@ -25046,6 +25108,33 @@ class TTSService {
|
|
|
25046
25108
|
throw error;
|
|
25047
25109
|
}
|
|
25048
25110
|
}
|
|
25111
|
+
async setPlaybackRate(rate) {
|
|
25112
|
+
const nextRate = this.normalizePlaybackRate(rate);
|
|
25113
|
+
await this.updateSettings({ rate: nextRate });
|
|
25114
|
+
if (this.state !== PlaybackState.PLAYING || !this.currentText || this.seekSegments.length === 0 || this.hasExplicitBreakSemantics(this.currentText)) {
|
|
25115
|
+
return;
|
|
25116
|
+
}
|
|
25117
|
+
await this.restartFromSeekIndex(this.getCurrentSeekSegmentIndex());
|
|
25118
|
+
}
|
|
25119
|
+
async seekBy(units) {
|
|
25120
|
+
if (!this.provider || !this.currentText)
|
|
25121
|
+
return;
|
|
25122
|
+
if (this.state !== PlaybackState.PLAYING && this.state !== PlaybackState.PAUSED) {
|
|
25123
|
+
return;
|
|
25124
|
+
}
|
|
25125
|
+
if (this.hasExplicitBreakSemantics(this.currentText))
|
|
25126
|
+
return;
|
|
25127
|
+
if (this.seekSegments.length === 0)
|
|
25128
|
+
return;
|
|
25129
|
+
const delta = Number.isFinite(units) ? Math.trunc(units) : 0;
|
|
25130
|
+
if (delta === 0)
|
|
25131
|
+
return;
|
|
25132
|
+
const currentIndex = this.getCurrentSeekSegmentIndex();
|
|
25133
|
+
const targetIndex = Math.max(0, Math.min(this.seekSegments.length - 1, currentIndex + delta));
|
|
25134
|
+
if (targetIndex === currentIndex)
|
|
25135
|
+
return;
|
|
25136
|
+
await this.restartFromSeekIndex(targetIndex);
|
|
25137
|
+
}
|
|
25049
25138
|
async seekForward(units = 1) {
|
|
25050
25139
|
const step = Number.isFinite(units) ? Math.max(1, Math.trunc(units)) : 1;
|
|
25051
25140
|
await this.seekBy(step);
|
|
@@ -25069,6 +25158,7 @@ class TTSService {
|
|
|
25069
25158
|
this.currentContentElement = null;
|
|
25070
25159
|
this.normalizedToDOM.clear();
|
|
25071
25160
|
this.currentBoundaryOffset = 0;
|
|
25161
|
+
this.activeWordBoundaryOffset = 0;
|
|
25072
25162
|
this.seekSegments = [];
|
|
25073
25163
|
this.sentenceHighlightSegments = [];
|
|
25074
25164
|
this.currentSeekSegmentIndex = 0;
|