ssml-builder-js 2.1.0 → 2.3.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 +81 -10
- package/dist/chunk-NPZ44CHU.mjs +3513 -0
- package/dist/chunk-NPZ44CHU.mjs.map +1 -0
- package/dist/{chunk-I3GP7OJU.mjs → chunk-PSN6XAFF.mjs} +8 -2
- package/dist/chunk-PSN6XAFF.mjs.map +1 -0
- package/dist/core.js +7 -1
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/elements.d.mts +72 -0
- package/dist/elements.d.ts +72 -0
- package/dist/elements.js +4583 -0
- package/dist/elements.js.map +1 -0
- package/dist/elements.mjs +1234 -0
- package/dist/elements.mjs.map +1 -0
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/react.d.mts +30 -1
- package/dist/react.d.ts +30 -1
- package/dist/react.js +923 -251
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +573 -3326
- package/dist/react.mjs.map +1 -1
- package/package.json +11 -2
- package/dist/chunk-I3GP7OJU.mjs.map +0 -1
package/dist/react.js
CHANGED
|
@@ -36,7 +36,9 @@ __export(react_exports, {
|
|
|
36
36
|
SSML_HOVER_COPY: () => SSML_HOVER_COPY,
|
|
37
37
|
SSML_INSERTIONS: () => SSML_INSERTIONS,
|
|
38
38
|
SsmlEditor: () => SsmlEditor,
|
|
39
|
-
createSsmlEditorInsertionDefinition: () => createSsmlEditorInsertionDefinition
|
|
39
|
+
createSsmlEditorInsertionDefinition: () => createSsmlEditorInsertionDefinition,
|
|
40
|
+
registerSsmlCodeLens: () => registerSsmlCodeLens,
|
|
41
|
+
updateTagAttribute: () => updateTagAttribute
|
|
40
42
|
});
|
|
41
43
|
module.exports = __toCommonJS(react_exports);
|
|
42
44
|
|
|
@@ -58,7 +60,7 @@ __export(ssmlPresets_exports, {
|
|
|
58
60
|
EMPHASIS_LEVEL_DESCRIPTIONS: () => EMPHASIS_LEVEL_DESCRIPTIONS,
|
|
59
61
|
EMPHASIS_LEVEL_PRESETS: () => EMPHASIS_LEVEL_PRESETS,
|
|
60
62
|
EXPRESS_AS_ROLE_PRESETS: () => EXPRESS_AS_ROLE_PRESETS,
|
|
61
|
-
|
|
63
|
+
EXPRESS_AS_STYLE_CATEGORIES: () => EXPRESS_AS_STYLE_CATEGORIES,
|
|
62
64
|
EXPRESS_AS_STYLE_DESCRIPTIONS: () => EXPRESS_AS_STYLE_DESCRIPTIONS,
|
|
63
65
|
EXPRESS_AS_STYLE_PRESETS: () => EXPRESS_AS_STYLE_PRESETS,
|
|
64
66
|
LANGUAGE_DESCRIPTIONS: () => LANGUAGE_DESCRIPTIONS,
|
|
@@ -80,6 +82,8 @@ __export(ssmlPresets_exports, {
|
|
|
80
82
|
SSML_PRESETS: () => SSML_PRESETS,
|
|
81
83
|
SSML_PRESET_EXAMPLES: () => SSML_PRESET_EXAMPLES,
|
|
82
84
|
VISEME_TYPE_PRESETS: () => VISEME_TYPE_PRESETS,
|
|
85
|
+
VOICE_STYLE_MAP: () => VOICE_STYLE_MAP,
|
|
86
|
+
getExpressAsStyleCategory: () => getExpressAsStyleCategory,
|
|
83
87
|
resolveExpressAsStyles: () => resolveExpressAsStyles
|
|
84
88
|
});
|
|
85
89
|
var SSML_PRESETS = [
|
|
@@ -124,21 +128,90 @@ var EXPRESS_AS_STYLE_PRESETS = [
|
|
|
124
128
|
"shouting",
|
|
125
129
|
"terrified",
|
|
126
130
|
"unfriendly",
|
|
127
|
-
"whispering"
|
|
131
|
+
"whispering",
|
|
132
|
+
"empathetic",
|
|
133
|
+
"relieved",
|
|
134
|
+
"fearful",
|
|
135
|
+
"depressed",
|
|
136
|
+
"disgruntled",
|
|
137
|
+
"embarrassed",
|
|
138
|
+
"narration-relaxed",
|
|
139
|
+
"poetry-reading",
|
|
140
|
+
"sports_commentary",
|
|
141
|
+
"sports_commentary_excited",
|
|
142
|
+
"story"
|
|
128
143
|
];
|
|
129
|
-
var
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
var EXPRESS_AS_STYLE_CATEGORIES = {
|
|
145
|
+
emotions: [
|
|
146
|
+
"cheerful",
|
|
147
|
+
"sad",
|
|
133
148
|
"angry",
|
|
149
|
+
"calm",
|
|
150
|
+
"fearful",
|
|
151
|
+
"depressed",
|
|
152
|
+
"disgruntled",
|
|
153
|
+
"embarrassed",
|
|
154
|
+
"empathetic",
|
|
155
|
+
"envious",
|
|
156
|
+
"excited",
|
|
157
|
+
"friendly",
|
|
158
|
+
"gentle",
|
|
159
|
+
"hopeful",
|
|
160
|
+
"relieved",
|
|
161
|
+
"serious",
|
|
162
|
+
"shouting",
|
|
163
|
+
"terrified",
|
|
164
|
+
"unfriendly",
|
|
165
|
+
"whispering"
|
|
166
|
+
],
|
|
167
|
+
scenarios: ["chat", "customerservice", "assistant", "livecommercial", "poetry-reading", "story"],
|
|
168
|
+
media: [
|
|
169
|
+
"newscast",
|
|
170
|
+
"newscast-casual",
|
|
171
|
+
"newscast-formal",
|
|
172
|
+
"narration-professional",
|
|
173
|
+
"narration-relaxed",
|
|
174
|
+
"documentary-narration",
|
|
175
|
+
"advertisement_upbeat",
|
|
176
|
+
"sports_commentary",
|
|
177
|
+
"sports_commentary_excited"
|
|
178
|
+
]
|
|
179
|
+
};
|
|
180
|
+
function getExpressAsStyleCategory(style) {
|
|
181
|
+
for (const [category, styles] of Object.entries(EXPRESS_AS_STYLE_CATEGORIES)) {
|
|
182
|
+
if (styles.includes(style)) {
|
|
183
|
+
return category;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return "other";
|
|
187
|
+
}
|
|
188
|
+
var VOICE_STYLE_MAP = {
|
|
189
|
+
"ja-JP-MayuNeural": ["calm", "cheerful", "sad"],
|
|
190
|
+
"ja-JP-KeitaNeural": ["chat"],
|
|
191
|
+
"ja-JP-NanamiNeural": ["chat", "customerservice", "cheerful", "whispering", "sad"],
|
|
192
|
+
"en-US-JennyMultilingualNeural": [
|
|
193
|
+
"cheerful",
|
|
194
|
+
"empathetic",
|
|
195
|
+
"excited",
|
|
196
|
+
"friendly",
|
|
197
|
+
"hopeful",
|
|
198
|
+
"sad",
|
|
199
|
+
"shouting",
|
|
200
|
+
"terrified",
|
|
201
|
+
"unfriendly",
|
|
202
|
+
"whispering"
|
|
203
|
+
],
|
|
204
|
+
"en-US-AndrewNeural": ["empathetic", "relieved"],
|
|
205
|
+
"en-US-JennyNeural": [
|
|
134
206
|
"assistant",
|
|
135
207
|
"chat",
|
|
136
|
-
"cheerful",
|
|
137
208
|
"customerservice",
|
|
209
|
+
"newscast",
|
|
210
|
+
"cheerful",
|
|
211
|
+
"empathetic",
|
|
138
212
|
"excited",
|
|
139
213
|
"friendly",
|
|
140
214
|
"hopeful",
|
|
141
|
-
"newscast",
|
|
142
215
|
"sad",
|
|
143
216
|
"shouting",
|
|
144
217
|
"terrified",
|
|
@@ -157,18 +230,58 @@ var EXPRESS_AS_STYLES_BY_VOICE = {
|
|
|
157
230
|
"terrified",
|
|
158
231
|
"unfriendly",
|
|
159
232
|
"whispering"
|
|
160
|
-
]
|
|
233
|
+
],
|
|
234
|
+
"ko-KR-SunHiNeural": ["cheerful", "sad"],
|
|
235
|
+
"zh-CN-XiaoxiaoNeural": [
|
|
236
|
+
"assistant",
|
|
237
|
+
"chat",
|
|
238
|
+
"customerservice",
|
|
239
|
+
"newscast",
|
|
240
|
+
"cheerful",
|
|
241
|
+
"empathetic",
|
|
242
|
+
"excited",
|
|
243
|
+
"friendly",
|
|
244
|
+
"hopeful",
|
|
245
|
+
"sad",
|
|
246
|
+
"terrified",
|
|
247
|
+
"whispering",
|
|
248
|
+
"poetry-reading",
|
|
249
|
+
"sports_commentary",
|
|
250
|
+
"sports_commentary_excited",
|
|
251
|
+
"story"
|
|
252
|
+
],
|
|
253
|
+
"zh-CN-YunxiNeural": [
|
|
254
|
+
"narration-relaxed",
|
|
255
|
+
"embarrassed",
|
|
256
|
+
"fearful",
|
|
257
|
+
"sad",
|
|
258
|
+
"disgruntled",
|
|
259
|
+
"serious",
|
|
260
|
+
"angry",
|
|
261
|
+
"depressed",
|
|
262
|
+
"chat",
|
|
263
|
+
"cheerful",
|
|
264
|
+
"assistant"
|
|
265
|
+
],
|
|
266
|
+
"fr-FR-DeniseNeural": ["cheerful", "sad"],
|
|
267
|
+
"fr-FR-HenriNeural": ["cheerful", "sad"],
|
|
268
|
+
"pt-BR-FranciscaNeural": ["calm"],
|
|
269
|
+
"it-IT-ElsaNeural": ["cheerful", "sad"],
|
|
270
|
+
"de-DE-KatjaNeural": ["cheerful", "sad"],
|
|
271
|
+
"de-DE-ConradNeural": ["cheerful", "sad"],
|
|
272
|
+
"ru-RU-SvetlanaNeural": ["cheerful", "sad", "angry", "disgruntled", "embarrassed", "fearful"]
|
|
161
273
|
};
|
|
162
|
-
var
|
|
163
|
-
Object.entries(
|
|
274
|
+
var VOICE_STYLE_MAP_BY_NORMALIZED_NAME = new Map(
|
|
275
|
+
Object.entries(VOICE_STYLE_MAP).map(([voiceName, styles]) => [voiceName.toLowerCase(), styles])
|
|
164
276
|
);
|
|
165
277
|
function resolveExpressAsStyles(voiceName, candidates = EXPRESS_AS_STYLE_PRESETS) {
|
|
166
|
-
|
|
278
|
+
const normalizedVoiceName = voiceName?.trim().toLowerCase();
|
|
279
|
+
if (!normalizedVoiceName) {
|
|
167
280
|
return candidates;
|
|
168
281
|
}
|
|
169
|
-
const supportedStyles =
|
|
282
|
+
const supportedStyles = VOICE_STYLE_MAP_BY_NORMALIZED_NAME.get(normalizedVoiceName);
|
|
170
283
|
if (supportedStyles === void 0) {
|
|
171
|
-
return
|
|
284
|
+
return [];
|
|
172
285
|
}
|
|
173
286
|
const supportedStyleSet = new Set(supportedStyles);
|
|
174
287
|
return candidates.filter((style) => supportedStyleSet.has(style));
|
|
@@ -418,6 +531,30 @@ var EXPRESS_AS_STYLE_DESCRIPTIONS = {
|
|
|
418
531
|
ja: "\u8208\u596E\u3057\u305F\u30B9\u30BF\u30A4\u30EB",
|
|
419
532
|
en: "Uses an excited style."
|
|
420
533
|
},
|
|
534
|
+
empathetic: {
|
|
535
|
+
ja: "\u5171\u611F\u3092\u793A\u3059\u30B9\u30BF\u30A4\u30EB",
|
|
536
|
+
en: "Uses an empathetic style."
|
|
537
|
+
},
|
|
538
|
+
relieved: {
|
|
539
|
+
ja: "\u5B89\u5FC3\u3057\u305F\u30B9\u30BF\u30A4\u30EB",
|
|
540
|
+
en: "Uses a relieved style."
|
|
541
|
+
},
|
|
542
|
+
fearful: {
|
|
543
|
+
ja: "\u6050\u308C\u3092\u611F\u3058\u3055\u305B\u308B\u30B9\u30BF\u30A4\u30EB",
|
|
544
|
+
en: "Uses a fearful style."
|
|
545
|
+
},
|
|
546
|
+
depressed: {
|
|
547
|
+
ja: "\u843D\u3061\u8FBC\u3093\u3060\u30B9\u30BF\u30A4\u30EB",
|
|
548
|
+
en: "Uses a depressed style."
|
|
549
|
+
},
|
|
550
|
+
disgruntled: {
|
|
551
|
+
ja: "\u4E0D\u6E80\u3092\u611F\u3058\u3055\u305B\u308B\u30B9\u30BF\u30A4\u30EB",
|
|
552
|
+
en: "Uses a disgruntled style."
|
|
553
|
+
},
|
|
554
|
+
embarrassed: {
|
|
555
|
+
ja: "\u6065\u305A\u304B\u3057\u305D\u3046\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
556
|
+
en: "Uses an embarrassed style."
|
|
557
|
+
},
|
|
421
558
|
serious: {
|
|
422
559
|
ja: "\u771F\u5263\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
423
560
|
en: "Uses a serious style."
|
|
@@ -457,6 +594,26 @@ var EXPRESS_AS_STYLE_DESCRIPTIONS = {
|
|
|
457
594
|
whispering: {
|
|
458
595
|
ja: "\u3055\u3055\u3084\u304F\u3088\u3046\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
459
596
|
en: "Uses a whispering style."
|
|
597
|
+
},
|
|
598
|
+
"narration-relaxed": {
|
|
599
|
+
ja: "\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
600
|
+
en: "Uses a relaxed narration style."
|
|
601
|
+
},
|
|
602
|
+
"poetry-reading": {
|
|
603
|
+
ja: "\u8A69\u306E\u6717\u8AAD\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
604
|
+
en: "Uses a poetry-reading style."
|
|
605
|
+
},
|
|
606
|
+
sports_commentary: {
|
|
607
|
+
ja: "\u30B9\u30DD\u30FC\u30C4\u5B9F\u6CC1\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
608
|
+
en: "Uses a sports commentary style."
|
|
609
|
+
},
|
|
610
|
+
sports_commentary_excited: {
|
|
611
|
+
ja: "\u8208\u596E\u3057\u305F\u30B9\u30DD\u30FC\u30C4\u5B9F\u6CC1\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
612
|
+
en: "Uses an excited sports commentary style."
|
|
613
|
+
},
|
|
614
|
+
story: {
|
|
615
|
+
ja: "\u7269\u8A9E\u306E\u6717\u8AAD\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
616
|
+
en: "Uses a storytelling style."
|
|
460
617
|
}
|
|
461
618
|
};
|
|
462
619
|
var SAY_AS_DESCRIPTIONS = {
|
|
@@ -568,7 +725,12 @@ var EDITOR_COPY = {
|
|
|
568
725
|
selectionCountSuffix: "\u6587\u5B57",
|
|
569
726
|
previewSelection: "\u9078\u629E\u90E8\u5206\u3092\u8A66\u8074",
|
|
570
727
|
previewSelectionTitle: "\u9078\u629E\u90E8\u5206\u306ESSML\u3092\u8A66\u8074",
|
|
571
|
-
noAvailableOptions: "\u5229\u7528\u53EF\u80FD\u306A\u9078\u629E\u80A2\u304C\u3042\u308A\u307E\u305B\u3093\u3002"
|
|
728
|
+
noAvailableOptions: "\u5229\u7528\u53EF\u80FD\u306A\u9078\u629E\u80A2\u304C\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
729
|
+
styleNotSupported: "\u3053\u306E\u97F3\u58F0\u306F\u30B9\u30BF\u30A4\u30EB\u6307\u5B9A\u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093",
|
|
730
|
+
categoryEmotions: "\u611F\u60C5\u30FB\u30C8\u30FC\u30F3",
|
|
731
|
+
categoryScenarios: "\u4F1A\u8A71\u30FB\u30B7\u30CA\u30EA\u30AA",
|
|
732
|
+
categoryMedia: "\u30E1\u30C7\u30A3\u30A2\u30FB\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3",
|
|
733
|
+
categoryOther: "\u305D\u306E\u4ED6"
|
|
572
734
|
},
|
|
573
735
|
en: {
|
|
574
736
|
editorAriaLabel: "SSML editor",
|
|
@@ -594,7 +756,12 @@ var EDITOR_COPY = {
|
|
|
594
756
|
selectionCountSuffix: " characters",
|
|
595
757
|
previewSelection: "Preview selection",
|
|
596
758
|
previewSelectionTitle: "Preview the selected SSML",
|
|
597
|
-
noAvailableOptions: "No options are available."
|
|
759
|
+
noAvailableOptions: "No options are available.",
|
|
760
|
+
styleNotSupported: "This voice does not support style selection.",
|
|
761
|
+
categoryEmotions: "Emotions / Tone",
|
|
762
|
+
categoryScenarios: "Conversations / Scenarios",
|
|
763
|
+
categoryMedia: "Media / Broadcast",
|
|
764
|
+
categoryOther: "Other"
|
|
598
765
|
}
|
|
599
766
|
};
|
|
600
767
|
var INLINE_BADGE_COPY = {
|
|
@@ -991,6 +1158,10 @@ var editorStyles = {
|
|
|
991
1158
|
font: "inherit",
|
|
992
1159
|
cursor: "pointer"
|
|
993
1160
|
},
|
|
1161
|
+
toolbarButtonActive: {
|
|
1162
|
+
border: "1px solid var(--ssml-editor-active-border)",
|
|
1163
|
+
backgroundColor: "var(--ssml-editor-active-bg)"
|
|
1164
|
+
},
|
|
994
1165
|
display: {
|
|
995
1166
|
display: "grid",
|
|
996
1167
|
gap: "0.5rem"
|
|
@@ -1036,12 +1207,35 @@ var editorStyles = {
|
|
|
1036
1207
|
whiteSpace: "nowrap",
|
|
1037
1208
|
cursor: "pointer"
|
|
1038
1209
|
},
|
|
1210
|
+
toolbarOptionGroup: {
|
|
1211
|
+
display: "grid",
|
|
1212
|
+
gap: "0.125rem",
|
|
1213
|
+
margin: 0,
|
|
1214
|
+
padding: 0,
|
|
1215
|
+
border: 0
|
|
1216
|
+
},
|
|
1217
|
+
toolbarOptionGroupLabel: {
|
|
1218
|
+
padding: "0.375rem 0.5rem 0.125rem",
|
|
1219
|
+
color: "var(--ssml-editor-color)",
|
|
1220
|
+
fontSize: "0.875rem",
|
|
1221
|
+
fontWeight: 600,
|
|
1222
|
+
whiteSpace: "nowrap"
|
|
1223
|
+
},
|
|
1039
1224
|
toolbarEmpty: {
|
|
1040
1225
|
margin: 0,
|
|
1041
1226
|
padding: "0.375rem 0.5rem",
|
|
1042
1227
|
color: "var(--ssml-editor-color)",
|
|
1043
1228
|
whiteSpace: "nowrap"
|
|
1044
1229
|
},
|
|
1230
|
+
toolbarEmptySelect: {
|
|
1231
|
+
padding: "0.375rem 0.5rem",
|
|
1232
|
+
border: "1px solid var(--ssml-editor-control-border)",
|
|
1233
|
+
borderRadius: "0.125rem",
|
|
1234
|
+
color: "var(--ssml-editor-color)",
|
|
1235
|
+
backgroundColor: "var(--ssml-editor-control-bg)",
|
|
1236
|
+
font: "inherit",
|
|
1237
|
+
textAlign: "left"
|
|
1238
|
+
},
|
|
1045
1239
|
helpPanel: {
|
|
1046
1240
|
display: "grid",
|
|
1047
1241
|
gap: "0.5rem",
|
|
@@ -1193,8 +1387,29 @@ function InsertionPopover({
|
|
|
1193
1387
|
menuRef,
|
|
1194
1388
|
onToggle,
|
|
1195
1389
|
onClose,
|
|
1196
|
-
onApply
|
|
1390
|
+
onApply,
|
|
1391
|
+
optionGroups
|
|
1197
1392
|
}) {
|
|
1393
|
+
const hasOptions = optionGroups ? optionGroups.some((group) => group.options.length > 0) : insertion.options.length > 0;
|
|
1394
|
+
const renderOption = (option) => /* @__PURE__ */ React.createElement(
|
|
1395
|
+
"button",
|
|
1396
|
+
{
|
|
1397
|
+
key: option.value,
|
|
1398
|
+
type: "button",
|
|
1399
|
+
role: "menuitem",
|
|
1400
|
+
style: editorStyles.toolbarOption,
|
|
1401
|
+
title: option.descriptions?.[language] ?? insertion.descriptions[language],
|
|
1402
|
+
disabled: isReadOnly,
|
|
1403
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
1404
|
+
onClick: () => {
|
|
1405
|
+
if (!isReadOnly) {
|
|
1406
|
+
onApply(insertion, option);
|
|
1407
|
+
}
|
|
1408
|
+
onClose();
|
|
1409
|
+
}
|
|
1410
|
+
},
|
|
1411
|
+
option.labels[language]
|
|
1412
|
+
);
|
|
1198
1413
|
const menu = isOpen && menuPosition && typeof document !== "undefined" ? /* @__PURE__ */ React.createElement(
|
|
1199
1414
|
"div",
|
|
1200
1415
|
{
|
|
@@ -1206,25 +1421,7 @@ function InsertionPopover({
|
|
|
1206
1421
|
role: "menu",
|
|
1207
1422
|
"aria-label": insertion.labels[language]
|
|
1208
1423
|
},
|
|
1209
|
-
|
|
1210
|
-
"button",
|
|
1211
|
-
{
|
|
1212
|
-
key: option.value,
|
|
1213
|
-
type: "button",
|
|
1214
|
-
role: "menuitem",
|
|
1215
|
-
style: editorStyles.toolbarOption,
|
|
1216
|
-
title: option.descriptions?.[language] ?? insertion.descriptions[language],
|
|
1217
|
-
disabled: isReadOnly,
|
|
1218
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
1219
|
-
onClick: () => {
|
|
1220
|
-
if (!isReadOnly) {
|
|
1221
|
-
onApply(insertion, option);
|
|
1222
|
-
}
|
|
1223
|
-
onClose();
|
|
1224
|
-
}
|
|
1225
|
-
},
|
|
1226
|
-
option.labels[language]
|
|
1227
|
-
))
|
|
1424
|
+
!hasOptions ? /* @__PURE__ */ React.createElement("div", { role: "presentation" }, /* @__PURE__ */ React.createElement("select", { disabled: true, value: "", style: editorStyles.toolbarEmptySelect }, /* @__PURE__ */ React.createElement("option", { value: "", disabled: true }, emptyOptionsMessage))) : optionGroups ? optionGroups.map((group) => /* @__PURE__ */ React.createElement("fieldset", { key: group.label, style: editorStyles.toolbarOptionGroup }, /* @__PURE__ */ React.createElement("legend", { style: editorStyles.toolbarOptionGroupLabel }, group.label), group.options.map(renderOption))) : insertion.options.map(renderOption)
|
|
1228
1425
|
) : null;
|
|
1229
1426
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { style: editorStyles.toolbarDropdown }, /* @__PURE__ */ React.createElement(
|
|
1230
1427
|
"button",
|
|
@@ -1249,6 +1446,8 @@ function InsertionPopovers({
|
|
|
1249
1446
|
insertions,
|
|
1250
1447
|
openPopoverId,
|
|
1251
1448
|
onToggle,
|
|
1449
|
+
emptyOptionsMessages,
|
|
1450
|
+
optionGroups,
|
|
1252
1451
|
...props
|
|
1253
1452
|
}) {
|
|
1254
1453
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, insertions.map((insertion) => /* @__PURE__ */ React.createElement(
|
|
@@ -1257,6 +1456,8 @@ function InsertionPopovers({
|
|
|
1257
1456
|
key: insertion.id,
|
|
1258
1457
|
...props,
|
|
1259
1458
|
insertion,
|
|
1459
|
+
emptyOptionsMessage: emptyOptionsMessages?.[insertion.id] ?? props.emptyOptionsMessage,
|
|
1460
|
+
optionGroups: optionGroups?.[insertion.id],
|
|
1260
1461
|
isOpen: openPopoverId === insertion.id,
|
|
1261
1462
|
onToggle: (trigger) => onToggle(insertion.id, trigger)
|
|
1262
1463
|
}
|
|
@@ -1264,23 +1465,57 @@ function InsertionPopovers({
|
|
|
1264
1465
|
}
|
|
1265
1466
|
|
|
1266
1467
|
// packages/ssml-editor-react/src/components/popovers/ProsodyPopovers.tsx
|
|
1267
|
-
|
|
1468
|
+
var CATEGORY_LABEL_KEYS = {
|
|
1469
|
+
emotions: "categoryEmotions",
|
|
1470
|
+
scenarios: "categoryScenarios",
|
|
1471
|
+
media: "categoryMedia",
|
|
1472
|
+
other: "categoryOther"
|
|
1473
|
+
};
|
|
1474
|
+
var CATEGORY_ORDER = ["emotions", "scenarios", "media", "other"];
|
|
1475
|
+
function isExpressAsInsertion(insertion) {
|
|
1476
|
+
return insertion.id === "emotion" && insertion.tagName?.toLowerCase() === "mstts:express-as";
|
|
1477
|
+
}
|
|
1478
|
+
function createOptionGroups(options, language) {
|
|
1479
|
+
const t = (key) => EDITOR_COPY[language][key];
|
|
1480
|
+
return CATEGORY_ORDER.map((category) => ({
|
|
1481
|
+
label: t(CATEGORY_LABEL_KEYS[category]),
|
|
1482
|
+
options: options.filter((option) => getExpressAsStyleCategory(option.value) === category)
|
|
1483
|
+
})).filter((group) => group.options.length > 0);
|
|
1484
|
+
}
|
|
1485
|
+
function ProsodyPopovers({ insertions, voiceName, language, ...props }) {
|
|
1486
|
+
const emptyOptionsMessages = {};
|
|
1268
1487
|
const filteredInsertions = insertions.map((insertion) => {
|
|
1269
|
-
if (insertion
|
|
1488
|
+
if (!isExpressAsInsertion(insertion)) {
|
|
1270
1489
|
return insertion;
|
|
1271
1490
|
}
|
|
1272
|
-
const
|
|
1491
|
+
const availableStyles = new Set(
|
|
1273
1492
|
resolveExpressAsStyles(
|
|
1274
1493
|
voiceName,
|
|
1275
1494
|
insertion.options.map((option) => option.value)
|
|
1276
1495
|
)
|
|
1277
1496
|
);
|
|
1497
|
+
if (availableStyles.size === 0) {
|
|
1498
|
+
emptyOptionsMessages[insertion.id] = EDITOR_COPY[language].styleNotSupported;
|
|
1499
|
+
}
|
|
1500
|
+
const availableOptions = insertion.options.filter((option) => availableStyles.has(option.value));
|
|
1278
1501
|
return {
|
|
1279
1502
|
...insertion,
|
|
1280
|
-
options:
|
|
1503
|
+
options: availableOptions
|
|
1281
1504
|
};
|
|
1282
1505
|
});
|
|
1283
|
-
|
|
1506
|
+
const optionGroups = Object.fromEntries(
|
|
1507
|
+
filteredInsertions.filter(isExpressAsInsertion).map((insertion) => [insertion.id, createOptionGroups(insertion.options, language)])
|
|
1508
|
+
);
|
|
1509
|
+
return /* @__PURE__ */ React.createElement(
|
|
1510
|
+
InsertionPopovers,
|
|
1511
|
+
{
|
|
1512
|
+
...props,
|
|
1513
|
+
emptyOptionsMessages,
|
|
1514
|
+
language,
|
|
1515
|
+
insertions: filteredInsertions,
|
|
1516
|
+
optionGroups
|
|
1517
|
+
}
|
|
1518
|
+
);
|
|
1284
1519
|
}
|
|
1285
1520
|
|
|
1286
1521
|
// packages/ssml-editor-react/src/components/popovers/TextPopovers.tsx
|
|
@@ -1355,6 +1590,7 @@ var SSML_ATTRS = {
|
|
|
1355
1590
|
STYLE: "style",
|
|
1356
1591
|
STYLE_DEGREE: "styledegree",
|
|
1357
1592
|
STYLE_DEGREE_CAMEL: "styleDegree",
|
|
1593
|
+
STYLE_DEGREE_HYPHEN: "style-degree",
|
|
1358
1594
|
ROLE: "role",
|
|
1359
1595
|
INTERPRET_AS: "interpret-as",
|
|
1360
1596
|
FORMAT: "format",
|
|
@@ -1898,7 +2134,12 @@ function convertElement(node) {
|
|
|
1898
2134
|
case SSML_TAGS.MSTTS_EXPRESS_AS: {
|
|
1899
2135
|
const element = { type: node.name };
|
|
1900
2136
|
const style = readAttribute(attributes, SSML_ATTRS.STYLE);
|
|
1901
|
-
const styleDegree = readAttribute(
|
|
2137
|
+
const styleDegree = readAttribute(
|
|
2138
|
+
attributes,
|
|
2139
|
+
SSML_ATTRS.STYLE_DEGREE,
|
|
2140
|
+
SSML_ATTRS.STYLE_DEGREE_CAMEL,
|
|
2141
|
+
SSML_ATTRS.STYLE_DEGREE_HYPHEN
|
|
2142
|
+
);
|
|
1902
2143
|
const role = readAttribute(attributes, SSML_ATTRS.ROLE);
|
|
1903
2144
|
if (style !== void 0) element.style = style;
|
|
1904
2145
|
if (styleDegree !== void 0) element.styleDegree = styleDegree;
|
|
@@ -2648,148 +2889,7 @@ function formatXmlFragment(xml) {
|
|
|
2648
2889
|
return preserveTrailingLineBreak(unwrapFormattedFragment(formatted) ?? xml, trailingLineBreaks);
|
|
2649
2890
|
}
|
|
2650
2891
|
|
|
2651
|
-
// packages/ssml-editor-react/src/
|
|
2652
|
-
function isLineStart(value, offset) {
|
|
2653
|
-
return offset === 0 || value[offset - 1] === "\n" || value[offset - 1] === "\r";
|
|
2654
|
-
}
|
|
2655
|
-
function isLineEnd(value, offset) {
|
|
2656
|
-
return offset === value.length || value[offset] === "\n" || value[offset] === "\r";
|
|
2657
|
-
}
|
|
2658
|
-
function getLineBreakAt(value, offset) {
|
|
2659
|
-
if (value.startsWith("\r\n", offset)) {
|
|
2660
|
-
return "\r\n";
|
|
2661
|
-
}
|
|
2662
|
-
if (value[offset] === "\n" || value[offset] === "\r") {
|
|
2663
|
-
return value[offset];
|
|
2664
|
-
}
|
|
2665
|
-
return "";
|
|
2666
|
-
}
|
|
2667
|
-
function startsWithLineBreak(value) {
|
|
2668
|
-
return value.startsWith("\n") || value.startsWith("\r");
|
|
2669
|
-
}
|
|
2670
|
-
function endsWithLineBreak(value) {
|
|
2671
|
-
return value.endsWith("\n") || value.endsWith("\r");
|
|
2672
|
-
}
|
|
2673
|
-
function createSsmlInsertionEdit(source, startOffset, endOffset, template, eol = "\n", selectedText = startOffset === endOffset ? "" : source.slice(startOffset, endOffset)) {
|
|
2674
|
-
if (template.mode === SSML_INSERTION_MODES.wrap) {
|
|
2675
|
-
const trailingLineBreak2 = getLineBreakAt(source, endOffset) === "" ? eol : "";
|
|
2676
|
-
return {
|
|
2677
|
-
replacement: `${template.prefix}${selectedText}${template.suffix}${trailingLineBreak2}`,
|
|
2678
|
-
selectionOffset: template.prefix.length
|
|
2679
|
-
};
|
|
2680
|
-
}
|
|
2681
|
-
const followingLineBreak = getLineBreakAt(source, endOffset);
|
|
2682
|
-
const leadingLineBreak = !isLineStart(source, startOffset) && !startsWithLineBreak(template.prefix) ? eol : "";
|
|
2683
|
-
const needsTrailingLineBreak = selectedText.length > 0 ? !selectedText.startsWith("\n") && !selectedText.startsWith("\r") : !isLineEnd(source, endOffset) || followingLineBreak === "";
|
|
2684
|
-
const trailingLineBreak = needsTrailingLineBreak && !endsWithLineBreak(template.prefix) ? eol : "";
|
|
2685
|
-
const insertionPrefix = `${leadingLineBreak}${template.prefix}`;
|
|
2686
|
-
return {
|
|
2687
|
-
replacement: `${insertionPrefix}${trailingLineBreak}${selectedText}`,
|
|
2688
|
-
selectionOffset: insertionPrefix.length + trailingLineBreak.length + (selectedText.length === 0 && trailingLineBreak === "" ? followingLineBreak.length : 0)
|
|
2689
|
-
};
|
|
2690
|
-
}
|
|
2691
|
-
|
|
2692
|
-
// packages/ssml-editor-react/src/ssmlContext.ts
|
|
2693
|
-
function findTagEnd2(source, start, limit) {
|
|
2694
|
-
let quote;
|
|
2695
|
-
for (let index = start + 1; index < limit; index += 1) {
|
|
2696
|
-
const character = source[index];
|
|
2697
|
-
if (quote !== void 0) {
|
|
2698
|
-
if (character === quote) {
|
|
2699
|
-
quote = void 0;
|
|
2700
|
-
}
|
|
2701
|
-
continue;
|
|
2702
|
-
}
|
|
2703
|
-
if (character === '"' || character === "'") {
|
|
2704
|
-
quote = character;
|
|
2705
|
-
continue;
|
|
2706
|
-
}
|
|
2707
|
-
if (character === ">") {
|
|
2708
|
-
return index;
|
|
2709
|
-
}
|
|
2710
|
-
}
|
|
2711
|
-
return -1;
|
|
2712
|
-
}
|
|
2713
|
-
function getVoiceName(tag) {
|
|
2714
|
-
return tag.match(/\bname\s*=\s*(["'])([\s\S]*?)\1/i)?.[2];
|
|
2715
|
-
}
|
|
2716
|
-
function closeElement(stack, name) {
|
|
2717
|
-
for (let index = stack.length - 1; index >= 0; index -= 1) {
|
|
2718
|
-
if (stack[index]?.name === name) {
|
|
2719
|
-
stack.splice(index);
|
|
2720
|
-
return;
|
|
2721
|
-
}
|
|
2722
|
-
}
|
|
2723
|
-
}
|
|
2724
|
-
function findSsmlVoiceContext(source, offset) {
|
|
2725
|
-
const limit = Math.max(0, Math.min(offset, source.length));
|
|
2726
|
-
const stack = [];
|
|
2727
|
-
let index = 0;
|
|
2728
|
-
while (index < limit) {
|
|
2729
|
-
const tagStart = source.indexOf("<", index);
|
|
2730
|
-
if (tagStart === -1 || tagStart >= limit) {
|
|
2731
|
-
break;
|
|
2732
|
-
}
|
|
2733
|
-
if (source.startsWith("<!--", tagStart)) {
|
|
2734
|
-
const end = source.indexOf("-->", tagStart + 4);
|
|
2735
|
-
index = end === -1 || end + 3 > limit ? limit : end + 3;
|
|
2736
|
-
continue;
|
|
2737
|
-
}
|
|
2738
|
-
if (source.startsWith("<![CDATA[", tagStart)) {
|
|
2739
|
-
const end = source.indexOf("]]>", tagStart + 9);
|
|
2740
|
-
index = end === -1 || end + 3 > limit ? limit : end + 3;
|
|
2741
|
-
continue;
|
|
2742
|
-
}
|
|
2743
|
-
if (source.startsWith("<?", tagStart)) {
|
|
2744
|
-
const end = source.indexOf("?>", tagStart + 2);
|
|
2745
|
-
index = end === -1 || end + 2 > limit ? limit : end + 2;
|
|
2746
|
-
continue;
|
|
2747
|
-
}
|
|
2748
|
-
const tagEnd = findTagEnd2(source, tagStart, limit);
|
|
2749
|
-
if (tagEnd === -1) {
|
|
2750
|
-
break;
|
|
2751
|
-
}
|
|
2752
|
-
const tag = source.slice(tagStart, tagEnd + 1);
|
|
2753
|
-
if (tag.startsWith("<!")) {
|
|
2754
|
-
index = tagEnd + 1;
|
|
2755
|
-
continue;
|
|
2756
|
-
}
|
|
2757
|
-
const closingMatch = tag.match(/^<\s*\/\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
2758
|
-
if (closingMatch?.[1]) {
|
|
2759
|
-
closeElement(stack, closingMatch[1].toLowerCase());
|
|
2760
|
-
index = tagEnd + 1;
|
|
2761
|
-
continue;
|
|
2762
|
-
}
|
|
2763
|
-
const openingMatch = tag.match(/^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
2764
|
-
if (openingMatch?.[1] && !/\/\s*>$/.test(tag)) {
|
|
2765
|
-
const name = openingMatch[1].toLowerCase();
|
|
2766
|
-
stack.push({
|
|
2767
|
-
name,
|
|
2768
|
-
...name === "voice" ? { voiceName: getVoiceName(tag) } : {}
|
|
2769
|
-
});
|
|
2770
|
-
}
|
|
2771
|
-
index = tagEnd + 1;
|
|
2772
|
-
}
|
|
2773
|
-
for (let stackIndex = stack.length - 1; stackIndex >= 0; stackIndex -= 1) {
|
|
2774
|
-
const element = stack[stackIndex];
|
|
2775
|
-
if (element?.name === "voice") {
|
|
2776
|
-
return element.voiceName === void 0 ? {} : { voiceName: element.voiceName };
|
|
2777
|
-
}
|
|
2778
|
-
}
|
|
2779
|
-
return void 0;
|
|
2780
|
-
}
|
|
2781
|
-
|
|
2782
|
-
// packages/ssml-editor-react/src/hooks/useSsmlEditorState.ts
|
|
2783
|
-
var TIMING_INSERTION_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence"]);
|
|
2784
|
-
var PROSODY_INSERTION_TAGS = /* @__PURE__ */ new Set(["prosody", "mstts:express-as", "voice", "emphasis"]);
|
|
2785
|
-
var TEXT_INSERTION_TAGS = /* @__PURE__ */ new Set(["sub", "say-as", "phoneme", "w", "lang"]);
|
|
2786
|
-
var EMPTY_SELECTION_OVERLAY = {
|
|
2787
|
-
selectedText: "",
|
|
2788
|
-
characterCount: 0,
|
|
2789
|
-
hasSelection: false,
|
|
2790
|
-
position: null,
|
|
2791
|
-
placement: "above"
|
|
2792
|
-
};
|
|
2892
|
+
// packages/ssml-editor-react/src/editableSsml.ts
|
|
2793
2893
|
function isSsmlElement(node) {
|
|
2794
2894
|
return typeof node !== "string" && node.type !== "text";
|
|
2795
2895
|
}
|
|
@@ -2884,48 +2984,6 @@ function preserveEmptyPairElements(nodes, startTags, startTagIndex) {
|
|
|
2884
2984
|
function getDocumentChildren2(document2) {
|
|
2885
2985
|
return document2.children ?? (document2.content === void 0 ? [] : [document2.content]);
|
|
2886
2986
|
}
|
|
2887
|
-
function getPartialContext(document2) {
|
|
2888
|
-
const children = getDocumentChildren2(document2);
|
|
2889
|
-
const voice = findFirstElement(children, isVoice);
|
|
2890
|
-
const prosody = findFirstElement(children, isProsody);
|
|
2891
|
-
const context = {
|
|
2892
|
-
version: document2.version,
|
|
2893
|
-
lang: document2.lang
|
|
2894
|
-
};
|
|
2895
|
-
if (voice) {
|
|
2896
|
-
context.voice = {
|
|
2897
|
-
name: voice.name,
|
|
2898
|
-
effect: voice.effect,
|
|
2899
|
-
attributes: voice.attributes
|
|
2900
|
-
};
|
|
2901
|
-
}
|
|
2902
|
-
if (prosody) {
|
|
2903
|
-
context.prosody = {
|
|
2904
|
-
rate: prosody.rate,
|
|
2905
|
-
pitch: prosody.pitch,
|
|
2906
|
-
volume: prosody.volume,
|
|
2907
|
-
contour: prosody.contour,
|
|
2908
|
-
range: prosody.range,
|
|
2909
|
-
attributes: prosody.attributes
|
|
2910
|
-
};
|
|
2911
|
-
}
|
|
2912
|
-
return context;
|
|
2913
|
-
}
|
|
2914
|
-
function findFirstElement(nodes, predicate) {
|
|
2915
|
-
for (const node of nodes) {
|
|
2916
|
-
if (!isSsmlElement(node)) {
|
|
2917
|
-
continue;
|
|
2918
|
-
}
|
|
2919
|
-
if (predicate(node)) {
|
|
2920
|
-
return node;
|
|
2921
|
-
}
|
|
2922
|
-
const child = findFirstElement(node.children ?? [], predicate);
|
|
2923
|
-
if (child) {
|
|
2924
|
-
return child;
|
|
2925
|
-
}
|
|
2926
|
-
}
|
|
2927
|
-
return void 0;
|
|
2928
|
-
}
|
|
2929
2987
|
function findFirstElementPath(nodes, predicate, ancestors = []) {
|
|
2930
2988
|
for (const node of nodes) {
|
|
2931
2989
|
if (!isSsmlElement(node)) {
|
|
@@ -3006,13 +3064,10 @@ function getEditableRegion(document2) {
|
|
|
3006
3064
|
...voice ? { voiceName: voice.name } : {}
|
|
3007
3065
|
};
|
|
3008
3066
|
}
|
|
3009
|
-
function getEditableChildren(document2) {
|
|
3010
|
-
return getEditableRegion(document2).children;
|
|
3011
|
-
}
|
|
3012
3067
|
function getEditableText(document2) {
|
|
3013
|
-
return serializeEditableText(
|
|
3068
|
+
return serializeEditableText(getEditableRegion(document2).children, document2.lang);
|
|
3014
3069
|
}
|
|
3015
|
-
function
|
|
3070
|
+
function updateEditableText(document2, value) {
|
|
3016
3071
|
const nextChildren = parseEditableText(value, document2.lang);
|
|
3017
3072
|
const editableChildren = nextChildren.length > 0 ? nextChildren : [value];
|
|
3018
3073
|
const children = getDocumentChildren2(document2);
|
|
@@ -3032,6 +3087,261 @@ function updateText(document2, value) {
|
|
|
3032
3087
|
}
|
|
3033
3088
|
return withChildren(document2, editableChildren);
|
|
3034
3089
|
}
|
|
3090
|
+
|
|
3091
|
+
// packages/ssml-editor-react/src/ssmlInsertion.ts
|
|
3092
|
+
function isLineStart(value, offset) {
|
|
3093
|
+
return offset === 0 || value[offset - 1] === "\n" || value[offset - 1] === "\r";
|
|
3094
|
+
}
|
|
3095
|
+
function isLineEnd(value, offset) {
|
|
3096
|
+
return offset === value.length || value[offset] === "\n" || value[offset] === "\r";
|
|
3097
|
+
}
|
|
3098
|
+
function getLineBreakAt(value, offset) {
|
|
3099
|
+
if (value.startsWith("\r\n", offset)) {
|
|
3100
|
+
return "\r\n";
|
|
3101
|
+
}
|
|
3102
|
+
if (value[offset] === "\n" || value[offset] === "\r") {
|
|
3103
|
+
return value[offset];
|
|
3104
|
+
}
|
|
3105
|
+
return "";
|
|
3106
|
+
}
|
|
3107
|
+
function startsWithLineBreak(value) {
|
|
3108
|
+
return value.startsWith("\n") || value.startsWith("\r");
|
|
3109
|
+
}
|
|
3110
|
+
function endsWithLineBreak(value) {
|
|
3111
|
+
return value.endsWith("\n") || value.endsWith("\r");
|
|
3112
|
+
}
|
|
3113
|
+
function createSsmlInsertionEdit(source, startOffset, endOffset, template, eol = "\n", selectedText = startOffset === endOffset ? "" : source.slice(startOffset, endOffset)) {
|
|
3114
|
+
if (template.mode === SSML_INSERTION_MODES.wrap) {
|
|
3115
|
+
const trailingLineBreak2 = getLineBreakAt(source, endOffset) === "" ? eol : "";
|
|
3116
|
+
return {
|
|
3117
|
+
replacement: `${template.prefix}${selectedText}${template.suffix}${trailingLineBreak2}`,
|
|
3118
|
+
selectionOffset: template.prefix.length
|
|
3119
|
+
};
|
|
3120
|
+
}
|
|
3121
|
+
const followingLineBreak = getLineBreakAt(source, endOffset);
|
|
3122
|
+
const leadingLineBreak = !isLineStart(source, startOffset) && !startsWithLineBreak(template.prefix) ? eol : "";
|
|
3123
|
+
const needsTrailingLineBreak = selectedText.length > 0 ? !selectedText.startsWith("\n") && !selectedText.startsWith("\r") : !isLineEnd(source, endOffset) || followingLineBreak === "";
|
|
3124
|
+
const trailingLineBreak = needsTrailingLineBreak && !endsWithLineBreak(template.prefix) ? eol : "";
|
|
3125
|
+
const insertionPrefix = `${leadingLineBreak}${template.prefix}`;
|
|
3126
|
+
return {
|
|
3127
|
+
replacement: `${insertionPrefix}${trailingLineBreak}${selectedText}`,
|
|
3128
|
+
selectionOffset: insertionPrefix.length + trailingLineBreak.length + (selectedText.length === 0 && trailingLineBreak === "" ? followingLineBreak.length : 0)
|
|
3129
|
+
};
|
|
3130
|
+
}
|
|
3131
|
+
|
|
3132
|
+
// packages/ssml-editor-react/src/ssmlContext.ts
|
|
3133
|
+
function findTagEnd2(source, start, limit) {
|
|
3134
|
+
let quote;
|
|
3135
|
+
for (let index = start + 1; index < limit; index += 1) {
|
|
3136
|
+
const character = source[index];
|
|
3137
|
+
if (quote !== void 0) {
|
|
3138
|
+
if (character === quote) {
|
|
3139
|
+
quote = void 0;
|
|
3140
|
+
}
|
|
3141
|
+
continue;
|
|
3142
|
+
}
|
|
3143
|
+
if (character === '"' || character === "'") {
|
|
3144
|
+
quote = character;
|
|
3145
|
+
continue;
|
|
3146
|
+
}
|
|
3147
|
+
if (character === ">") {
|
|
3148
|
+
return index;
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
return -1;
|
|
3152
|
+
}
|
|
3153
|
+
function getVoiceName(tag) {
|
|
3154
|
+
return tag.match(/\bname\s*=\s*(["'])([\s\S]*?)\1/i)?.[2];
|
|
3155
|
+
}
|
|
3156
|
+
function escapeXmlAttribute(value) {
|
|
3157
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
3158
|
+
}
|
|
3159
|
+
function updateTagAttribute(text, tagRange, attributeName, newValue) {
|
|
3160
|
+
const start = Math.max(0, Math.min(tagRange.start, text.length));
|
|
3161
|
+
const end = Math.max(start, Math.min(tagRange.end, text.length));
|
|
3162
|
+
const tag = text.slice(start, end);
|
|
3163
|
+
const escapedAttributeName = attributeName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3164
|
+
const attributePattern = new RegExp(`(\\b${escapedAttributeName}\\s*=\\s*)(["'])([\\s\\S]*?)\\2`, "i");
|
|
3165
|
+
const escapedValue = escapeXmlAttribute(newValue);
|
|
3166
|
+
const match = tag.match(attributePattern);
|
|
3167
|
+
if (match?.index !== void 0) {
|
|
3168
|
+
const valueStart = match.index + match[0].indexOf(match[2]) + 1;
|
|
3169
|
+
const valueEnd = valueStart + (match[3]?.length ?? 0);
|
|
3170
|
+
return `${text.slice(0, start)}${tag.slice(0, valueStart)}${escapedValue}${tag.slice(valueEnd)}${text.slice(end)}`;
|
|
3171
|
+
}
|
|
3172
|
+
const insertionIndex = tag.endsWith("/>") ? tag.length - 2 : tag.length - 1;
|
|
3173
|
+
const attribute = ` ${attributeName}="${escapedValue}"`;
|
|
3174
|
+
return `${text.slice(0, start)}${tag.slice(0, insertionIndex)}${attribute}${tag.slice(insertionIndex)}${text.slice(end)}`;
|
|
3175
|
+
}
|
|
3176
|
+
function closeElement(stack, name) {
|
|
3177
|
+
for (let index = stack.length - 1; index >= 0; index -= 1) {
|
|
3178
|
+
if (stack[index]?.name === name) {
|
|
3179
|
+
stack.splice(index);
|
|
3180
|
+
return;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
function findActiveSsmlTags(source, offset) {
|
|
3185
|
+
const limit = Math.max(0, Math.min(offset, source.length));
|
|
3186
|
+
const stack = [];
|
|
3187
|
+
let index = 0;
|
|
3188
|
+
while (index < source.length) {
|
|
3189
|
+
const tagStart = source.indexOf("<", index);
|
|
3190
|
+
if (tagStart === -1 || tagStart > limit) {
|
|
3191
|
+
break;
|
|
3192
|
+
}
|
|
3193
|
+
const nonContentEnd = source.startsWith("<!--", tagStart) ? source.indexOf("-->", tagStart + 4) : source.startsWith("<![CDATA[", tagStart) ? source.indexOf("]]>", tagStart + 9) : source.startsWith("<?", tagStart) ? source.indexOf("?>", tagStart + 2) : void 0;
|
|
3194
|
+
if (nonContentEnd !== void 0) {
|
|
3195
|
+
const delimiterLength = source.startsWith("<?", tagStart) ? 2 : 3;
|
|
3196
|
+
const end = nonContentEnd === -1 ? source.length : nonContentEnd + delimiterLength;
|
|
3197
|
+
if (limit < end) {
|
|
3198
|
+
break;
|
|
3199
|
+
}
|
|
3200
|
+
index = end;
|
|
3201
|
+
continue;
|
|
3202
|
+
}
|
|
3203
|
+
const tagEnd = findTagEnd2(source, tagStart, source.length);
|
|
3204
|
+
const tag = source.slice(tagStart, tagEnd === -1 ? source.length : tagEnd + 1);
|
|
3205
|
+
const closingMatch = tag.match(/^<\s*\/\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
3206
|
+
const openingMatch = tag.match(/^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
3207
|
+
if (tagEnd === -1 || limit <= tagEnd) {
|
|
3208
|
+
if (openingMatch?.[1]) {
|
|
3209
|
+
stack.push({ name: openingMatch[1].toLowerCase() });
|
|
3210
|
+
}
|
|
3211
|
+
break;
|
|
3212
|
+
}
|
|
3213
|
+
if (closingMatch?.[1]) {
|
|
3214
|
+
closeElement(stack, closingMatch[1].toLowerCase());
|
|
3215
|
+
} else if (openingMatch?.[1] && !/\/\s*>$/.test(tag)) {
|
|
3216
|
+
stack.push({ name: openingMatch[1].toLowerCase() });
|
|
3217
|
+
}
|
|
3218
|
+
index = tagEnd + 1;
|
|
3219
|
+
}
|
|
3220
|
+
return new Set(stack.map(({ name }) => name));
|
|
3221
|
+
}
|
|
3222
|
+
function findSsmlVoiceContext(source, offset) {
|
|
3223
|
+
const limit = Math.max(0, Math.min(offset, source.length));
|
|
3224
|
+
const stack = [];
|
|
3225
|
+
let index = 0;
|
|
3226
|
+
while (index < limit) {
|
|
3227
|
+
const tagStart = source.indexOf("<", index);
|
|
3228
|
+
if (tagStart === -1 || tagStart >= limit) {
|
|
3229
|
+
break;
|
|
3230
|
+
}
|
|
3231
|
+
if (source.startsWith("<!--", tagStart)) {
|
|
3232
|
+
const end = source.indexOf("-->", tagStart + 4);
|
|
3233
|
+
index = end === -1 || end + 3 > limit ? limit : end + 3;
|
|
3234
|
+
continue;
|
|
3235
|
+
}
|
|
3236
|
+
if (source.startsWith("<![CDATA[", tagStart)) {
|
|
3237
|
+
const end = source.indexOf("]]>", tagStart + 9);
|
|
3238
|
+
index = end === -1 || end + 3 > limit ? limit : end + 3;
|
|
3239
|
+
continue;
|
|
3240
|
+
}
|
|
3241
|
+
if (source.startsWith("<?", tagStart)) {
|
|
3242
|
+
const end = source.indexOf("?>", tagStart + 2);
|
|
3243
|
+
index = end === -1 || end + 2 > limit ? limit : end + 2;
|
|
3244
|
+
continue;
|
|
3245
|
+
}
|
|
3246
|
+
const tagEnd = findTagEnd2(source, tagStart, limit);
|
|
3247
|
+
if (tagEnd === -1) {
|
|
3248
|
+
break;
|
|
3249
|
+
}
|
|
3250
|
+
const tag = source.slice(tagStart, tagEnd + 1);
|
|
3251
|
+
if (tag.startsWith("<!")) {
|
|
3252
|
+
index = tagEnd + 1;
|
|
3253
|
+
continue;
|
|
3254
|
+
}
|
|
3255
|
+
const closingMatch = tag.match(/^<\s*\/\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
3256
|
+
if (closingMatch?.[1]) {
|
|
3257
|
+
closeElement(stack, closingMatch[1].toLowerCase());
|
|
3258
|
+
index = tagEnd + 1;
|
|
3259
|
+
continue;
|
|
3260
|
+
}
|
|
3261
|
+
const openingMatch = tag.match(/^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
3262
|
+
if (openingMatch?.[1] && !/\/\s*>$/.test(tag)) {
|
|
3263
|
+
const name = openingMatch[1].toLowerCase();
|
|
3264
|
+
stack.push({
|
|
3265
|
+
name,
|
|
3266
|
+
...name === "voice" ? { voiceName: getVoiceName(tag) } : {}
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
index = tagEnd + 1;
|
|
3270
|
+
}
|
|
3271
|
+
for (let stackIndex = stack.length - 1; stackIndex >= 0; stackIndex -= 1) {
|
|
3272
|
+
const element = stack[stackIndex];
|
|
3273
|
+
if (element?.name === "voice") {
|
|
3274
|
+
return element.voiceName === void 0 ? {} : { voiceName: element.voiceName };
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
return void 0;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
// packages/ssml-editor-react/src/hooks/useSsmlEditorState.ts
|
|
3281
|
+
var TIMING_INSERTION_TAGS = /* @__PURE__ */ new Set(["break", "mstts:silence"]);
|
|
3282
|
+
var PROSODY_INSERTION_TAGS = /* @__PURE__ */ new Set(["prosody", "mstts:express-as", "voice", "emphasis"]);
|
|
3283
|
+
var TEXT_INSERTION_TAGS = /* @__PURE__ */ new Set(["sub", "say-as", "phoneme", "w", "lang"]);
|
|
3284
|
+
var EMPTY_SELECTION_OVERLAY = {
|
|
3285
|
+
selectedText: "",
|
|
3286
|
+
characterCount: 0,
|
|
3287
|
+
hasSelection: false,
|
|
3288
|
+
position: null,
|
|
3289
|
+
placement: "above"
|
|
3290
|
+
};
|
|
3291
|
+
function isSsmlElement2(node) {
|
|
3292
|
+
return typeof node !== "string" && node.type !== "text";
|
|
3293
|
+
}
|
|
3294
|
+
function isVoice2(element) {
|
|
3295
|
+
return element.type === "voice";
|
|
3296
|
+
}
|
|
3297
|
+
function isProsody2(element) {
|
|
3298
|
+
return element.type === "prosody";
|
|
3299
|
+
}
|
|
3300
|
+
function getDocumentChildren3(document2) {
|
|
3301
|
+
return document2.children ?? (document2.content === void 0 ? [] : [document2.content]);
|
|
3302
|
+
}
|
|
3303
|
+
function getPartialContext(document2) {
|
|
3304
|
+
const children = getDocumentChildren3(document2);
|
|
3305
|
+
const voice = findFirstElement(children, isVoice2);
|
|
3306
|
+
const prosody = findFirstElement(children, isProsody2);
|
|
3307
|
+
const context = {
|
|
3308
|
+
version: document2.version,
|
|
3309
|
+
lang: document2.lang
|
|
3310
|
+
};
|
|
3311
|
+
if (voice) {
|
|
3312
|
+
context.voice = {
|
|
3313
|
+
name: voice.name,
|
|
3314
|
+
effect: voice.effect,
|
|
3315
|
+
attributes: voice.attributes
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
if (prosody) {
|
|
3319
|
+
context.prosody = {
|
|
3320
|
+
rate: prosody.rate,
|
|
3321
|
+
pitch: prosody.pitch,
|
|
3322
|
+
volume: prosody.volume,
|
|
3323
|
+
contour: prosody.contour,
|
|
3324
|
+
range: prosody.range,
|
|
3325
|
+
attributes: prosody.attributes
|
|
3326
|
+
};
|
|
3327
|
+
}
|
|
3328
|
+
return context;
|
|
3329
|
+
}
|
|
3330
|
+
function findFirstElement(nodes, predicate) {
|
|
3331
|
+
for (const node of nodes) {
|
|
3332
|
+
if (!isSsmlElement2(node)) {
|
|
3333
|
+
continue;
|
|
3334
|
+
}
|
|
3335
|
+
if (predicate(node)) {
|
|
3336
|
+
return node;
|
|
3337
|
+
}
|
|
3338
|
+
const child = findFirstElement(node.children ?? [], predicate);
|
|
3339
|
+
if (child) {
|
|
3340
|
+
return child;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
return void 0;
|
|
3344
|
+
}
|
|
3035
3345
|
function getSelectionInfo(editor) {
|
|
3036
3346
|
const model = editor.getModel();
|
|
3037
3347
|
const selection = editor.getSelection();
|
|
@@ -3167,9 +3477,11 @@ function useSsmlEditorState({
|
|
|
3167
3477
|
const [decorationsVisible, setDecorationsVisible] = (0, import_react.useState)(showDecorations);
|
|
3168
3478
|
const [isHelpOpen, setIsHelpOpen] = (0, import_react.useState)(false);
|
|
3169
3479
|
const [syntaxError, setSyntaxError] = (0, import_react.useState)(null);
|
|
3480
|
+
const [activeTags, setActiveTags] = (0, import_react.useState)(() => /* @__PURE__ */ new Set());
|
|
3170
3481
|
const [openPopoverId, setOpenPopoverId] = (0, import_react.useState)(null);
|
|
3171
3482
|
const [popoverVoiceName, setPopoverVoiceName] = (0, import_react.useState)(void 0);
|
|
3172
3483
|
const [popoverPosition, setPopoverPosition] = (0, import_react.useState)(null);
|
|
3484
|
+
const pendingCodeLensAttributeRef = (0, import_react.useRef)(null);
|
|
3173
3485
|
const helpPanelId = (0, import_react.useId)();
|
|
3174
3486
|
const draftDocumentRef = (0, import_react.useRef)(document2);
|
|
3175
3487
|
const onSelectionChangeRef = (0, import_react.useRef)(onSelectionChange);
|
|
@@ -3195,6 +3507,7 @@ function useSsmlEditorState({
|
|
|
3195
3507
|
setDecorationsVisible(showDecorations);
|
|
3196
3508
|
}, [showDecorations]);
|
|
3197
3509
|
const closePopover = (0, import_react.useCallback)((restoreFocus = false) => {
|
|
3510
|
+
pendingCodeLensAttributeRef.current = null;
|
|
3198
3511
|
setOpenPopoverId(null);
|
|
3199
3512
|
setPopoverVoiceName(void 0);
|
|
3200
3513
|
setPopoverPosition(null);
|
|
@@ -3203,6 +3516,7 @@ function useSsmlEditorState({
|
|
|
3203
3516
|
}
|
|
3204
3517
|
}, []);
|
|
3205
3518
|
const togglePopover = (0, import_react.useCallback)((id, trigger) => {
|
|
3519
|
+
pendingCodeLensAttributeRef.current = null;
|
|
3206
3520
|
setOpenPopoverId((currentId) => {
|
|
3207
3521
|
if (currentId === id) {
|
|
3208
3522
|
setPopoverVoiceName(void 0);
|
|
@@ -3226,13 +3540,41 @@ function useSsmlEditorState({
|
|
|
3226
3540
|
}
|
|
3227
3541
|
const updatePopoverPosition = () => {
|
|
3228
3542
|
const trigger = activePopoverTriggerRef.current;
|
|
3229
|
-
if (
|
|
3543
|
+
if (trigger) {
|
|
3544
|
+
const triggerBounds = trigger.getBoundingClientRect();
|
|
3545
|
+
setPopoverPosition({
|
|
3546
|
+
top: triggerBounds.bottom + 4,
|
|
3547
|
+
left: triggerBounds.left
|
|
3548
|
+
});
|
|
3549
|
+
return;
|
|
3550
|
+
}
|
|
3551
|
+
const pending = pendingCodeLensAttributeRef.current;
|
|
3552
|
+
const editor = editorRef.current;
|
|
3553
|
+
const model = editor?.getModel();
|
|
3554
|
+
if (!pending || !editor || !model) {
|
|
3555
|
+
return;
|
|
3556
|
+
}
|
|
3557
|
+
const position = model.getPositionAt(pending.tagRange.start);
|
|
3558
|
+
const visiblePosition = editor.getScrolledVisiblePosition(position);
|
|
3559
|
+
const editorElement = editor.getDomNode();
|
|
3560
|
+
if (!visiblePosition || !editorElement) {
|
|
3230
3561
|
return;
|
|
3231
3562
|
}
|
|
3232
|
-
const
|
|
3563
|
+
const editorBounds = editorElement.getBoundingClientRect();
|
|
3564
|
+
const menu = activePopoverMenuRef.current;
|
|
3565
|
+
const margin = 8;
|
|
3233
3566
|
setPopoverPosition({
|
|
3234
|
-
top:
|
|
3235
|
-
|
|
3567
|
+
top: Math.max(
|
|
3568
|
+
margin,
|
|
3569
|
+
Math.min(
|
|
3570
|
+
editorBounds.top + visiblePosition.top + visiblePosition.height + 4,
|
|
3571
|
+
window.innerHeight - (menu?.offsetHeight ?? 0) - margin
|
|
3572
|
+
)
|
|
3573
|
+
),
|
|
3574
|
+
left: Math.max(
|
|
3575
|
+
margin,
|
|
3576
|
+
Math.min(editorBounds.left + visiblePosition.left, window.innerWidth - (menu?.offsetWidth ?? 0) - margin)
|
|
3577
|
+
)
|
|
3236
3578
|
});
|
|
3237
3579
|
};
|
|
3238
3580
|
const handlePointerDown = (event) => {
|
|
@@ -3269,6 +3611,14 @@ function useSsmlEditorState({
|
|
|
3269
3611
|
});
|
|
3270
3612
|
}
|
|
3271
3613
|
}, []);
|
|
3614
|
+
const updateActiveTags = (0, import_react.useCallback)((nextTags) => {
|
|
3615
|
+
setActiveTags((currentTags) => {
|
|
3616
|
+
if (currentTags.size === nextTags.size && [...currentTags].every((tag) => nextTags.has(tag))) {
|
|
3617
|
+
return currentTags;
|
|
3618
|
+
}
|
|
3619
|
+
return new Set(nextTags);
|
|
3620
|
+
});
|
|
3621
|
+
}, []);
|
|
3272
3622
|
const commit = (0, import_react.useCallback)(
|
|
3273
3623
|
(nextDocument) => {
|
|
3274
3624
|
draftDocumentRef.current = nextDocument;
|
|
@@ -3280,7 +3630,7 @@ function useSsmlEditorState({
|
|
|
3280
3630
|
);
|
|
3281
3631
|
const handleTextChange = (0, import_react.useCallback)(
|
|
3282
3632
|
(value) => {
|
|
3283
|
-
commit(
|
|
3633
|
+
commit(updateEditableText(draftDocumentRef.current, value));
|
|
3284
3634
|
if (editorRef.current) {
|
|
3285
3635
|
refreshSelectionOverlay(editorRef.current, false);
|
|
3286
3636
|
}
|
|
@@ -3289,11 +3639,48 @@ function useSsmlEditorState({
|
|
|
3289
3639
|
);
|
|
3290
3640
|
const handleInsert = (0, import_react.useCallback)(
|
|
3291
3641
|
(insertion, option) => {
|
|
3292
|
-
|
|
3293
|
-
|
|
3642
|
+
const editor = editorRef.current;
|
|
3643
|
+
const pending = pendingCodeLensAttributeRef.current;
|
|
3644
|
+
if (!editor) {
|
|
3645
|
+
return;
|
|
3294
3646
|
}
|
|
3647
|
+
if (pending?.insertionId === insertion.id) {
|
|
3648
|
+
const model = editor.getModel();
|
|
3649
|
+
if (model && model.getVersionId() === pending.modelVersionId) {
|
|
3650
|
+
const source = model.getValue();
|
|
3651
|
+
const tagText = source.slice(pending.tagRange.start, pending.tagRange.end);
|
|
3652
|
+
const updatedTag = updateTagAttribute(
|
|
3653
|
+
tagText,
|
|
3654
|
+
{ start: 0, end: tagText.length },
|
|
3655
|
+
pending.attributeName,
|
|
3656
|
+
option.value
|
|
3657
|
+
);
|
|
3658
|
+
const start = model.getPositionAt(pending.tagRange.start);
|
|
3659
|
+
const end = model.getPositionAt(pending.tagRange.end);
|
|
3660
|
+
editor.pushUndoStop();
|
|
3661
|
+
editor.executeEdits("ssml-code-lens", [
|
|
3662
|
+
{
|
|
3663
|
+
range: {
|
|
3664
|
+
startLineNumber: start.lineNumber,
|
|
3665
|
+
startColumn: start.column,
|
|
3666
|
+
endLineNumber: end.lineNumber,
|
|
3667
|
+
endColumn: end.column
|
|
3668
|
+
},
|
|
3669
|
+
text: updatedTag
|
|
3670
|
+
}
|
|
3671
|
+
]);
|
|
3672
|
+
editor.pushUndoStop();
|
|
3673
|
+
editor.focus();
|
|
3674
|
+
}
|
|
3675
|
+
pendingCodeLensAttributeRef.current = null;
|
|
3676
|
+
if (!model || model.getVersionId() !== pending.modelVersionId) {
|
|
3677
|
+
closePopover();
|
|
3678
|
+
}
|
|
3679
|
+
return;
|
|
3680
|
+
}
|
|
3681
|
+
applySsmlInsertion(editor, insertion, option);
|
|
3295
3682
|
},
|
|
3296
|
-
[]
|
|
3683
|
+
[closePopover]
|
|
3297
3684
|
);
|
|
3298
3685
|
const handleInsertBreak = (0, import_react.useCallback)(
|
|
3299
3686
|
(insertion, option) => {
|
|
@@ -3324,7 +3711,7 @@ function useSsmlEditorState({
|
|
|
3324
3711
|
}, [commit]);
|
|
3325
3712
|
const handleFormat = (0, import_react.useCallback)(() => {
|
|
3326
3713
|
const value = editorRef.current?.getValue() ?? getEditableText(draftDocumentRef.current);
|
|
3327
|
-
commit(
|
|
3714
|
+
commit(updateEditableText(draftDocumentRef.current, formatXmlFragment(value)));
|
|
3328
3715
|
}, [commit]);
|
|
3329
3716
|
const handleUndo = (0, import_react.useCallback)(() => {
|
|
3330
3717
|
editorRef.current?.trigger("toolbar", "undo", null);
|
|
@@ -3354,16 +3741,65 @@ function useSsmlEditorState({
|
|
|
3354
3741
|
);
|
|
3355
3742
|
const getFullSsml = (0, import_react.useCallback)(
|
|
3356
3743
|
() => buildSsml(
|
|
3357
|
-
editorRef.current ?
|
|
3744
|
+
editorRef.current ? updateEditableText(draftDocumentRef.current, editorRef.current.getValue()) : draftDocumentRef.current
|
|
3358
3745
|
),
|
|
3359
3746
|
[]
|
|
3360
3747
|
);
|
|
3361
3748
|
const getOuterVoiceName = (0, import_react.useCallback)(() => getEditableRegion(draftDocumentRef.current).voiceName, []);
|
|
3749
|
+
const handleCodeLensAction = (0, import_react.useCallback)((action) => {
|
|
3750
|
+
const editor = editorRef.current;
|
|
3751
|
+
const model = editor?.getModel();
|
|
3752
|
+
if (!editor || !model) {
|
|
3753
|
+
return;
|
|
3754
|
+
}
|
|
3755
|
+
if (action.type === "attribute") {
|
|
3756
|
+
pendingCodeLensAttributeRef.current = {
|
|
3757
|
+
insertionId: action.insertionId,
|
|
3758
|
+
attributeName: action.attributeName,
|
|
3759
|
+
tagRange: action.tagRange,
|
|
3760
|
+
modelVersionId: model.getVersionId()
|
|
3761
|
+
};
|
|
3762
|
+
activePopoverTriggerRef.current = null;
|
|
3763
|
+
setPopoverVoiceName(getEffectiveVoiceName(editor, draftDocumentRef.current));
|
|
3764
|
+
setOpenPopoverId(action.insertionId);
|
|
3765
|
+
setPopoverPosition(null);
|
|
3766
|
+
return;
|
|
3767
|
+
}
|
|
3768
|
+
const source = model.getValue();
|
|
3769
|
+
const toEditorRange = (range) => {
|
|
3770
|
+
const start = model.getPositionAt(range.start);
|
|
3771
|
+
const end = model.getPositionAt(range.end);
|
|
3772
|
+
return {
|
|
3773
|
+
startLineNumber: start.lineNumber,
|
|
3774
|
+
startColumn: start.column,
|
|
3775
|
+
endLineNumber: end.lineNumber,
|
|
3776
|
+
endColumn: end.column
|
|
3777
|
+
};
|
|
3778
|
+
};
|
|
3779
|
+
const edits = action.type === "delete" ? [{ range: toEditorRange(action.tagRange), text: "" }] : (() => {
|
|
3780
|
+
const elementText = source.slice(action.elementRange.start, action.elementRange.end);
|
|
3781
|
+
const closingOffset = elementText.search(/<\/\s*prosody\s*>/i);
|
|
3782
|
+
const closingStart = closingOffset === -1 ? action.elementRange.end : action.elementRange.start + closingOffset;
|
|
3783
|
+
const closingEnd = closingOffset === -1 ? action.elementRange.end : source.indexOf(">", closingStart) === -1 ? action.elementRange.end : source.indexOf(">", closingStart) + 1;
|
|
3784
|
+
return [
|
|
3785
|
+
{ range: toEditorRange(action.tagRange), text: "" },
|
|
3786
|
+
{ range: toEditorRange({ start: closingStart, end: closingEnd }), text: "" }
|
|
3787
|
+
];
|
|
3788
|
+
})();
|
|
3789
|
+
editor.pushUndoStop();
|
|
3790
|
+
editor.executeEdits("ssml-code-lens", edits);
|
|
3791
|
+
editor.pushUndoStop();
|
|
3792
|
+
pendingCodeLensAttributeRef.current = null;
|
|
3793
|
+
setOpenPopoverId(null);
|
|
3794
|
+
setPopoverPosition(null);
|
|
3795
|
+
editor.focus();
|
|
3796
|
+
}, []);
|
|
3362
3797
|
return {
|
|
3363
3798
|
editorRef,
|
|
3364
3799
|
draftDocument,
|
|
3365
3800
|
text: getEditableText(draftDocument),
|
|
3366
3801
|
selectionOverlay,
|
|
3802
|
+
activeTags,
|
|
3367
3803
|
isDarkTheme: resolvedTheme === "dark" || resolvedTheme === "system" && isDark,
|
|
3368
3804
|
decorationsVisible,
|
|
3369
3805
|
setDecorationsVisible,
|
|
@@ -3385,10 +3821,12 @@ function useSsmlEditorState({
|
|
|
3385
3821
|
previewSelection,
|
|
3386
3822
|
canPreviewSelection: onPreviewSelection !== void 0,
|
|
3387
3823
|
refreshSelectionOverlay,
|
|
3824
|
+
updateActiveTags,
|
|
3388
3825
|
getSelectedSsml: getSelectedSsmlValue,
|
|
3389
3826
|
getCurrentLineSsml: getCurrentLineSsmlValue,
|
|
3390
3827
|
getFullSsml,
|
|
3391
3828
|
getOuterVoiceName,
|
|
3829
|
+
handleCodeLensAction,
|
|
3392
3830
|
openPopoverId,
|
|
3393
3831
|
popoverVoiceName,
|
|
3394
3832
|
popoverPosition,
|
|
@@ -3618,7 +4056,8 @@ function registerSsmlCompletionProvider(monaco, options = {}) {
|
|
|
3618
4056
|
...attributeValues?.map((value2) => ({
|
|
3619
4057
|
label: value2,
|
|
3620
4058
|
kind: monaco.languages.CompletionItemKind.Value,
|
|
3621
|
-
insertText: value2
|
|
4059
|
+
insertText: value2,
|
|
4060
|
+
range
|
|
3622
4061
|
})) ?? []
|
|
3623
4062
|
]
|
|
3624
4063
|
};
|
|
@@ -3736,6 +4175,180 @@ function registerSsmlCodeActions(monaco) {
|
|
|
3736
4175
|
});
|
|
3737
4176
|
}
|
|
3738
4177
|
|
|
4178
|
+
// packages/ssml-editor-react/src/ssmlCodeLens.ts
|
|
4179
|
+
var CODE_LENS_COMMAND = "ssml-editor.codeLens";
|
|
4180
|
+
function findTagEnd3(source, start) {
|
|
4181
|
+
let quote;
|
|
4182
|
+
for (let index = start + 1; index < source.length; index += 1) {
|
|
4183
|
+
const character = source[index];
|
|
4184
|
+
if (quote !== void 0) {
|
|
4185
|
+
if (character === quote) {
|
|
4186
|
+
quote = void 0;
|
|
4187
|
+
}
|
|
4188
|
+
} else if (character === '"' || character === "'") {
|
|
4189
|
+
quote = character;
|
|
4190
|
+
} else if (character === ">") {
|
|
4191
|
+
return index;
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
return -1;
|
|
4195
|
+
}
|
|
4196
|
+
function getAttributeValue(tag, attributeName) {
|
|
4197
|
+
const escapedName = attributeName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4198
|
+
return tag.match(new RegExp(`\\b${escapedName}\\s*=\\s*(["'])([\\s\\S]*?)\\1`, "i"))?.[2];
|
|
4199
|
+
}
|
|
4200
|
+
function getTagRange(start, end) {
|
|
4201
|
+
return { start, end };
|
|
4202
|
+
}
|
|
4203
|
+
function getElementEnd(source, tagName, tagEnd) {
|
|
4204
|
+
const openingTag = source.slice(0, tagEnd + 1);
|
|
4205
|
+
if (/\/\s*>$/.test(openingTag)) {
|
|
4206
|
+
return tagEnd + 1;
|
|
4207
|
+
}
|
|
4208
|
+
let depth = 1;
|
|
4209
|
+
let index = tagEnd + 1;
|
|
4210
|
+
while (index < source.length) {
|
|
4211
|
+
const nextStart = source.indexOf("<", index);
|
|
4212
|
+
if (nextStart === -1) {
|
|
4213
|
+
break;
|
|
4214
|
+
}
|
|
4215
|
+
if (source.startsWith("<!--", nextStart)) {
|
|
4216
|
+
index = source.indexOf("-->", nextStart + 4);
|
|
4217
|
+
index = index === -1 ? source.length : index + 3;
|
|
4218
|
+
continue;
|
|
4219
|
+
}
|
|
4220
|
+
const nextEnd = findTagEnd3(source, nextStart);
|
|
4221
|
+
if (nextEnd === -1) {
|
|
4222
|
+
break;
|
|
4223
|
+
}
|
|
4224
|
+
const nextTag = source.slice(nextStart, nextEnd + 1);
|
|
4225
|
+
const closingMatch = nextTag.match(/^<\s*\/\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
4226
|
+
const openingMatch = nextTag.match(/^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
4227
|
+
if (closingMatch?.[1]?.toLowerCase() === tagName) {
|
|
4228
|
+
depth -= 1;
|
|
4229
|
+
if (depth === 0) {
|
|
4230
|
+
return nextEnd + 1;
|
|
4231
|
+
}
|
|
4232
|
+
} else if (openingMatch?.[1]?.toLowerCase() === tagName && !/\/\s*>$/.test(nextTag)) {
|
|
4233
|
+
depth += 1;
|
|
4234
|
+
}
|
|
4235
|
+
index = nextEnd + 1;
|
|
4236
|
+
}
|
|
4237
|
+
return tagEnd + 1;
|
|
4238
|
+
}
|
|
4239
|
+
function createLens(model, start, end, title, action) {
|
|
4240
|
+
const startPosition = model.getPositionAt(start);
|
|
4241
|
+
const endPosition = model.getPositionAt(end);
|
|
4242
|
+
return {
|
|
4243
|
+
range: {
|
|
4244
|
+
startLineNumber: startPosition.lineNumber,
|
|
4245
|
+
startColumn: startPosition.column,
|
|
4246
|
+
endLineNumber: endPosition.lineNumber,
|
|
4247
|
+
endColumn: endPosition.column
|
|
4248
|
+
},
|
|
4249
|
+
command: {
|
|
4250
|
+
id: CODE_LENS_COMMAND,
|
|
4251
|
+
title,
|
|
4252
|
+
arguments: [action]
|
|
4253
|
+
}
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
function registerSsmlCodeLens(monaco, editor, onOpenPopover) {
|
|
4257
|
+
const provider = {
|
|
4258
|
+
provideCodeLenses(model) {
|
|
4259
|
+
const source = model.getValue();
|
|
4260
|
+
const lenses = [];
|
|
4261
|
+
let index = 0;
|
|
4262
|
+
while (index < source.length) {
|
|
4263
|
+
const tagStart = source.indexOf("<", index);
|
|
4264
|
+
if (tagStart === -1) {
|
|
4265
|
+
break;
|
|
4266
|
+
}
|
|
4267
|
+
if (source.startsWith("<!--", tagStart)) {
|
|
4268
|
+
index = source.indexOf("-->", tagStart + 4);
|
|
4269
|
+
index = index === -1 ? source.length : index + 3;
|
|
4270
|
+
continue;
|
|
4271
|
+
}
|
|
4272
|
+
const tagEnd = findTagEnd3(source, tagStart);
|
|
4273
|
+
if (tagEnd === -1) {
|
|
4274
|
+
break;
|
|
4275
|
+
}
|
|
4276
|
+
const tag = source.slice(tagStart, tagEnd + 1);
|
|
4277
|
+
const tagName = tag.match(/^<\s*(prosody|break)\b/i)?.[1]?.toLowerCase();
|
|
4278
|
+
index = tagEnd + 1;
|
|
4279
|
+
if (!tagName) {
|
|
4280
|
+
continue;
|
|
4281
|
+
}
|
|
4282
|
+
const tagRange = getTagRange(tagStart, tagEnd + 1);
|
|
4283
|
+
const elementEnd = getElementEnd(source, tagName, tagEnd);
|
|
4284
|
+
const elementRange = { start: tagStart, end: elementEnd };
|
|
4285
|
+
if (tagName === "prosody") {
|
|
4286
|
+
lenses.push(
|
|
4287
|
+
createLens(
|
|
4288
|
+
model,
|
|
4289
|
+
tagStart,
|
|
4290
|
+
tagEnd + 1,
|
|
4291
|
+
`\u26A1 Rate: ${getAttributeValue(tag, "rate") ?? "default"} (Click to edit)`,
|
|
4292
|
+
{ type: "attribute", insertionId: "rate", attributeName: "rate", tagRange }
|
|
4293
|
+
),
|
|
4294
|
+
createLens(
|
|
4295
|
+
model,
|
|
4296
|
+
tagStart,
|
|
4297
|
+
tagEnd + 1,
|
|
4298
|
+
`\u26A1 Pitch: ${getAttributeValue(tag, "pitch") ?? "default"} (Click to edit)`,
|
|
4299
|
+
{ type: "attribute", insertionId: "pitch", attributeName: "pitch", tagRange }
|
|
4300
|
+
),
|
|
4301
|
+
createLens(model, tagStart, tagEnd + 1, "Unwrap", {
|
|
4302
|
+
type: "unwrap",
|
|
4303
|
+
tagRange,
|
|
4304
|
+
elementRange
|
|
4305
|
+
})
|
|
4306
|
+
);
|
|
4307
|
+
} else if (/\/\s*>$/.test(tag)) {
|
|
4308
|
+
lenses.push(
|
|
4309
|
+
createLens(
|
|
4310
|
+
model,
|
|
4311
|
+
tagStart,
|
|
4312
|
+
tagEnd + 1,
|
|
4313
|
+
`\u26A1 Time: ${getAttributeValue(tag, "time") ?? "default"} (Click to edit)`,
|
|
4314
|
+
{ type: "attribute", insertionId: "break", attributeName: "time", tagRange }
|
|
4315
|
+
),
|
|
4316
|
+
createLens(model, tagStart, tagEnd + 1, "Delete", {
|
|
4317
|
+
type: "delete",
|
|
4318
|
+
tagRange,
|
|
4319
|
+
elementRange
|
|
4320
|
+
})
|
|
4321
|
+
);
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
return { lenses, dispose: () => void 0 };
|
|
4325
|
+
}
|
|
4326
|
+
};
|
|
4327
|
+
const disposable = monaco.languages.registerCodeLensProvider("xml", provider);
|
|
4328
|
+
const commandHandler = (_accessor, ...args) => {
|
|
4329
|
+
const action = args[0];
|
|
4330
|
+
if (action && typeof action === "object" && "type" in action) {
|
|
4331
|
+
onOpenPopover(action);
|
|
4332
|
+
}
|
|
4333
|
+
};
|
|
4334
|
+
const commandDisposable = typeof monaco.editor?.registerCommand === "function" ? monaco.editor.registerCommand(CODE_LENS_COMMAND, commandHandler) : typeof monaco.registerCommand === "function" ? monaco.registerCommand(CODE_LENS_COMMAND, commandHandler) : editor.addAction({
|
|
4335
|
+
id: CODE_LENS_COMMAND,
|
|
4336
|
+
label: "SSML CodeLens",
|
|
4337
|
+
run: (_editor, ...args) => {
|
|
4338
|
+
const action = args[0];
|
|
4339
|
+
if (action && typeof action === "object" && "type" in action) {
|
|
4340
|
+
onOpenPopover(action);
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
});
|
|
4344
|
+
return {
|
|
4345
|
+
dispose: () => {
|
|
4346
|
+
commandDisposable.dispose();
|
|
4347
|
+
disposable.dispose();
|
|
4348
|
+
}
|
|
4349
|
+
};
|
|
4350
|
+
}
|
|
4351
|
+
|
|
3739
4352
|
// packages/ssml-editor-react/src/ssmlHover.ts
|
|
3740
4353
|
var {
|
|
3741
4354
|
BREAK_STRENGTH_PRESETS: BREAK_STRENGTH_PRESETS2,
|
|
@@ -4085,7 +4698,7 @@ function toRange(source, token) {
|
|
|
4085
4698
|
function containsOffset(token, offset) {
|
|
4086
4699
|
return offset >= token.start && offset < token.end;
|
|
4087
4700
|
}
|
|
4088
|
-
function
|
|
4701
|
+
function findTagEnd4(source, start) {
|
|
4089
4702
|
let quote;
|
|
4090
4703
|
for (let index = start; index < source.length; index += 1) {
|
|
4091
4704
|
const character = source[index];
|
|
@@ -4216,7 +4829,7 @@ function findTagAtOffset(source, offset) {
|
|
|
4216
4829
|
searchStart = tokenEnd2;
|
|
4217
4830
|
continue;
|
|
4218
4831
|
}
|
|
4219
|
-
const tagEnd =
|
|
4832
|
+
const tagEnd = findTagEnd4(source, start + 1);
|
|
4220
4833
|
const contentEnd = tagEnd ?? source.length;
|
|
4221
4834
|
const tokenEnd = tagEnd === void 0 ? source.length : tagEnd + 1;
|
|
4222
4835
|
if (offset < tokenEnd) {
|
|
@@ -4432,8 +5045,11 @@ function useSsmlMonaco({
|
|
|
4432
5045
|
language,
|
|
4433
5046
|
text,
|
|
4434
5047
|
decorationsVisible,
|
|
5048
|
+
enableCodeLens,
|
|
4435
5049
|
getOuterVoiceName,
|
|
5050
|
+
onOpenPopover,
|
|
4436
5051
|
onSelectionOverlayChange,
|
|
5052
|
+
onActiveTagsChange,
|
|
4437
5053
|
onSyntaxErrorChange
|
|
4438
5054
|
}) {
|
|
4439
5055
|
const internalEditorRef = (0, import_react2.useRef)(null);
|
|
@@ -4441,22 +5057,30 @@ function useSsmlMonaco({
|
|
|
4441
5057
|
const monacoRef = (0, import_react2.useRef)(null);
|
|
4442
5058
|
const completionProviderRef = (0, import_react2.useRef)(null);
|
|
4443
5059
|
const codeActionProviderRef = (0, import_react2.useRef)(null);
|
|
5060
|
+
const codeLensProviderRef = (0, import_react2.useRef)(null);
|
|
4444
5061
|
const releaseHoverProviderRef = (0, import_react2.useRef)(null);
|
|
4445
5062
|
const selectionChangeRef = (0, import_react2.useRef)(null);
|
|
5063
|
+
const cursorPositionChangeRef = (0, import_react2.useRef)(null);
|
|
4446
5064
|
const diagnosticsChangeRef = (0, import_react2.useRef)(null);
|
|
4447
5065
|
const diagnosticsTimeoutRef = (0, import_react2.useRef)(null);
|
|
4448
5066
|
const selectionLayoutDisposablesRef = (0, import_react2.useRef)([]);
|
|
4449
5067
|
const inlineDecorationIdsRef = (0, import_react2.useRef)([]);
|
|
4450
5068
|
const languageRef = (0, import_react2.useRef)(language);
|
|
4451
5069
|
const decorationsVisibleRef = (0, import_react2.useRef)(decorationsVisible);
|
|
5070
|
+
const enableCodeLensRef = (0, import_react2.useRef)(enableCodeLens);
|
|
4452
5071
|
const getOuterVoiceNameRef = (0, import_react2.useRef)(getOuterVoiceName);
|
|
4453
5072
|
const onSelectionOverlayChangeRef = (0, import_react2.useRef)(onSelectionOverlayChange);
|
|
5073
|
+
const onActiveTagsChangeRef = (0, import_react2.useRef)(onActiveTagsChange);
|
|
4454
5074
|
const onSyntaxErrorChangeRef = (0, import_react2.useRef)(onSyntaxErrorChange);
|
|
5075
|
+
const onOpenPopoverRef = (0, import_react2.useRef)(onOpenPopover);
|
|
4455
5076
|
languageRef.current = language;
|
|
4456
5077
|
decorationsVisibleRef.current = decorationsVisible;
|
|
5078
|
+
enableCodeLensRef.current = enableCodeLens;
|
|
4457
5079
|
getOuterVoiceNameRef.current = getOuterVoiceName;
|
|
4458
5080
|
onSelectionOverlayChangeRef.current = onSelectionOverlayChange;
|
|
5081
|
+
onActiveTagsChangeRef.current = onActiveTagsChange;
|
|
4459
5082
|
onSyntaxErrorChangeRef.current = onSyntaxErrorChange;
|
|
5083
|
+
onOpenPopoverRef.current = onOpenPopover;
|
|
4460
5084
|
const runSsmlDiagnostics = (0, import_react2.useCallback)((editor, monaco) => {
|
|
4461
5085
|
const model = editor.getModel();
|
|
4462
5086
|
if (!model) {
|
|
@@ -4485,6 +5109,15 @@ function useSsmlMonaco({
|
|
|
4485
5109
|
diagnosticsChangeRef.current?.dispose();
|
|
4486
5110
|
diagnosticsChangeRef.current = null;
|
|
4487
5111
|
}, []);
|
|
5112
|
+
const syncActiveTags = (0, import_react2.useCallback)((editor) => {
|
|
5113
|
+
const model = editor.getModel();
|
|
5114
|
+
const position = editor.getPosition();
|
|
5115
|
+
if (!model || !position) {
|
|
5116
|
+
onActiveTagsChangeRef.current(/* @__PURE__ */ new Set());
|
|
5117
|
+
return;
|
|
5118
|
+
}
|
|
5119
|
+
onActiveTagsChangeRef.current(findActiveSsmlTags(model.getValue(), model.getOffsetAt(position)));
|
|
5120
|
+
}, []);
|
|
4488
5121
|
const disposeMonacoResources = (0, import_react2.useCallback)(() => {
|
|
4489
5122
|
clearSsmlDiagnosticsResources();
|
|
4490
5123
|
const model = editorRef.current?.getModel();
|
|
@@ -4494,10 +5127,14 @@ function useSsmlMonaco({
|
|
|
4494
5127
|
}
|
|
4495
5128
|
selectionChangeRef.current?.dispose();
|
|
4496
5129
|
selectionChangeRef.current = null;
|
|
5130
|
+
cursorPositionChangeRef.current?.dispose();
|
|
5131
|
+
cursorPositionChangeRef.current = null;
|
|
4497
5132
|
completionProviderRef.current?.dispose();
|
|
4498
5133
|
completionProviderRef.current = null;
|
|
4499
5134
|
codeActionProviderRef.current?.dispose();
|
|
4500
5135
|
codeActionProviderRef.current = null;
|
|
5136
|
+
codeLensProviderRef.current?.dispose();
|
|
5137
|
+
codeLensProviderRef.current = null;
|
|
4501
5138
|
for (const disposable of selectionLayoutDisposablesRef.current) {
|
|
4502
5139
|
disposable.dispose();
|
|
4503
5140
|
}
|
|
@@ -4515,6 +5152,9 @@ function useSsmlMonaco({
|
|
|
4515
5152
|
selectionChangeRef.current = editor.onDidChangeCursorSelection(() => {
|
|
4516
5153
|
onSelectionOverlayChangeRef.current(editor, true);
|
|
4517
5154
|
});
|
|
5155
|
+
cursorPositionChangeRef.current = editor.onDidChangeCursorPosition(() => {
|
|
5156
|
+
syncActiveTags(editor);
|
|
5157
|
+
});
|
|
4518
5158
|
diagnosticsChangeRef.current = editor.onDidChangeModelContent(() => {
|
|
4519
5159
|
const model2 = editor.getModel();
|
|
4520
5160
|
if (model2) {
|
|
@@ -4526,6 +5166,7 @@ function useSsmlMonaco({
|
|
|
4526
5166
|
inlineDecorationIdsRef.current
|
|
4527
5167
|
);
|
|
4528
5168
|
}
|
|
5169
|
+
syncActiveTags(editor);
|
|
4529
5170
|
scheduleSsmlDiagnostics(editor, monaco);
|
|
4530
5171
|
});
|
|
4531
5172
|
selectionLayoutDisposablesRef.current = [
|
|
@@ -4538,6 +5179,13 @@ function useSsmlMonaco({
|
|
|
4538
5179
|
model: editor.getModel()
|
|
4539
5180
|
});
|
|
4540
5181
|
codeActionProviderRef.current = registerSsmlCodeActions(monaco);
|
|
5182
|
+
if (enableCodeLensRef.current) {
|
|
5183
|
+
codeLensProviderRef.current = registerSsmlCodeLens(
|
|
5184
|
+
monaco,
|
|
5185
|
+
editor,
|
|
5186
|
+
(action) => onOpenPopoverRef.current(action)
|
|
5187
|
+
);
|
|
5188
|
+
}
|
|
4541
5189
|
releaseHoverProviderRef.current = acquireSsmlHoverProvider(monaco, languageRef.current);
|
|
4542
5190
|
runSsmlDiagnostics(editor, monaco);
|
|
4543
5191
|
const model = editor.getModel();
|
|
@@ -4551,9 +5199,19 @@ function useSsmlMonaco({
|
|
|
4551
5199
|
);
|
|
4552
5200
|
}
|
|
4553
5201
|
onSelectionOverlayChangeRef.current(editor, true);
|
|
5202
|
+
syncActiveTags(editor);
|
|
4554
5203
|
},
|
|
4555
|
-
[disposeMonacoResources, editorRef, runSsmlDiagnostics, scheduleSsmlDiagnostics]
|
|
5204
|
+
[disposeMonacoResources, editorRef, runSsmlDiagnostics, scheduleSsmlDiagnostics, syncActiveTags]
|
|
4556
5205
|
);
|
|
5206
|
+
(0, import_react2.useEffect)(() => {
|
|
5207
|
+
const editor = editorRef.current;
|
|
5208
|
+
const monaco = monacoRef.current;
|
|
5209
|
+
if (!editor || !monaco) {
|
|
5210
|
+
return;
|
|
5211
|
+
}
|
|
5212
|
+
codeLensProviderRef.current?.dispose();
|
|
5213
|
+
codeLensProviderRef.current = enableCodeLens ? registerSsmlCodeLens(monaco, editor, (action) => onOpenPopoverRef.current(action)) : null;
|
|
5214
|
+
}, [editorRef, enableCodeLens]);
|
|
4557
5215
|
(0, import_react2.useEffect)(() => {
|
|
4558
5216
|
const monaco = monacoRef.current;
|
|
4559
5217
|
if (!monaco) {
|
|
@@ -4594,7 +5252,7 @@ var TEXT_POPOVER_TAGS = /* @__PURE__ */ new Set(["sub", "say-as", "phoneme", "w"
|
|
|
4594
5252
|
function localizedText(value) {
|
|
4595
5253
|
return { ja: value, en: value };
|
|
4596
5254
|
}
|
|
4597
|
-
function
|
|
5255
|
+
function escapeXmlAttribute2(value) {
|
|
4598
5256
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
4599
5257
|
}
|
|
4600
5258
|
function createSsmlEditorInsertionDefinition(definition) {
|
|
@@ -4611,7 +5269,7 @@ function createSsmlEditorInsertionDefinition(definition) {
|
|
|
4611
5269
|
parameterDescription: definition.parameterDescription ?? localizedText(`Selects the value for the <${definition.tagName}> element.`),
|
|
4612
5270
|
options: definition.options,
|
|
4613
5271
|
createTemplate: (value) => {
|
|
4614
|
-
const attributeValue = definition.attribute ? `${attribute}${
|
|
5272
|
+
const attributeValue = definition.attribute ? `${attribute}${escapeXmlAttribute2(value)}"` : "";
|
|
4615
5273
|
if (mode === "wrap") {
|
|
4616
5274
|
return {
|
|
4617
5275
|
prefix: `<${definition.tagName}${attributeValue}>`,
|
|
@@ -4940,6 +5598,8 @@ var STYLE_CSS = `
|
|
|
4940
5598
|
--ssml-editor-border: #d1d5db;
|
|
4941
5599
|
--ssml-editor-control-bg: #f9fafb;
|
|
4942
5600
|
--ssml-editor-control-border: #9ca3af;
|
|
5601
|
+
--ssml-editor-active-bg: #dbeafe;
|
|
5602
|
+
--ssml-editor-active-border: #2563eb;
|
|
4943
5603
|
--ssml-editor-preview-bg: #f3f4f6;
|
|
4944
5604
|
--ssml-editor-error: #b91c1c;
|
|
4945
5605
|
--ssml-editor-error-bg: #fef2f2;
|
|
@@ -4957,6 +5617,8 @@ var STYLE_CSS = `
|
|
|
4957
5617
|
--ssml-editor-border: #374151;
|
|
4958
5618
|
--ssml-editor-control-bg: #111827;
|
|
4959
5619
|
--ssml-editor-control-border: #4b5563;
|
|
5620
|
+
--ssml-editor-active-bg: #1e3a8a;
|
|
5621
|
+
--ssml-editor-active-border: #60a5fa;
|
|
4960
5622
|
--ssml-editor-preview-bg: #111827;
|
|
4961
5623
|
--ssml-editor-error: #fca5a5;
|
|
4962
5624
|
--ssml-editor-error-bg: #450a0a;
|
|
@@ -5070,6 +5732,7 @@ var SsmlEditor = (0, import_react3.forwardRef)(function SsmlEditor2({
|
|
|
5070
5732
|
showToolbarIcons = true,
|
|
5071
5733
|
showToolbarLabels = false,
|
|
5072
5734
|
showDecorations = false,
|
|
5735
|
+
enableCodeLens = true,
|
|
5073
5736
|
buttonVisibility,
|
|
5074
5737
|
editorOptions,
|
|
5075
5738
|
settings,
|
|
@@ -5176,6 +5839,7 @@ var SsmlEditor = (0, import_react3.forwardRef)(function SsmlEditor2({
|
|
|
5176
5839
|
editorRef,
|
|
5177
5840
|
text,
|
|
5178
5841
|
selectionOverlay,
|
|
5842
|
+
activeTags,
|
|
5179
5843
|
isDarkTheme,
|
|
5180
5844
|
decorationsVisible,
|
|
5181
5845
|
setDecorationsVisible,
|
|
@@ -5196,10 +5860,12 @@ var SsmlEditor = (0, import_react3.forwardRef)(function SsmlEditor2({
|
|
|
5196
5860
|
previewSelection,
|
|
5197
5861
|
canPreviewSelection,
|
|
5198
5862
|
refreshSelectionOverlay,
|
|
5863
|
+
updateActiveTags,
|
|
5199
5864
|
getSelectedSsml: getSelectedSsml2,
|
|
5200
5865
|
getCurrentLineSsml: getCurrentLineSsml2,
|
|
5201
5866
|
getFullSsml,
|
|
5202
5867
|
getOuterVoiceName,
|
|
5868
|
+
handleCodeLensAction,
|
|
5203
5869
|
openPopoverId,
|
|
5204
5870
|
popoverVoiceName,
|
|
5205
5871
|
popoverPosition,
|
|
@@ -5224,7 +5890,10 @@ var SsmlEditor = (0, import_react3.forwardRef)(function SsmlEditor2({
|
|
|
5224
5890
|
decorationsVisible,
|
|
5225
5891
|
getOuterVoiceName,
|
|
5226
5892
|
onSelectionOverlayChange: refreshSelectionOverlay,
|
|
5227
|
-
|
|
5893
|
+
onActiveTagsChange: updateActiveTags,
|
|
5894
|
+
onSyntaxErrorChange: setSyntaxError,
|
|
5895
|
+
enableCodeLens,
|
|
5896
|
+
onOpenPopover: handleCodeLensAction
|
|
5228
5897
|
});
|
|
5229
5898
|
(0, import_react3.useImperativeHandle)(
|
|
5230
5899
|
ref,
|
|
@@ -5239,12 +5908,13 @@ var SsmlEditor = (0, import_react3.forwardRef)(function SsmlEditor2({
|
|
|
5239
5908
|
const isTimingPopover = insertion.tagName !== void 0 && TIMING_POPOVER_TAGS.has(insertion.tagName);
|
|
5240
5909
|
const isProsodyPopover = insertion.tagName !== void 0 && PROSODY_POPOVER_TAGS.has(insertion.tagName);
|
|
5241
5910
|
const isTextPopover = insertion.tagName !== void 0 && TEXT_POPOVER_TAGS.has(insertion.tagName);
|
|
5911
|
+
const insertionButtonStyle = insertion.tagName && activeTags.has(insertion.tagName.toLowerCase()) ? { ...toolbarButtonStyle, ...editorStyles.toolbarButtonActive } : toolbarButtonStyle;
|
|
5242
5912
|
const props = {
|
|
5243
5913
|
language,
|
|
5244
5914
|
isDarkTheme,
|
|
5245
5915
|
showToolbarIcons,
|
|
5246
5916
|
showToolbarText,
|
|
5247
|
-
toolbarButtonStyle,
|
|
5917
|
+
toolbarButtonStyle: insertionButtonStyle,
|
|
5248
5918
|
emptyOptionsMessage: copy.noAvailableOptions,
|
|
5249
5919
|
isReadOnly,
|
|
5250
5920
|
openPopoverId,
|
|
@@ -5502,6 +6172,8 @@ var SsmlEditor = (0, import_react3.forwardRef)(function SsmlEditor2({
|
|
|
5502
6172
|
SSML_HOVER_COPY,
|
|
5503
6173
|
SSML_INSERTIONS,
|
|
5504
6174
|
SsmlEditor,
|
|
5505
|
-
createSsmlEditorInsertionDefinition
|
|
6175
|
+
createSsmlEditorInsertionDefinition,
|
|
6176
|
+
registerSsmlCodeLens,
|
|
6177
|
+
updateTagAttribute
|
|
5506
6178
|
});
|
|
5507
6179
|
//# sourceMappingURL=react.js.map
|