ssml-builder-js 2.8.0 → 2.9.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/react.mjs CHANGED
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import {
3
+ AUDIO_DURATION_DESCRIPTIONS,
4
+ AUDIO_DURATION_PRESETS,
3
5
  BREAK_TIME_DESCRIPTIONS,
4
6
  BREAK_TIME_PRESETS,
5
7
  DEFAULT_LOCALE,
@@ -41,12 +43,13 @@ import {
41
43
  resolveExpressAsStyles,
42
44
  updateEditableText,
43
45
  updateTagAttribute,
46
+ validateAzureSsml,
44
47
  validateSsml
45
- } from "./chunk-4RQETJUI.mjs";
48
+ } from "./chunk-JNJVTEL6.mjs";
46
49
  import "./chunk-6S5ODO6A.mjs";
47
50
 
48
51
  // packages/ssml-editor-react/src/SsmlEditor.tsx
49
- import { Fragment, forwardRef, useImperativeHandle } from "react";
52
+ import { Fragment, forwardRef, useEffect as useEffect3, useImperativeHandle, useState as useState3 } from "react";
50
53
  import Editor from "@monaco-editor/react";
51
54
 
52
55
  // packages/ssml-editor-react/src/buttonVisibility.ts
@@ -139,6 +142,14 @@ var editorStyles = {
139
142
  display: "grid",
140
143
  gap: "0.5rem"
141
144
  },
145
+ visual: {
146
+ display: "grid",
147
+ gap: "0.75rem",
148
+ minHeight: "8rem",
149
+ padding: "0.75rem",
150
+ border: "1px solid var(--ssml-editor-control-border)",
151
+ borderRadius: "0.25rem"
152
+ },
142
153
  toolbarIconOnly: {
143
154
  justifyContent: "center",
144
155
  minWidth: "2.25rem",
@@ -503,7 +514,7 @@ function TimingPopovers(props) {
503
514
 
504
515
  // packages/ssml-editor-react/src/hooks/useSsmlEditorState.ts
505
516
  import { useCallback, useEffect, useId, useRef, useState } from "react";
506
- var TIMING_INSERTION_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence"]);
517
+ var TIMING_INSERTION_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence", "mstts:audioduration"]);
507
518
  var PROSODY_INSERTION_TAGS = /* @__PURE__ */ new Set(["prosody", "mstts:express-as", "voice", "emphasis"]);
508
519
  var TEXT_INSERTION_TAGS = /* @__PURE__ */ new Set(["sub", "say-as", "phoneme", "w", "lang"]);
509
520
  var EMPTY_SELECTION_OVERLAY = {
@@ -1407,7 +1418,7 @@ function registerSsmlCodeLens(monaco, editor, onOpenPopover) {
1407
1418
  break;
1408
1419
  }
1409
1420
  const tag = source.slice(tagStart, tagEnd + 1);
1410
- const tagName = tag.match(/^<\s*(prosody|break)\b/i)?.[1]?.toLowerCase();
1421
+ const tagName = tag.match(/^<\s*(prosody|break|mstts:audioduration)\b/i)?.[1]?.toLowerCase();
1411
1422
  index = tagEnd + 1;
1412
1423
  if (!tagName) {
1413
1424
  continue;
@@ -1437,7 +1448,22 @@ function registerSsmlCodeLens(monaco, editor, onOpenPopover) {
1437
1448
  elementRange
1438
1449
  })
1439
1450
  );
1440
- } else if (/\/\s*>$/.test(tag)) {
1451
+ } else if (tagName === "mstts:audioduration" && /\/\s*>$/.test(tag)) {
1452
+ lenses.push(
1453
+ createLens(
1454
+ model,
1455
+ tagStart,
1456
+ tagEnd + 1,
1457
+ `\u26A1 Duration: ${getAttributeValue(tag, "value") ?? "default"} (Click to edit)`,
1458
+ { type: "attribute", insertionId: "mstts:audioduration", attributeName: "value", tagRange }
1459
+ ),
1460
+ createLens(model, tagStart, tagEnd + 1, "Delete", {
1461
+ type: "delete",
1462
+ tagRange,
1463
+ elementRange
1464
+ })
1465
+ );
1466
+ } else if (tagName === "break" && /\/\s*>$/.test(tag)) {
1441
1467
  lenses.push(
1442
1468
  createLens(
1443
1469
  model,
@@ -1782,9 +1808,143 @@ function useSsmlMonaco({
1782
1808
  return { editorRef, onMount };
1783
1809
  }
1784
1810
 
1811
+ // packages/ssml-editor-react/src/components/VisualSsmlEditor.tsx
1812
+ import { useMemo, useState as useState2 } from "react";
1813
+ function isElement(node) {
1814
+ return typeof node !== "string" && node.type !== "text";
1815
+ }
1816
+ function elementLabel(element) {
1817
+ return element.type === "custom" || element.type === "element" ? element.name : element.type;
1818
+ }
1819
+ function collectTextLeaves(nodes, path = [], ancestors = []) {
1820
+ return nodes.flatMap((node, index) => {
1821
+ const currentPath = [...path, index];
1822
+ if (typeof node === "string") return [{ ancestors, path: currentPath, value: node }];
1823
+ if (node.type === "text") return [{ ancestors, path: currentPath, value: node.value }];
1824
+ return collectTextLeaves(node.children ?? [], currentPath, [...ancestors, elementLabel(node)]);
1825
+ });
1826
+ }
1827
+ function updateNodesAtPath(nodes, path, update) {
1828
+ if (path.length === 0) return nodes;
1829
+ const [index, ...rest] = path;
1830
+ return nodes.flatMap((node, nodeIndex) => {
1831
+ if (nodeIndex !== index) return [node];
1832
+ if (rest.length === 0) {
1833
+ const next = update(node);
1834
+ return Array.isArray(next) ? next : [next];
1835
+ }
1836
+ if (!isElement(node)) return [node];
1837
+ return [{ ...node, children: updateNodesAtPath(node.children ?? [], rest, update) }];
1838
+ });
1839
+ }
1840
+ function updateTextAtPath(document2, path, value) {
1841
+ return { ...document2, children: updateNodesAtPath(document2.children ?? [], path, () => value) };
1842
+ }
1843
+ function wrapTextAtPath(document2, path, start, end, tag, attributes) {
1844
+ return {
1845
+ ...document2,
1846
+ children: updateNodesAtPath(document2.children ?? [], path, (node) => {
1847
+ const value = typeof node === "string" ? node : node.type === "text" ? node.value : "";
1848
+ if (!value || start === end) return node;
1849
+ if (tag === "break") {
1850
+ return [
1851
+ value.slice(0, start),
1852
+ { type: tag, attributes, children: [] },
1853
+ value.slice(start)
1854
+ ].filter((part) => typeof part === "string" ? part.length > 0 : true);
1855
+ }
1856
+ const selected = value.slice(start, end);
1857
+ const wrapped = { type: tag, attributes, children: [selected] };
1858
+ return [value.slice(0, start), wrapped, value.slice(end)].filter(
1859
+ (part) => typeof part === "string" ? part.length > 0 : true
1860
+ );
1861
+ })
1862
+ };
1863
+ }
1864
+ function TreeNode({
1865
+ node,
1866
+ path,
1867
+ selectedPath,
1868
+ onSelect
1869
+ }) {
1870
+ if (!isElement(node)) return null;
1871
+ const name = elementLabel(node);
1872
+ const isSelected = selectedPath?.join(".") === path.join(".");
1873
+ return /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement("button", { type: "button", "aria-current": isSelected ? "true" : void 0, onClick: () => onSelect(path) }, `<${name}>`), (node.children ?? []).length > 0 && /* @__PURE__ */ React.createElement("ul", null, node.children?.map((child, index) => /* @__PURE__ */ React.createElement(
1874
+ TreeNode,
1875
+ {
1876
+ key: `${path.join(".")}/${isElement(child) ? elementLabel(child) : JSON.stringify(child)}`,
1877
+ node: child,
1878
+ path: [...path, index],
1879
+ selectedPath,
1880
+ onSelect
1881
+ }
1882
+ ))));
1883
+ }
1884
+ function VisualSsmlEditor({
1885
+ document: document2,
1886
+ readOnly = false,
1887
+ onChange,
1888
+ onPreviewSelection
1889
+ }) {
1890
+ const [selectedPath, setSelectedPath] = useState2(null);
1891
+ const [selection, setSelection] = useState2({ start: 0, end: 0 });
1892
+ const textLeaves = useMemo(() => collectTextLeaves(document2.children ?? []), [document2]);
1893
+ const selectedLeaf = textLeaves.find((leaf) => leaf.path.join(".") === selectedPath?.join(".")) ?? textLeaves[0];
1894
+ const diagnostics = useMemo(() => validateAzureSsml(buildSsml(document2)), [document2]);
1895
+ const commit = (nextDocument) => onChange?.(nextDocument);
1896
+ const applyWrapper = (tag, attributes) => {
1897
+ if (readOnly || !selectedLeaf) return;
1898
+ const start = selection.start === selection.end ? 0 : selection.start;
1899
+ const end = selection.start === selection.end ? selectedLeaf.value.length : selection.end;
1900
+ commit(wrapTextAtPath(document2, selectedLeaf.path, start, end, tag, attributes));
1901
+ };
1902
+ 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(
1903
+ TreeNode,
1904
+ {
1905
+ key: isElement(node) ? elementLabel(node) : JSON.stringify(node),
1906
+ node,
1907
+ path: [index],
1908
+ selectedPath,
1909
+ onSelect: setSelectedPath
1910
+ }
1911
+ )))), /* @__PURE__ */ React.createElement("div", { className: "ssml-editor-visual-form" }, selectedLeaf ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("label", null, "Text", /* @__PURE__ */ React.createElement(
1912
+ "textarea",
1913
+ {
1914
+ value: selectedLeaf.value,
1915
+ readOnly,
1916
+ onSelect: (event) => setSelection({ start: event.currentTarget.selectionStart, end: event.currentTarget.selectionEnd }),
1917
+ onChange: (event) => commit(updateTextAtPath(document2, selectedLeaf.path, event.target.value))
1918
+ }
1919
+ )), /* @__PURE__ */ React.createElement("fieldset", { className: "ssml-editor-visual-actions" }, /* @__PURE__ */ React.createElement("legend", null, "Apply SSML formatting"), /* @__PURE__ */ React.createElement("button", { type: "button", disabled: readOnly, onClick: () => applyWrapper("prosody", { rate: "slow" }) }, "Rate"), /* @__PURE__ */ React.createElement("button", { type: "button", disabled: readOnly, onClick: () => applyWrapper("prosody", { pitch: "high" }) }, "Pitch"), /* @__PURE__ */ React.createElement(
1920
+ "button",
1921
+ {
1922
+ type: "button",
1923
+ disabled: readOnly,
1924
+ onClick: () => applyWrapper("mstts:express-as", { style: "cheerful" })
1925
+ },
1926
+ "Emotion"
1927
+ ), /* @__PURE__ */ React.createElement("button", { type: "button", disabled: readOnly, onClick: () => applyWrapper("break", { time: "500ms" }) }, "Pause"), /* @__PURE__ */ React.createElement(
1928
+ "button",
1929
+ {
1930
+ type: "button",
1931
+ disabled: readOnly,
1932
+ onClick: () => applyWrapper("phoneme", { alphabet: "ipa", ph: selectedLeaf.value })
1933
+ },
1934
+ "Pronunciation"
1935
+ ), onPreviewSelection && /* @__PURE__ */ React.createElement(
1936
+ "button",
1937
+ {
1938
+ type: "button",
1939
+ onClick: () => onPreviewSelection(buildSsml({ ...document2, children: [selectedLeaf.value] }))
1940
+ },
1941
+ "Preview selection"
1942
+ ))) : /* @__PURE__ */ React.createElement("p", null, "Select an element or text node to edit it."))));
1943
+ }
1944
+
1785
1945
  // packages/ssml-editor-react/src/SsmlEditor.tsx
1786
1946
  var UNGROUPED_TOOLBAR_GROUP = "__ssml-editor-ungrouped__";
1787
- var TIMING_POPOVER_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence"]);
1947
+ var TIMING_POPOVER_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence", "mstts:audioduration"]);
1788
1948
  var PROSODY_POPOVER_TAGS = /* @__PURE__ */ new Set(["prosody", "mstts:express-as", "voice", "emphasis"]);
1789
1949
  var TEXT_POPOVER_TAGS = /* @__PURE__ */ new Set(["sub", "say-as", "phoneme", "w", "lang"]);
1790
1950
  function localizedText(value) {
@@ -2012,13 +2172,34 @@ var SSML_INSERTIONS = [
2012
2172
  suffix: "",
2013
2173
  mode: "insert"
2014
2174
  })
2175
+ },
2176
+ {
2177
+ id: "mstts:audioduration",
2178
+ icon: "\u25F7",
2179
+ tagName: "mstts:audioduration",
2180
+ selfClosing: true,
2181
+ labels: { ja: "\u97F3\u58F0\u9577", en: "Audio duration" },
2182
+ descriptions: {
2183
+ ja: "\u5408\u6210\u97F3\u58F0\u306E\u76EE\u6A19\u6642\u9593\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
2184
+ en: "Sets the target duration of synthesized audio."
2185
+ },
2186
+ parameterDescription: {
2187
+ ja: "\u76EE\u6A19\u6642\u9593\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
2188
+ en: "Selects the target duration."
2189
+ },
2190
+ options: createInsertionOptions(AUDIO_DURATION_PRESETS, AUDIO_DURATION_DESCRIPTIONS),
2191
+ createTemplate: (value) => ({
2192
+ prefix: `<mstts:audioduration value="${value}"/>`,
2193
+ suffix: "",
2194
+ mode: "insert"
2195
+ })
2015
2196
  }
2016
2197
  ];
2017
2198
  var DEFAULT_INSERTION_GROUPS = [
2018
2199
  {
2019
2200
  id: "pauses",
2020
2201
  labels: { ja: "\u9593\u30FB\u7121\u97F3", en: "Pauses" },
2021
- insertionIds: ["break", "mstts:silence"]
2202
+ insertionIds: ["break", "mstts:silence", "mstts:audioduration"]
2022
2203
  },
2023
2204
  {
2024
2205
  id: "prosody",
@@ -2227,6 +2408,60 @@ var STYLE_CSS = `
2227
2408
  > .ssml-editor-help-settings-summary::before {
2228
2409
  content: "\u25BE";
2229
2410
  }
2411
+ [data-ssml-editor] .ssml-editor-visual-layout {
2412
+ display: grid;
2413
+ grid-template-columns: minmax(12rem, 0.35fr) minmax(16rem, 1fr);
2414
+ gap: 1rem;
2415
+ }
2416
+ [data-ssml-editor] .ssml-editor-visual-tree,
2417
+ [data-ssml-editor] .ssml-editor-visual-form {
2418
+ display: grid;
2419
+ gap: 0.5rem;
2420
+ align-content: start;
2421
+ }
2422
+ [data-ssml-editor] .ssml-editor-visual-tree ul {
2423
+ margin: 0;
2424
+ padding-left: 1.25rem;
2425
+ }
2426
+ [data-ssml-editor] .ssml-editor-visual-tree button,
2427
+ [data-ssml-editor] .ssml-editor-visual-breadcrumb button,
2428
+ [data-ssml-editor] .ssml-editor-visual-actions button {
2429
+ padding: 0.35rem 0.5rem;
2430
+ border: 1px solid var(--ssml-editor-control-border);
2431
+ border-radius: 0.25rem;
2432
+ color: var(--ssml-editor-color);
2433
+ background: var(--ssml-editor-control-bg);
2434
+ cursor: pointer;
2435
+ }
2436
+ [data-ssml-editor] .ssml-editor-visual-tree button[aria-current] {
2437
+ border-color: var(--ssml-editor-active-border);
2438
+ background: var(--ssml-editor-active-bg);
2439
+ }
2440
+ [data-ssml-editor] .ssml-editor-visual-breadcrumb,
2441
+ [data-ssml-editor] .ssml-editor-visual-actions {
2442
+ display: flex;
2443
+ flex-wrap: wrap;
2444
+ gap: 0.4rem;
2445
+ align-items: center;
2446
+ }
2447
+ [data-ssml-editor] .ssml-editor-visual-form textarea {
2448
+ box-sizing: border-box;
2449
+ width: 100%;
2450
+ min-height: 6rem;
2451
+ padding: 0.5rem;
2452
+ color: var(--ssml-editor-color);
2453
+ background: var(--ssml-editor-control-bg);
2454
+ border: 1px solid var(--ssml-editor-control-border);
2455
+ border-radius: 0.25rem;
2456
+ font: inherit;
2457
+ }
2458
+ [data-ssml-editor] .ssml-editor-visual-errors {
2459
+ padding: 0.5rem;
2460
+ color: var(--ssml-editor-error);
2461
+ background: var(--ssml-editor-error-bg);
2462
+ border: 1px solid var(--ssml-editor-error);
2463
+ border-radius: 0.25rem;
2464
+ }
2230
2465
  `.trim();
2231
2466
  function injectEditorTheme() {
2232
2467
  if (typeof document !== "undefined" && !document.getElementById(STYLE_ID)) {
@@ -2296,8 +2531,11 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
2296
2531
  toolbarStyle,
2297
2532
  displayClassName,
2298
2533
  displayStyle,
2299
- loadingFallback
2534
+ loadingFallback,
2535
+ editMode: editModeProp = "code"
2300
2536
  }, ref) {
2537
+ const [editMode, setEditMode] = useState3(editModeProp);
2538
+ useEffect3(() => setEditMode(editModeProp), [editModeProp]);
2301
2539
  const resolvedEditorOptions = {
2302
2540
  ...settings,
2303
2541
  ...editorOptions,
@@ -2375,6 +2613,7 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
2375
2613
  );
2376
2614
  const {
2377
2615
  editorRef,
2616
+ draftDocument,
2378
2617
  text,
2379
2618
  selectionOverlay,
2380
2619
  activeTags,
@@ -2386,6 +2625,7 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
2386
2625
  syntaxError,
2387
2626
  setSyntaxError,
2388
2627
  helpPanelId,
2628
+ commit,
2389
2629
  handleTextChange,
2390
2630
  handleInsert,
2391
2631
  handleInsertBreak,
@@ -2645,10 +2885,39 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
2645
2885
  "aria-label": copy.toolbarAriaLabel,
2646
2886
  "data-ssml-editor-toolbar-actions": ""
2647
2887
  },
2648
- renderToolbarItems()
2888
+ renderToolbarItems(),
2889
+ /* @__PURE__ */ React.createElement("span", { style: editorStyles.toolbarSeparator, "aria-hidden": "true" }),
2890
+ /* @__PURE__ */ React.createElement(
2891
+ "button",
2892
+ {
2893
+ type: "button",
2894
+ style: editMode === "visual" ? { ...toolbarButtonStyle, ...editorStyles.toolbarButtonActive } : toolbarButtonStyle,
2895
+ "aria-pressed": editMode === "visual",
2896
+ onClick: () => setEditMode("visual")
2897
+ },
2898
+ "Visual"
2899
+ ),
2900
+ /* @__PURE__ */ React.createElement(
2901
+ "button",
2902
+ {
2903
+ type: "button",
2904
+ style: editMode === "code" ? { ...toolbarButtonStyle, ...editorStyles.toolbarButtonActive } : toolbarButtonStyle,
2905
+ "aria-pressed": editMode === "code",
2906
+ onClick: () => setEditMode("code")
2907
+ },
2908
+ "Code"
2909
+ )
2649
2910
  )
2650
2911
  ),
2651
- /* @__PURE__ */ React.createElement("div", { className: displayClassName, style: { ...editorStyles.display, ...displayStyle }, "data-ssml-editor-display": "" }, isHelpOpen && isSsmlEditorButtonVisible(buttonVisibility, "help") && /* @__PURE__ */ React.createElement("section", { id: helpPanelId, style: editorStyles.helpPanel, "aria-label": copy.helpHeading }, /* @__PURE__ */ React.createElement("h3", { style: editorStyles.helpHeading }, copy.helpHeading), /* @__PURE__ */ React.createElement("p", { style: editorStyles.helpDescription }, copy.helpDescription), helpInsertions.length > 0 && /* @__PURE__ */ React.createElement("ul", { style: editorStyles.helpList }, helpInsertions.map((insertion) => /* @__PURE__ */ React.createElement("li", { key: insertion.id, style: editorStyles.helpItem }, /* @__PURE__ */ React.createElement("details", { className: "ssml-editor-help-settings-accordion", style: editorStyles.helpSettingsAccordion }, /* @__PURE__ */ React.createElement("summary", { className: "ssml-editor-help-settings-summary", style: editorStyles.helpSettingsSummary }, /* @__PURE__ */ React.createElement("span", { style: editorStyles.helpIcon, "aria-hidden": "true" }, insertion.icon), /* @__PURE__ */ React.createElement("span", { style: editorStyles.helpSettingsSummaryContent }, /* @__PURE__ */ React.createElement("strong", null, insertion.labels[language]), " ", insertion.tagName && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("code", null, `<${insertion.tagName}${insertion.selfClosing ? "/>" : ">"}`), " \u2014", " "), insertion.descriptions[language])), /* @__PURE__ */ React.createElement("p", { style: editorStyles.helpSettingsDescription }, /* @__PURE__ */ React.createElement("strong", null, copy.parameters, ":"), " ", insertion.parameterDescription[language]), /* @__PURE__ */ React.createElement("ul", { style: editorStyles.helpSettingsList }, insertion.options.map((option) => /* @__PURE__ */ React.createElement("li", { key: option.value }, /* @__PURE__ */ React.createElement("strong", null, option.labels[language]), option.descriptions && /* @__PURE__ */ React.createElement(React.Fragment, null, " \u2014 ", option.descriptions[language]))))))))), /* @__PURE__ */ React.createElement("div", { style: { ...editorStyles.editor, minHeight: editorMinHeight } }, /* @__PURE__ */ React.createElement(
2912
+ /* @__PURE__ */ React.createElement("div", { className: displayClassName, style: { ...editorStyles.display, ...displayStyle }, "data-ssml-editor-display": "" }, isHelpOpen && isSsmlEditorButtonVisible(buttonVisibility, "help") && /* @__PURE__ */ React.createElement("section", { id: helpPanelId, style: editorStyles.helpPanel, "aria-label": copy.helpHeading }, /* @__PURE__ */ React.createElement("h3", { style: editorStyles.helpHeading }, copy.helpHeading), /* @__PURE__ */ React.createElement("p", { style: editorStyles.helpDescription }, copy.helpDescription), helpInsertions.length > 0 && /* @__PURE__ */ React.createElement("ul", { style: editorStyles.helpList }, helpInsertions.map((insertion) => /* @__PURE__ */ React.createElement("li", { key: insertion.id, style: editorStyles.helpItem }, /* @__PURE__ */ React.createElement("details", { className: "ssml-editor-help-settings-accordion", style: editorStyles.helpSettingsAccordion }, /* @__PURE__ */ React.createElement("summary", { className: "ssml-editor-help-settings-summary", style: editorStyles.helpSettingsSummary }, /* @__PURE__ */ React.createElement("span", { style: editorStyles.helpIcon, "aria-hidden": "true" }, insertion.icon), /* @__PURE__ */ React.createElement("span", { style: editorStyles.helpSettingsSummaryContent }, /* @__PURE__ */ React.createElement("strong", null, insertion.labels[language]), " ", insertion.tagName && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("code", null, `<${insertion.tagName}${insertion.selfClosing ? "/>" : ">"}`), " \u2014", " "), insertion.descriptions[language])), /* @__PURE__ */ React.createElement("p", { style: editorStyles.helpSettingsDescription }, /* @__PURE__ */ React.createElement("strong", null, copy.parameters, ":"), " ", insertion.parameterDescription[language]), /* @__PURE__ */ React.createElement("ul", { style: editorStyles.helpSettingsList }, insertion.options.map((option) => /* @__PURE__ */ React.createElement("li", { key: option.value }, /* @__PURE__ */ React.createElement("strong", null, option.labels[language]), option.descriptions && /* @__PURE__ */ React.createElement(React.Fragment, null, " \u2014 ", option.descriptions[language]))))))))), editMode === "visual" ? /* @__PURE__ */ React.createElement("div", { style: editorStyles.visual }, /* @__PURE__ */ React.createElement(
2913
+ VisualSsmlEditor,
2914
+ {
2915
+ document: draftDocument,
2916
+ readOnly: isReadOnly,
2917
+ onChange: commit,
2918
+ onPreviewSelection
2919
+ }
2920
+ )) : /* @__PURE__ */ React.createElement("div", { style: { ...editorStyles.editor, minHeight: editorMinHeight } }, /* @__PURE__ */ React.createElement(
2652
2921
  Editor,
2653
2922
  {
2654
2923
  height: editorHeight,
@@ -2709,6 +2978,7 @@ export {
2709
2978
  SSML_HOVER_COPY,
2710
2979
  SSML_INSERTIONS,
2711
2980
  SsmlEditor,
2981
+ VisualSsmlEditor,
2712
2982
  createSsmlEditorInsertionDefinition,
2713
2983
  registerSsmlCodeLens,
2714
2984
  updateTagAttribute