ssml-builder-js 2.8.1 → 2.10.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/README.md CHANGED
@@ -48,7 +48,7 @@ Azure TTS クライアントも `ssml-builder-js` から利用できます。
48
48
 
49
49
  ### リポジトリを開発する場合
50
50
 
51
- Node.js 24 以降を用意し、リポジトリのルートで依存関係をインストールします。
51
+ Node.js 22.6 以降をサポートします。Node.js 24 LTS 以降を推奨します(Node.js 22.6 未満は、現在の TypeScript 実行設定に必要な型消去機能を満たしません)。
52
52
 
53
53
  ```sh
54
54
  npm ci
@@ -83,6 +83,31 @@ Playground の表示言語が日本語以外の場合、埋め込みエディタ
83
83
  SSML 全体または選択部分を Azure Speech で合成してブラウザーで再生でき、音声には
84
84
  SSML 本文のキャプションが付きます。生成された SSML は画面下部に表示されます。
85
85
 
86
+ ### Next.js で Monaco と選択範囲試聴を使う
87
+
88
+ Pages Router と App Router のどちらでも、Monaco を `next/dynamic` の `ssr: false` でクライアントへ分離します。`onPreviewSelection` から `/api/synthesize` Route Handler(Pages Router では同じ検証を `pages/api/synthesize.ts` に実装)へ部分 SSML を送り、Azure のキーはサーバー環境変数だけに置きます。リポジトリ内の `apps/playground/app/components/NextSsmlEditor.tsx` がこの構成の実装例です。
89
+
90
+ ```tsx
91
+ "use client";
92
+ import dynamic from "next/dynamic";
93
+ const SsmlEditor = dynamic(
94
+ () => import("ssml-builder-js/react").then(({ SsmlEditor }) => SsmlEditor),
95
+ { ssr: false },
96
+ );
97
+
98
+ export function ClientEditor(props) {
99
+ return <SsmlEditor {...props} onPreviewSelection={(ssml) =>
100
+ fetch("/api/synthesize", {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/json" },
103
+ body: JSON.stringify({ ssml }),
104
+ })
105
+ } />;
106
+ }
107
+ ```
108
+
109
+ Route Handler/API Route では `validateSsml` と `validateAzureSsml` を実行してから Azure TTS を呼び出し、キーをクライアントへ渡さないでください。
110
+
86
111
  ## `ssml-core` の利用方法
87
112
 
88
113
  `SsmlDocument` は `version`、`lang`、`children` を持つオブジェクトです。`children` には文字列、テキストノード、SSML 要素を入れられます。`children` を使う形式が推奨され、旧形式の `content` プロパティも `buildSsml` の入力として利用できます。
@@ -136,7 +161,11 @@ const parsed = parseSsml(ssml);
136
161
  | `validateSsml(xml)` | SSML の構文エラーを `{ message, position }` または `null` で返す |
137
162
  | `extractSsmlText(xml)` | タグを除いた全テキストノードを文書順に抽出 |
138
163
  | `mapSsmlTextNodes(xml, transform, options?)` | タグ構造を維持したままテキストノードだけを同期・非同期変換。スキップタグとコンテキストフィルターに対応 |
164
+ | `extractSsmlTranslatableText(xml, options?)` | `phoneme`、`say-as`、`sub` などを除外した翻訳対象本文を文書順に抽出 |
165
+ | `fromPlainTextToSsml(text, options?)` | プレーンテキストを `<speak>`、段落 `<p>`、文 `<s>` を含む SSML に変換 |
166
+ | `validateSsmlStructureIntegrity(original, translated)` | 翻訳前後のタグ階層・タグ名・属性の一致を検証 |
139
167
  | `validateAzureSsml(xml, options?)` | Azure Speech 向けの意味検証結果を Diagnostic 配列で返す(各診断に `source: "ssml-static-validator"` を付与) |
168
+ | `getAzureVoiceCatalogMetadata()` / `getBuiltInVoiceCatalogMetadata()` | 組み込み音声カタログの生成日時、API バージョン、リージョン、収録数を返す |
140
169
 
141
170
  ### 3段階の検証モデル
142
171
 
@@ -148,7 +177,9 @@ SSML の検証は、構文、Azure 固有の静的な意味、実サービスの
148
177
  | 静的意味 | `validateAzureSsml` | Azure SSML の必須要素、属性値、音声と `xml:lang` の整合性、音声スタイル、文字数、`audio` URL/オリジン | Azure 側の最新音声一覧、キー・リージョン権限、サービス障害、実際の音声生成結果 |
149
178
  | ランタイム | `AzureTtsClient.synthesize` / Azure Speech API | アカウント、リージョン、キー、最新の音声・スタイル提供状況、サービス側の SSML 制約、通信状態 | 静的検証の代替ではないため、入力検証や SSRF 対策を自動で補完しない |
150
179
 
151
- `voice`、`prosody`、`break`、`express-as`、`say-as`、`phoneme`、`audio`、`lang`、`mark` などの要素を型付きで表現できます。`type: "custom"` と `name` を指定すれば、未定義の XML 要素や追加属性も扱えます。`mstts:` 要素を含むドキュメントを生成すると、必要な Azure Speech 名前空間が自動的に追加されます。
180
+ `voice`、`prosody`、`break`、`express-as`、`say-as`、`phoneme`、`audio`、`lang`、`mark` に加えて、`mstts:dialog`、`mstts:turn`、`mstts:backgroundaudio`、`mstts:ttsembedding`、`mstts:embedding`、`mstts:voiceconversion` を型付きで表現できます。`type: "custom"` と `name` を指定すれば、未定義の XML 要素や追加属性も扱えます。`mstts:` 要素を含むドキュメントを生成すると、必要な Azure Speech 名前空間が自動的に追加されます。
181
+
182
+ `mstts:turn` は `voice` またはマルチトーカー用の `speaker` を指定でき、`mstts:ttsembedding` は `speakerProfileId`、`mstts:embedding` は `id`、`mstts:voiceconversion` は `url` と `profile` を専用プロパティで指定できます。`mstts:backgroundaudio` は `<speak>` 直下の先頭要素として 1 文書に 1 つだけ配置します。
152
183
 
153
184
  `validateAzureSsml` は Azure Speech へ送信する前に実行する事前静的チェックです。返却される診断の `source` はパッケージ側の静的解析結果であることを示し、Azure Speech サービス側でのランタイム生成結果や実際の合成可否を表すものではありません。
154
185
 
@@ -158,6 +189,8 @@ SSML の検証は、構文、Azure 固有の静的な意味、実サービスの
158
189
 
159
190
  `mapSsmlTextNodes` の第 3 引数で、翻訳対象外タグとコンテキストフィルターを指定できます。デフォルトでは `phoneme`、`say-as`、`sub` の本文を変換しません。`filter` には `parentTag`、`parentAttributes`、`ancestorTags`、`path` が渡されます。
160
191
 
192
+ 移行処理では `extractSsmlTranslatableText` で翻訳対象だけを抽出し、`validateSsmlStructureIntegrity` で翻訳後にタグ階層と属性が変わっていないことを確認できます。新しい原稿は `fromPlainTextToSsml` で `<p>` と `<s>` を含む初期文書へ変換できます。
193
+
161
194
  ```ts
162
195
  const translated = await mapSsmlTextNodes(ssml, translate, {
163
196
  skipTags: ["phoneme", "say-as", "sub", "custom-no-translate"],
@@ -175,7 +208,9 @@ const diagnostics = validateAzureSsml(ssml, {
175
208
  });
176
209
  ```
177
210
 
178
- 音声カタログは `AzureVoiceDefinition` の `name`、`locale`、`secondaryLocales`、`styles` で表現できます。`voiceDefinitions`(または `voiceCatalog`)を渡すと、組み込み台帳を外部定義で補完・上書きできます。`customVoiceStyleMap` は既存利用者向けに引き続き利用でき、指定した音声のスタイルを上書きします。組み込み台帳にない音声は `azure-unknown-voice`(`unknownVoicePolicy` に従う)、登録済み音声への非対応スタイルは `azure-unsupported-style`、ロケール不一致は `azure-locale-mismatch` として区別されます。
211
+ 音声カタログは `AzureVoiceDefinition` の `name`、`locale`、`secondaryLocales`、`styles`、`supportedTags`、`unsupportedTags`、`models` で表現できます。`voiceDefinitions`(または `voiceCatalog`)を渡すと、組み込み台帳を外部定義で補完・上書きできます。`supportedTags`/`unsupportedTags` による音声別制約違反は `azure-unsupported-tag-for-voice` としてエラーになります。組み込み台帳にない音声は `azure-unknown-voice`(`unknownVoicePolicy` に従う)、登録済み音声への非対応スタイルは `azure-unsupported-style`、ロケール不一致は `azure-locale-mismatch` として区別されます。
212
+
213
+ `npm run sync:voices -- --regions eastus,japaneast` は Azure List Voices API をリージョンごとに取得し、重複を除いた TypeScript 音声定義と `azureVoiceCatalog.json`(生成日時、API バージョン、リージョン、収録数)を更新します。認証情報は `AZURE_SPEECH_KEY` と `AZURE_SPEECH_REGION(S)`、または CLI オプションで指定します。
179
214
 
180
215
  ```ts
181
216
  const diagnostics = validateAzureSsml(ssml, {
@@ -210,6 +245,8 @@ Azure Speech は `<audio>` の URL を取得するため、任意の URL をそ
210
245
 
211
246
  `SsmlEditor` は `SsmlDocument` を受け取り、ツールバーと本文の表示エリアだけを表示するシンプルなコンポーネントです。ツールバーから選択範囲の速度、音量、ピッチなどの設定、元に戻す・やり直す操作ができます。音声の選択と表示はアプリ側で行います。本文の編集には Monaco Editor を使用し、変更時に SSML の構文を検証します。構文エラーはエディター上のマーカーとエラーメッセージで表示されます。XML のタグ名やパラメータへホバーすると SSML の説明を確認できます。テキストを選択すると、選択文字数と試聴を行うフローティングアクションが表示されます。`enableCodeLens`(デフォルトは `true`)が有効な場合、`prosody`、`break`、`mstts:audioduration` タグの上に属性編集やタグ操作の CodeLens が表示されます。`showDecorations` が有効な場合、`break` と `prosody` のタグに間やピッチ変化を示すインラインバッジが表示され、Monaco のインライン装飾も有効になります。生成された SSML は `onSsmlChange` で受け取り、アプリ側で自由に表示できます。`SsmlEditorRef` を `ref` に渡すと、全体、選択範囲、または現在行の SSML を取得できます。画面表示は日本語(デフォルト)と英語に対応しています。
212
247
 
248
+ `editMode="visual"` を指定するかツールバーの **Visual** を選ぶと、XML を直接見ずに構造ツリーとパンくずから親要素を選択し、フォームで本文の変更、rate、pitch、emotion、pause、pronunciation の適用ができます。Azure の配置違反や属性エラーはビジュアル領域にも表示されます。`editMode="code"` で Monaco に戻ります。
249
+
213
250
  `<mstts:express-as>` の `style` 属性補完と標準の感情メニューは、カーソルまたは選択範囲を囲む最内の `<voice name="...">` が対応するスタイルだけを表示します。音声名が未指定の場合は全候補を表示し、登録済みでスタイル非対応の音声や未登録の音声では候補がないことを表示します。`emotionStyles` を指定した場合、感情メニューではその値と登録済み音声の対応スタイルの共通部分を使用します。
214
251
 
215
252
  ```tsx
@@ -247,6 +284,7 @@ export function App() {
247
284
  - `ref`: `SsmlEditorRef` の `getFullSsml()` で全体の SSML、`getSelectedSsml()` で選択範囲(未選択時は内容が空でないカーソル行)の SSML、`getCurrentLineSsml()` で現在行の SSML を取得。選択範囲やカーソル行が空の場合は `null` を返します
248
285
  - `onSelectionChange`: 選択テキスト、文字数、選択状態を受け取るコールバック
249
286
  - `onPreviewSelection`: フローティングアクションの試聴ボタン押下時に、選択部分の SSML を受け取るコールバック。省略時は試聴ボタンが無効になります。Azure などの音声 API はこのコールバックから呼び出してください
287
+ - `editMode`: 初期編集モード(`"code"` または `"visual"`)。Visual モードは構造ツリーとフォームによる構造化編集を提供します
250
288
  - `locale`: 画面表示の言語(`"ja"` または `"en"`)。省略時は `"ja"`。ホバーヘルプを含む UI の翻訳にも使用されます
251
289
  - `language`: `locale` の旧名称。既存コードとの互換性のため利用できますが、新しいコードでは `locale` を使用してください
252
290
  - `showToolbar`: ツールバー領域を表示するかどうか(デフォルトは `true`)
@@ -276,7 +314,7 @@ export function App() {
276
314
 
277
315
  ## `ssml-editor-elements` の利用方法
278
316
 
279
- `ssml-builder-js/elements` は、React などに依存しない `<ssml-editor>` Web Component を登録します。`monaco-editor` を別途インストールし、`value`、`theme`、`readonly` 属性または同名プロパティを使用できます。React エディターと同じ SSML ツールバーと説明表示も利用でき、`locale`、`show-toolbar`、`show-toolbar-labels`、`show-decorations` で表示を調整できます。編集時には `{ value }` を `detail` に持つ `change` イベントが発生します。
317
+ `ssml-builder-js/elements` は、React などに依存しない `<ssml-editor>` Web Component を登録します。`monaco-editor` を別途インストールし、`value`、`theme`、`readonly` 属性または同名プロパティを使用できます。React エディターと同じ SSML ツールバーと説明表示も利用でき、`locale`、`show-toolbar`、`show-toolbar-labels`、`show-decorations` で表示を調整できます。`edit-mode="visual"` または `editor.editMode = "visual"` で構造ツリーとフォームのビジュアル編集に切り替えられます。編集時には `{ value }` を `detail` に持つ `change` イベントが発生し、ビジュアルモードの試聴は `{ ssml }` を持つ `preview-selection` イベントで受け取れます。
280
318
 
281
319
  ```ts
282
320
  import "ssml-builder-js/elements";
@@ -342,8 +380,8 @@ Next.js Route Handler ではキーをブラウザへ渡さず、サーバー側
342
380
 
343
381
  ```ts
344
382
  // app/api/synthesize/route.ts
345
- import { AzureTtsClient, AzureTtsError } from "@ssml-builder-js/azure-tts-client";
346
- import { validateAzureSsml, validateSsml } from "@ssml-builder-js/ssml-core";
383
+ import { AzureTtsClient, AzureTtsError } from "ssml-builder-js";
384
+ import { validateAzureSsml, validateSsml } from "ssml-builder-js/core";
347
385
 
348
386
  export const runtime = "nodejs";
349
387
 
@@ -460,7 +498,7 @@ The Azure TTS client is also available from `ssml-builder-js`.
460
498
 
461
499
  ### Developing this repository
462
500
 
463
- Install Node.js 24 or later, then install dependencies from the repository root:
501
+ Node.js 22.6 or later is supported; Node.js 24 LTS or later is recommended. Versions below Node.js 22.6 do not provide the type-stripping capability required by the current TypeScript execution configuration:
464
502
 
465
503
  ```sh
466
504
  npm ci
@@ -495,6 +533,31 @@ manually, and the manual choice is stored in the browser. You can synthesize the
495
533
  SSML document or the selected text and play it in the browser with an SSML caption track;
496
534
  the generated SSML is shown below the editor.
497
535
 
536
+ ### Using Monaco and selection preview with Next.js
537
+
538
+ For both the Pages Router and App Router, keep Monaco in a client-only module with `next/dynamic` and `{ ssr: false }`. Send the partial SSML from `onPreviewSelection` to the `/api/synthesize` Route Handler (or the equivalent `pages/api/synthesize.ts` API Route), and keep the Azure key in server-only environment variables. The repository example is `apps/playground/app/components/NextSsmlEditor.tsx`.
539
+
540
+ ```tsx
541
+ "use client";
542
+ import dynamic from "next/dynamic";
543
+ const SsmlEditor = dynamic(
544
+ () => import("ssml-builder-js/react").then(({ SsmlEditor }) => SsmlEditor),
545
+ { ssr: false },
546
+ );
547
+
548
+ export function ClientEditor(props) {
549
+ return <SsmlEditor {...props} onPreviewSelection={(ssml) =>
550
+ fetch("/api/synthesize", {
551
+ method: "POST",
552
+ headers: { "Content-Type": "application/json" },
553
+ body: JSON.stringify({ ssml }),
554
+ })
555
+ } />;
556
+ }
557
+ ```
558
+
559
+ The Route Handler/API Route must run `validateSsml` and `validateAzureSsml` before calling Azure TTS. Never send the subscription key to the browser.
560
+
498
561
  ## Using `ssml-core`
499
562
 
500
563
  `SsmlDocument` is an object with `version`, `lang`, and `children` properties. `children` can contain strings, text nodes, and SSML elements. The `children` form is recommended; the legacy `content` property is also accepted as input by `buildSsml`.
@@ -548,7 +611,11 @@ The main `buildSsml` and `parseSsml` signatures are:
548
611
  | `validateSsml(xml)` | Returns `{ message, position }` for a syntax error, or `null` |
549
612
  | `extractSsmlText(xml)` | Extracts all text nodes in document order |
550
613
  | `mapSsmlTextNodes(xml, transform, options?)` | Transforms only text nodes while preserving the XML structure; supports sync/async transforms, skipped tags, and context filters |
614
+ | `extractSsmlTranslatableText(xml, options?)` | Extracts translation-target text in document order while skipping `phoneme`, `say-as`, `sub`, and other configured tags |
615
+ | `fromPlainTextToSsml(text, options?)` | Converts plain text into an initial `<speak>` document containing paragraphs (`<p>`) and sentences (`<s>`) |
616
+ | `validateSsmlStructureIntegrity(original, translated)` | Checks that tag hierarchy, element names, and attributes are unchanged after translation |
551
617
  | `validateAzureSsml(xml, options?)` | Returns Azure Speech semantic-validation diagnostics (each diagnostic has `source: "ssml-static-validator"`) |
618
+ | `getAzureVoiceCatalogMetadata()` / `getBuiltInVoiceCatalogMetadata()` | Returns generation time, API version, regions, and voice count for the bundled voice catalog |
552
619
 
553
620
  ### Three-stage validation model
554
621
 
@@ -560,12 +627,16 @@ SSML validation separates XML syntax, Azure-specific static semantics, and runti
560
627
  | Static semantics | `validateAzureSsml` | Required Azure SSML elements, attribute values, voice/`xml:lang` alignment, voice styles, character limits, and `audio` URL/origin policy | Azure's latest voice catalog, key/region permissions, service incidents, and the actual generated audio |
561
628
  | Runtime | `AzureTtsClient.synthesize` / Azure Speech API | Account, region, key, current voice/style availability, service-side SSML constraints, and network state | It does not replace input validation or automatically provide SSRF protection |
562
629
 
563
- Typed representations are available for elements such as `voice`, `prosody`, `break`, `express-as`, `say-as`, `phoneme`, `audio`, `lang`, and `mark`. Use `type: "custom"` and `name` to handle undefined XML elements or additional attributes. When a document contains `mstts:` elements, the required Azure Speech namespace is added automatically.
630
+ Typed representations are available for elements such as `voice`, `prosody`, `break`, `express-as`, `say-as`, `phoneme`, `audio`, `lang`, and `mark`, plus `mstts:dialog`, `mstts:turn`, `mstts:backgroundaudio`, `mstts:ttsembedding`, `mstts:embedding`, and `mstts:voiceconversion`. Use `type: "custom"` and `name` to handle undefined XML elements or additional attributes. When a document contains `mstts:` elements, the required Azure Speech namespace is added automatically.
631
+
632
+ `mstts:turn` accepts either `voice` or the multi-talker `speaker` property. The typed extension properties include `speakerProfileId` for `mstts:ttsembedding`, `id` for `mstts:embedding`, and `url` plus `profile` for `mstts:voiceconversion`. `mstts:backgroundaudio` must be the first direct child element of `<speak>` and may appear only once per document.
564
633
 
565
634
  `validateAzureSsml` is a preflight static check performed by this package before sending SSML to Azure Speech. The `source` on each returned diagnostic identifies package-side static analysis; it is independent of Azure Speech's runtime generation result and does not guarantee that synthesis will succeed.
566
635
 
567
636
  Use `mapSsmlTextNodes` to replace translatable content without changing tags, attributes, or nesting. The transform receives the immediate parent tag and ancestor `path`, and may return a `string` or a `Promise<string>`. The third argument supports `skipTags` and a `filter` callback; `phoneme`, `say-as`, and `sub` are skipped by default. The callback receives `parentTag`, decoded `parentAttributes`, `ancestorTags`, and `path`.
568
637
 
638
+ For migration workflows, use `extractSsmlTranslatableText` to produce only translation-target text, `validateSsmlStructureIntegrity` to detect tag or attribute changes after translation, and `fromPlainTextToSsml` to create a starter document with `<p>` and `<s>` elements.
639
+
569
640
  ```ts
570
641
  const translated = await mapSsmlTextNodes(ssml, translate, {
571
642
  skipTags: ["phoneme", "say-as", "sub", "custom-no-translate"],
@@ -583,7 +654,9 @@ const diagnostics = validateAzureSsml(ssml, {
583
654
  });
584
655
  ```
585
656
 
586
- The catalog is represented by `AzureVoiceDefinition` with `name`, `locale`, optional `secondaryLocales`, and optional `styles`. Pass `voiceDefinitions` (or `voiceCatalog`) to supplement or override the built-in catalog with an external definition. `customVoiceStyleMap` remains supported for backward compatibility and overrides styles for the named voice. Diagnostics distinguish an unregistered voice (`azure-unknown-voice`, controlled by `unknownVoicePolicy`), an unsupported style on a registered voice (`azure-unsupported-style`), and a locale mismatch (`azure-locale-mismatch`). The `<mstts:audioduration value="10s"/>` element accepts positive `ms` or `s` values and `hh:mm:ss[.fff]` clock values.
657
+ The catalog is represented by `AzureVoiceDefinition` with `name`, `locale`, optional `secondaryLocales`, `styles`, `supportedTags`, `unsupportedTags`, and `models`. Pass `voiceDefinitions` (or `voiceCatalog`) to supplement or override the built-in catalog with an external definition. A tag that violates `supportedTags` or `unsupportedTags` produces `azure-unsupported-tag-for-voice` with error severity. `customVoiceStyleMap` remains supported for backward compatibility and overrides styles for the named voice. Diagnostics distinguish an unregistered voice (`azure-unknown-voice`, controlled by `unknownVoicePolicy`), an unsupported style on a registered voice (`azure-unsupported-style`), and a locale mismatch (`azure-locale-mismatch`). The `<mstts:audioduration value="10s"/>` element accepts positive `ms` or `s` values and `hh:mm:ss[.fff]` clock values.
658
+
659
+ `npm run sync:voices -- --regions eastus,japaneast` fetches Azure's List Voices API for each region, deduplicates the results, and updates the generated TypeScript definitions plus `azureVoiceCatalog.json` with generation time, API version, regions, and voice count. Provide credentials through `AZURE_SPEECH_KEY` and `AZURE_SPEECH_REGION(S)`, or CLI options.
587
660
 
588
661
  ```ts
589
662
  const diagnostics = validateAzureSsml(ssml, {
@@ -618,6 +691,8 @@ Azure Speech fetches `<audio>` URLs, so a server that accepts arbitrary user-pro
618
691
 
619
692
  `SsmlEditor` accepts an `SsmlDocument` and renders only a toolbar and text display area. The toolbar applies rate, volume, and pitch settings to the selection and provides undo and redo actions. The application is responsible for selecting and displaying the voice. Monaco Editor is used for text editing, and SSML syntax is validated whenever the text changes. Syntax errors are shown with editor markers and an error message. Hovering over XML tag names or parameters shows SSML descriptions. Selecting text displays a floating action bar with the character count and preview action. When `enableCodeLens` is enabled (the default), CodeLens quick controls for editing and unwrapping `prosody` tags and editing or deleting `break` tags are shown above those tags. When `showDecorations` is enabled, inline badges for pause and pitch changes are rendered next to `break` and `prosody` tags, and Monaco inline decorations are enabled. Generated SSML is provided through `onSsmlChange` so the application can display it wherever it needs. Pass an `SsmlEditorRef` through `ref` to retrieve full, selected, or current-line SSML, and use `onSelectionChange` to observe selection text and state. The UI supports Japanese (the default) and English.
620
693
 
694
+ Set `editMode="visual"`, or choose **Visual** in the toolbar, to edit without viewing XML source. The structured editor provides a structure tree, parent breadcrumb selection, text editing, and form actions for rate, pitch, emotion, pause, and pronunciation. Azure placement and attribute diagnostics are shown in the visual area. Choose `editMode="code"` to return to Monaco.
695
+
621
696
  Completion for the `<mstts:express-as>` `style` attribute and the built-in Emotion menu only show styles supported by the innermost `<voice name="...">` around the cursor or selection. When no voice name is available, all candidates are shown; a registered voice without supported styles or an explicitly unregistered voice displays an empty-state message. When `emotionStyles` is supplied, the Emotion menu uses its intersection with the registered voice's supported styles.
622
697
 
623
698
  ```tsx
@@ -655,6 +730,7 @@ export function App() {
655
730
  - `ref`: An `SsmlEditorRef`; `getFullSsml()` returns the full SSML, `getSelectedSsml()` returns the selected text (or the cursor line when it contains content), and `getCurrentLineSsml()` returns the current cursor line. The selection and line methods return `null` when their target is empty
656
731
  - `onSelectionChange`: A callback that receives selected text, its character count, and whether a selection exists
657
732
  - `onPreviewSelection`: A callback that receives the selected partial SSML when the floating preview action is pressed. The preview action is disabled when this callback is omitted; call an audio API such as Azure from the callback
733
+ - `editMode`: Initial editor mode (`"code"` or `"visual"`). Visual mode provides structured tree and form editing
658
734
  - `locale`: The UI language (`"ja"` or `"en"`); defaults to `"ja"` and also controls hover-help translations
659
735
  - `language`: Legacy name for `locale`, retained for compatibility; use `locale` in new code
660
736
  - `showToolbar`: Whether to display the toolbar (defaults to `true`)
@@ -684,7 +760,7 @@ Click the **Description** button to see descriptions of each control, button, an
684
760
 
685
761
  ## Using `ssml-editor-elements`
686
762
 
687
- `ssml-builder-js/elements` registers a framework-independent `<ssml-editor>` Web Component without React. Install `monaco-editor` separately, then use the `value`, `theme`, and `readonly` attributes or properties. The component includes the same SSML toolbar and help display as the React editor; use `locale`, `show-toolbar`, `show-toolbar-labels`, and `show-decorations` to customize it. Editing dispatches a `change` event whose `detail` is `{ value: string }`.
763
+ `ssml-builder-js/elements` registers a framework-independent `<ssml-editor>` Web Component without React. Install `monaco-editor` separately, then use the `value`, `theme`, and `readonly` attributes or properties. The component includes the same SSML toolbar and help display as the React editor; use `locale`, `show-toolbar`, `show-toolbar-labels`, and `show-decorations` to customize it. Set `edit-mode="visual"` or `editor.editMode = "visual"` to use the structured tree and form editor. Editing dispatches a `change` event whose `detail` is `{ value: string }`; visual preview dispatches a `preview-selection` event whose detail is `{ ssml: string }`.
688
764
 
689
765
  ```ts
690
766
  import "ssml-builder-js/elements";
@@ -750,8 +826,8 @@ Keep the subscription key on the server by using a Next.js Route Handler (or an
750
826
 
751
827
  ```ts
752
828
  // app/api/synthesize/route.ts
753
- import { AzureTtsClient, AzureTtsError } from "@ssml-builder-js/azure-tts-client";
754
- import { validateAzureSsml, validateSsml } from "@ssml-builder-js/ssml-core";
829
+ import { AzureTtsClient, AzureTtsError } from "ssml-builder-js";
830
+ import { validateAzureSsml, validateSsml } from "ssml-builder-js/core";
755
831
 
756
832
  export const runtime = "nodejs";
757
833