@ssml-builder-js/ssml-editor-react 2.10.0 → 2.11.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 +11 -0
- package/dist/index.js +155 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +155 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/VisualSsmlEditor.tsx +153 -1
- package/src/constants/azureVoiceStyleMap.generated.ts +3 -0
- package/src/constants/ssmlPresets.ts +3 -2
- package/src/ssmlCompletion.ts +1 -1
- package/src/ssmlHover.ts +6 -6
- package/test/ui-components.test.tsx +62 -0
package/dist/index.mjs
CHANGED
|
@@ -19,6 +19,7 @@ var ssmlPresets_exports = {};
|
|
|
19
19
|
__export(ssmlPresets_exports, {
|
|
20
20
|
AUDIO_DURATION_DESCRIPTIONS: () => AUDIO_DURATION_DESCRIPTIONS,
|
|
21
21
|
AUDIO_DURATION_PRESETS: () => AUDIO_DURATION_PRESETS,
|
|
22
|
+
BACKGROUND_AUDIO_DURATION_PRESETS: () => BACKGROUND_AUDIO_DURATION_PRESETS,
|
|
22
23
|
BREAK_STRENGTH_PRESETS: () => BREAK_STRENGTH_PRESETS,
|
|
23
24
|
BREAK_TIME_DESCRIPTIONS: () => BREAK_TIME_DESCRIPTIONS,
|
|
24
25
|
BREAK_TIME_PRESETS: () => BREAK_TIME_PRESETS,
|
|
@@ -100,6 +101,9 @@ var AZURE_VOICE_STYLE_MAP = {
|
|
|
100
101
|
],
|
|
101
102
|
"es-ES-ElviraNeural": [],
|
|
102
103
|
"fil-PH-AngeloNeural": [],
|
|
104
|
+
"fil-PH-Angelo:DragonHDLatestNeural": [],
|
|
105
|
+
"fil-PH-BlessicaNeural": [],
|
|
106
|
+
"fil-PH-Blessica:DragonHDLatestNeural": [],
|
|
103
107
|
"fr-FR-DeniseNeural": ["cheerful", "sad"],
|
|
104
108
|
"fr-FR-HenriNeural": ["cheerful", "sad"],
|
|
105
109
|
"id-ID-GadisNeural": [],
|
|
@@ -377,6 +381,7 @@ var SAY_AS_PRESETS = [
|
|
|
377
381
|
var LANGUAGE_PRESETS = ["ja-JP", "en-US", "de-DE", "fr-FR"];
|
|
378
382
|
var SILENCE_VALUE_PRESETS = ["300ms", "500ms", "1s"];
|
|
379
383
|
var AUDIO_DURATION_PRESETS = ["5s", "10s", "30s"];
|
|
384
|
+
var BACKGROUND_AUDIO_DURATION_PRESETS = ["0", "500", "1000", "3000", "10000"];
|
|
380
385
|
var SILENCE_TYPE_PRESETS = [
|
|
381
386
|
"Leading",
|
|
382
387
|
"Tailing",
|
|
@@ -438,8 +443,8 @@ var SSML_ATTRIBUTE_PRESETS = {
|
|
|
438
443
|
},
|
|
439
444
|
"mstts:backgroundaudio": {
|
|
440
445
|
volume: PROSODY_VOLUME_PRESETS,
|
|
441
|
-
fadein:
|
|
442
|
-
fadeout:
|
|
446
|
+
fadein: BACKGROUND_AUDIO_DURATION_PRESETS,
|
|
447
|
+
fadeout: BACKGROUND_AUDIO_DURATION_PRESETS
|
|
443
448
|
},
|
|
444
449
|
silence: {
|
|
445
450
|
type: SILENCE_TYPE_PRESETS,
|
|
@@ -3288,7 +3293,7 @@ var SSML_COMPLETION_SNIPPETS = [
|
|
|
3288
3293
|
},
|
|
3289
3294
|
{
|
|
3290
3295
|
label: "mstts:backgroundaudio",
|
|
3291
|
-
insertText: `<mstts:backgroundaudio src="\${1:https://example.com/audio.mp3}" volume="\${2
|
|
3296
|
+
insertText: `<mstts:backgroundaudio src="\${1:https://example.com/audio.mp3}" volume="\${2:70}" fadein="\${3:1000}" fadeout="\${4:1000}" />`
|
|
3292
3297
|
},
|
|
3293
3298
|
{
|
|
3294
3299
|
label: "mstts:ttsembedding",
|
|
@@ -3989,18 +3994,18 @@ var SSML_TAG_DEFINITIONS = [
|
|
|
3989
3994
|
},
|
|
3990
3995
|
{
|
|
3991
3996
|
name: "volume",
|
|
3992
|
-
description: "The background audio volume
|
|
3993
|
-
example: "
|
|
3997
|
+
description: "The background audio volume from 0 to 100.",
|
|
3998
|
+
example: "70"
|
|
3994
3999
|
},
|
|
3995
4000
|
{
|
|
3996
4001
|
name: "fadein",
|
|
3997
|
-
description: "The fade-in duration
|
|
3998
|
-
example: "
|
|
4002
|
+
description: "The fade-in duration in milliseconds from 0 to 10000.",
|
|
4003
|
+
example: "1000"
|
|
3999
4004
|
},
|
|
4000
4005
|
{
|
|
4001
4006
|
name: "fadeout",
|
|
4002
|
-
description: "The fade-out duration
|
|
4003
|
-
example: "
|
|
4007
|
+
description: "The fade-out duration in milliseconds from 0 to 10000.",
|
|
4008
|
+
example: "1000"
|
|
4004
4009
|
}
|
|
4005
4010
|
]
|
|
4006
4011
|
},
|
|
@@ -4659,6 +4664,46 @@ function updateNodesAtPath(nodes, path, update) {
|
|
|
4659
4664
|
function updateTextAtPath(document2, path, value) {
|
|
4660
4665
|
return { ...document2, children: updateNodesAtPath(document2.children ?? [], path, () => value) };
|
|
4661
4666
|
}
|
|
4667
|
+
function getNodeAtPath(nodes, path) {
|
|
4668
|
+
let current;
|
|
4669
|
+
let currentNodes = nodes;
|
|
4670
|
+
for (const index of path) {
|
|
4671
|
+
current = currentNodes[index];
|
|
4672
|
+
if (current === void 0) return void 0;
|
|
4673
|
+
if (!isElement(current)) {
|
|
4674
|
+
currentNodes = [];
|
|
4675
|
+
} else {
|
|
4676
|
+
currentNodes = current.children ?? [];
|
|
4677
|
+
}
|
|
4678
|
+
}
|
|
4679
|
+
return current;
|
|
4680
|
+
}
|
|
4681
|
+
function updateElementAtPath(document2, path, update) {
|
|
4682
|
+
return {
|
|
4683
|
+
...document2,
|
|
4684
|
+
children: updateNodesAtPath(document2.children ?? [], path, (node) => isElement(node) ? update(node) : node)
|
|
4685
|
+
};
|
|
4686
|
+
}
|
|
4687
|
+
function updateElementText(element, value) {
|
|
4688
|
+
return { ...element, children: [value] };
|
|
4689
|
+
}
|
|
4690
|
+
function updateOptionalElementProperty(document2, path, property, value) {
|
|
4691
|
+
return updateElementAtPath(document2, path, (element) => {
|
|
4692
|
+
const next = { ...element };
|
|
4693
|
+
if (value.trim()) next[property] = value;
|
|
4694
|
+
else delete next[property];
|
|
4695
|
+
return next;
|
|
4696
|
+
});
|
|
4697
|
+
}
|
|
4698
|
+
function addDialogTurn(document2, path) {
|
|
4699
|
+
return updateElementAtPath(document2, path, (element) => ({
|
|
4700
|
+
...element,
|
|
4701
|
+
children: [
|
|
4702
|
+
...element.children ?? [],
|
|
4703
|
+
{ type: "mstts:turn", voice: "en-US-JennyNeural", children: ["New dialog turn"] }
|
|
4704
|
+
]
|
|
4705
|
+
}));
|
|
4706
|
+
}
|
|
4662
4707
|
function wrapTextAtPath(document2, path, start, end, tag, attributes) {
|
|
4663
4708
|
return {
|
|
4664
4709
|
...document2,
|
|
@@ -4713,6 +4758,7 @@ function VisualSsmlEditor({
|
|
|
4713
4758
|
const [selection, setSelection] = useState2({ start: 0, end: 0 });
|
|
4714
4759
|
const textLeaves = useMemo(() => collectTextLeaves(document2.children ?? []), [document2]);
|
|
4715
4760
|
const selectedLeaf = textLeaves.find((leaf) => leaf.path.join(".") === selectedPath?.join(".")) ?? textLeaves[0];
|
|
4761
|
+
const selectedElement = selectedPath ? getNodeAtPath(document2.children ?? [], selectedPath) : void 0;
|
|
4716
4762
|
const diagnostics = useMemo(() => validateAzureSsml(buildSsml3(document2)), [document2]);
|
|
4717
4763
|
const commit = (nextDocument) => onChange?.(nextDocument);
|
|
4718
4764
|
const applyWrapper = (tag, attributes) => {
|
|
@@ -4747,7 +4793,106 @@ function VisualSsmlEditor({
|
|
|
4747
4793
|
isElement(node) ? elementLabel(node) : JSON.stringify(node)
|
|
4748
4794
|
)) })
|
|
4749
4795
|
] }),
|
|
4750
|
-
/* @__PURE__ */ jsx6("div", { className: "ssml-editor-visual-form", children:
|
|
4796
|
+
/* @__PURE__ */ jsx6("div", { className: "ssml-editor-visual-form", children: selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:dialog" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
4797
|
+
/* @__PURE__ */ jsx6("legend", { children: "Dialog" }),
|
|
4798
|
+
/* @__PURE__ */ jsx6("p", { children: "Add and edit speaker turns in this dialog." }),
|
|
4799
|
+
/* @__PURE__ */ jsx6(
|
|
4800
|
+
"button",
|
|
4801
|
+
{
|
|
4802
|
+
type: "button",
|
|
4803
|
+
disabled: readOnly,
|
|
4804
|
+
onClick: () => commit(addDialogTurn(document2, selectedPath ?? [])),
|
|
4805
|
+
children: "Add turn"
|
|
4806
|
+
}
|
|
4807
|
+
)
|
|
4808
|
+
] }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:turn" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
4809
|
+
/* @__PURE__ */ jsx6("legend", { children: "Dialog turn" }),
|
|
4810
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4811
|
+
"Voice",
|
|
4812
|
+
/* @__PURE__ */ jsx6(
|
|
4813
|
+
"input",
|
|
4814
|
+
{
|
|
4815
|
+
value: selectedElement.voice ?? "",
|
|
4816
|
+
readOnly,
|
|
4817
|
+
onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "voice", event.target.value))
|
|
4818
|
+
}
|
|
4819
|
+
)
|
|
4820
|
+
] }),
|
|
4821
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4822
|
+
"Speaker",
|
|
4823
|
+
/* @__PURE__ */ jsx6(
|
|
4824
|
+
"input",
|
|
4825
|
+
{
|
|
4826
|
+
value: selectedElement.speaker ?? "",
|
|
4827
|
+
readOnly,
|
|
4828
|
+
onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "speaker", event.target.value))
|
|
4829
|
+
}
|
|
4830
|
+
)
|
|
4831
|
+
] }),
|
|
4832
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4833
|
+
"Turn text",
|
|
4834
|
+
/* @__PURE__ */ jsx6(
|
|
4835
|
+
"textarea",
|
|
4836
|
+
{
|
|
4837
|
+
value: selectedElement.children?.filter((child) => typeof child === "string").join("") ?? "",
|
|
4838
|
+
readOnly,
|
|
4839
|
+
onChange: (event) => commit(
|
|
4840
|
+
updateElementAtPath(
|
|
4841
|
+
document2,
|
|
4842
|
+
selectedPath ?? [],
|
|
4843
|
+
(element) => updateElementText(element, event.target.value)
|
|
4844
|
+
)
|
|
4845
|
+
)
|
|
4846
|
+
}
|
|
4847
|
+
)
|
|
4848
|
+
] })
|
|
4849
|
+
] }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:backgroundaudio" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
|
|
4850
|
+
/* @__PURE__ */ jsx6("legend", { children: "Background audio" }),
|
|
4851
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4852
|
+
"Source URL",
|
|
4853
|
+
/* @__PURE__ */ jsx6(
|
|
4854
|
+
"input",
|
|
4855
|
+
{
|
|
4856
|
+
value: selectedElement.src ?? "",
|
|
4857
|
+
readOnly,
|
|
4858
|
+
onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "src", event.target.value))
|
|
4859
|
+
}
|
|
4860
|
+
)
|
|
4861
|
+
] }),
|
|
4862
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4863
|
+
"Volume",
|
|
4864
|
+
/* @__PURE__ */ jsx6(
|
|
4865
|
+
"input",
|
|
4866
|
+
{
|
|
4867
|
+
value: selectedElement.volume === void 0 ? "" : String(selectedElement.volume),
|
|
4868
|
+
readOnly,
|
|
4869
|
+
onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "volume", event.target.value))
|
|
4870
|
+
}
|
|
4871
|
+
)
|
|
4872
|
+
] }),
|
|
4873
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4874
|
+
"Fade in",
|
|
4875
|
+
/* @__PURE__ */ jsx6(
|
|
4876
|
+
"input",
|
|
4877
|
+
{
|
|
4878
|
+
value: selectedElement.fadeIn === void 0 ? "" : String(selectedElement.fadeIn),
|
|
4879
|
+
readOnly,
|
|
4880
|
+
onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "fadeIn", event.target.value))
|
|
4881
|
+
}
|
|
4882
|
+
)
|
|
4883
|
+
] }),
|
|
4884
|
+
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4885
|
+
"Fade out",
|
|
4886
|
+
/* @__PURE__ */ jsx6(
|
|
4887
|
+
"input",
|
|
4888
|
+
{
|
|
4889
|
+
value: selectedElement.fadeOut === void 0 ? "" : String(selectedElement.fadeOut),
|
|
4890
|
+
readOnly,
|
|
4891
|
+
onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "fadeOut", event.target.value))
|
|
4892
|
+
}
|
|
4893
|
+
)
|
|
4894
|
+
] })
|
|
4895
|
+
] }) : selectedLeaf ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
|
|
4751
4896
|
/* @__PURE__ */ jsxs2("label", { children: [
|
|
4752
4897
|
"Text",
|
|
4753
4898
|
/* @__PURE__ */ jsx6(
|