@ssml-builder-js/ssml-editor-react 2.9.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 CHANGED
@@ -1,5 +1,27 @@
1
1
  # @ssml-builder-js/ssml-editor-react
2
2
 
3
+ ## 2.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Release v2.11.0 with Azure voice catalog APIs and synchronization tools, expanded editor voice support, and stricter background audio validation.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @ssml-builder-js/ssml-core@2.11.0
13
+
14
+ ## 2.10.0
15
+
16
+ ### Minor Changes
17
+
18
+ - Release v2.10.0 with expanded Azure SSML extension attributes, stricter background audio and multi-talker validation, and updated package entrypoint documentation.
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies
23
+ - @ssml-builder-js/ssml-core@2.10.0
24
+
3
25
  ## 2.9.0
4
26
 
5
27
  ### Minor Changes
package/dist/index.js CHANGED
@@ -57,6 +57,7 @@ var ssmlPresets_exports = {};
57
57
  __export(ssmlPresets_exports, {
58
58
  AUDIO_DURATION_DESCRIPTIONS: () => AUDIO_DURATION_DESCRIPTIONS,
59
59
  AUDIO_DURATION_PRESETS: () => AUDIO_DURATION_PRESETS,
60
+ BACKGROUND_AUDIO_DURATION_PRESETS: () => BACKGROUND_AUDIO_DURATION_PRESETS,
60
61
  BREAK_STRENGTH_PRESETS: () => BREAK_STRENGTH_PRESETS,
61
62
  BREAK_TIME_DESCRIPTIONS: () => BREAK_TIME_DESCRIPTIONS,
62
63
  BREAK_TIME_PRESETS: () => BREAK_TIME_PRESETS,
@@ -138,6 +139,9 @@ var AZURE_VOICE_STYLE_MAP = {
138
139
  ],
139
140
  "es-ES-ElviraNeural": [],
140
141
  "fil-PH-AngeloNeural": [],
142
+ "fil-PH-Angelo:DragonHDLatestNeural": [],
143
+ "fil-PH-BlessicaNeural": [],
144
+ "fil-PH-Blessica:DragonHDLatestNeural": [],
141
145
  "fr-FR-DeniseNeural": ["cheerful", "sad"],
142
146
  "fr-FR-HenriNeural": ["cheerful", "sad"],
143
147
  "id-ID-GadisNeural": [],
@@ -415,6 +419,7 @@ var SAY_AS_PRESETS = [
415
419
  var LANGUAGE_PRESETS = ["ja-JP", "en-US", "de-DE", "fr-FR"];
416
420
  var SILENCE_VALUE_PRESETS = ["300ms", "500ms", "1s"];
417
421
  var AUDIO_DURATION_PRESETS = ["5s", "10s", "30s"];
422
+ var BACKGROUND_AUDIO_DURATION_PRESETS = ["0", "500", "1000", "3000", "10000"];
418
423
  var SILENCE_TYPE_PRESETS = [
419
424
  "Leading",
420
425
  "Tailing",
@@ -476,8 +481,8 @@ var SSML_ATTRIBUTE_PRESETS = {
476
481
  },
477
482
  "mstts:backgroundaudio": {
478
483
  volume: PROSODY_VOLUME_PRESETS,
479
- fadein: AUDIO_DURATION_PRESETS,
480
- fadeout: AUDIO_DURATION_PRESETS
484
+ fadein: BACKGROUND_AUDIO_DURATION_PRESETS,
485
+ fadeout: BACKGROUND_AUDIO_DURATION_PRESETS
481
486
  },
482
487
  silence: {
483
488
  type: SILENCE_TYPE_PRESETS,
@@ -3326,7 +3331,7 @@ var SSML_COMPLETION_SNIPPETS = [
3326
3331
  },
3327
3332
  {
3328
3333
  label: "mstts:backgroundaudio",
3329
- insertText: `<mstts:backgroundaudio src="\${1:https://example.com/audio.mp3}" volume="\${2:-3dB}" />`
3334
+ insertText: `<mstts:backgroundaudio src="\${1:https://example.com/audio.mp3}" volume="\${2:70}" fadein="\${3:1000}" fadeout="\${4:1000}" />`
3330
3335
  },
3331
3336
  {
3332
3337
  label: "mstts:ttsembedding",
@@ -4027,18 +4032,18 @@ var SSML_TAG_DEFINITIONS = [
4027
4032
  },
4028
4033
  {
4029
4034
  name: "volume",
4030
- description: "The background audio volume, for example `-3dB` or `medium`.",
4031
- example: "-3dB"
4035
+ description: "The background audio volume from 0 to 100.",
4036
+ example: "70"
4032
4037
  },
4033
4038
  {
4034
4039
  name: "fadein",
4035
- description: "The fade-in duration, for example `1s`.",
4036
- example: "1s"
4040
+ description: "The fade-in duration in milliseconds from 0 to 10000.",
4041
+ example: "1000"
4037
4042
  },
4038
4043
  {
4039
4044
  name: "fadeout",
4040
- description: "The fade-out duration, for example `500ms`.",
4041
- example: "500ms"
4045
+ description: "The fade-out duration in milliseconds from 0 to 10000.",
4046
+ example: "1000"
4042
4047
  }
4043
4048
  ]
4044
4049
  },
@@ -4694,6 +4699,46 @@ function updateNodesAtPath(nodes, path, update) {
4694
4699
  function updateTextAtPath(document2, path, value) {
4695
4700
  return { ...document2, children: updateNodesAtPath(document2.children ?? [], path, () => value) };
4696
4701
  }
4702
+ function getNodeAtPath(nodes, path) {
4703
+ let current;
4704
+ let currentNodes = nodes;
4705
+ for (const index of path) {
4706
+ current = currentNodes[index];
4707
+ if (current === void 0) return void 0;
4708
+ if (!isElement(current)) {
4709
+ currentNodes = [];
4710
+ } else {
4711
+ currentNodes = current.children ?? [];
4712
+ }
4713
+ }
4714
+ return current;
4715
+ }
4716
+ function updateElementAtPath(document2, path, update) {
4717
+ return {
4718
+ ...document2,
4719
+ children: updateNodesAtPath(document2.children ?? [], path, (node) => isElement(node) ? update(node) : node)
4720
+ };
4721
+ }
4722
+ function updateElementText(element, value) {
4723
+ return { ...element, children: [value] };
4724
+ }
4725
+ function updateOptionalElementProperty(document2, path, property, value) {
4726
+ return updateElementAtPath(document2, path, (element) => {
4727
+ const next = { ...element };
4728
+ if (value.trim()) next[property] = value;
4729
+ else delete next[property];
4730
+ return next;
4731
+ });
4732
+ }
4733
+ function addDialogTurn(document2, path) {
4734
+ return updateElementAtPath(document2, path, (element) => ({
4735
+ ...element,
4736
+ children: [
4737
+ ...element.children ?? [],
4738
+ { type: "mstts:turn", voice: "en-US-JennyNeural", children: ["New dialog turn"] }
4739
+ ]
4740
+ }));
4741
+ }
4697
4742
  function wrapTextAtPath(document2, path, start, end, tag, attributes) {
4698
4743
  return {
4699
4744
  ...document2,
@@ -4748,6 +4793,7 @@ function VisualSsmlEditor({
4748
4793
  const [selection, setSelection] = (0, import_react3.useState)({ start: 0, end: 0 });
4749
4794
  const textLeaves = (0, import_react3.useMemo)(() => collectTextLeaves(document2.children ?? []), [document2]);
4750
4795
  const selectedLeaf = textLeaves.find((leaf) => leaf.path.join(".") === selectedPath?.join(".")) ?? textLeaves[0];
4796
+ const selectedElement = selectedPath ? getNodeAtPath(document2.children ?? [], selectedPath) : void 0;
4751
4797
  const diagnostics = (0, import_react3.useMemo)(() => (0, import_ssml_core4.validateAzureSsml)((0, import_ssml_core4.buildSsml)(document2)), [document2]);
4752
4798
  const commit = (nextDocument) => onChange?.(nextDocument);
4753
4799
  const applyWrapper = (tag, attributes) => {
@@ -4782,7 +4828,106 @@ function VisualSsmlEditor({
4782
4828
  isElement(node) ? elementLabel(node) : JSON.stringify(node)
4783
4829
  )) })
4784
4830
  ] }),
4785
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ssml-editor-visual-form", children: selectedLeaf ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
4831
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ssml-editor-visual-form", children: selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:dialog" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("fieldset", { children: [
4832
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: "Dialog" }),
4833
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { children: "Add and edit speaker turns in this dialog." }),
4834
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4835
+ "button",
4836
+ {
4837
+ type: "button",
4838
+ disabled: readOnly,
4839
+ onClick: () => commit(addDialogTurn(document2, selectedPath ?? [])),
4840
+ children: "Add turn"
4841
+ }
4842
+ )
4843
+ ] }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:turn" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("fieldset", { children: [
4844
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: "Dialog turn" }),
4845
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4846
+ "Voice",
4847
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4848
+ "input",
4849
+ {
4850
+ value: selectedElement.voice ?? "",
4851
+ readOnly,
4852
+ onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "voice", event.target.value))
4853
+ }
4854
+ )
4855
+ ] }),
4856
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4857
+ "Speaker",
4858
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4859
+ "input",
4860
+ {
4861
+ value: selectedElement.speaker ?? "",
4862
+ readOnly,
4863
+ onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "speaker", event.target.value))
4864
+ }
4865
+ )
4866
+ ] }),
4867
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4868
+ "Turn text",
4869
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4870
+ "textarea",
4871
+ {
4872
+ value: selectedElement.children?.filter((child) => typeof child === "string").join("") ?? "",
4873
+ readOnly,
4874
+ onChange: (event) => commit(
4875
+ updateElementAtPath(
4876
+ document2,
4877
+ selectedPath ?? [],
4878
+ (element) => updateElementText(element, event.target.value)
4879
+ )
4880
+ )
4881
+ }
4882
+ )
4883
+ ] })
4884
+ ] }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:backgroundaudio" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("fieldset", { children: [
4885
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: "Background audio" }),
4886
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4887
+ "Source URL",
4888
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4889
+ "input",
4890
+ {
4891
+ value: selectedElement.src ?? "",
4892
+ readOnly,
4893
+ onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "src", event.target.value))
4894
+ }
4895
+ )
4896
+ ] }),
4897
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4898
+ "Volume",
4899
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4900
+ "input",
4901
+ {
4902
+ value: selectedElement.volume === void 0 ? "" : String(selectedElement.volume),
4903
+ readOnly,
4904
+ onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "volume", event.target.value))
4905
+ }
4906
+ )
4907
+ ] }),
4908
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4909
+ "Fade in",
4910
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4911
+ "input",
4912
+ {
4913
+ value: selectedElement.fadeIn === void 0 ? "" : String(selectedElement.fadeIn),
4914
+ readOnly,
4915
+ onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "fadeIn", event.target.value))
4916
+ }
4917
+ )
4918
+ ] }),
4919
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4920
+ "Fade out",
4921
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4922
+ "input",
4923
+ {
4924
+ value: selectedElement.fadeOut === void 0 ? "" : String(selectedElement.fadeOut),
4925
+ readOnly,
4926
+ onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "fadeOut", event.target.value))
4927
+ }
4928
+ )
4929
+ ] })
4930
+ ] }) : selectedLeaf ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
4786
4931
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4787
4932
  "Text",
4788
4933
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(