@naersen/tts-rich-text 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
4
 
5
+ ## 0.10.1 - 2026-10-29
6
+
7
+ ### 修复
8
+
9
+ - 对齐 TTS 网关分句策略:默认超长段拆分阈值由 64 调整为 128 个视觉单位,以段中点为目标,依次优先选择分号、逗号/顿号/冒号、空格作为切点,无自然切点时在中点硬切。
10
+ - 尾段平衡改为按字符长度计算,在合并文本的中点附近选择最近标点或空格,并保留分句边界空格。
11
+
12
+ ### 升级提示
13
+
14
+ - TTS 输出字段名称、类型及标注默认值保持不变;相同文本导出的句子数量、切分边界和对应标注位置可能变化。
15
+ - 128 是拆分阈值和切点搜索上界,不是输出句子的硬性长度上限。
16
+
5
17
  ## 0.10.0 - 2026-10-28
6
18
 
7
19
  ### 新增
package/README.md CHANGED
@@ -195,9 +195,13 @@ const getPlaybackSpeed = () => selectedVoice.value.speed / 50
195
195
 
196
196
  ### 分句策略
197
197
 
198
- `convertToTtsFormat()` 使用 `splitTextToSentences()` 生成 `sentences`。默认按视觉长度计算,中文、全角字符计 2,其他字符计 1;每段最小目标长度为 32,最大目标长度为 64。
198
+ `convertToTtsFormat()` 使用 `splitTextToSentences()` 生成 `sentences`。默认按视觉长度计算,中文、全角字符计 2,其他字符计 1;句末标点分割的最小段宽度为 32,超长段拆分阈值为 128(约 64 个汉字)。短句累积达到 32 且以句末标点结尾时输出,不足 32 的尾部残段并入前一段。
199
199
 
200
- 超长内容优先在分号处分割,其次是逗号或冒号、空格,顿号仅在没有其他自然切点时使用。数字中的小数点和千分位逗号不会被当作分句点,过短尾段会自动重平衡。
200
+ 超长内容以段中点为目标,在目标字符位置的三分之一到视觉宽度达到 128 的位置之间寻找切点。优先选择分号,其次是同级的逗号、顿号、冒号,最后是空格;没有自然切点时在中点硬切。按参考文档,上界之前未达到视觉中点时回退到字符中点,因此 128 是拆分阈值和搜索上界,不保证所有输出段都不超过 128。
201
+
202
+ 数字中的小数点和千分位逗号不会被当作标点切点。尾段长度小于平均长度的 40% 时,与前一段合并后,在字符中点附近按最近标点或空格重新切分;长度和中点均按 `string.length` 计算,不区分标点优先级。
203
+
204
+ 本组件使用普通段落,在导出 TTS 数据时执行分句。参考文档中的 96/144 阈值用于气泡创建和编辑重分,不作为本组件导出的触发条件;回车仍由编辑器创建段落。
201
205
 
202
206
  需要自定义长度时,可以从核心入口调用:
203
207
 
@@ -206,7 +210,7 @@ import { splitTextToSentences } from '@naersen/tts-rich-text/core'
206
210
 
207
211
  const sentences = splitTextToSentences(text, {
208
212
  minSegmentLength: 32,
209
- maxSegmentLength: 64,
213
+ maxSegmentLength: 128,
210
214
  rebalanceRatio: 0.4
211
215
  })
212
216
  ```
package/dist/core.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const f = {
2
2
  DELETE_NODE: "deleteNode",
3
3
  CONVERT_TO_TEXT: "convertToText"
4
- }, p = {
4
+ }, g = {
5
5
  stop: {
6
6
  label: "停顿",
7
7
  icon: "editor-stop",
@@ -70,7 +70,7 @@ const f = {
70
70
  type: "ignore",
71
71
  deleteMode: f.CONVERT_TO_TEXT
72
72
  }
73
- }, D = [
73
+ }, S = [
74
74
  { label: "笑声", value: "笑声", tag: "[laughter]" },
75
75
  { label: "叹气", value: "叹气", tag: "[sigh]" },
76
76
  { label: "吸气", value: "吸气", tag: "[sniff]" },
@@ -85,7 +85,7 @@ const f = {
85
85
  { label: "惊讶(哇)", value: "惊讶(哇)", tag: "[surprise-wa]" },
86
86
  { label: "惊讶(哟)", value: "惊讶(哟)", tag: "[surprise-yo]" },
87
87
  { label: "不满", value: "不满", tag: "[dissatisfaction-hnn]" }
88
- ], x = [
88
+ ], _ = [
89
89
  { value: "zh", label: "中文" },
90
90
  { value: "en", label: "英语" },
91
91
  { value: "jp", label: "日语" },
@@ -96,10 +96,10 @@ const f = {
96
96
  { value: "it", label: "意大利语" },
97
97
  { value: "pt", label: "葡萄牙语" },
98
98
  { value: "ru", label: "俄语" }
99
- ], w = [
99
+ ], v = [
100
100
  { label: "停顿 0.5 秒", value: 0.5 },
101
101
  { label: "停顿 1 秒", value: 1 }
102
- ], fe = {
102
+ ], pe = {
103
103
  SENTENCE: "sentence",
104
104
  CUSTOM_TAG: "customTag",
105
105
  /**
@@ -107,16 +107,16 @@ const f = {
107
107
  * 工具栏与右键面板都要用它来主动收起气泡,避免两个浮层叠在一起。
108
108
  */
109
109
  BUBBLE_MENU_KEY: "ttsRichTextBubbleMenu"
110
- }, he = (e) => {
110
+ }, fe = (e) => {
111
111
  var t;
112
- return ((t = p[e]) == null ? void 0 : t.deleteMode) === f.DELETE_NODE;
113
- }, de = (e) => e === p.stop.type || e === p.customStop.type, Te = (e) => e === p.customStop.type ? { time: w[0].value } : {}, Ee = (e, t) => e === p.customStop.type ? `${t == null ? void 0 : t.time} 秒` : "", y = Object.keys(p), d = {
114
- tools: y.filter((e) => e !== p.tone.type),
115
- languages: x,
112
+ return ((t = g[e]) == null ? void 0 : t.deleteMode) === f.DELETE_NODE;
113
+ }, he = (e) => e === g.stop.type || e === g.customStop.type, de = (e) => e === g.customStop.type ? { time: v[0].value } : {}, Te = (e, t) => e === g.customStop.type ? `${t == null ? void 0 : t.time} 秒` : "", x = Object.keys(g), d = {
114
+ tools: x.filter((e) => e !== g.tone.type),
115
+ languages: _,
116
116
  maxPinyinLength: 4,
117
117
  maxNumberLength: 16,
118
118
  enablePreview: !0
119
- }, B = {
119
+ }, F = {
120
120
  1: {
121
121
  tools: [
122
122
  "customStop",
@@ -129,12 +129,12 @@ const f = {
129
129
  "upload",
130
130
  "ignore"
131
131
  ],
132
- languages: x.filter((e) => ["zh", "en"].includes(e.value))
132
+ languages: _.filter((e) => ["zh", "en"].includes(e.value))
133
133
  },
134
134
  2: d,
135
- 3: { tools: y.filter((e) => e !== p.language.type) }
136
- }, me = (e, t = {}) => {
137
- const n = B[e] ?? d;
135
+ 3: { tools: x.filter((e) => e !== g.language.type) }
136
+ }, Ee = (e, t = {}) => {
137
+ const n = F[e] ?? d;
138
138
  return {
139
139
  ...d,
140
140
  ...n,
@@ -142,7 +142,7 @@ const f = {
142
142
  tools: t.tools ?? n.tools ?? d.tools,
143
143
  languages: t.languages ?? n.languages ?? d.languages
144
144
  };
145
- }, be = () => ({
145
+ }, me = () => ({
146
146
  type: "doc",
147
147
  content: [
148
148
  {
@@ -150,13 +150,13 @@ const f = {
150
150
  content: []
151
151
  }
152
152
  ]
153
- }), H = /[\u4e00-\u9fff]/, U = /\s/g, V = 0.28, $ = 0.14, _e = (e, t = 1) => {
153
+ }), A = /[\u4e00-\u9fff]/, M = /\s/g, D = 0.28, w = 0.14, be = (e, t = 1) => {
154
154
  const n = Number.isFinite(t) && t > 0 ? t : 1;
155
- return Array.from(e.replace(U, "")).reduce(
156
- (s, l) => s + (H.test(l) ? V : $),
155
+ return Array.from(e.replace(M, "")).reduce(
156
+ (s, a) => s + (A.test(a) ? D : w),
157
157
  0
158
158
  ) / n;
159
- }, R = {
159
+ }, N = {
160
160
  0: "零",
161
161
  1: "一",
162
162
  2: "二",
@@ -167,7 +167,7 @@ const f = {
167
167
  7: "七",
168
168
  8: "八",
169
169
  9: "九"
170
- }, k = {
170
+ }, B = {
171
171
  0: "洞",
172
172
  1: "幺",
173
173
  2: "二",
@@ -178,49 +178,49 @@ const f = {
178
178
  7: "七",
179
179
  8: "八",
180
180
  9: "九"
181
- }, j = ["", "十", "百", "千"], X = ["", "万", "亿", "万亿"];
182
- function z(e) {
183
- return e ? e.split("").map((t) => R[t] || t).join("") : "";
181
+ }, H = ["", "十", "百", "千"], k = ["", "万", "亿", "万亿"];
182
+ function U(e) {
183
+ return e ? e.split("").map((t) => N[t] || t).join("") : "";
184
184
  }
185
- function Ne(e) {
186
- return e ? e.split("").map((t) => k[t] || t).join("") : "";
185
+ function _e(e) {
186
+ return e ? e.split("").map((t) => B[t] || t).join("") : "";
187
187
  }
188
- function G(e) {
188
+ function $(e) {
189
189
  const t = e.length;
190
190
  let n = "", o = !1;
191
191
  for (let s = 0; s < t; s++) {
192
- const l = e[s], r = t - 1 - s;
193
- l === "0" ? !o && n !== "" && (o = !0) : (o && (n += "零", o = !1), n += R[l] + j[r]);
192
+ const a = e[s], r = t - 1 - s;
193
+ a === "0" ? !o && n !== "" && (o = !0) : (o && (n += "零", o = !1), n += N[a] + H[r]);
194
194
  }
195
195
  return n.startsWith("一十") && n.length === 2 && (n = n.substring(1)), n;
196
196
  }
197
- function O(e) {
197
+ function y(e) {
198
198
  if (!e) return "";
199
199
  if (e === "0" || (e = e.replace(/^0+/, "") || "0", e === "0")) return "零";
200
200
  let t = "";
201
201
  const n = e.length, o = [];
202
202
  for (let s = n; s > 0; s -= 4) {
203
- const l = Math.max(0, s - 4);
204
- o.unshift(e.substring(l, s));
203
+ const a = Math.max(0, s - 4);
204
+ o.unshift(e.substring(a, s));
205
205
  }
206
206
  for (let s = 0; s < o.length; s++) {
207
- const l = o[s], r = G(l);
207
+ const a = o[s], r = $(a);
208
208
  if (r !== "") {
209
- const a = o.length - 1 - s;
210
- t += r + X[a];
209
+ const l = o.length - 1 - s;
210
+ t += r + k[l];
211
211
  }
212
212
  }
213
213
  return t;
214
214
  }
215
- function q(e) {
216
- return O(e);
215
+ function V(e) {
216
+ return y(e);
217
217
  }
218
218
  const xe = [
219
- { label: "基数读法", func: z },
219
+ { label: "基数读法", func: U },
220
220
  // { label: '位数读法', func: toPhoneReading },
221
- { label: "位数读法", func: O },
222
- { label: "口语读法", func: q }
223
- ], W = /[\u0000-\u0008\u000B-\u001F\u007F-\u009F\u00AD\u200B-\u200F\u202A-\u202E\u2060-\u206F\uFE00-\uFE0F\uFEFF\uFFFD\uE000-\uF8FF]/g, Y = /[\t\f\v\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g, L = {
221
+ { label: "位数读法", func: y },
222
+ { label: "口语读法", func: V }
223
+ ], j = /[\u0000-\u0008\u000B-\u001F\u007F-\u009F\u00AD\u200B-\u200F\u202A-\u202E\u2060-\u206F\uFE00-\uFE0F\uFEFF\uFFFD\uE000-\uF8FF]/g, X = /[\t\f\v\u00A0\u1680\u2000-\u200A\u202F\u205F\u3000]/g, R = {
224
224
  "‘": "'",
225
225
  "’": "'",
226
226
  "‚": "'",
@@ -252,222 +252,211 @@ const xe = [
252
252
  "︔": ";",
253
253
  "︕": "!",
254
254
  "︖": "?"
255
- }, K = new RegExp(`[${Object.keys(L).join("")}]`, "g"), J = (e) => e.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A\uFF10-\uFF19]/g, (t) => String.fromCharCode(t.charCodeAt(0) - 65248)), Z = (e) => J(e).replace(/\r\n?/g, `
255
+ }, z = new RegExp(`[${Object.keys(R).join("")}]`, "g"), G = (e) => e.replace(/[\uFF21-\uFF3A\uFF41-\uFF5A\uFF10-\uFF19]/g, (t) => String.fromCharCode(t.charCodeAt(0) - 65248)), q = (e) => G(e).replace(/\r\n?/g, `
256
256
  `).replace(/[\u2028\u2029]/g, `
257
- `).replace(W, "").replace(Y, " ").replace(K, (t) => L[t] || "").replace(/ *\n */g, `
257
+ `).replace(j, "").replace(X, " ").replace(z, (t) => R[t] || "").replace(/ *\n */g, `
258
258
  `).replace(/\n{3,}/g, `
259
259
 
260
- `), ye = (e) => {
260
+ `), Ne = (e) => {
261
261
  if (typeof window > "u" || !e)
262
262
  return e;
263
263
  const n = new DOMParser().parseFromString(e, "text/html"), o = n.createTreeWalker(n.body, NodeFilter.SHOW_TEXT);
264
264
  let s = o.nextNode();
265
265
  for (; s; )
266
- s.textContent = Z(s.textContent || ""), s = o.nextNode();
266
+ s.textContent = q(s.textContent || ""), s = o.nextNode();
267
267
  return n.body.innerHTML;
268
- }, Q = {
268
+ }, W = {
269
269
  minSegmentLength: 32,
270
- maxSegmentLength: 64,
270
+ maxSegmentLength: 128,
271
271
  rebalanceRatio: 0.4
272
- }, I = /[一-鿿㐀-䶿豈-﫿 -〿＀-￯]/, C = /[。!?!?\.]/, P = /[;;]/, S = /[,,::]/, ee = /[、]/, v = "", F = "", h = (e) => {
272
+ }, L = /[一-鿿㐀-䶿豈-﫿 -〿＀-￯]/, K = /[。!?!?\.]/, Y = /[;;]/, J = /[,,、::]/, Z = /[。!?!?,,、;;::]/, I = "", O = "", h = (e) => {
273
273
  let t = 0;
274
274
  for (const n of e)
275
- t += I.test(n) ? 2 : 1;
275
+ t += L.test(n) ? 2 : 1;
276
276
  return t;
277
- }, te = (e) => e.replace(/\r/g, "").split(`
278
- `).map((t) => t.trim()).filter(Boolean).join(" ").replace(/\s+/g, " ").trim(), ne = (e) => {
277
+ }, Q = (e) => e.replace(/\r/g, "").split(`
278
+ `).map((t) => t.trim()).filter(Boolean).join(" ").replace(/\s+/g, " ").trim(), ee = (e) => {
279
279
  let t = e, n = "";
280
280
  for (; n !== t; )
281
- n = t, t = t.replace(/(\d),(\d)/g, `$1${v}$2`);
281
+ n = t, t = t.replace(/(\d),(\d)/g, `$1${I}$2`);
282
282
  for (n = ""; n !== t; )
283
- n = t, t = t.replace(/(\d)\.(\d)/g, `$1${F}$2`);
283
+ n = t, t = t.replace(/(\d)\.(\d)/g, `$1${O}$2`);
284
284
  return t;
285
- }, b = (e) => e.split(v).join(",").split(F).join("."), m = (e, t) => {
286
- let n = 0;
287
- for (let o = 0; o < e.length; o += 1)
288
- if (n += I.test(e[o]) ? 2 : 1, n >= t)
289
- return o + 1;
290
- return e.length;
291
- }, _ = (e, t, n, o, s) => {
292
- let l = -1, r = Number.POSITIVE_INFINITY;
293
- const a = Math.max(1, n), c = Math.min(e.length - 1, o);
294
- for (let i = a; i <= c; i += 1) {
285
+ }, m = (e) => e.split(I).join(",").split(O).join("."), te = (e, t, n, o, s) => {
286
+ let a = -1, r = Number.POSITIVE_INFINITY;
287
+ const l = Math.max(1, n), c = Math.min(e.length, o);
288
+ for (let i = l; i <= c; i += 1) {
295
289
  if (!s.test(e[i - 1]))
296
290
  continue;
297
291
  const u = Math.abs(i - t);
298
- if (u < r && (r = u, l = i), i > t && l >= 0)
292
+ if (u < r && (r = u, a = i), i > t && a >= 0)
299
293
  break;
300
294
  }
301
- return l;
302
- }, oe = (e, t, n, o) => {
303
- let s = -1, l = Number.POSITIVE_INFINITY;
304
- const r = Math.max(1, n), a = Math.min(e.length - 1, o);
305
- for (let c = r; c <= a; c += 1) {
295
+ return a;
296
+ }, ne = (e, t, n, o) => {
297
+ let s = -1, a = Number.POSITIVE_INFINITY;
298
+ const r = Math.max(1, n), l = Math.min(e.length, o);
299
+ for (let c = r; c <= l; c += 1) {
306
300
  if (e[c - 1] !== " ")
307
301
  continue;
308
302
  const i = Math.abs(c - t);
309
- if (i < l && (l = i, s = c), c > t && s >= 0)
303
+ if (i < a && (a = i, s = c), c > t && s >= 0)
310
304
  break;
311
305
  }
312
306
  return s;
313
- }, M = (e, t, n, o, s) => {
314
- for (const r of s) {
315
- const a = _(
307
+ }, C = (e, t, n, o, s) => {
308
+ for (const a of s) {
309
+ const r = te(
316
310
  e,
317
311
  t,
318
312
  n,
319
313
  o,
320
- r
314
+ a
321
315
  );
322
- if (a >= 0)
323
- return a;
316
+ if (r >= 0)
317
+ return r;
324
318
  }
325
- const l = oe(e, t, n, o);
326
- return l >= 0 ? l : _(
327
- e,
328
- t,
329
- n,
330
- o,
331
- ee
332
- );
333
- }, re = (e, t) => {
319
+ return ne(e, t, n, o);
320
+ }, oe = (e, t) => {
334
321
  const n = [];
335
- let o = e.trim();
322
+ let o = e;
336
323
  for (; o && h(o) > t; ) {
337
- const s = h(o), l = Math.min(Math.floor(s / 2), t), r = m(o, l), a = Math.max(1, Math.floor(r / 3)), c = Math.max(
338
- r + 1,
339
- m(o, t)
340
- );
341
- let i = M(o, r, a, c, [
342
- P,
343
- S
324
+ const s = h(o), a = Math.floor(s / 2);
325
+ let r = 0, l = 0, c = 0;
326
+ for (let p = 0; p < o.length; p += 1)
327
+ if (c += L.test(o[p]) ? 2 : 1, !r && c >= a && (r = p + 1), c >= t) {
328
+ l = p + 1;
329
+ break;
330
+ }
331
+ l || (l = o.length), r || (r = Math.floor(o.length / 2));
332
+ const i = Math.max(1, Math.floor(r / 3));
333
+ let u = C(o, r, i, l, [
334
+ Y,
335
+ J
344
336
  ]);
345
- (i < 0 || i >= o.length) && (i = r), n.push(o.slice(0, i).trim()), o = o.slice(i).trim();
337
+ (u < 0 || u >= o.length) && (u = r), n.push(o.slice(0, u)), o = o.slice(u);
346
338
  }
347
- return o && n.push(o), n;
348
- }, se = (e, t) => {
339
+ return o.trim() && n.push(o), n;
340
+ }, re = (e, t) => {
349
341
  if (e.length <= 1)
350
342
  return e;
351
- const n = e[e.length - 1], o = e.reduce((T, E) => T + h(E), 0) / e.length, s = Math.floor(o * t);
352
- if (h(n) >= s)
343
+ const n = e[e.length - 1], o = e.reduce((p, T) => p + T.length, 0) / e.length, s = Math.floor(o * t);
344
+ if (n.length >= s)
353
345
  return e;
354
- const r = `${e[e.length - 2]}${n}`, a = Math.floor(h(r) / 2), c = m(r, a), i = Math.max(1, Math.floor(c / 3));
355
- let u = M(r, c, i, r.length, [
356
- C,
357
- P,
358
- S
346
+ const r = `${e[e.length - 2]}${n}`, l = Math.floor(r.length / 2), c = Math.max(1, Math.floor(l / 3)), i = C(r, l, c, r.length, [
347
+ Z
359
348
  ]);
360
- if (u <= 0 || u >= r.length)
349
+ if (i <= 0 || i >= r.length)
361
350
  return e;
362
- const g = [...e];
363
- return g[g.length - 2] = r.slice(0, u).trim(), g[g.length - 1] = r.slice(u).trim(), g.filter(Boolean);
364
- }, ae = (e, t = {}) => {
351
+ const u = [...e];
352
+ return u[u.length - 2] = r.slice(0, i), u[u.length - 1] = r.slice(i), u.filter(Boolean);
353
+ }, se = (e, t = {}) => {
365
354
  const n = {
366
- ...Q,
355
+ ...W,
367
356
  ...t
368
- }, o = te(e);
357
+ }, o = Q(e);
369
358
  if (!o)
370
359
  return [];
371
- const s = ne(o);
360
+ const s = ee(o);
372
361
  if (h(s) <= n.minSegmentLength)
373
- return [b(s)];
374
- const l = [], r = s.split(new RegExp("(?<=[。!?!?\\.])"));
375
- let a = "";
362
+ return [m(s)];
363
+ const a = [], r = s.split(new RegExp("(?<=[。!?!?\\.])"));
364
+ let l = "";
376
365
  for (const i of r) {
377
366
  if (!i)
378
367
  continue;
379
- a += i;
380
- const u = a[a.length - 1] ?? "";
381
- h(a) >= n.minSegmentLength && C.test(u) && (l.push(a.trim()), a = "");
368
+ l += i;
369
+ const u = l[l.length - 1] ?? "";
370
+ h(l) >= n.minSegmentLength && K.test(u) && (a.push(l), l = "");
382
371
  }
383
- a && (l.length > 0 && h(a) < n.minSegmentLength ? l[l.length - 1] += a : l.push(a.trim()));
384
- const c = l.flatMap((i) => h(i) <= n.maxSegmentLength ? [i] : re(i, n.maxSegmentLength));
385
- return se(c, n.rebalanceRatio).map(
386
- b
372
+ l && (a.length > 0 && h(l) < n.minSegmentLength ? a[a.length - 1] += l : a.push(l));
373
+ const c = a.flatMap((i) => h(i) <= n.maxSegmentLength ? [i] : oe(i, n.maxSegmentLength));
374
+ return re(c, n.rebalanceRatio).map(
375
+ m
387
376
  );
388
- }, A = (e) => e.type === "text" ? e.text || "" : (e.content || []).map(A).join(""), le = (e) => {
377
+ }, P = (e) => e.type === "text" ? e.text || "" : (e.content || []).map(P).join(""), le = (e) => {
389
378
  const t = e.content || [];
390
379
  let n = "";
391
- const o = [], s = [], l = {
392
- [p.stop.type]: ({ position: r, actionCode: a }) => {
380
+ const o = [], s = [], a = {
381
+ [g.stop.type]: ({ position: r, actionCode: l }) => {
393
382
  o.push({
394
383
  action: "insert",
395
384
  model: "control",
396
385
  payload: "。 ",
397
386
  position: r,
398
387
  text: "",
399
- actionCode: a
388
+ actionCode: l
400
389
  });
401
390
  },
402
- [p.customStop.type]: ({ payload: r, position: a, actionCode: c }) => {
391
+ [g.customStop.type]: ({ payload: r, position: l, actionCode: c }) => {
403
392
  o.push({
404
393
  action: "insert",
405
394
  model: "control",
406
395
  payload: `[stop:${r == null ? void 0 : r.time}]`,
407
- position: a,
396
+ position: l,
408
397
  text: "",
409
398
  actionCode: c
410
399
  });
411
400
  },
412
- [p.continue.type]: ({ position: r, text: a, actionCode: c }) => {
401
+ [g.continue.type]: ({ position: r, text: l, actionCode: c }) => {
413
402
  o.push({
414
403
  action: "replace",
415
404
  model: "replace",
416
- payload: `《${a}》`,
405
+ payload: `《${l}》`,
417
406
  position: r,
418
- text: a,
407
+ text: l,
419
408
  actionCode: c
420
409
  });
421
410
  },
422
- [p.replace.type]: ({ payload: r, position: a, text: c, actionCode: i }) => {
411
+ [g.replace.type]: ({ payload: r, position: l, text: c, actionCode: i }) => {
423
412
  o.push({
424
413
  action: "replace",
425
414
  model: "replace",
426
415
  payload: `${r == null ? void 0 : r.text}`,
427
- position: a,
416
+ position: l,
428
417
  text: c,
429
418
  actionCode: i
430
419
  });
431
420
  },
432
- [p.pinyin.type]: ({ payload: r, position: a, text: c, actionCode: i }) => {
421
+ [g.pinyin.type]: ({ payload: r, position: l, text: c, actionCode: i }) => {
433
422
  o.push({
434
423
  action: "replace",
435
424
  model: "pinyin",
436
425
  payload: `${r == null ? void 0 : r.text}`,
437
- position: a,
426
+ position: l,
438
427
  text: c,
439
428
  actionCode: i
440
429
  });
441
430
  },
442
- [p.language.type]: ({ payload: r, position: a, text: c, actionCode: i }) => {
431
+ [g.language.type]: ({ payload: r, position: l, text: c, actionCode: i }) => {
443
432
  o.push({
444
433
  action: "language",
445
434
  model: "language",
446
435
  payload: `${r == null ? void 0 : r.code}`,
447
- position: a,
436
+ position: l,
448
437
  text: c,
449
438
  actionCode: i
450
439
  });
451
440
  },
452
- [p.tone.type]: ({ payload: r, position: a, actionCode: c }) => {
441
+ [g.tone.type]: ({ payload: r, position: l, actionCode: c }) => {
453
442
  var u;
454
- const i = (u = D.find((g) => g.value === (r == null ? void 0 : r.code))) == null ? void 0 : u.tag;
443
+ const i = (u = S.find((p) => p.value === (r == null ? void 0 : r.code))) == null ? void 0 : u.tag;
455
444
  i && o.push({
456
445
  action: "insert",
457
446
  model: "control",
458
447
  payload: i,
459
- position: a,
448
+ position: l,
460
449
  text: "",
461
450
  actionCode: c
462
451
  });
463
452
  },
464
- [p.ignore.type]: ({ position: r, text: a, actionCode: c }) => {
453
+ [g.ignore.type]: ({ position: r, text: l, actionCode: c }) => {
465
454
  o.push({
466
455
  action: "replace",
467
456
  model: "replace",
468
457
  payload: " ",
469
458
  position: r,
470
- text: a,
459
+ text: l,
471
460
  actionCode: c
472
461
  });
473
462
  }
@@ -479,106 +468,106 @@ const xe = [
479
468
  return;
480
469
  }
481
470
  if (r.type !== "customTag") return;
482
- const a = (T = r.attrs) == null ? void 0 : T.categ, c = (E = r.attrs) == null ? void 0 : E.payload, i = n.length, u = A(r), g = l[a];
471
+ const l = (T = r.attrs) == null ? void 0 : T.categ, c = (E = r.attrs) == null ? void 0 : E.payload, i = n.length, u = P(r), p = a[l];
483
472
  u && s.push({
484
473
  start: i,
485
474
  end: i + u.length
486
- }), g && g({
475
+ }), p && p({
487
476
  payload: c,
488
477
  position: i,
489
478
  text: u,
490
- actionCode: a
479
+ actionCode: l
491
480
  }), n += u;
492
481
  }), {
493
482
  text: n,
494
483
  protectedRanges: s,
495
484
  playments: o
496
485
  };
497
- }, N = (e) => e.type === "text" || e.type === "customTag", ie = (e) => {
486
+ }, b = (e) => e.type === "text" || e.type === "customTag", ae = (e) => {
498
487
  const t = e.content || [];
499
488
  if (e.type === "paragraph") return [e];
500
489
  if (e.type === "doc")
501
490
  return t.filter((o) => o.type === "paragraph");
502
491
  const n = t.filter((o) => o.type === "paragraph");
503
- return n.length ? n : t.some(N) ? [
492
+ return n.length ? n : t.some(b) ? [
504
493
  {
505
494
  type: "paragraph",
506
- content: t.filter(N)
495
+ content: t.filter(b)
507
496
  }
508
497
  ] : [];
509
- }, ce = (e, t) => {
498
+ }, ie = (e, t) => {
510
499
  let n = 0;
511
500
  return t.map((o) => {
512
- const s = e.indexOf(o, n), l = s >= 0 ? s : n, r = l + o.length;
501
+ const s = e.indexOf(o, n), a = s >= 0 ? s : n, r = a + o.length;
513
502
  return n = r, {
514
503
  text: o,
515
- start: l,
504
+ start: a,
516
505
  end: r
517
506
  };
518
507
  });
519
- }, ue = (e, t) => e.reduce((n, o) => {
508
+ }, ce = (e, t) => e.reduce((n, o) => {
520
509
  if (t.some(
521
- (l) => o.start > l.start && o.start < l.end
510
+ (a) => o.start > a.start && o.start < a.end
522
511
  ) && n.length) {
523
- const l = n[n.length - 1];
524
- return l.text += o.text, l.end = o.end, n;
512
+ const a = n[n.length - 1];
513
+ return a.text += o.text, a.end = o.end, n;
525
514
  }
526
515
  return n.push({ ...o }), n;
527
- }, []), pe = (e, t, n, o) => e.position >= t && e.position < n ? !0 : !e.text && o && e.position === n, ge = (e) => {
528
- const t = ae(e.text);
516
+ }, []), ue = (e, t, n, o) => e.position >= t && e.position < n ? !0 : !e.text && o && e.position === n, ge = (e) => {
517
+ const t = se(e.text);
529
518
  if (t.length <= 1) return [e];
530
- const n = ue(
531
- ce(e.text, t),
519
+ const n = ce(
520
+ ie(e.text, t),
532
521
  e.protectedRanges || []
533
522
  );
534
523
  return n.map((o, s) => {
535
- const l = s === n.length - 1, r = e.playments.filter(
536
- (a) => pe(a, o.start, o.end, l)
537
- ).map((a) => ({
538
- ...a,
539
- position: a.position - o.start
524
+ const a = s === n.length - 1, r = e.playments.filter(
525
+ (l) => ue(l, o.start, o.end, a)
526
+ ).map((l) => ({
527
+ ...l,
528
+ position: l.position - o.start
540
529
  }));
541
530
  return {
542
531
  text: o.text,
543
532
  playments: r
544
533
  };
545
534
  });
546
- }, Re = (e) => {
535
+ }, ye = (e) => {
547
536
  const t = {
548
537
  playments: [],
549
538
  sentences: []
550
539
  };
551
- return ie(e).forEach((o) => {
540
+ return ae(e).forEach((o) => {
552
541
  const s = le(o);
553
- !s.text && !s.playments.length || ge(s).forEach(({ text: l, playments: r }) => {
554
- t.sentences.push(l), t.playments.push(r);
542
+ !s.text && !s.playments.length || ge(s).forEach(({ text: a, playments: r }) => {
543
+ t.sentences.push(a), t.playments.push(r);
555
544
  });
556
545
  }), t;
557
546
  };
558
547
  export {
559
548
  f as DeleteMode,
560
- fe as EditorConst,
561
- x as LanguageOptions,
549
+ pe as EditorConst,
550
+ _ as LanguageOptions,
562
551
  xe as NumberToTextTools,
563
- w as StopOptions,
564
- D as ToneOptions,
565
- p as ToolConfig,
566
- y as allToolTypes,
567
- Re as convertToTtsFormat,
568
- _e as estimateTtsDuration,
569
- Te as getDefaultLockPayload,
570
- be as getInitContent,
571
- Ee as getLockPayloadLabel,
552
+ v as StopOptions,
553
+ S as ToneOptions,
554
+ g as ToolConfig,
555
+ x as allToolTypes,
556
+ ye as convertToTtsFormat,
557
+ be as estimateTtsDuration,
558
+ de as getDefaultLockPayload,
559
+ me as getInitContent,
560
+ Te as getLockPayloadLabel,
572
561
  h as getVisualLength,
573
- he as isInsertTagType,
574
- de as isLockableTagType,
575
- me as resolveTtsEditorFeatures,
576
- ye as sanitizePastedHtml,
577
- Z as sanitizePastedText,
578
- ae as splitTextToSentences,
579
- z as toCardinal,
580
- q as toColloquial,
581
- Ne as toPhoneReading,
582
- O as toPositional,
562
+ fe as isInsertTagType,
563
+ he as isLockableTagType,
564
+ Ee as resolveTtsEditorFeatures,
565
+ Ne as sanitizePastedHtml,
566
+ q as sanitizePastedText,
567
+ se as splitTextToSentences,
568
+ U as toCardinal,
569
+ V as toColloquial,
570
+ _e as toPhoneReading,
571
+ y as toPositional,
583
572
  le as transformParagraph
584
573
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naersen/tts-rich-text",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "description": "Reusable Vue 3 rich-text editor for TTS workflows",
5
5
  "type": "module",
6
6
  "files": [