@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 +11 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +67 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/VisualSsmlEditor.tsx +79 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ssml-builder-js/ssml-editor-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "React-based SSML editor component",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -52,6 +52,6 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@ssml-builder-js/ssml-core": "^2.
|
|
55
|
+
"@ssml-builder-js/ssml-core": "^2.14.0"
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -13,7 +13,10 @@ export interface VisualVoiceCatalogEntry {
|
|
|
13
13
|
name: string;
|
|
14
14
|
locale: string;
|
|
15
15
|
region?: string;
|
|
16
|
+
regions?: readonly string[];
|
|
16
17
|
styles?: readonly string[];
|
|
18
|
+
supportedTags?: readonly string[];
|
|
19
|
+
unsupportedTags?: readonly string[];
|
|
17
20
|
preview?: boolean;
|
|
18
21
|
status?: "ga" | "preview" | "deprecated";
|
|
19
22
|
}
|
|
@@ -21,6 +24,7 @@ export interface VisualVoiceCatalogEntry {
|
|
|
21
24
|
export interface VoiceSelectorRenderProps {
|
|
22
25
|
value: string;
|
|
23
26
|
voices: readonly VisualVoiceCatalogEntry[];
|
|
27
|
+
selectedVoice?: VisualVoiceCatalogEntry;
|
|
24
28
|
readOnly: boolean;
|
|
25
29
|
locale: SsmlEditorLocale;
|
|
26
30
|
onChange: (voice: string) => void;
|
|
@@ -240,28 +244,82 @@ function filteredVoices(
|
|
|
240
244
|
): readonly VisualVoiceCatalogEntry[] {
|
|
241
245
|
return (voiceCatalog ?? []).filter((voice) => {
|
|
242
246
|
if (locale && voice.locale.toLowerCase() !== locale.toLowerCase()) return false;
|
|
243
|
-
|
|
247
|
+
const regions = [voice.region, ...(voice.regions ?? [])].filter((candidate): candidate is string =>
|
|
248
|
+
Boolean(candidate),
|
|
249
|
+
);
|
|
250
|
+
if (region && regions.length > 0 && !regions.some((candidate) => candidate.toLowerCase() === region.toLowerCase()))
|
|
251
|
+
return false;
|
|
244
252
|
if (style && !voice.styles?.some((candidate) => candidate.toLowerCase() === style.toLowerCase())) return false;
|
|
245
253
|
return true;
|
|
246
254
|
});
|
|
247
255
|
}
|
|
248
256
|
|
|
249
|
-
function
|
|
257
|
+
function VoiceCapabilityMatrix({
|
|
258
|
+
voice,
|
|
259
|
+
locale,
|
|
260
|
+
}: {
|
|
261
|
+
voice: VisualVoiceCatalogEntry;
|
|
262
|
+
locale: SsmlEditorLocale;
|
|
263
|
+
}): ReactElement {
|
|
264
|
+
const status = voice.status ?? (voice.preview ? "preview" : undefined);
|
|
250
265
|
return (
|
|
251
|
-
<
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
266
|
+
<div className="ssml-editor-voice-capabilities" data-voice-capabilities="">
|
|
267
|
+
<div>
|
|
268
|
+
{locale === "ja" ? "ステータス" : "Status"}: {status?.toUpperCase() ?? (locale === "ja" ? "GA" : "GA")}
|
|
269
|
+
{status === "preview" || status === "deprecated" ? (
|
|
270
|
+
<span role="status" aria-label={status} className="ssml-editor-voice-warning-badge">
|
|
271
|
+
{status === "preview" ? "⚠ Preview" : "⚠ Deprecated"}
|
|
272
|
+
</span>
|
|
273
|
+
) : null}
|
|
274
|
+
</div>
|
|
275
|
+
{(voice.regions?.length || voice.region) && (
|
|
276
|
+
<div>
|
|
277
|
+
{locale === "ja" ? "リージョン" : "Regions"}:{" "}
|
|
278
|
+
{[...(voice.regions ?? []), ...(voice.region ? [voice.region] : [])]
|
|
279
|
+
.filter((region, index, all) => all.indexOf(region) === index)
|
|
280
|
+
.join(", ")}
|
|
281
|
+
</div>
|
|
282
|
+
)}
|
|
283
|
+
{voice.supportedTags && voice.supportedTags.length > 0 && (
|
|
284
|
+
<div>
|
|
285
|
+
{locale === "ja" ? "対応タグ" : "Supported tags"}: {voice.supportedTags.join(", ")}
|
|
286
|
+
</div>
|
|
287
|
+
)}
|
|
288
|
+
{voice.unsupportedTags && voice.unsupportedTags.length > 0 && (
|
|
289
|
+
<div className="ssml-editor-voice-unsupported">
|
|
290
|
+
{locale === "ja" ? "非対応タグ" : "Unsupported tags"}: {voice.unsupportedTags.join(", ")}
|
|
291
|
+
</div>
|
|
292
|
+
)}
|
|
293
|
+
</div>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function DefaultVoiceSelector({
|
|
298
|
+
value,
|
|
299
|
+
voices,
|
|
300
|
+
selectedVoice,
|
|
301
|
+
readOnly,
|
|
302
|
+
locale,
|
|
303
|
+
onChange,
|
|
304
|
+
}: VoiceSelectorRenderProps): ReactElement {
|
|
305
|
+
return (
|
|
306
|
+
<>
|
|
307
|
+
<select
|
|
308
|
+
aria-label={locale === "ja" ? "音声" : "Voice"}
|
|
309
|
+
value={value}
|
|
310
|
+
disabled={readOnly}
|
|
311
|
+
onChange={(event) => onChange(event.target.value)}
|
|
312
|
+
>
|
|
313
|
+
<option value="">{locale === "ja" ? "音声を選択" : "Select a voice"}</option>
|
|
314
|
+
{voices.map((voice) => (
|
|
315
|
+
<option key={voice.name} value={voice.name}>
|
|
316
|
+
{voice.name}
|
|
317
|
+
{voice.preview || voice.status === "preview" ? " (preview)" : ""}
|
|
318
|
+
</option>
|
|
319
|
+
))}
|
|
320
|
+
</select>
|
|
321
|
+
{selectedVoice ? <VoiceCapabilityMatrix voice={selectedVoice} locale={locale} /> : null}
|
|
322
|
+
</>
|
|
265
323
|
);
|
|
266
324
|
}
|
|
267
325
|
|
|
@@ -297,6 +355,9 @@ function VisualElementInspector({
|
|
|
297
355
|
}
|
|
298
356
|
const fields = getElementFields(element);
|
|
299
357
|
const availableVoices = filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle);
|
|
358
|
+
const selectedVoice = voiceCatalog?.find(
|
|
359
|
+
(voice) => voice.name === (element.type === "voice" ? element.name : undefined),
|
|
360
|
+
);
|
|
300
361
|
const renderSelector = renderVoiceSelector ?? DefaultVoiceSelector;
|
|
301
362
|
return (
|
|
302
363
|
<fieldset>
|
|
@@ -352,6 +413,7 @@ function VisualElementInspector({
|
|
|
352
413
|
renderSelector({
|
|
353
414
|
value: inputValue,
|
|
354
415
|
voices: availableVoices,
|
|
416
|
+
selectedVoice,
|
|
355
417
|
readOnly,
|
|
356
418
|
locale,
|
|
357
419
|
onChange: (value) => commit(updateOptionalElementProperty(document, path, field.key, value)),
|
|
@@ -577,6 +639,7 @@ export function VisualSsmlEditor({
|
|
|
577
639
|
(renderVoiceSelector ?? DefaultVoiceSelector)({
|
|
578
640
|
value: selectedElement.voice ?? "",
|
|
579
641
|
voices: filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle),
|
|
642
|
+
selectedVoice: voiceCatalog?.find((voice) => voice.name === selectedElement.voice),
|
|
580
643
|
readOnly,
|
|
581
644
|
locale,
|
|
582
645
|
onChange: (value) =>
|