ssml-builder-js 2.1.0 → 2.2.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.
@@ -0,0 +1,1234 @@
1
+ import {
2
+ BREAK_TIME_DESCRIPTIONS,
3
+ BREAK_TIME_PRESETS,
4
+ EDITOR_COPY,
5
+ EMPHASIS_LEVEL_DESCRIPTIONS,
6
+ EMPHASIS_LEVEL_PRESETS,
7
+ EXPRESS_AS_STYLE_DESCRIPTIONS,
8
+ EXPRESS_AS_STYLE_PRESETS,
9
+ LANGUAGE_DESCRIPTIONS,
10
+ LANGUAGE_PRESETS,
11
+ PROSODY_PITCH_DESCRIPTIONS,
12
+ PROSODY_PITCH_PRESETS,
13
+ PROSODY_RATE_DESCRIPTIONS,
14
+ PROSODY_RATE_PRESETS,
15
+ PROSODY_VOLUME_DESCRIPTIONS,
16
+ PROSODY_VOLUME_PRESETS,
17
+ SAY_AS_DESCRIPTIONS,
18
+ SAY_AS_PRESETS,
19
+ SILENCE_VALUE_DESCRIPTIONS,
20
+ SILENCE_VALUE_PRESETS,
21
+ buildSsml,
22
+ clearSsmlDocument,
23
+ createSsmlInsertionEdit,
24
+ findActiveSsmlTags,
25
+ findSsmlHoverTarget,
26
+ findSsmlVoiceContext,
27
+ formatSsmlHover,
28
+ formatXmlFragment,
29
+ getEditableRegion,
30
+ getEditableText,
31
+ getExpressAsStyleCategory,
32
+ parseSsml,
33
+ registerSsmlCompletionProvider,
34
+ resolveExpressAsStyles,
35
+ updateEditableText
36
+ } from "./chunk-2XJER2BG.mjs";
37
+ import "./chunk-6S5ODO6A.mjs";
38
+
39
+ // packages/ssml-editor-react/src/ssmlInsertions.ts
40
+ function createInsertionOptions(values, descriptions) {
41
+ return values.map((value) => ({
42
+ value,
43
+ labels: { ja: value, en: value },
44
+ ...descriptions?.[value] ? { descriptions: descriptions[value] } : {}
45
+ }));
46
+ }
47
+ var SSML_INSERTIONS = [
48
+ {
49
+ id: "break",
50
+ icon: "\u23F8",
51
+ tagName: "break",
52
+ selfClosing: true,
53
+ labels: { ja: "\u9593", en: "Break" },
54
+ descriptions: {
55
+ ja: "\u6307\u5B9A\u3057\u305F\u6642\u9593\u3060\u3051\u7121\u97F3\u306E\u9593\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
56
+ en: "Inserts a silent pause for the selected duration."
57
+ },
58
+ parameterDescription: {
59
+ ja: "\u7121\u97F3\u306B\u3059\u308B\u6642\u9593\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
60
+ en: "Selects the duration of the silent pause."
61
+ },
62
+ options: createInsertionOptions(BREAK_TIME_PRESETS, BREAK_TIME_DESCRIPTIONS),
63
+ createTemplate: (value) => ({
64
+ prefix: `<break time="${value}"/>`,
65
+ suffix: "",
66
+ mode: "insert"
67
+ })
68
+ },
69
+ {
70
+ id: "emphasis",
71
+ icon: "\u2726",
72
+ tagName: "emphasis",
73
+ labels: { ja: "\u5F37\u8ABF", en: "Emphasis" },
74
+ descriptions: {
75
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u5F37\u8ABF\u30EC\u30D9\u30EB\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
76
+ en: "Changes the emphasis level of the selected text."
77
+ },
78
+ parameterDescription: {
79
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u5F37\u8ABF\u30EC\u30D9\u30EB\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
80
+ en: "Selects the emphasis level for the selected text."
81
+ },
82
+ options: createInsertionOptions(EMPHASIS_LEVEL_PRESETS, EMPHASIS_LEVEL_DESCRIPTIONS),
83
+ createTemplate: (value) => ({
84
+ prefix: `<emphasis level="${value}">`,
85
+ suffix: "</emphasis>",
86
+ mode: "wrap"
87
+ })
88
+ },
89
+ {
90
+ id: "rate",
91
+ icon: "\u2195",
92
+ tagName: "prosody",
93
+ labels: { ja: "\u901F\u5EA6", en: "Rate" },
94
+ descriptions: {
95
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u901F\u5EA6\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
96
+ en: "Changes the speech rate of the selected text."
97
+ },
98
+ parameterDescription: {
99
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u901F\u5EA6\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
100
+ en: "Selects the speech rate for the selected text."
101
+ },
102
+ options: createInsertionOptions(PROSODY_RATE_PRESETS, PROSODY_RATE_DESCRIPTIONS),
103
+ createTemplate: (value) => ({
104
+ prefix: `<prosody rate="${value}">`,
105
+ suffix: "</prosody>",
106
+ mode: "wrap"
107
+ })
108
+ },
109
+ {
110
+ id: "pitch",
111
+ icon: "\u2197",
112
+ tagName: "prosody",
113
+ labels: { ja: "\u9AD8\u3055", en: "Pitch" },
114
+ descriptions: {
115
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u58F0\u306E\u9AD8\u3055\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
116
+ en: "Changes the pitch of the selected text."
117
+ },
118
+ parameterDescription: {
119
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u58F0\u306E\u9AD8\u3055\u3092\u534A\u97F3\u5358\u4F4D\u3067\u9078\u629E\u3057\u307E\u3059\u3002",
120
+ en: "Selects the pitch adjustment in semitone steps."
121
+ },
122
+ options: createInsertionOptions(PROSODY_PITCH_PRESETS, PROSODY_PITCH_DESCRIPTIONS),
123
+ createTemplate: (value) => ({
124
+ prefix: `<prosody pitch="${value}">`,
125
+ suffix: "</prosody>",
126
+ mode: "wrap"
127
+ })
128
+ },
129
+ {
130
+ id: "volume",
131
+ icon: "\u{1F50A}",
132
+ tagName: "prosody",
133
+ labels: { ja: "\u97F3\u91CF", en: "Volume" },
134
+ descriptions: {
135
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u97F3\u91CF\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
136
+ en: "Changes the volume of the selected text."
137
+ },
138
+ parameterDescription: {
139
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u97F3\u91CF\u30EC\u30D9\u30EB\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
140
+ en: "Selects the volume level for the selected text."
141
+ },
142
+ options: createInsertionOptions(PROSODY_VOLUME_PRESETS, PROSODY_VOLUME_DESCRIPTIONS),
143
+ createTemplate: (value) => ({
144
+ prefix: `<prosody volume="${value}">`,
145
+ suffix: "</prosody>",
146
+ mode: "wrap"
147
+ })
148
+ },
149
+ {
150
+ id: "emotion",
151
+ icon: "\u263A",
152
+ tagName: "mstts:express-as",
153
+ labels: { ja: "\u611F\u60C5", en: "Emotion" },
154
+ descriptions: {
155
+ ja: "\u9078\u629E\u7BC4\u56F2\u306B\u97F3\u58F0\u306E\u611F\u60C5\u30B9\u30BF\u30A4\u30EB\u3092\u9069\u7528\u3057\u307E\u3059\u3002",
156
+ en: "Applies a voice emotion style to the selected text."
157
+ },
158
+ parameterDescription: {
159
+ ja: "\u9078\u629E\u7BC4\u56F2\u306B\u9069\u7528\u3059\u308B\u97F3\u58F0\u306E\u611F\u60C5\u30B9\u30BF\u30A4\u30EB\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
160
+ en: "Selects the voice emotion style to apply."
161
+ },
162
+ options: createInsertionOptions(EXPRESS_AS_STYLE_PRESETS, EXPRESS_AS_STYLE_DESCRIPTIONS),
163
+ createTemplate: (value) => ({
164
+ prefix: `<mstts:express-as style="${value}">`,
165
+ suffix: "</mstts:express-as>",
166
+ mode: "wrap"
167
+ })
168
+ },
169
+ {
170
+ id: "say-as",
171
+ icon: "Aa",
172
+ tagName: "say-as",
173
+ labels: { ja: "\u8AAD\u307F\u4E0A\u3052", en: "Say as" },
174
+ descriptions: {
175
+ ja: "\u6570\u5B57\u3084\u65E5\u4ED8\u306A\u3069\u306E\u8AAD\u307F\u4E0A\u3052\u65B9\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
176
+ en: "Specifies how values such as numbers or dates are spoken."
177
+ },
178
+ parameterDescription: {
179
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u65B9\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
180
+ en: "Selects how the selected text is spoken."
181
+ },
182
+ options: createInsertionOptions(SAY_AS_PRESETS, SAY_AS_DESCRIPTIONS),
183
+ createTemplate: (value) => ({
184
+ prefix: `<say-as interpret-as="${value}">`,
185
+ suffix: "</say-as>",
186
+ mode: "wrap"
187
+ })
188
+ },
189
+ {
190
+ id: "lang",
191
+ icon: "\u6587",
192
+ tagName: "lang",
193
+ labels: { ja: "\u8A00\u8A9E", en: "Language" },
194
+ descriptions: {
195
+ ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u8A00\u8A9E\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
196
+ en: "Changes the speaking language of the selected text."
197
+ },
198
+ parameterDescription: {
199
+ ja: "\u9078\u629E\u7BC4\u56F2\u306B\u9069\u7528\u3059\u308B BCP-47 \u8A00\u8A9E\u30BF\u30B0\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
200
+ en: "Selects the BCP-47 language tag for the selected text."
201
+ },
202
+ options: createInsertionOptions(LANGUAGE_PRESETS, LANGUAGE_DESCRIPTIONS),
203
+ createTemplate: (value) => ({
204
+ prefix: `<lang xml:lang="${value}">`,
205
+ suffix: "</lang>",
206
+ mode: "wrap"
207
+ })
208
+ },
209
+ {
210
+ id: "mstts:silence",
211
+ icon: "\u23F3",
212
+ tagName: "mstts:silence",
213
+ selfClosing: true,
214
+ labels: { ja: "\u7121\u97F3", en: "Silence" },
215
+ descriptions: {
216
+ ja: "\u7121\u97F3\u6642\u9593\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
217
+ en: "Inserts a silence interval."
218
+ },
219
+ parameterDescription: {
220
+ ja: "\u7121\u97F3\u306B\u3059\u308B\u6642\u9593\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
221
+ en: "Selects the silence duration."
222
+ },
223
+ options: createInsertionOptions(SILENCE_VALUE_PRESETS, SILENCE_VALUE_DESCRIPTIONS),
224
+ createTemplate: (value) => ({
225
+ prefix: `<mstts:silence type="Leading" value="${value}"/>`,
226
+ suffix: "",
227
+ mode: "insert"
228
+ })
229
+ }
230
+ ];
231
+ var DEFAULT_INSERTION_GROUPS = [
232
+ {
233
+ id: "pauses",
234
+ labels: { ja: "\u9593\u30FB\u7121\u97F3", en: "Pauses" },
235
+ insertionIds: ["break", "mstts:silence"]
236
+ },
237
+ {
238
+ id: "prosody",
239
+ labels: { ja: "\u58F0\u306E\u8ABF\u6574", en: "Voice" },
240
+ insertionIds: ["rate", "pitch", "volume"]
241
+ },
242
+ {
243
+ id: "expression",
244
+ labels: { ja: "\u8868\u73FE", en: "Expression" },
245
+ insertionIds: ["emphasis", "emotion"]
246
+ },
247
+ {
248
+ id: "pronunciation",
249
+ labels: { ja: "\u8AAD\u307F\u4E0A\u3052", en: "Pronunciation" },
250
+ insertionIds: ["say-as", "lang"]
251
+ }
252
+ ];
253
+
254
+ // packages/ssml-editor-elements/src/SsmlEditorElement.ts
255
+ var HTMLElementBase = typeof HTMLElement === "undefined" ? class {
256
+ } : HTMLElement;
257
+ var STYLE_ID = "ssml-editor-elements-theme";
258
+ var STYLE_CSS = `
259
+ [data-ssml-editor] {
260
+ --ssml-editor-color: #111827;
261
+ --ssml-editor-bg: #ffffff;
262
+ --ssml-editor-border: #d1d5db;
263
+ --ssml-editor-control-bg: #f9fafb;
264
+ --ssml-editor-control-border: #9ca3af;
265
+ --ssml-editor-active-bg: #dbeafe;
266
+ --ssml-editor-active-border: #2563eb;
267
+ --ssml-editor-preview-bg: #f3f4f6;
268
+ }
269
+ section[data-ssml-editor] {
270
+ display: grid;
271
+ grid-template-rows: auto minmax(8rem, 1fr);
272
+ gap: 0.75rem;
273
+ box-sizing: border-box;
274
+ width: 100%;
275
+ min-height: 100%;
276
+ padding: 1rem;
277
+ border: 1px solid var(--ssml-editor-border);
278
+ border-radius: 0.5rem;
279
+ color: var(--ssml-editor-color);
280
+ background: var(--ssml-editor-bg);
281
+ }
282
+ [data-ssml-editor][data-theme="dark"] {
283
+ --ssml-editor-color: #f9fafb;
284
+ --ssml-editor-bg: #1f2937;
285
+ --ssml-editor-border: #374151;
286
+ --ssml-editor-control-bg: #111827;
287
+ --ssml-editor-control-border: #4b5563;
288
+ --ssml-editor-active-bg: #1e3a8a;
289
+ --ssml-editor-active-border: #60a5fa;
290
+ --ssml-editor-preview-bg: #111827;
291
+ }
292
+ [data-ssml-editor] .ssml-editor-toolbar {
293
+ display: flex;
294
+ align-items: center;
295
+ flex-wrap: wrap;
296
+ gap: 0.5rem;
297
+ }
298
+ [data-ssml-editor] .ssml-editor-toolbar-actions {
299
+ display: flex;
300
+ align-items: center;
301
+ flex-wrap: wrap;
302
+ gap: 0.5rem;
303
+ }
304
+ [data-ssml-editor] .ssml-editor-toolbar-separator {
305
+ width: 1px;
306
+ height: 2.25rem;
307
+ margin: 0 0.25rem;
308
+ background: var(--ssml-editor-border);
309
+ }
310
+ [data-ssml-editor] .ssml-editor-toolbar-dropdown {
311
+ display: inline-block;
312
+ }
313
+ [data-ssml-editor] .ssml-editor-toolbar-button {
314
+ display: inline-flex;
315
+ align-items: center;
316
+ gap: 0.375rem;
317
+ min-height: 2.25rem;
318
+ padding: 0.375rem 0.625rem;
319
+ border: 1px solid var(--ssml-editor-control-border);
320
+ border-radius: 0.25rem;
321
+ color: var(--ssml-editor-color);
322
+ background: var(--ssml-editor-control-bg);
323
+ font: inherit;
324
+ cursor: pointer;
325
+ }
326
+ [data-ssml-editor] .ssml-editor-toolbar-button:hover,
327
+ [data-ssml-editor] .ssml-editor-toolbar-option:hover {
328
+ background: var(--ssml-editor-preview-bg);
329
+ }
330
+ [data-ssml-editor] .ssml-editor-toolbar-button:disabled {
331
+ cursor: not-allowed;
332
+ opacity: 0.55;
333
+ }
334
+ [data-ssml-editor] .ssml-editor-toolbar-button[data-active="true"] {
335
+ border-color: var(--ssml-editor-active-border);
336
+ background: var(--ssml-editor-active-bg);
337
+ }
338
+ [data-ssml-editor] .ssml-editor-toolbar-icon {
339
+ display: inline-flex;
340
+ width: 1.25rem;
341
+ justify-content: center;
342
+ font-size: 1.1rem;
343
+ line-height: 1;
344
+ }
345
+ [data-ssml-editor] .ssml-editor-toolbar-chevron {
346
+ font-size: 0.7rem;
347
+ line-height: 1;
348
+ }
349
+ [data-ssml-editor] .ssml-editor-toolbar-switch {
350
+ display: inline-flex;
351
+ align-items: center;
352
+ gap: 0.375rem;
353
+ min-height: 2.25rem;
354
+ }
355
+ [data-ssml-editor] .ssml-editor-switch-track {
356
+ display: inline-flex;
357
+ align-items: center;
358
+ width: 2.75rem;
359
+ height: 1.5rem;
360
+ padding: 0.1875rem;
361
+ border: 0;
362
+ border-radius: 999px;
363
+ background: var(--ssml-editor-control-border);
364
+ cursor: pointer;
365
+ transition: background-color 0.2s ease;
366
+ }
367
+ [data-ssml-editor] .ssml-editor-switch-track[aria-checked="true"] {
368
+ background: var(--ssml-editor-active-border);
369
+ }
370
+ [data-ssml-editor] .ssml-editor-switch-track:focus-visible {
371
+ outline: 2px solid var(--ssml-editor-active-border);
372
+ outline-offset: 2px;
373
+ }
374
+ [data-ssml-editor] .ssml-editor-switch-thumb {
375
+ width: 1.125rem;
376
+ height: 1.125rem;
377
+ border-radius: 50%;
378
+ background: var(--ssml-editor-bg);
379
+ transition: transform 0.2s ease;
380
+ }
381
+ [data-ssml-editor] .ssml-editor-switch-track[aria-checked="true"] .ssml-editor-switch-thumb {
382
+ transform: translateX(1.25rem);
383
+ }
384
+ [data-ssml-editor].ssml-editor-toolbar-menu {
385
+ position: fixed;
386
+ z-index: 9999;
387
+ display: grid;
388
+ min-width: max-content;
389
+ max-height: min(24rem, calc(100vh - 1rem));
390
+ gap: 0.125rem;
391
+ padding: 0.25rem;
392
+ border: 1px solid var(--ssml-editor-control-border);
393
+ border-radius: 0.25rem;
394
+ background: var(--ssml-editor-control-bg);
395
+ box-shadow: 0 0.25rem 0.75rem rgb(0 0 0 / 20%);
396
+ overflow-y: auto;
397
+ }
398
+ [data-ssml-editor] .ssml-editor-toolbar-option {
399
+ padding: 0.375rem 0.5rem;
400
+ border: 0;
401
+ border-radius: 0.125rem;
402
+ color: var(--ssml-editor-color);
403
+ background: transparent;
404
+ font: inherit;
405
+ text-align: left;
406
+ white-space: nowrap;
407
+ cursor: pointer;
408
+ }
409
+ [data-ssml-editor] .ssml-editor-toolbar-option-group {
410
+ display: grid;
411
+ gap: 0.125rem;
412
+ margin: 0;
413
+ padding: 0;
414
+ border: 0;
415
+ }
416
+ [data-ssml-editor] .ssml-editor-toolbar-option-group legend {
417
+ padding: 0.375rem 0.5rem 0.125rem;
418
+ font-size: 0.875rem;
419
+ font-weight: 600;
420
+ white-space: nowrap;
421
+ }
422
+ [data-ssml-editor] .ssml-editor-help {
423
+ display: grid;
424
+ gap: 0.5rem;
425
+ padding: 0.75rem;
426
+ border: 1px solid var(--ssml-editor-control-border);
427
+ border-radius: 0.25rem;
428
+ background: var(--ssml-editor-preview-bg);
429
+ }
430
+ [data-ssml-editor] .ssml-editor-help h3,
431
+ [data-ssml-editor] .ssml-editor-help p {
432
+ margin: 0;
433
+ }
434
+ [data-ssml-editor] .ssml-editor-help-list {
435
+ display: grid;
436
+ gap: 0.375rem;
437
+ margin: 0;
438
+ padding-left: 1.25rem;
439
+ }
440
+ [data-ssml-editor] .ssml-editor-help-item {
441
+ list-style: none;
442
+ }
443
+ [data-ssml-editor] .ssml-editor-help-item details {
444
+ margin-top: 0.375rem;
445
+ border: 1px solid var(--ssml-editor-control-border);
446
+ border-radius: 0.25rem;
447
+ background: var(--ssml-editor-control-bg);
448
+ }
449
+ [data-ssml-editor] .ssml-editor-help-item summary {
450
+ padding: 0.5rem 0.625rem;
451
+ cursor: pointer;
452
+ }
453
+ [data-ssml-editor] .ssml-editor-help-item details p,
454
+ [data-ssml-editor] .ssml-editor-help-item details ul {
455
+ margin: 0.5rem 0.75rem 0.75rem;
456
+ font-size: 0.875rem;
457
+ }
458
+ [data-ssml-editor] .ssml-editor-display {
459
+ display: grid;
460
+ grid-template-rows: auto minmax(8rem, 1fr);
461
+ gap: 0.5rem;
462
+ min-height: 0;
463
+ }
464
+ [data-ssml-editor] .ssml-editor-editor {
465
+ position: relative;
466
+ min-height: 8rem;
467
+ height: 100%;
468
+ border: 1px solid var(--ssml-editor-control-border);
469
+ border-radius: 0.25rem;
470
+ overflow: visible;
471
+ }
472
+ `.trim();
473
+ function injectStyles() {
474
+ if (typeof document === "undefined" || document.getElementById(STYLE_ID)) {
475
+ return;
476
+ }
477
+ const style = document.createElement("style");
478
+ style.id = STYLE_ID;
479
+ style.textContent = STYLE_CSS;
480
+ document.head.appendChild(style);
481
+ }
482
+ function isDarkTheme(theme) {
483
+ return theme === "vs-dark" || theme.toLowerCase().includes("dark");
484
+ }
485
+ function getMenuPosition(trigger, menu) {
486
+ const bounds = trigger.getBoundingClientRect();
487
+ const margin = 8;
488
+ const top = Math.min(bounds.bottom + 4, window.innerHeight - menu.offsetHeight - margin);
489
+ const left = Math.min(bounds.left, window.innerWidth - menu.offsetWidth - margin);
490
+ return {
491
+ top: Math.max(margin, top),
492
+ left: Math.max(margin, left)
493
+ };
494
+ }
495
+ var SsmlEditorElement = class extends HTMLElementBase {
496
+ constructor() {
497
+ super(...arguments);
498
+ this.editor = null;
499
+ this.model = null;
500
+ this.monaco = null;
501
+ this.root = null;
502
+ this.toolbar = null;
503
+ this.toolbarActions = null;
504
+ this.display = null;
505
+ this.editorContainer = null;
506
+ this.helpPanel = null;
507
+ this.openMenu = null;
508
+ this.openMenuTrigger = null;
509
+ this.toolbarButtons = /* @__PURE__ */ new Map();
510
+ this.contentDisposable = null;
511
+ this.cursorDisposable = null;
512
+ this.completionDisposable = null;
513
+ this.hoverDisposable = null;
514
+ this.suppressChangeEvent = false;
515
+ this.initializationToken = 0;
516
+ this.documentState = null;
517
+ this.decorationsVisible = false;
518
+ this.helpOpen = false;
519
+ this.handleDocumentPointerDown = (event) => {
520
+ const target = event.target;
521
+ if (this.openMenu && target instanceof Node && !this.openMenu.contains(target) && !this.openMenuTrigger?.contains(target)) {
522
+ this.closeMenu();
523
+ }
524
+ };
525
+ this.handleDocumentKeyDown = (event) => {
526
+ if (event.key === "Escape" && this.openMenu) {
527
+ this.closeMenu(true);
528
+ }
529
+ };
530
+ }
531
+ get value() {
532
+ return this.valueState ?? this.getAttribute("value") ?? "";
533
+ }
534
+ set value(value) {
535
+ this.valueState = value;
536
+ this.setAttribute("value", value);
537
+ }
538
+ get theme() {
539
+ return this.getAttribute("theme") || "light";
540
+ }
541
+ set theme(theme) {
542
+ this.setAttribute("theme", theme);
543
+ }
544
+ get readonly() {
545
+ return this.hasAttribute("readonly");
546
+ }
547
+ set readonly(readonly) {
548
+ if (readonly) {
549
+ this.setAttribute("readonly", "");
550
+ } else {
551
+ this.removeAttribute("readonly");
552
+ }
553
+ }
554
+ get locale() {
555
+ return this.getAttribute("locale") === "en" ? "en" : "ja";
556
+ }
557
+ set locale(locale) {
558
+ this.setAttribute("locale", locale);
559
+ }
560
+ prepareDocument(value) {
561
+ try {
562
+ this.documentState = parseSsml(value);
563
+ return getEditableText(this.documentState);
564
+ } catch {
565
+ this.documentState = null;
566
+ return value;
567
+ }
568
+ }
569
+ connectedCallback() {
570
+ if (this.editor || this.root) {
571
+ return;
572
+ }
573
+ injectStyles();
574
+ document.addEventListener("pointerdown", this.handleDocumentPointerDown);
575
+ document.addEventListener("keydown", this.handleDocumentKeyDown);
576
+ this.render();
577
+ const token = ++this.initializationToken;
578
+ void this.initialize(token);
579
+ }
580
+ disconnectedCallback() {
581
+ this.initializationToken += 1;
582
+ document.removeEventListener("pointerdown", this.handleDocumentPointerDown);
583
+ document.removeEventListener("keydown", this.handleDocumentKeyDown);
584
+ this.closeMenu();
585
+ this.disposeEditor();
586
+ }
587
+ attributeChangedCallback(name, _oldValue, newValue) {
588
+ if (name === "value") {
589
+ this.valueState = newValue ?? "";
590
+ if (this.editor) {
591
+ const value = newValue ?? "";
592
+ const editableValue = this.prepareDocument(value);
593
+ if (this.editor.getValue() !== editableValue) {
594
+ this.suppressChangeEvent = true;
595
+ try {
596
+ this.editor.setValue(editableValue);
597
+ } finally {
598
+ this.suppressChangeEvent = false;
599
+ }
600
+ }
601
+ }
602
+ return;
603
+ }
604
+ if (name === "theme" && this.monaco) {
605
+ this.monaco.editor.setTheme(this.theme);
606
+ this.updateTheme();
607
+ return;
608
+ }
609
+ if (name === "readonly") {
610
+ this.editor?.updateOptions({ readOnly: this.readonly });
611
+ this.renderToolbar();
612
+ return;
613
+ }
614
+ if (name === "locale" || name === "show-toolbar" || name === "show-toolbar-labels") {
615
+ this.renderToolbar();
616
+ this.renderHelp();
617
+ return;
618
+ }
619
+ if (name === "show-decorations") {
620
+ this.decorationsVisible = newValue !== null;
621
+ this.updateDecorations();
622
+ }
623
+ }
624
+ render() {
625
+ const root = document.createElement("section");
626
+ root.dataset.ssmlEditor = "";
627
+ root.setAttribute("aria-label", EDITOR_COPY[this.locale].editorAriaLabel);
628
+ root.dataset.theme = isDarkTheme(this.theme) ? "dark" : "light";
629
+ const toolbar = document.createElement("div");
630
+ toolbar.className = "ssml-editor-toolbar";
631
+ toolbar.dataset.ssmlEditorToolbar = "";
632
+ const toolbarActions = document.createElement("div");
633
+ toolbarActions.className = "ssml-editor-toolbar-actions";
634
+ toolbarActions.setAttribute("role", "toolbar");
635
+ toolbarActions.setAttribute("aria-label", EDITOR_COPY[this.locale].toolbarAriaLabel);
636
+ toolbarActions.dataset.ssmlEditorToolbarActions = "";
637
+ toolbar.append(toolbarActions);
638
+ const display = document.createElement("div");
639
+ display.className = "ssml-editor-display";
640
+ display.dataset.ssmlEditorDisplay = "";
641
+ const editorContainer = document.createElement("div");
642
+ editorContainer.className = "ssml-editor-editor";
643
+ display.append(editorContainer);
644
+ root.append(toolbar, display);
645
+ this.replaceChildren(root);
646
+ this.root = root;
647
+ this.toolbar = toolbar;
648
+ this.toolbarActions = toolbarActions;
649
+ this.display = display;
650
+ this.editorContainer = editorContainer;
651
+ this.renderToolbar();
652
+ this.renderHelp();
653
+ }
654
+ renderToolbar() {
655
+ const toolbar = this.toolbar;
656
+ const toolbarActions = this.toolbarActions;
657
+ if (!toolbar || !toolbarActions) {
658
+ return;
659
+ }
660
+ this.closeMenu();
661
+ const copy = EDITOR_COPY[this.locale];
662
+ toolbar.hidden = this.getAttribute("show-toolbar") === "false";
663
+ toolbar.setAttribute("aria-label", copy.toolbarAriaLabel);
664
+ toolbarActions.setAttribute("aria-label", copy.toolbarAriaLabel);
665
+ toolbarActions.replaceChildren();
666
+ this.toolbarButtons.clear();
667
+ if (toolbar.hidden) {
668
+ return;
669
+ }
670
+ const insertionById = new Map(SSML_INSERTIONS.map((insertion) => [insertion.id, insertion]));
671
+ const toolbarIds = [
672
+ "undo",
673
+ "redo",
674
+ ...DEFAULT_INSERTION_GROUPS.flatMap((group) => group.insertionIds),
675
+ "clearAll",
676
+ "format",
677
+ "decorations",
678
+ "help"
679
+ ];
680
+ const groupByButtonId = /* @__PURE__ */ new Map();
681
+ for (const group of DEFAULT_INSERTION_GROUPS) {
682
+ for (const buttonId of group.insertionIds) {
683
+ groupByButtonId.set(buttonId, group.id);
684
+ }
685
+ }
686
+ groupByButtonId.set("undo", "history");
687
+ groupByButtonId.set("redo", "history");
688
+ groupByButtonId.set("clearAll", "document");
689
+ groupByButtonId.set("format", "document");
690
+ groupByButtonId.set("decorations", "document");
691
+ groupByButtonId.set("help", "help");
692
+ let previousGroup;
693
+ for (const id of toolbarIds) {
694
+ const group = groupByButtonId.get(id);
695
+ if (previousGroup !== void 0 && group !== previousGroup) {
696
+ const separator = document.createElement("span");
697
+ separator.className = "ssml-editor-toolbar-separator";
698
+ separator.setAttribute("aria-hidden", "true");
699
+ toolbarActions.append(separator);
700
+ }
701
+ previousGroup = group;
702
+ const insertion = insertionById.get(id);
703
+ if (insertion) {
704
+ toolbarActions.append(this.createInsertionButton(insertion));
705
+ } else if (id === "decorations") {
706
+ toolbarActions.append(this.createDecorationsSwitch());
707
+ } else {
708
+ toolbarActions.append(this.createActionButton(id));
709
+ }
710
+ }
711
+ this.updateActiveButtons();
712
+ }
713
+ createActionButton(id) {
714
+ const copy = EDITOR_COPY[this.locale];
715
+ const labels = {
716
+ undo: copy.undo,
717
+ redo: copy.redo,
718
+ clearAll: copy.clearAll,
719
+ format: copy.format,
720
+ help: copy.help
721
+ };
722
+ const icons = {
723
+ undo: "\u21A9",
724
+ redo: "\u21AA",
725
+ clearAll: "\xD7",
726
+ format: "\u2261",
727
+ help: "?"
728
+ };
729
+ const titles = {
730
+ undo: copy.undoTitle,
731
+ redo: copy.redoTitle,
732
+ clearAll: copy.clearAllTitle,
733
+ format: copy.formatTitle,
734
+ help: copy.helpTitle
735
+ };
736
+ const button = document.createElement("button");
737
+ button.type = "button";
738
+ button.className = "ssml-editor-toolbar-button";
739
+ button.dataset.ssmlEditorButton = id;
740
+ button.setAttribute("aria-label", labels[id] ?? id);
741
+ button.title = titles[id] ?? labels[id] ?? id;
742
+ button.disabled = this.readonly && id !== "help";
743
+ if (id === "help") {
744
+ button.setAttribute("aria-expanded", String(this.helpOpen));
745
+ }
746
+ const icon = document.createElement("span");
747
+ icon.className = "ssml-editor-toolbar-icon";
748
+ icon.setAttribute("aria-hidden", "true");
749
+ icon.textContent = icons[id] ?? "";
750
+ button.append(icon);
751
+ if (this.hasAttribute("show-toolbar-labels")) {
752
+ button.append(document.createTextNode(labels[id] ?? id));
753
+ }
754
+ button.addEventListener("click", () => {
755
+ if (id === "help") {
756
+ this.helpOpen = !this.helpOpen;
757
+ button.setAttribute("aria-expanded", String(this.helpOpen));
758
+ this.renderHelp();
759
+ } else if (!this.readonly) {
760
+ this.handleAction(id);
761
+ }
762
+ });
763
+ this.toolbarButtons.set(id, button);
764
+ return button;
765
+ }
766
+ createDecorationsSwitch() {
767
+ const copy = EDITOR_COPY[this.locale];
768
+ const wrapper = document.createElement("div");
769
+ wrapper.className = "ssml-editor-toolbar-switch";
770
+ const icon = document.createElement("span");
771
+ icon.className = "ssml-editor-toolbar-icon";
772
+ icon.setAttribute("aria-hidden", "true");
773
+ icon.textContent = "\u2606";
774
+ wrapper.append(icon);
775
+ if (this.hasAttribute("show-toolbar-labels")) {
776
+ wrapper.append(document.createTextNode(copy.decorations));
777
+ }
778
+ const button = document.createElement("button");
779
+ button.type = "button";
780
+ button.className = "ssml-editor-switch-track";
781
+ button.dataset.ssmlEditorButton = "decorations";
782
+ button.setAttribute("role", "switch");
783
+ button.setAttribute("aria-label", copy.decorations);
784
+ button.addEventListener("click", () => {
785
+ this.decorationsVisible = !this.decorationsVisible;
786
+ this.updateDecorations();
787
+ });
788
+ wrapper.append(button);
789
+ this.toolbarButtons.set("decorations", button);
790
+ this.updateDecorations();
791
+ return wrapper;
792
+ }
793
+ createInsertionButton(insertion) {
794
+ const button = document.createElement("button");
795
+ button.type = "button";
796
+ button.className = "ssml-editor-toolbar-button";
797
+ button.dataset.ssmlEditorButton = insertion.id;
798
+ button.setAttribute("aria-label", insertion.labels[this.locale]);
799
+ button.setAttribute("aria-haspopup", "menu");
800
+ button.setAttribute("aria-expanded", "false");
801
+ button.title = insertion.titles?.[this.locale] ?? `${insertion.labels[this.locale]} \u2014 ${insertion.descriptions[this.locale]}`;
802
+ const icon = document.createElement("span");
803
+ icon.className = "ssml-editor-toolbar-icon";
804
+ icon.setAttribute("aria-hidden", "true");
805
+ icon.textContent = insertion.icon;
806
+ button.append(icon);
807
+ if (this.hasAttribute("show-toolbar-labels")) {
808
+ button.append(document.createTextNode(insertion.labels[this.locale]));
809
+ }
810
+ const chevron = document.createElement("span");
811
+ chevron.className = "ssml-editor-toolbar-chevron";
812
+ chevron.setAttribute("aria-hidden", "true");
813
+ chevron.textContent = "\u25BE";
814
+ button.append(chevron);
815
+ button.addEventListener("click", () => this.toggleInsertionMenu(insertion, button));
816
+ this.toolbarButtons.set(insertion.id, button);
817
+ const wrapper = document.createElement("div");
818
+ wrapper.className = "ssml-editor-toolbar-dropdown";
819
+ wrapper.append(button);
820
+ return wrapper;
821
+ }
822
+ toggleInsertionMenu(insertion, trigger) {
823
+ if (this.openMenuTrigger === trigger) {
824
+ this.closeMenu();
825
+ return;
826
+ }
827
+ this.closeMenu();
828
+ const menu = this.createInsertionMenu(insertion);
829
+ document.body.append(menu);
830
+ const position = getMenuPosition(trigger, menu);
831
+ menu.style.top = `${position.top}px`;
832
+ menu.style.left = `${position.left}px`;
833
+ trigger.setAttribute("aria-expanded", "true");
834
+ trigger.setAttribute("aria-controls", menu.id);
835
+ this.openMenu = menu;
836
+ this.openMenuTrigger = trigger;
837
+ }
838
+ createInsertionMenu(insertion) {
839
+ const menu = document.createElement("div");
840
+ menu.className = "ssml-editor-toolbar-menu";
841
+ menu.dataset.ssmlEditor = "";
842
+ menu.dataset.theme = isDarkTheme(this.theme) ? "dark" : "light";
843
+ menu.id = `ssml-editor-elements-menu-${insertion.id.replace(/[^A-Za-z0-9_-]/g, "-")}`;
844
+ menu.setAttribute("role", "menu");
845
+ menu.setAttribute("aria-label", insertion.labels[this.locale]);
846
+ menu.addEventListener("pointerdown", (event) => event.stopPropagation());
847
+ const options = this.getInsertionOptions(insertion);
848
+ if (options.length === 0) {
849
+ const empty = document.createElement("p");
850
+ empty.className = "ssml-editor-toolbar-option";
851
+ empty.textContent = EDITOR_COPY[this.locale].noAvailableOptions;
852
+ menu.append(empty);
853
+ } else {
854
+ for (const group of this.getOptionGroups(insertion, options)) {
855
+ if (group.label) {
856
+ const fieldset = document.createElement("fieldset");
857
+ fieldset.className = "ssml-editor-toolbar-option-group";
858
+ const legend = document.createElement("legend");
859
+ legend.textContent = group.label;
860
+ fieldset.append(legend);
861
+ for (const option of group.options) {
862
+ fieldset.append(this.createOptionButton(insertion, option));
863
+ }
864
+ menu.append(fieldset);
865
+ } else {
866
+ for (const option of group.options) {
867
+ menu.append(this.createOptionButton(insertion, option));
868
+ }
869
+ }
870
+ }
871
+ }
872
+ return menu;
873
+ }
874
+ getInsertionOptions(insertion) {
875
+ if (insertion.id !== "emotion") {
876
+ return insertion.options;
877
+ }
878
+ const model = this.model;
879
+ const selection = this.editor?.getSelection();
880
+ const voiceContext = model && selection ? findSsmlVoiceContext(model.getValue(), model.getOffsetAt(selection.getStartPosition())) : void 0;
881
+ const voiceName = voiceContext === void 0 ? this.documentState ? getEditableRegion(this.documentState).voiceName : void 0 : voiceContext.voiceName;
882
+ const availableStyles = new Set(
883
+ resolveExpressAsStyles(
884
+ voiceName,
885
+ insertion.options.map((option) => option.value)
886
+ )
887
+ );
888
+ return insertion.options.filter((option) => availableStyles.has(option.value));
889
+ }
890
+ getOptionGroups(insertion, options) {
891
+ if (insertion.id !== "emotion") {
892
+ return [{ label: "", options }];
893
+ }
894
+ const copy = EDITOR_COPY[this.locale];
895
+ const labels = {
896
+ emotions: copy.categoryEmotions,
897
+ scenarios: copy.categoryScenarios,
898
+ media: copy.categoryMedia,
899
+ other: copy.categoryOther
900
+ };
901
+ const categories = ["emotions", "scenarios", "media", "other"];
902
+ return categories.map((category) => ({
903
+ label: labels[category],
904
+ options: options.filter((option) => getExpressAsStyleCategory(option.value) === category)
905
+ })).filter((group) => group.options.length > 0);
906
+ }
907
+ createOptionButton(insertion, option) {
908
+ const button = document.createElement("button");
909
+ button.type = "button";
910
+ button.className = "ssml-editor-toolbar-option";
911
+ button.setAttribute("role", "menuitem");
912
+ button.title = option.descriptions?.[this.locale] ?? insertion.descriptions[this.locale];
913
+ button.textContent = option.labels[this.locale];
914
+ button.disabled = this.readonly;
915
+ button.addEventListener("click", () => {
916
+ if (!this.readonly) {
917
+ this.applyInsertion(insertion, option);
918
+ }
919
+ this.closeMenu(true);
920
+ });
921
+ button.addEventListener("mousedown", (event) => event.preventDefault());
922
+ return button;
923
+ }
924
+ handleAction(id) {
925
+ if (!this.editor) {
926
+ return;
927
+ }
928
+ if (id === "undo" || id === "redo") {
929
+ this.editor.trigger("ssml-toolbar", id, null);
930
+ this.editor.focus();
931
+ } else if (id === "clearAll") {
932
+ if (this.documentState) {
933
+ this.replaceDocument(clearSsmlDocument(this.documentState));
934
+ }
935
+ } else if (id === "format") {
936
+ if (this.documentState) {
937
+ this.replaceDocument(updateEditableText(this.documentState, formatXmlFragment(this.editor.getValue())));
938
+ } else {
939
+ this.replaceEditorValue(formatXmlFragment(this.editor.getValue()));
940
+ }
941
+ }
942
+ }
943
+ applyInsertion(insertion, option) {
944
+ const editor = this.editor;
945
+ const model = this.model;
946
+ const selection = editor?.getSelection();
947
+ if (!editor || !model || !selection) {
948
+ return;
949
+ }
950
+ const startOffset = model.getOffsetAt(selection.getStartPosition());
951
+ const endOffset = model.getOffsetAt(selection.getEndPosition());
952
+ const selectedText = selection.isEmpty() ? "" : model.getValueInRange(selection);
953
+ const result = createSsmlInsertionEdit(
954
+ model.getValue(),
955
+ startOffset,
956
+ endOffset,
957
+ insertion.createTemplate(option.value),
958
+ model.getEOL(),
959
+ selectedText
960
+ );
961
+ editor.pushUndoStop();
962
+ const applied = editor.executeEdits("ssml-toolbar", [{ range: selection, text: result.replacement }]);
963
+ editor.pushUndoStop();
964
+ if (!applied) {
965
+ return;
966
+ }
967
+ const start = model.getPositionAt(startOffset + result.selectionOffset);
968
+ const end = model.getPositionAt(endOffset + result.selectionOffset);
969
+ editor.setSelection({
970
+ selectionStartLineNumber: start.lineNumber,
971
+ selectionStartColumn: start.column,
972
+ positionLineNumber: end.lineNumber,
973
+ positionColumn: end.column
974
+ });
975
+ editor.focus();
976
+ }
977
+ replaceEditorValue(value) {
978
+ const editor = this.editor;
979
+ const model = editor?.getModel();
980
+ if (!editor || !model || editor.getValue() === value) {
981
+ return;
982
+ }
983
+ editor.pushUndoStop();
984
+ editor.executeEdits("ssml-editor-toolbar", [
985
+ {
986
+ range: model.getFullModelRange(),
987
+ text: value,
988
+ forceMoveMarkers: true
989
+ }
990
+ ]);
991
+ editor.pushUndoStop();
992
+ editor.focus();
993
+ }
994
+ replaceDocument(document2) {
995
+ const editor = this.editor;
996
+ const model = editor?.getModel();
997
+ const editableValue = getEditableText(document2);
998
+ const fullValue = buildSsml(document2);
999
+ this.documentState = document2;
1000
+ this.valueState = fullValue;
1001
+ if (!editor || !model || editor.getValue() === editableValue) {
1002
+ this.updateActiveButtons();
1003
+ this.dispatchChange(fullValue);
1004
+ return;
1005
+ }
1006
+ editor.pushUndoStop();
1007
+ editor.executeEdits("ssml-editor-toolbar", [
1008
+ {
1009
+ range: model.getFullModelRange(),
1010
+ text: editableValue,
1011
+ forceMoveMarkers: true
1012
+ }
1013
+ ]);
1014
+ editor.pushUndoStop();
1015
+ editor.focus();
1016
+ }
1017
+ dispatchChange(value) {
1018
+ if (this.suppressChangeEvent) {
1019
+ return;
1020
+ }
1021
+ this.dispatchEvent(
1022
+ new CustomEvent("change", {
1023
+ detail: { value },
1024
+ bubbles: true,
1025
+ composed: true
1026
+ })
1027
+ );
1028
+ }
1029
+ updateDecorations() {
1030
+ const button = this.toolbarButtons.get("decorations");
1031
+ if (button) {
1032
+ const copy = EDITOR_COPY[this.locale];
1033
+ button.setAttribute("aria-checked", String(this.decorationsVisible));
1034
+ button.title = this.decorationsVisible ? copy.decorationsHideTitle : copy.decorationsShowTitle;
1035
+ }
1036
+ this.editor?.updateOptions({
1037
+ inlayHints: { enabled: this.decorationsVisible ? "on" : "off" }
1038
+ });
1039
+ }
1040
+ renderHelp() {
1041
+ const display = this.display;
1042
+ if (!display) {
1043
+ return;
1044
+ }
1045
+ this.helpPanel?.remove();
1046
+ this.helpPanel = null;
1047
+ const root = this.root;
1048
+ if (root) {
1049
+ root.setAttribute("aria-label", EDITOR_COPY[this.locale].editorAriaLabel);
1050
+ this.updateTheme();
1051
+ }
1052
+ if (!this.helpOpen || this.getAttribute("show-toolbar") === "false") {
1053
+ return;
1054
+ }
1055
+ const copy = EDITOR_COPY[this.locale];
1056
+ const panel = document.createElement("section");
1057
+ panel.className = "ssml-editor-help";
1058
+ panel.setAttribute("aria-label", copy.helpHeading);
1059
+ const heading = document.createElement("h3");
1060
+ heading.textContent = copy.helpHeading;
1061
+ const description = document.createElement("p");
1062
+ description.textContent = copy.helpDescription;
1063
+ const list = document.createElement("ul");
1064
+ list.className = "ssml-editor-help-list";
1065
+ for (const insertion of SSML_INSERTIONS) {
1066
+ const item = document.createElement("li");
1067
+ item.className = "ssml-editor-help-item";
1068
+ const details = document.createElement("details");
1069
+ const summary = document.createElement("summary");
1070
+ summary.textContent = `${insertion.icon} ${insertion.labels[this.locale]} \u2014 ${insertion.descriptions[this.locale]}`;
1071
+ const parameters = document.createElement("p");
1072
+ parameters.textContent = `${copy.parameters}: ${insertion.parameterDescription[this.locale]}`;
1073
+ const options = document.createElement("ul");
1074
+ for (const option of insertion.options) {
1075
+ const optionItem = document.createElement("li");
1076
+ optionItem.textContent = `${option.labels[this.locale]}${option.descriptions?.[this.locale] ? ` \u2014 ${option.descriptions[this.locale]}` : ""}`;
1077
+ options.append(optionItem);
1078
+ }
1079
+ details.append(summary, parameters, options);
1080
+ item.append(details);
1081
+ list.append(item);
1082
+ }
1083
+ panel.append(heading, description, list);
1084
+ display.prepend(panel);
1085
+ this.helpPanel = panel;
1086
+ }
1087
+ updateTheme() {
1088
+ if (this.root) {
1089
+ this.root.dataset.theme = isDarkTheme(this.theme) ? "dark" : "light";
1090
+ }
1091
+ }
1092
+ updateActiveButtons() {
1093
+ const editor = this.editor;
1094
+ const model = this.model;
1095
+ const selection = editor?.getSelection();
1096
+ if (!editor || !model || !selection) {
1097
+ return;
1098
+ }
1099
+ const activeTags = findActiveSsmlTags(model.getValue(), model.getOffsetAt(selection.getStartPosition()));
1100
+ for (const insertion of SSML_INSERTIONS) {
1101
+ const button = this.toolbarButtons.get(insertion.id);
1102
+ if (button) {
1103
+ button.dataset.active = String(
1104
+ insertion.tagName !== void 0 && activeTags.has(insertion.tagName.toLowerCase())
1105
+ );
1106
+ }
1107
+ }
1108
+ }
1109
+ async initialize(token) {
1110
+ const container = this.editorContainer;
1111
+ if (!container) {
1112
+ return;
1113
+ }
1114
+ const monacoModule = await import("monaco-editor");
1115
+ if (token !== this.initializationToken || !this.isConnected) {
1116
+ return;
1117
+ }
1118
+ const model = monacoModule.editor.createModel(this.prepareDocument(this.value), "xml");
1119
+ const editor = monacoModule.editor.create(container, {
1120
+ model,
1121
+ theme: this.theme,
1122
+ readOnly: this.readonly,
1123
+ automaticLayout: true,
1124
+ minimap: { enabled: false },
1125
+ wordWrap: "on",
1126
+ inlayHints: { enabled: this.decorationsVisible ? "on" : "off" }
1127
+ });
1128
+ if (token !== this.initializationToken || !this.isConnected) {
1129
+ editor.dispose();
1130
+ model.dispose();
1131
+ return;
1132
+ }
1133
+ this.monaco = monacoModule;
1134
+ this.model = model;
1135
+ this.editor = editor;
1136
+ this.contentDisposable = editor.onDidChangeModelContent(() => {
1137
+ const value = editor.getValue();
1138
+ let nextValue = value;
1139
+ if (this.documentState) {
1140
+ this.documentState = updateEditableText(this.documentState, value);
1141
+ nextValue = buildSsml(this.documentState);
1142
+ }
1143
+ this.valueState = nextValue;
1144
+ this.updateActiveButtons();
1145
+ this.dispatchChange(nextValue);
1146
+ });
1147
+ this.cursorDisposable = editor.onDidChangeCursorPosition(() => this.updateActiveButtons());
1148
+ this.completionDisposable = registerSsmlCompletionProvider(monacoModule, {
1149
+ model,
1150
+ getOuterVoiceName: () => this.documentState ? getEditableRegion(this.documentState).voiceName : void 0
1151
+ });
1152
+ this.hoverDisposable = monacoModule.languages.registerHoverProvider("xml", {
1153
+ provideHover: (hoverModel, position) => {
1154
+ const target = findSsmlHoverTarget(hoverModel.getValue(), position.lineNumber, position.column);
1155
+ if (!target) {
1156
+ return void 0;
1157
+ }
1158
+ return {
1159
+ contents: [
1160
+ {
1161
+ isTrusted: false,
1162
+ supportHtml: false,
1163
+ value: formatSsmlHover(target)
1164
+ }
1165
+ ],
1166
+ range: target.range
1167
+ };
1168
+ }
1169
+ });
1170
+ this.updateActiveButtons();
1171
+ }
1172
+ closeMenu(restoreFocus = false) {
1173
+ this.openMenu?.remove();
1174
+ this.openMenu = null;
1175
+ if (this.openMenuTrigger) {
1176
+ this.openMenuTrigger.setAttribute("aria-expanded", "false");
1177
+ this.openMenuTrigger.removeAttribute("aria-controls");
1178
+ if (restoreFocus) {
1179
+ this.openMenuTrigger.focus();
1180
+ }
1181
+ }
1182
+ this.openMenuTrigger = null;
1183
+ }
1184
+ disposeEditor() {
1185
+ this.closeMenu();
1186
+ this.contentDisposable?.dispose();
1187
+ this.contentDisposable = null;
1188
+ this.cursorDisposable?.dispose();
1189
+ this.cursorDisposable = null;
1190
+ this.completionDisposable?.dispose();
1191
+ this.completionDisposable = null;
1192
+ this.hoverDisposable?.dispose();
1193
+ this.hoverDisposable = null;
1194
+ this.editor?.dispose();
1195
+ this.editor = null;
1196
+ this.model?.dispose();
1197
+ this.model = null;
1198
+ this.monaco = null;
1199
+ this.root?.remove();
1200
+ this.root = null;
1201
+ this.toolbar = null;
1202
+ this.toolbarActions = null;
1203
+ this.display = null;
1204
+ this.editorContainer = null;
1205
+ this.helpPanel = null;
1206
+ this.toolbarButtons.clear();
1207
+ }
1208
+ };
1209
+ SsmlEditorElement.tagName = "ssml-editor";
1210
+ SsmlEditorElement.observedAttributes = [
1211
+ "value",
1212
+ "theme",
1213
+ "readonly",
1214
+ "locale",
1215
+ "show-toolbar",
1216
+ "show-toolbar-labels",
1217
+ "show-decorations"
1218
+ ];
1219
+
1220
+ // packages/ssml-editor-elements/src/index.ts
1221
+ function defineSsmlEditorElement() {
1222
+ if (typeof customElements === "undefined" || customElements.get(SsmlEditorElement.tagName)) {
1223
+ return;
1224
+ }
1225
+ customElements.define(SsmlEditorElement.tagName, SsmlEditorElement);
1226
+ }
1227
+
1228
+ // src/elements.ts
1229
+ defineSsmlEditorElement();
1230
+ export {
1231
+ SsmlEditorElement,
1232
+ defineSsmlEditorElement
1233
+ };
1234
+ //# sourceMappingURL=elements.mjs.map