@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/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: AUDIO_DURATION_PRESETS,
442
- fadeout: AUDIO_DURATION_PRESETS
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:-3dB}" />`
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, for example `-3dB` or `medium`.",
3993
- example: "-3dB"
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, for example `1s`.",
3998
- example: "1s"
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, for example `500ms`.",
4003
- example: "500ms"
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: selectedLeaf ? /* @__PURE__ */ jsxs2(Fragment3, { 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(