@ssml-builder-js/ssml-editor-react 2.13.0 → 2.15.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/CHANGELOG.md +22 -0
- package/dist/index.d.mts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +148 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/SsmlEditor.tsx +8 -0
- package/src/components/VisualSsmlEditor.tsx +165 -17
- package/test/ui-components.test.tsx +28 -0
package/dist/index.mjs
CHANGED
|
@@ -4999,29 +4999,107 @@ function localizedElementLabel(element, locale) {
|
|
|
4999
4999
|
function filteredVoices(voiceCatalog, locale, region, style) {
|
|
5000
5000
|
return (voiceCatalog ?? []).filter((voice) => {
|
|
5001
5001
|
if (locale && voice.locale.toLowerCase() !== locale.toLowerCase()) return false;
|
|
5002
|
-
|
|
5002
|
+
const regions = [voice.region, ...voice.regions ?? []].filter(
|
|
5003
|
+
(candidate) => Boolean(candidate)
|
|
5004
|
+
);
|
|
5005
|
+
if (region && regions.length > 0 && !regions.some((candidate) => candidate.toLowerCase() === region.toLowerCase()))
|
|
5006
|
+
return false;
|
|
5003
5007
|
if (style && !voice.styles?.some((candidate) => candidate.toLowerCase() === style.toLowerCase())) return false;
|
|
5004
5008
|
return true;
|
|
5005
5009
|
});
|
|
5006
5010
|
}
|
|
5007
|
-
function
|
|
5008
|
-
|
|
5009
|
-
|
|
5011
|
+
function VoiceCapabilityMatrix({
|
|
5012
|
+
voice,
|
|
5013
|
+
locale
|
|
5014
|
+
}) {
|
|
5015
|
+
const status = voice.status ?? (voice.preview ? "preview" : void 0);
|
|
5016
|
+
return /* @__PURE__ */ jsxs2("div", { className: "ssml-editor-voice-capabilities", "data-voice-capabilities": "", children: [
|
|
5017
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
5018
|
+
locale === "ja" ? "\u30B9\u30C6\u30FC\u30BF\u30B9" : "Status",
|
|
5019
|
+
": ",
|
|
5020
|
+
status?.toUpperCase() ?? (locale === "ja" ? "GA" : "GA"),
|
|
5021
|
+
status === "preview" || status === "deprecated" ? /* @__PURE__ */ jsx6("span", { role: "status", "aria-label": status, className: "ssml-editor-voice-warning-badge", children: status === "preview" ? "\u26A0 Preview" : "\u26A0 Deprecated" }) : null
|
|
5022
|
+
] }),
|
|
5023
|
+
(voice.regions?.length || voice.region) && /* @__PURE__ */ jsxs2("div", { children: [
|
|
5024
|
+
locale === "ja" ? "\u30EA\u30FC\u30B8\u30E7\u30F3" : "Regions",
|
|
5025
|
+
":",
|
|
5026
|
+
" ",
|
|
5027
|
+
[...voice.regions ?? [], ...voice.region ? [voice.region] : []].filter((region, index, all) => all.indexOf(region) === index).join(", ")
|
|
5028
|
+
] }),
|
|
5029
|
+
voice.supportedTags && voice.supportedTags.length > 0 && /* @__PURE__ */ jsxs2("div", { children: [
|
|
5030
|
+
locale === "ja" ? "\u5BFE\u5FDC\u30BF\u30B0" : "Supported tags",
|
|
5031
|
+
": ",
|
|
5032
|
+
voice.supportedTags.join(", ")
|
|
5033
|
+
] }),
|
|
5034
|
+
voice.unsupportedTags && voice.unsupportedTags.length > 0 && /* @__PURE__ */ jsxs2("div", { className: "ssml-editor-voice-unsupported", children: [
|
|
5035
|
+
locale === "ja" ? "\u975E\u5BFE\u5FDC\u30BF\u30B0" : "Unsupported tags",
|
|
5036
|
+
": ",
|
|
5037
|
+
voice.unsupportedTags.join(", ")
|
|
5038
|
+
] })
|
|
5039
|
+
] });
|
|
5040
|
+
}
|
|
5041
|
+
function diagnosticMatchesElement(diagnostic, element) {
|
|
5042
|
+
const name = elementLabel(element).toLowerCase().replace("expressas", "mstts:express-as");
|
|
5043
|
+
if (diagnostic.code === "azure-unsupported-style") return name === "mstts:express-as" || name === "express-as";
|
|
5044
|
+
if (diagnostic.code === "azure-unsupported-tag-for-voice") {
|
|
5045
|
+
return diagnostic.message.toLowerCase().includes(`<${name}>`) || diagnostic.message.toLowerCase().includes(`<${name.replace("mstts:", "")}>`);
|
|
5046
|
+
}
|
|
5047
|
+
if (diagnostic.code === "azure-locale-mismatch" || diagnostic.code === "azure-unsupported-model-for-voice")
|
|
5048
|
+
return name === "voice" || name === "mstts:turn";
|
|
5049
|
+
return false;
|
|
5050
|
+
}
|
|
5051
|
+
function elementWarnings(diagnostics, element) {
|
|
5052
|
+
return diagnostics.filter((diagnostic) => diagnosticMatchesElement(diagnostic, element));
|
|
5053
|
+
}
|
|
5054
|
+
function fieldWarnings(diagnostics, element, field) {
|
|
5055
|
+
return elementWarnings(diagnostics, element).filter((diagnostic) => {
|
|
5056
|
+
if (diagnostic.code === "azure-unsupported-style") return field.key === "style";
|
|
5057
|
+
return field.key === "name" || field.key === "voice";
|
|
5058
|
+
});
|
|
5059
|
+
}
|
|
5060
|
+
function WarningBadge({ messages }) {
|
|
5061
|
+
if (messages.length === 0) return null;
|
|
5062
|
+
return /* @__PURE__ */ jsx6(
|
|
5063
|
+
"span",
|
|
5010
5064
|
{
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
voice.name,
|
|
5019
|
-
voice.preview || voice.status === "preview" ? " (preview)" : ""
|
|
5020
|
-
] }, voice.name))
|
|
5021
|
-
]
|
|
5065
|
+
role: "status",
|
|
5066
|
+
"aria-label": messages.map((message) => message.message).join(" "),
|
|
5067
|
+
title: messages.map((message) => message.message).join(" "),
|
|
5068
|
+
"data-ssml-warning-badge": "",
|
|
5069
|
+
"data-testid": "ssml-editor-warning-badge",
|
|
5070
|
+
className: "ssml-editor-warning-badge",
|
|
5071
|
+
children: "\u26A0"
|
|
5022
5072
|
}
|
|
5023
5073
|
);
|
|
5024
5074
|
}
|
|
5075
|
+
function DefaultVoiceSelector({
|
|
5076
|
+
value,
|
|
5077
|
+
voices,
|
|
5078
|
+
selectedVoice,
|
|
5079
|
+
readOnly,
|
|
5080
|
+
locale,
|
|
5081
|
+
onChange
|
|
5082
|
+
}) {
|
|
5083
|
+
return /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
5084
|
+
/* @__PURE__ */ jsxs2(
|
|
5085
|
+
"select",
|
|
5086
|
+
{
|
|
5087
|
+
"aria-label": locale === "ja" ? "\u97F3\u58F0" : "Voice",
|
|
5088
|
+
value,
|
|
5089
|
+
disabled: readOnly,
|
|
5090
|
+
onChange: (event) => onChange(event.target.value),
|
|
5091
|
+
children: [
|
|
5092
|
+
/* @__PURE__ */ jsx6("option", { value: "", children: locale === "ja" ? "\u97F3\u58F0\u3092\u9078\u629E" : "Select a voice" }),
|
|
5093
|
+
voices.map((voice) => /* @__PURE__ */ jsxs2("option", { value: voice.name, children: [
|
|
5094
|
+
voice.name,
|
|
5095
|
+
voice.preview || voice.status === "preview" ? " (preview)" : ""
|
|
5096
|
+
] }, voice.name))
|
|
5097
|
+
]
|
|
5098
|
+
}
|
|
5099
|
+
),
|
|
5100
|
+
selectedVoice ? /* @__PURE__ */ jsx6(VoiceCapabilityMatrix, { voice: selectedVoice, locale }) : null
|
|
5101
|
+
] });
|
|
5102
|
+
}
|
|
5025
5103
|
function VisualElementInspector({
|
|
5026
5104
|
document: document2,
|
|
5027
5105
|
element,
|
|
@@ -5034,16 +5112,24 @@ function VisualElementInspector({
|
|
|
5034
5112
|
voiceCatalog,
|
|
5035
5113
|
voiceLocale,
|
|
5036
5114
|
voiceRegion,
|
|
5037
|
-
voiceStyle
|
|
5115
|
+
voiceStyle,
|
|
5116
|
+
diagnostics
|
|
5038
5117
|
}) {
|
|
5039
5118
|
if (customInspector) {
|
|
5040
5119
|
return /* @__PURE__ */ jsx6(Fragment3, { children: customInspector({ document: document2, element, path, readOnly, onChange: commit, locale }) });
|
|
5041
5120
|
}
|
|
5042
5121
|
const fields = getElementFields(element);
|
|
5043
5122
|
const availableVoices = filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle);
|
|
5123
|
+
const selectedVoice = voiceCatalog?.find(
|
|
5124
|
+
(voice) => voice.name === (element.type === "voice" ? element.name : void 0)
|
|
5125
|
+
);
|
|
5044
5126
|
const renderSelector = renderVoiceSelector ?? DefaultVoiceSelector;
|
|
5045
5127
|
return /* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
5046
|
-
/* @__PURE__ */
|
|
5128
|
+
/* @__PURE__ */ jsxs2("legend", { children: [
|
|
5129
|
+
`<${elementLabel(element)}>`,
|
|
5130
|
+
" ",
|
|
5131
|
+
/* @__PURE__ */ jsx6(WarningBadge, { messages: elementWarnings(diagnostics, element) })
|
|
5132
|
+
] }),
|
|
5047
5133
|
fields.length === 0 ? /* @__PURE__ */ jsx6("p", { children: "This element is preserved in the visual tree. Edit its attributes in Code mode." }) : fields.map((field) => {
|
|
5048
5134
|
const value = element[field.key];
|
|
5049
5135
|
const inputValue = value === void 0 ? "" : String(value);
|
|
@@ -5083,9 +5169,11 @@ function VisualElementInspector({
|
|
|
5083
5169
|
url: "\u97F3\u58F0\u5909\u63DB URL",
|
|
5084
5170
|
profile: "\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB"
|
|
5085
5171
|
}[field.key] ?? field.label : field.label,
|
|
5172
|
+
/* @__PURE__ */ jsx6(WarningBadge, { messages: fieldWarnings(diagnostics, element, field) }),
|
|
5086
5173
|
field.key === "name" && elementLabel(element) === "voice" && voiceCatalog ? renderSelector({
|
|
5087
5174
|
value: inputValue,
|
|
5088
5175
|
voices: availableVoices,
|
|
5176
|
+
selectedVoice,
|
|
5089
5177
|
readOnly,
|
|
5090
5178
|
locale,
|
|
5091
5179
|
onChange: (value2) => commit(updateOptionalElementProperty(document2, path, field.key, value2))
|
|
@@ -5162,20 +5250,25 @@ function TreeNode({
|
|
|
5162
5250
|
node,
|
|
5163
5251
|
path,
|
|
5164
5252
|
selectedPath,
|
|
5165
|
-
onSelect
|
|
5253
|
+
onSelect,
|
|
5254
|
+
getWarnings
|
|
5166
5255
|
}) {
|
|
5167
5256
|
if (!isElement(node)) return null;
|
|
5168
5257
|
const name = elementLabel(node);
|
|
5169
5258
|
const isSelected = selectedPath?.join(".") === path.join(".");
|
|
5170
5259
|
return /* @__PURE__ */ jsxs2("li", { children: [
|
|
5171
|
-
/* @__PURE__ */
|
|
5260
|
+
/* @__PURE__ */ jsxs2("button", { type: "button", "aria-current": isSelected ? "true" : void 0, onClick: () => onSelect(path), children: [
|
|
5261
|
+
`<${name}>`,
|
|
5262
|
+
/* @__PURE__ */ jsx6(WarningBadge, { messages: getWarnings(node) })
|
|
5263
|
+
] }),
|
|
5172
5264
|
(node.children ?? []).length > 0 && /* @__PURE__ */ jsx6("ul", { children: node.children?.map((child, index) => /* @__PURE__ */ jsx6(
|
|
5173
5265
|
TreeNode,
|
|
5174
5266
|
{
|
|
5175
5267
|
node: child,
|
|
5176
5268
|
path: [...path, index],
|
|
5177
5269
|
selectedPath,
|
|
5178
|
-
onSelect
|
|
5270
|
+
onSelect,
|
|
5271
|
+
getWarnings
|
|
5179
5272
|
},
|
|
5180
5273
|
`${path.join(".")}/${isElement(child) ? elementLabel(child) : JSON.stringify(child)}`
|
|
5181
5274
|
)) })
|
|
@@ -5192,7 +5285,9 @@ function VisualSsmlEditor({
|
|
|
5192
5285
|
voiceCatalog,
|
|
5193
5286
|
voiceLocale,
|
|
5194
5287
|
voiceRegion,
|
|
5195
|
-
voiceStyle
|
|
5288
|
+
voiceStyle,
|
|
5289
|
+
voiceModel,
|
|
5290
|
+
model
|
|
5196
5291
|
}) {
|
|
5197
5292
|
const [selectedPath, setSelectedPath] = useState2(null);
|
|
5198
5293
|
const [selection, setSelection] = useState2({ start: 0, end: 0 });
|
|
@@ -5200,7 +5295,27 @@ function VisualSsmlEditor({
|
|
|
5200
5295
|
const selectedLeaf = textLeaves.find((leaf) => leaf.path.join(".") === selectedPath?.join(".")) ?? textLeaves[0];
|
|
5201
5296
|
const selectedElement = selectedPath ? getNodeAtPath(document2.children ?? [], selectedPath) : void 0;
|
|
5202
5297
|
const selectedCustomInspector = selectedElement && isElement(selectedElement) ? customInspectors?.[elementLabel(selectedElement)] ?? customInspectors?.[selectedElement.type] : void 0;
|
|
5203
|
-
const
|
|
5298
|
+
const validationOptions = useMemo(
|
|
5299
|
+
() => ({
|
|
5300
|
+
model: voiceModel ?? model,
|
|
5301
|
+
customVoiceDefinitions: voiceCatalog?.map((voice) => ({
|
|
5302
|
+
name: voice.name,
|
|
5303
|
+
locale: voice.locale,
|
|
5304
|
+
regions: voice.regions ?? (voice.region ? [voice.region] : void 0),
|
|
5305
|
+
styles: voice.styles,
|
|
5306
|
+
supportedTags: voice.supportedTags,
|
|
5307
|
+
unsupportedTags: voice.unsupportedTags,
|
|
5308
|
+
models: voice.models,
|
|
5309
|
+
status: voice.status ?? (voice.preview ? "preview" : "ga")
|
|
5310
|
+
}))
|
|
5311
|
+
}),
|
|
5312
|
+
[model, voiceCatalog, voiceModel]
|
|
5313
|
+
);
|
|
5314
|
+
const diagnostics = useMemo(
|
|
5315
|
+
() => validateAzureSsml(buildSsml3(document2), validationOptions),
|
|
5316
|
+
[document2, validationOptions]
|
|
5317
|
+
);
|
|
5318
|
+
const getWarnings = (element) => elementWarnings(diagnostics, element);
|
|
5204
5319
|
const commit = (nextDocument) => onChange?.(nextDocument);
|
|
5205
5320
|
const applyWrapper = (tag, attributes) => {
|
|
5206
5321
|
if (readOnly || !selectedLeaf) return;
|
|
@@ -5229,7 +5344,8 @@ function VisualSsmlEditor({
|
|
|
5229
5344
|
node,
|
|
5230
5345
|
path: [index],
|
|
5231
5346
|
selectedPath,
|
|
5232
|
-
onSelect: setSelectedPath
|
|
5347
|
+
onSelect: setSelectedPath,
|
|
5348
|
+
getWarnings
|
|
5233
5349
|
},
|
|
5234
5350
|
isElement(node) ? elementLabel(node) : JSON.stringify(node)
|
|
5235
5351
|
)) })
|
|
@@ -5257,9 +5373,11 @@ function VisualSsmlEditor({
|
|
|
5257
5373
|
/* @__PURE__ */ jsx6("legend", { children: localizedElementLabel(selectedElement, locale) }),
|
|
5258
5374
|
/* @__PURE__ */ jsxs2("label", { htmlFor: "ssml-visual-turn-voice", children: [
|
|
5259
5375
|
locale === "ja" ? "\u97F3\u58F0" : "Voice",
|
|
5376
|
+
/* @__PURE__ */ jsx6(WarningBadge, { messages: elementWarnings(diagnostics, selectedElement) }),
|
|
5260
5377
|
voiceCatalog ? (renderVoiceSelector ?? DefaultVoiceSelector)({
|
|
5261
5378
|
value: selectedElement.voice ?? "",
|
|
5262
5379
|
voices: filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle),
|
|
5380
|
+
selectedVoice: voiceCatalog?.find((voice) => voice.name === selectedElement.voice),
|
|
5263
5381
|
readOnly,
|
|
5264
5382
|
locale,
|
|
5265
5383
|
onChange: (value) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "voice", value))
|
|
@@ -5361,7 +5479,8 @@ function VisualSsmlEditor({
|
|
|
5361
5479
|
voiceCatalog,
|
|
5362
5480
|
voiceLocale,
|
|
5363
5481
|
voiceRegion,
|
|
5364
|
-
voiceStyle
|
|
5482
|
+
voiceStyle,
|
|
5483
|
+
diagnostics
|
|
5365
5484
|
}
|
|
5366
5485
|
) : selectedLeaf ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
5367
5486
|
/* @__PURE__ */ jsxs2("label", { children: [
|
|
@@ -6006,6 +6125,8 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
|
|
|
6006
6125
|
voiceLocale,
|
|
6007
6126
|
voiceRegion,
|
|
6008
6127
|
voiceStyle,
|
|
6128
|
+
voiceModel,
|
|
6129
|
+
model,
|
|
6009
6130
|
emotionStyles,
|
|
6010
6131
|
className,
|
|
6011
6132
|
style,
|
|
@@ -6454,7 +6575,9 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
|
|
|
6454
6575
|
voiceCatalog,
|
|
6455
6576
|
voiceLocale,
|
|
6456
6577
|
voiceRegion,
|
|
6457
|
-
voiceStyle
|
|
6578
|
+
voiceStyle,
|
|
6579
|
+
voiceModel,
|
|
6580
|
+
model
|
|
6458
6581
|
}
|
|
6459
6582
|
) }) : /* @__PURE__ */ jsxs3("div", { style: { ...editorStyles.editor, minHeight: editorMinHeight }, children: [
|
|
6460
6583
|
/* @__PURE__ */ jsx7(
|