ssml-builder-js 2.16.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/{chunk-NKLZGITR.mjs → chunk-2SYLELUT.mjs} +4 -2
- package/dist/{chunk-NKLZGITR.mjs.map → chunk-2SYLELUT.mjs.map} +1 -1
- package/dist/{chunk-HI74FTKY.mjs → chunk-5AZWURHW.mjs} +4 -2
- package/dist/{chunk-HI74FTKY.mjs.map → chunk-5AZWURHW.mjs.map} +1 -1
- package/dist/{chunk-F2EMU3HM.mjs → chunk-SLZ7PE6W.mjs} +2 -2
- package/dist/core.d.mts +4 -0
- package/dist/core.d.ts +4 -0
- package/dist/core.js +3 -1
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/elements.js +3 -1
- package/dist/elements.js.map +1 -1
- package/dist/elements.mjs +2 -2
- package/dist/{index.d-DR5Qz43p.d.mts → index.d-tpKoP1jl.d.mts} +12 -1
- package/dist/{index.d-DR5Qz43p.d.ts → index.d-tpKoP1jl.d.ts} +12 -1
- package/dist/index.d.mts +78 -11
- package/dist/index.d.ts +78 -11
- package/dist/index.js +336 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +330 -72
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +5 -2
- package/dist/react.d.ts +5 -2
- package/dist/react.js +111 -25
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +110 -26
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
- /package/dist/{chunk-F2EMU3HM.mjs.map → chunk-SLZ7PE6W.mjs.map} +0 -0
package/dist/react.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement, CSSProperties } from 'react';
|
|
3
|
-
import { d as SsmlDocument, e as SsmlElement } from './index.d-
|
|
3
|
+
import { d as SsmlDocument, e as SsmlElement, f as AzureVoiceCatalogMetadata } from './index.d-tpKoP1jl.mjs';
|
|
4
4
|
import { OnMount, Monaco } from '@monaco-editor/react';
|
|
5
5
|
|
|
6
6
|
type SsmlEditorInsertionButton = "break" | "emphasis" | "rate" | "pitch" | "volume" | "emotion" | "say-as" | "phoneme" | "audio" | "sub" | "lang" | "mark" | "bookmark" | "mstts:silence" | "mstts:audioduration" | "mstts:viseme" | (string & {});
|
|
@@ -119,8 +119,9 @@ interface VisualSsmlEditorProps {
|
|
|
119
119
|
voiceModel?: string;
|
|
120
120
|
/** Alias for voiceModel. */
|
|
121
121
|
model?: string;
|
|
122
|
+
voiceCatalogMetadata?: AzureVoiceCatalogMetadata;
|
|
122
123
|
}
|
|
123
|
-
declare function VisualSsmlEditor({ document, readOnly, onChange, onPreviewSelection, locale, customInspectors, renderVoiceSelector, voiceCatalog, voiceLocale, voiceRegion, voiceStyle, voiceModel, model, }: VisualSsmlEditorProps): ReactElement;
|
|
124
|
+
declare function VisualSsmlEditor({ document, readOnly, onChange, onPreviewSelection, locale, customInspectors, renderVoiceSelector, voiceCatalog, voiceLocale, voiceRegion, voiceStyle, voiceModel, model, voiceCatalogMetadata, }: VisualSsmlEditorProps): ReactElement;
|
|
124
125
|
|
|
125
126
|
type SsmlEditorInsertionMode = "insert" | "wrap";
|
|
126
127
|
interface SsmlEditorInsertionOption {
|
|
@@ -310,6 +311,8 @@ interface SsmlEditorProps {
|
|
|
310
311
|
voiceModel?: string;
|
|
311
312
|
/** Alias for voiceModel. */
|
|
312
313
|
model?: string;
|
|
314
|
+
/** Metadata for the voice catalog snapshot, used to warn when it is stale. */
|
|
315
|
+
voiceCatalogMetadata?: AzureVoiceCatalogMetadata;
|
|
313
316
|
/** Candidate style values shown by the built-in emotion insertion. */
|
|
314
317
|
emotionStyles?: readonly string[];
|
|
315
318
|
/** Class name applied to the editor container. */
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ReactElement, CSSProperties } from 'react';
|
|
3
|
-
import { d as SsmlDocument, e as SsmlElement } from './index.d-
|
|
3
|
+
import { d as SsmlDocument, e as SsmlElement, f as AzureVoiceCatalogMetadata } from './index.d-tpKoP1jl.js';
|
|
4
4
|
import { OnMount, Monaco } from '@monaco-editor/react';
|
|
5
5
|
|
|
6
6
|
type SsmlEditorInsertionButton = "break" | "emphasis" | "rate" | "pitch" | "volume" | "emotion" | "say-as" | "phoneme" | "audio" | "sub" | "lang" | "mark" | "bookmark" | "mstts:silence" | "mstts:audioduration" | "mstts:viseme" | (string & {});
|
|
@@ -119,8 +119,9 @@ interface VisualSsmlEditorProps {
|
|
|
119
119
|
voiceModel?: string;
|
|
120
120
|
/** Alias for voiceModel. */
|
|
121
121
|
model?: string;
|
|
122
|
+
voiceCatalogMetadata?: AzureVoiceCatalogMetadata;
|
|
122
123
|
}
|
|
123
|
-
declare function VisualSsmlEditor({ document, readOnly, onChange, onPreviewSelection, locale, customInspectors, renderVoiceSelector, voiceCatalog, voiceLocale, voiceRegion, voiceStyle, voiceModel, model, }: VisualSsmlEditorProps): ReactElement;
|
|
124
|
+
declare function VisualSsmlEditor({ document, readOnly, onChange, onPreviewSelection, locale, customInspectors, renderVoiceSelector, voiceCatalog, voiceLocale, voiceRegion, voiceStyle, voiceModel, model, voiceCatalogMetadata, }: VisualSsmlEditorProps): ReactElement;
|
|
124
125
|
|
|
125
126
|
type SsmlEditorInsertionMode = "insert" | "wrap";
|
|
126
127
|
interface SsmlEditorInsertionOption {
|
|
@@ -310,6 +311,8 @@ interface SsmlEditorProps {
|
|
|
310
311
|
voiceModel?: string;
|
|
311
312
|
/** Alias for voiceModel. */
|
|
312
313
|
model?: string;
|
|
314
|
+
/** Metadata for the voice catalog snapshot, used to warn when it is stale. */
|
|
315
|
+
voiceCatalogMetadata?: AzureVoiceCatalogMetadata;
|
|
313
316
|
/** Candidate style values shown by the built-in emotion insertion. */
|
|
314
317
|
emotionStyles?: readonly string[];
|
|
315
318
|
/** Class name applied to the editor container. */
|
package/dist/react.js
CHANGED
|
@@ -1743,6 +1743,8 @@ function InsertionPopover({
|
|
|
1743
1743
|
toolbarButtonStyle,
|
|
1744
1744
|
emptyOptionsMessage,
|
|
1745
1745
|
isReadOnly,
|
|
1746
|
+
disabled = false,
|
|
1747
|
+
disabledReason,
|
|
1746
1748
|
isOpen,
|
|
1747
1749
|
menuPosition,
|
|
1748
1750
|
menuRef,
|
|
@@ -1760,7 +1762,7 @@ function InsertionPopover({
|
|
|
1760
1762
|
role: "menuitem",
|
|
1761
1763
|
style: editorStyles.toolbarOption,
|
|
1762
1764
|
title: option.descriptions?.[language] ?? insertion.descriptions[language],
|
|
1763
|
-
disabled: isReadOnly,
|
|
1765
|
+
disabled: isReadOnly || disabled,
|
|
1764
1766
|
onMouseDown: (event) => event.preventDefault(),
|
|
1765
1767
|
onClick: () => {
|
|
1766
1768
|
if (!isReadOnly) {
|
|
@@ -1789,11 +1791,12 @@ function InsertionPopover({
|
|
|
1789
1791
|
{
|
|
1790
1792
|
type: "button",
|
|
1791
1793
|
style: toolbarButtonStyle,
|
|
1792
|
-
title: getInsertionTitle(insertion, language),
|
|
1794
|
+
title: disabledReason ?? getInsertionTitle(insertion, language),
|
|
1793
1795
|
"aria-label": insertion.labels[language],
|
|
1794
1796
|
"aria-haspopup": "menu",
|
|
1795
1797
|
"aria-expanded": isOpen,
|
|
1796
1798
|
"aria-controls": isOpen ? `ssml-editor-popover-${insertion.id}` : void 0,
|
|
1799
|
+
disabled: isReadOnly || disabled,
|
|
1797
1800
|
onClick: (event) => onToggle(event.currentTarget)
|
|
1798
1801
|
},
|
|
1799
1802
|
showToolbarIcons && /* @__PURE__ */ React.createElement("span", { style: editorStyles.toolbarIcon, "aria-hidden": "true" }, insertion.icon),
|
|
@@ -3747,7 +3750,9 @@ var AZURE_VOICE_CATALOG_METADATA = {
|
|
|
3747
3750
|
apiVersion: "2025-10-01",
|
|
3748
3751
|
generatedAt: "2026-08-28T00:00:00.000Z",
|
|
3749
3752
|
regions: [],
|
|
3750
|
-
voiceCount: AZURE_VOICE_DEFINITIONS.length
|
|
3753
|
+
voiceCount: AZURE_VOICE_DEFINITIONS.length,
|
|
3754
|
+
expiresAt: "2026-09-04T00:00:00.000Z",
|
|
3755
|
+
regionDiffs: {}
|
|
3751
3756
|
};
|
|
3752
3757
|
|
|
3753
3758
|
// packages/ssml-editor-react/src/clearSsmlDocument.ts
|
|
@@ -6884,6 +6889,21 @@ function filteredVoices(voiceCatalog, locale, region, style) {
|
|
|
6884
6889
|
return true;
|
|
6885
6890
|
});
|
|
6886
6891
|
}
|
|
6892
|
+
function voiceForPath(document2, path, voiceCatalog) {
|
|
6893
|
+
if (!path || !voiceCatalog) return void 0;
|
|
6894
|
+
const ancestors = getElementAncestors(document2.children ?? [], path);
|
|
6895
|
+
const node = getNodeAtPath(document2.children ?? [], path);
|
|
6896
|
+
const candidates = [...ancestors, ...node && isElement(node) ? [node] : []].reverse();
|
|
6897
|
+
const voiceName = candidates.find((element) => element.type === "voice")?.name ?? candidates.find((element) => element.type === "mstts:turn")?.voice;
|
|
6898
|
+
return voiceName ? voiceCatalog.find((voice) => voice.name.toLowerCase() === voiceName.toLowerCase()) : void 0;
|
|
6899
|
+
}
|
|
6900
|
+
function isVisualTagSupported(tagName, voice) {
|
|
6901
|
+
if (!voice) return true;
|
|
6902
|
+
const tag = tagName.toLowerCase();
|
|
6903
|
+
const unsupported = new Set((voice.unsupportedTags ?? []).map((candidate) => candidate.toLowerCase()));
|
|
6904
|
+
const supported = voice.supportedTags?.map((candidate) => candidate.toLowerCase());
|
|
6905
|
+
return !unsupported.has(tag) && (supported === void 0 || supported.includes(tag));
|
|
6906
|
+
}
|
|
6887
6907
|
function VoiceCapabilityMatrix({
|
|
6888
6908
|
voice,
|
|
6889
6909
|
locale
|
|
@@ -6958,10 +6978,12 @@ function VisualElementInspector({
|
|
|
6958
6978
|
voiceLocale,
|
|
6959
6979
|
voiceRegion,
|
|
6960
6980
|
voiceStyle,
|
|
6961
|
-
diagnostics
|
|
6981
|
+
diagnostics,
|
|
6982
|
+
voiceDefinition
|
|
6962
6983
|
}) {
|
|
6984
|
+
const tagSupported = isVisualTagSupported(elementLabel(element), voiceDefinition);
|
|
6963
6985
|
if (customInspector) {
|
|
6964
|
-
return /* @__PURE__ */ React.createElement(React.Fragment, null, customInspector({ document: document2, element, path, readOnly, onChange: commit, locale }));
|
|
6986
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, customInspector({ document: document2, element, path, readOnly: readOnly || !tagSupported, onChange: commit, locale }));
|
|
6965
6987
|
}
|
|
6966
6988
|
const fields = getElementFields(element);
|
|
6967
6989
|
const availableVoices = filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle);
|
|
@@ -6969,7 +6991,7 @@ function VisualElementInspector({
|
|
|
6969
6991
|
(voice) => voice.name === (element.type === "voice" ? element.name : void 0)
|
|
6970
6992
|
);
|
|
6971
6993
|
const renderSelector = renderVoiceSelector ?? DefaultVoiceSelector;
|
|
6972
|
-
return /* @__PURE__ */ React.createElement("fieldset",
|
|
6994
|
+
return /* @__PURE__ */ React.createElement("fieldset", { disabled: readOnly || !tagSupported, style: !tagSupported ? { border: "1px solid #c0392b" } : void 0 }, /* @__PURE__ */ React.createElement("legend", null, `<${elementLabel(element)}>`, " ", /* @__PURE__ */ React.createElement(WarningBadge, { messages: elementWarnings(diagnostics, element) })), fields.length === 0 ? /* @__PURE__ */ React.createElement("p", null, "This element is preserved in the visual tree. Edit its attributes in Code mode.") : fields.map((field) => {
|
|
6973
6995
|
const value = element[field.key];
|
|
6974
6996
|
const inputValue = value === void 0 ? "" : String(value);
|
|
6975
6997
|
const inputId = `ssml-visual-${field.key}`;
|
|
@@ -7018,6 +7040,7 @@ function VisualElementInspector({
|
|
|
7018
7040
|
{
|
|
7019
7041
|
id: inputId,
|
|
7020
7042
|
value: inputValue,
|
|
7043
|
+
disabled: readOnly || !tagSupported,
|
|
7021
7044
|
readOnly,
|
|
7022
7045
|
onChange: (event) => commit(updateOptionalElementProperty(document2, path, field.key, event.target.value))
|
|
7023
7046
|
}
|
|
@@ -7026,6 +7049,7 @@ function VisualElementInspector({
|
|
|
7026
7049
|
{
|
|
7027
7050
|
id: inputId,
|
|
7028
7051
|
value: inputValue,
|
|
7052
|
+
disabled: readOnly || !tagSupported,
|
|
7029
7053
|
readOnly,
|
|
7030
7054
|
onChange: (event) => commit(updateOptionalElementProperty(document2, path, field.key, event.target.value))
|
|
7031
7055
|
}
|
|
@@ -7089,18 +7113,27 @@ function TreeNode({
|
|
|
7089
7113
|
}) {
|
|
7090
7114
|
if (!isElement(node)) return null;
|
|
7091
7115
|
const name = elementLabel(node);
|
|
7116
|
+
const messages = getWarnings(node);
|
|
7092
7117
|
const isSelected = selectedPath?.join(".") === path.join(".");
|
|
7093
|
-
return /* @__PURE__ */ React.createElement(
|
|
7094
|
-
|
|
7118
|
+
return /* @__PURE__ */ React.createElement(
|
|
7119
|
+
"li",
|
|
7095
7120
|
{
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7121
|
+
"data-ssml-diagnostic": messages.length > 0 ? "error" : void 0,
|
|
7122
|
+
style: messages.length > 0 ? { border: "1px solid #c0392b", borderRadius: "0.25rem" } : void 0
|
|
7123
|
+
},
|
|
7124
|
+
/* @__PURE__ */ React.createElement("button", { type: "button", "aria-current": isSelected ? "true" : void 0, onClick: () => onSelect(path) }, `<${name}>`, /* @__PURE__ */ React.createElement(WarningBadge, { messages: getWarnings(node) })),
|
|
7125
|
+
(node.children ?? []).length > 0 && /* @__PURE__ */ React.createElement("ul", null, node.children?.map((child, index) => /* @__PURE__ */ React.createElement(
|
|
7126
|
+
TreeNode,
|
|
7127
|
+
{
|
|
7128
|
+
key: `${path.join(".")}/${isElement(child) ? elementLabel(child) : JSON.stringify(child)}`,
|
|
7129
|
+
node: child,
|
|
7130
|
+
path: [...path, index],
|
|
7131
|
+
selectedPath,
|
|
7132
|
+
onSelect,
|
|
7133
|
+
getWarnings
|
|
7134
|
+
}
|
|
7135
|
+
)))
|
|
7136
|
+
);
|
|
7104
7137
|
}
|
|
7105
7138
|
function VisualSsmlEditor({
|
|
7106
7139
|
document: document2,
|
|
@@ -7115,13 +7148,16 @@ function VisualSsmlEditor({
|
|
|
7115
7148
|
voiceRegion,
|
|
7116
7149
|
voiceStyle,
|
|
7117
7150
|
voiceModel,
|
|
7118
|
-
model
|
|
7151
|
+
model,
|
|
7152
|
+
voiceCatalogMetadata
|
|
7119
7153
|
}) {
|
|
7120
7154
|
const [selectedPath, setSelectedPath] = (0, import_react3.useState)(null);
|
|
7121
7155
|
const [selection, setSelection] = (0, import_react3.useState)({ start: 0, end: 0 });
|
|
7122
7156
|
const textLeaves = (0, import_react3.useMemo)(() => collectTextLeaves(document2.children ?? []), [document2]);
|
|
7123
7157
|
const selectedLeaf = textLeaves.find((leaf) => leaf.path.join(".") === selectedPath?.join(".")) ?? textLeaves[0];
|
|
7124
7158
|
const selectedElement = selectedPath ? getNodeAtPath(document2.children ?? [], selectedPath) : void 0;
|
|
7159
|
+
const activeVoice = voiceForPath(document2, selectedPath ?? selectedLeaf?.path, voiceCatalog);
|
|
7160
|
+
const staleCatalog = voiceCatalogMetadata?.expiresAt ? Date.parse(voiceCatalogMetadata.expiresAt) <= Date.now() : false;
|
|
7125
7161
|
const selectedCustomInspector = selectedElement && isElement(selectedElement) ? customInspectors?.[elementLabel(selectedElement)] ?? customInspectors?.[selectedElement.type] : void 0;
|
|
7126
7162
|
const validationOptions = (0, import_react3.useMemo)(
|
|
7127
7163
|
() => ({
|
|
@@ -7151,7 +7187,7 @@ function VisualSsmlEditor({
|
|
|
7151
7187
|
const end = selection.start === selection.end ? selectedLeaf.value.length : selection.end;
|
|
7152
7188
|
commit(wrapTextAtPath(document2, selectedLeaf.path, start, end, tag, attributes));
|
|
7153
7189
|
};
|
|
7154
|
-
return /* @__PURE__ */ React.createElement("div", { className: "ssml-editor-visual", "data-ssml-editor-visual": "" }, /* @__PURE__ */ React.createElement("fieldset", { className: "ssml-editor-visual-breadcrumb" }, /* @__PURE__ */ React.createElement("legend", null, "SSML structure breadcrumb"), /* @__PURE__ */ React.createElement("span", null, "<speak>"), selectedLeaf?.ancestors.map((ancestor, index) => /* @__PURE__ */ React.createElement("span", { key: selectedLeaf?.ancestors.slice(0, index + 1).join("/") }, " / <", ancestor, ">")), selectedPath && /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => setSelectedPath(null) }, "Clear parent")), diagnostics.length > 0 && /* @__PURE__ */ React.createElement("div", { role: "alert", "aria-invalid": "true", className: "ssml-editor-visual-errors" }, diagnostics.map((diagnostic) => /* @__PURE__ */ React.createElement("div", { key: `${diagnostic.code}-${diagnostic.message}` }, diagnostic.message))), /* @__PURE__ */ React.createElement("div", { className: "ssml-editor-visual-layout" }, /* @__PURE__ */ React.createElement("nav", { "aria-label": "SSML structure tree", className: "ssml-editor-visual-tree" }, /* @__PURE__ */ React.createElement("strong", null, "Structure"), /* @__PURE__ */ React.createElement("ul", null, document2.children?.map((node, index) => /* @__PURE__ */ React.createElement(
|
|
7190
|
+
return /* @__PURE__ */ React.createElement("div", { className: "ssml-editor-visual", "data-ssml-editor-visual": "" }, /* @__PURE__ */ React.createElement("fieldset", { className: "ssml-editor-visual-breadcrumb" }, /* @__PURE__ */ React.createElement("legend", null, "SSML structure breadcrumb"), /* @__PURE__ */ React.createElement("span", null, "<speak>"), selectedLeaf?.ancestors.map((ancestor, index) => /* @__PURE__ */ React.createElement("span", { key: selectedLeaf?.ancestors.slice(0, index + 1).join("/") }, " / <", ancestor, ">")), selectedPath && /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => setSelectedPath(null) }, "Clear parent")), diagnostics.length > 0 && /* @__PURE__ */ React.createElement("div", { role: "alert", "aria-invalid": "true", className: "ssml-editor-visual-errors" }, diagnostics.map((diagnostic) => /* @__PURE__ */ React.createElement("div", { key: `${diagnostic.code}-${diagnostic.message}` }, diagnostic.message))), staleCatalog && /* @__PURE__ */ React.createElement("div", { role: "status", className: "ssml-editor-visual-catalog-warning" }, locale === "ja" ? "\u97F3\u58F0\u30AB\u30BF\u30ED\u30B0\u304C\u53E4\u304F\u306A\u3063\u3066\u3044\u307E\u3059\u3002\u66F4\u65B0\u3057\u3066\u304F\u3060\u3055\u3044\u3002" : "The voice catalog is stale. Refresh it before synthesizing."), /* @__PURE__ */ React.createElement("div", { className: "ssml-editor-visual-layout" }, /* @__PURE__ */ React.createElement("nav", { "aria-label": "SSML structure tree", className: "ssml-editor-visual-tree" }, /* @__PURE__ */ React.createElement("strong", null, "Structure"), /* @__PURE__ */ React.createElement("ul", null, document2.children?.map((node, index) => /* @__PURE__ */ React.createElement(
|
|
7155
7191
|
TreeNode,
|
|
7156
7192
|
{
|
|
7157
7193
|
key: isElement(node) ? elementLabel(node) : JSON.stringify(node),
|
|
@@ -7165,14 +7201,14 @@ function VisualSsmlEditor({
|
|
|
7165
7201
|
document: document2,
|
|
7166
7202
|
element: selectedElement,
|
|
7167
7203
|
path: selectedPath ?? [],
|
|
7168
|
-
readOnly,
|
|
7204
|
+
readOnly: readOnly || !isVisualTagSupported(elementLabel(selectedElement), activeVoice),
|
|
7169
7205
|
onChange: commit,
|
|
7170
7206
|
locale
|
|
7171
7207
|
}) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:dialog" ? /* @__PURE__ */ React.createElement("fieldset", null, /* @__PURE__ */ React.createElement("legend", null, localizedElementLabel(selectedElement, locale)), /* @__PURE__ */ React.createElement("p", null, SSML_ELEMENT_COPY[locale][elementLabel(selectedElement)]?.description), /* @__PURE__ */ React.createElement(
|
|
7172
7208
|
"button",
|
|
7173
7209
|
{
|
|
7174
7210
|
type: "button",
|
|
7175
|
-
disabled: readOnly,
|
|
7211
|
+
disabled: readOnly || !isVisualTagSupported("mstts:dialog", activeVoice),
|
|
7176
7212
|
onClick: () => commit(addDialogTurn(document2, selectedPath ?? []))
|
|
7177
7213
|
},
|
|
7178
7214
|
locale === "ja" ? "\u30BF\u30FC\u30F3\u3092\u8FFD\u52A0" : "Add turn"
|
|
@@ -7254,7 +7290,8 @@ function VisualSsmlEditor({
|
|
|
7254
7290
|
voiceLocale,
|
|
7255
7291
|
voiceRegion,
|
|
7256
7292
|
voiceStyle,
|
|
7257
|
-
diagnostics
|
|
7293
|
+
diagnostics,
|
|
7294
|
+
voiceDefinition: activeVoice
|
|
7258
7295
|
}
|
|
7259
7296
|
) : selectedLeaf ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("label", null, "Text", /* @__PURE__ */ React.createElement(
|
|
7260
7297
|
"textarea",
|
|
@@ -7264,19 +7301,43 @@ function VisualSsmlEditor({
|
|
|
7264
7301
|
onSelect: (event) => setSelection({ start: event.currentTarget.selectionStart, end: event.currentTarget.selectionEnd }),
|
|
7265
7302
|
onChange: (event) => commit(updateTextAtPath(document2, selectedLeaf.path, event.target.value))
|
|
7266
7303
|
}
|
|
7267
|
-
)), /* @__PURE__ */ React.createElement("fieldset", { className: "ssml-editor-visual-actions" }, /* @__PURE__ */ React.createElement("legend", null, "Apply SSML formatting"), /* @__PURE__ */ React.createElement(
|
|
7304
|
+
)), /* @__PURE__ */ React.createElement("fieldset", { className: "ssml-editor-visual-actions" }, /* @__PURE__ */ React.createElement("legend", null, "Apply SSML formatting"), /* @__PURE__ */ React.createElement(
|
|
7268
7305
|
"button",
|
|
7269
7306
|
{
|
|
7270
7307
|
type: "button",
|
|
7271
|
-
disabled: readOnly,
|
|
7308
|
+
disabled: readOnly || !isVisualTagSupported("prosody", activeVoice),
|
|
7309
|
+
onClick: () => applyWrapper("prosody", { rate: "slow" })
|
|
7310
|
+
},
|
|
7311
|
+
"Rate"
|
|
7312
|
+
), /* @__PURE__ */ React.createElement(
|
|
7313
|
+
"button",
|
|
7314
|
+
{
|
|
7315
|
+
type: "button",
|
|
7316
|
+
disabled: readOnly || !isVisualTagSupported("prosody", activeVoice),
|
|
7317
|
+
onClick: () => applyWrapper("prosody", { pitch: "high" })
|
|
7318
|
+
},
|
|
7319
|
+
"Pitch"
|
|
7320
|
+
), /* @__PURE__ */ React.createElement(
|
|
7321
|
+
"button",
|
|
7322
|
+
{
|
|
7323
|
+
type: "button",
|
|
7324
|
+
disabled: readOnly || !isVisualTagSupported("mstts:express-as", activeVoice),
|
|
7272
7325
|
onClick: () => applyWrapper("mstts:express-as", { style: "cheerful" })
|
|
7273
7326
|
},
|
|
7274
7327
|
"Emotion"
|
|
7275
|
-
), /* @__PURE__ */ React.createElement(
|
|
7328
|
+
), /* @__PURE__ */ React.createElement(
|
|
7276
7329
|
"button",
|
|
7277
7330
|
{
|
|
7278
7331
|
type: "button",
|
|
7279
|
-
disabled: readOnly,
|
|
7332
|
+
disabled: readOnly || !isVisualTagSupported("break", activeVoice),
|
|
7333
|
+
onClick: () => applyWrapper("break", { time: "500ms" })
|
|
7334
|
+
},
|
|
7335
|
+
"Pause"
|
|
7336
|
+
), /* @__PURE__ */ React.createElement(
|
|
7337
|
+
"button",
|
|
7338
|
+
{
|
|
7339
|
+
type: "button",
|
|
7340
|
+
disabled: readOnly || !isVisualTagSupported("phoneme", activeVoice),
|
|
7280
7341
|
onClick: () => applyWrapper("phoneme", { alphabet: "ipa", ph: selectedLeaf.value })
|
|
7281
7342
|
},
|
|
7282
7343
|
"Pronunciation"
|
|
@@ -7295,6 +7356,23 @@ var UNGROUPED_TOOLBAR_GROUP = "__ssml-editor-ungrouped__";
|
|
|
7295
7356
|
var TIMING_POPOVER_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence", "mstts:audioduration"]);
|
|
7296
7357
|
var PROSODY_POPOVER_TAGS = /* @__PURE__ */ new Set(["prosody", "mstts:express-as", "voice", "emphasis"]);
|
|
7297
7358
|
var TEXT_POPOVER_TAGS = /* @__PURE__ */ new Set(["sub", "say-as", "phoneme", "w", "lang"]);
|
|
7359
|
+
function isVoiceTagSupported(tagName, voice) {
|
|
7360
|
+
if (!tagName || !voice) return true;
|
|
7361
|
+
const tag = tagName.toLowerCase();
|
|
7362
|
+
const unsupported = new Set((voice.unsupportedTags ?? []).map((candidate) => candidate.toLowerCase()));
|
|
7363
|
+
const supported = voice.supportedTags?.map((candidate) => candidate.toLowerCase());
|
|
7364
|
+
return !unsupported.has(tag) && (supported === void 0 || supported.includes(tag));
|
|
7365
|
+
}
|
|
7366
|
+
function findFirstVoiceName(nodes) {
|
|
7367
|
+
for (const node of nodes) {
|
|
7368
|
+
if (typeof node === "string" || node.type === "text") continue;
|
|
7369
|
+
if (node.type === "voice" && node.name) return node.name;
|
|
7370
|
+
if (node.type === "mstts:turn" && node.voice) return node.voice;
|
|
7371
|
+
const nested = findFirstVoiceName(node.children ?? []);
|
|
7372
|
+
if (nested) return nested;
|
|
7373
|
+
}
|
|
7374
|
+
return void 0;
|
|
7375
|
+
}
|
|
7298
7376
|
function localizedText(value) {
|
|
7299
7377
|
return { ja: value, en: value };
|
|
7300
7378
|
}
|
|
@@ -7880,6 +7958,7 @@ var SsmlEditor = (0, import_react4.forwardRef)(function SsmlEditor2({
|
|
|
7880
7958
|
voiceStyle,
|
|
7881
7959
|
voiceModel,
|
|
7882
7960
|
model,
|
|
7961
|
+
voiceCatalogMetadata,
|
|
7883
7962
|
emotionStyles,
|
|
7884
7963
|
className,
|
|
7885
7964
|
style,
|
|
@@ -8043,6 +8122,10 @@ var SsmlEditor = (0, import_react4.forwardRef)(function SsmlEditor2({
|
|
|
8043
8122
|
const isProsodyPopover = insertion.tagName !== void 0 && PROSODY_POPOVER_TAGS.has(insertion.tagName);
|
|
8044
8123
|
const isTextPopover = insertion.tagName !== void 0 && TEXT_POPOVER_TAGS.has(insertion.tagName);
|
|
8045
8124
|
const insertionButtonStyle = insertion.tagName && activeTags.has(insertion.tagName.toLowerCase()) ? { ...toolbarButtonStyle, ...editorStyles.toolbarButtonActive } : toolbarButtonStyle;
|
|
8125
|
+
const activeVoiceName = popoverVoiceName ?? findFirstVoiceName(draftDocument.children ?? []);
|
|
8126
|
+
const activeVoice = voiceCatalog?.find((voice) => voice.name.toLowerCase() === activeVoiceName?.toLowerCase());
|
|
8127
|
+
const insertionDisabled = !isVoiceTagSupported(insertion.tagName, activeVoice);
|
|
8128
|
+
const disabledReason = insertionDisabled ? language === "ja" ? `\u9078\u629E\u4E2D\u306E\u97F3\u58F0\u306F <${insertion.tagName}> \u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093\u3002` : `The selected voice does not support <${insertion.tagName}>.` : void 0;
|
|
8046
8129
|
const props = {
|
|
8047
8130
|
language,
|
|
8048
8131
|
isDarkTheme,
|
|
@@ -8051,6 +8134,8 @@ var SsmlEditor = (0, import_react4.forwardRef)(function SsmlEditor2({
|
|
|
8051
8134
|
toolbarButtonStyle: insertionButtonStyle,
|
|
8052
8135
|
emptyOptionsMessage: copy.noAvailableOptions,
|
|
8053
8136
|
isReadOnly,
|
|
8137
|
+
disabled: insertionDisabled,
|
|
8138
|
+
disabledReason,
|
|
8054
8139
|
openPopoverId,
|
|
8055
8140
|
menuPosition: popoverPosition,
|
|
8056
8141
|
menuRef: setPopoverMenuRef,
|
|
@@ -8279,6 +8364,7 @@ var SsmlEditor = (0, import_react4.forwardRef)(function SsmlEditor2({
|
|
|
8279
8364
|
voiceLocale,
|
|
8280
8365
|
voiceRegion,
|
|
8281
8366
|
voiceStyle,
|
|
8367
|
+
voiceCatalogMetadata,
|
|
8282
8368
|
voiceModel,
|
|
8283
8369
|
model
|
|
8284
8370
|
}
|