@ssml-builder-js/ssml-editor-react 2.13.0 → 2.14.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,16 @@
1
1
  # @ssml-builder-js/ssml-editor-react
2
2
 
3
+ ## 2.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add safe container-aware audio merging, preflight-validated SSML chunk synthesis with structured progress events, source mapping metadata, controlled URL validation, and voice capability details in the Visual Editor.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @ssml-builder-js/ssml-core@2.14.0
13
+
3
14
  ## 2.13.0
4
15
 
5
16
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -78,13 +78,17 @@ interface VisualVoiceCatalogEntry {
78
78
  name: string;
79
79
  locale: string;
80
80
  region?: string;
81
+ regions?: readonly string[];
81
82
  styles?: readonly string[];
83
+ supportedTags?: readonly string[];
84
+ unsupportedTags?: readonly string[];
82
85
  preview?: boolean;
83
86
  status?: "ga" | "preview" | "deprecated";
84
87
  }
85
88
  interface VoiceSelectorRenderProps {
86
89
  value: string;
87
90
  voices: readonly VisualVoiceCatalogEntry[];
91
+ selectedVoice?: VisualVoiceCatalogEntry;
88
92
  readOnly: boolean;
89
93
  locale: SsmlEditorLocale;
90
94
  onChange: (voice: string) => void;
package/dist/index.d.ts CHANGED
@@ -78,13 +78,17 @@ interface VisualVoiceCatalogEntry {
78
78
  name: string;
79
79
  locale: string;
80
80
  region?: string;
81
+ regions?: readonly string[];
81
82
  styles?: readonly string[];
83
+ supportedTags?: readonly string[];
84
+ unsupportedTags?: readonly string[];
82
85
  preview?: boolean;
83
86
  status?: "ga" | "preview" | "deprecated";
84
87
  }
85
88
  interface VoiceSelectorRenderProps {
86
89
  value: string;
87
90
  voices: readonly VisualVoiceCatalogEntry[];
91
+ selectedVoice?: VisualVoiceCatalogEntry;
88
92
  readOnly: boolean;
89
93
  locale: SsmlEditorLocale;
90
94
  onChange: (voice: string) => void;
package/dist/index.js CHANGED
@@ -5035,28 +5035,72 @@ function localizedElementLabel(element, locale) {
5035
5035
  function filteredVoices(voiceCatalog, locale, region, style) {
5036
5036
  return (voiceCatalog ?? []).filter((voice) => {
5037
5037
  if (locale && voice.locale.toLowerCase() !== locale.toLowerCase()) return false;
5038
- if (region && voice.region && voice.region.toLowerCase() !== region.toLowerCase()) return false;
5038
+ const regions = [voice.region, ...voice.regions ?? []].filter(
5039
+ (candidate) => Boolean(candidate)
5040
+ );
5041
+ if (region && regions.length > 0 && !regions.some((candidate) => candidate.toLowerCase() === region.toLowerCase()))
5042
+ return false;
5039
5043
  if (style && !voice.styles?.some((candidate) => candidate.toLowerCase() === style.toLowerCase())) return false;
5040
5044
  return true;
5041
5045
  });
5042
5046
  }
5043
- function DefaultVoiceSelector({ value, voices, readOnly, locale, onChange }) {
5044
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
5045
- "select",
5046
- {
5047
- "aria-label": locale === "ja" ? "\u97F3\u58F0" : "Voice",
5048
- value,
5049
- disabled: readOnly,
5050
- onChange: (event) => onChange(event.target.value),
5051
- children: [
5052
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: locale === "ja" ? "\u97F3\u58F0\u3092\u9078\u629E" : "Select a voice" }),
5053
- voices.map((voice) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("option", { value: voice.name, children: [
5054
- voice.name,
5055
- voice.preview || voice.status === "preview" ? " (preview)" : ""
5056
- ] }, voice.name))
5057
- ]
5058
- }
5059
- );
5047
+ function VoiceCapabilityMatrix({
5048
+ voice,
5049
+ locale
5050
+ }) {
5051
+ const status = voice.status ?? (voice.preview ? "preview" : void 0);
5052
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ssml-editor-voice-capabilities", "data-voice-capabilities": "", children: [
5053
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
5054
+ locale === "ja" ? "\u30B9\u30C6\u30FC\u30BF\u30B9" : "Status",
5055
+ ": ",
5056
+ status?.toUpperCase() ?? (locale === "ja" ? "GA" : "GA"),
5057
+ status === "preview" || status === "deprecated" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { role: "status", "aria-label": status, className: "ssml-editor-voice-warning-badge", children: status === "preview" ? "\u26A0 Preview" : "\u26A0 Deprecated" }) : null
5058
+ ] }),
5059
+ (voice.regions?.length || voice.region) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
5060
+ locale === "ja" ? "\u30EA\u30FC\u30B8\u30E7\u30F3" : "Regions",
5061
+ ":",
5062
+ " ",
5063
+ [...voice.regions ?? [], ...voice.region ? [voice.region] : []].filter((region, index, all) => all.indexOf(region) === index).join(", ")
5064
+ ] }),
5065
+ voice.supportedTags && voice.supportedTags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
5066
+ locale === "ja" ? "\u5BFE\u5FDC\u30BF\u30B0" : "Supported tags",
5067
+ ": ",
5068
+ voice.supportedTags.join(", ")
5069
+ ] }),
5070
+ voice.unsupportedTags && voice.unsupportedTags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ssml-editor-voice-unsupported", children: [
5071
+ locale === "ja" ? "\u975E\u5BFE\u5FDC\u30BF\u30B0" : "Unsupported tags",
5072
+ ": ",
5073
+ voice.unsupportedTags.join(", ")
5074
+ ] })
5075
+ ] });
5076
+ }
5077
+ function DefaultVoiceSelector({
5078
+ value,
5079
+ voices,
5080
+ selectedVoice,
5081
+ readOnly,
5082
+ locale,
5083
+ onChange
5084
+ }) {
5085
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5086
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
5087
+ "select",
5088
+ {
5089
+ "aria-label": locale === "ja" ? "\u97F3\u58F0" : "Voice",
5090
+ value,
5091
+ disabled: readOnly,
5092
+ onChange: (event) => onChange(event.target.value),
5093
+ children: [
5094
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "", children: locale === "ja" ? "\u97F3\u58F0\u3092\u9078\u629E" : "Select a voice" }),
5095
+ voices.map((voice) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("option", { value: voice.name, children: [
5096
+ voice.name,
5097
+ voice.preview || voice.status === "preview" ? " (preview)" : ""
5098
+ ] }, voice.name))
5099
+ ]
5100
+ }
5101
+ ),
5102
+ selectedVoice ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VoiceCapabilityMatrix, { voice: selectedVoice, locale }) : null
5103
+ ] });
5060
5104
  }
5061
5105
  function VisualElementInspector({
5062
5106
  document: document2,
@@ -5077,6 +5121,9 @@ function VisualElementInspector({
5077
5121
  }
5078
5122
  const fields = getElementFields(element);
5079
5123
  const availableVoices = filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle);
5124
+ const selectedVoice = voiceCatalog?.find(
5125
+ (voice) => voice.name === (element.type === "voice" ? element.name : void 0)
5126
+ );
5080
5127
  const renderSelector = renderVoiceSelector ?? DefaultVoiceSelector;
5081
5128
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("fieldset", { children: [
5082
5129
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: `<${elementLabel(element)}>` }),
@@ -5122,6 +5169,7 @@ function VisualElementInspector({
5122
5169
  field.key === "name" && elementLabel(element) === "voice" && voiceCatalog ? renderSelector({
5123
5170
  value: inputValue,
5124
5171
  voices: availableVoices,
5172
+ selectedVoice,
5125
5173
  readOnly,
5126
5174
  locale,
5127
5175
  onChange: (value2) => commit(updateOptionalElementProperty(document2, path, field.key, value2))
@@ -5296,6 +5344,7 @@ function VisualSsmlEditor({
5296
5344
  voiceCatalog ? (renderVoiceSelector ?? DefaultVoiceSelector)({
5297
5345
  value: selectedElement.voice ?? "",
5298
5346
  voices: filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle),
5347
+ selectedVoice: voiceCatalog?.find((voice) => voice.name === selectedElement.voice),
5299
5348
  readOnly,
5300
5349
  locale,
5301
5350
  onChange: (value) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "voice", value))