kindy-editor 3.2.7 → 3.2.9

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.
@@ -1,4 +1,4 @@
1
- import { p as u } from "./qrcode-B-JKix2T.js";
1
+ import { p as u } from "./qrcode-CR8i1-w0.js";
2
2
  function p(e) {
3
3
  return e.type ?? "paragraph";
4
4
  }
@@ -1,4 +1,4 @@
1
- import { p as j, c as _, e as F, t as k, D as L } from "./qrcode-B-JKix2T.js";
1
+ import { p as j, c as _, e as F, t as k, D as L } from "./qrcode-CR8i1-w0.js";
2
2
  const s = (e) => Math.round(e * 100) / 100;
3
3
  function A(e) {
4
4
  const o = { font: e.fontFamily, sizePx: e.fontSizePx };
@@ -332,7 +332,7 @@ function H(e, o = {}, r = {}) {
332
332
  if (i && e.search(i).total === 0)
333
333
  return e.searchClear(), f(`text not found: ${i}`);
334
334
  if (!e.getSelection()) return f("no selection (pass 'find' or select_range first)");
335
- const { insertText: d } = await import("./editorApp-BtDzRfJq.js").then((m) => m.c);
335
+ const { insertText: d } = await import("./kindy-editor-Bo4FnkLV.js").then((m) => m.c);
336
336
  return e.dispatch(d(t)), i && e.searchClear(), g("inserted");
337
337
  }
338
338
  }), a({
@@ -95,11 +95,13 @@ if (editor.canExecuteHostTableAction("deleteRow", { tableId: "table_1", row: 1 }
95
95
  ```
96
96
 
97
97
  #### 3. Nhập giá trị vào 1 ô (`setTableCellValue`)
98
- Cập nhật nội dung một ô theo tọa độ `(row, column)`. Tự động giữ nguyên định dạng cell/paragraph (font, kích thước, căn lề, màu sắc) và hỗ trợ xuống dòng:
98
+ Cập nhật nội dung một ô theo tọa độ `(row, column)`. Tự động giữ nguyên định dạng cell/paragraph (font, kích thước, căn lề, màu sắc), tăng `revision`, giải phóng layout cache của bảng, tự động phân trang lại khi kích thước hàng thay đổi và lên lịch repaint mượt mà qua `requestAnimationFrame`:
99
99
 
100
100
  ```ts
101
101
  await editor.setTableCellValue("table_1", 1, 2, "250.000 đ");
102
102
  ```
103
+ - **Không cần gọi `setDocument()`**: Thay đổi được áp dụng ngay lập tức mà không phải rebuild lại DOM editor.
104
+ - **Giữ nguyên trạng thái**: Bảo toàn `mode="view"`, vị trí scroll, zoom và vùng chọn ô (`cellSelection`).
103
105
 
104
106
  #### 4. Thay thế nhiều dòng dữ liệu cùng lúc (`replaceTableRows`)
105
107
  Cập nhật hàng loạt dòng dữ liệu trong một transaction nguyên tử (atomic update).
@@ -124,6 +126,17 @@ await editor.replaceTableRows(
124
126
  );
125
127
  ```
126
128
 
129
+ #### 5. Giải phóng Cache Layout thủ công (`invalidateLayout`)
130
+ Ép buộc giải phóng cache đo đạc layout của bảng hoặc toàn bộ tài liệu:
131
+
132
+ ```ts
133
+ // Giải phóng cache bảng và repaint
134
+ await editor.invalidateLayout("table_1");
135
+
136
+ // Hoặc giải phóng toàn bộ cache
137
+ await editor.invalidateLayout();
138
+ ```
139
+
127
140
  ## API tương tác canvas thông thường
128
141
 
129
142
  ```ts
@@ -568,11 +568,20 @@ const tables = editor.getTables();
568
568
 
569
569
  ### 10.3 Cập nhật giá trị ô (`editor.setTableCellValue()`)
570
570
 
571
+ Cập nhật nội dung một ô theo tọa độ `(row, column)`. Tự động tăng `revision`, giải phóng layout cache (`linesCache`, `tableCache`), tự động phân trang lại nếu chiều cao hàng thay đổi, và lên lịch repaint mượt mà qua `requestAnimationFrame`:
572
+
571
573
  ```ts
572
574
  // Cập nhật ô dòng 1, cột 2 (0-indexed)
573
575
  await editor.setTableCellValue("tbl_invoice", 1, 2, "Khám tổng quát");
574
576
  ```
575
577
 
578
+ ::: tip Tự động Repaint & Giữ Nguyên Viewport
579
+ - **Không cần gọi `setDocument()`**: Canvas sẽ tự động tính lại layout và repaint ngay sau khi gọi `setTableCellValue()`.
580
+ - **Bảo toàn trạng thái**: Giữ nguyên `mode="view"`, vị trí scroll, tỷ lệ zoom và vùng chọn ô (`cellSelection`).
581
+ - **Bảng tách nhiều trang (Multi-page Fragments)**: Nếu nội dung dài làm tăng chiều cao hàng và đẩy các hàng sang trang sau, hệ thống tự động phân trang lại và repaint tất cả các trang/fragment bị ảnh hưởng.
582
+ - **Kế thừa định dạng thông minh**: Khi thêm dòng hoặc nhập liệu vào dòng dữ liệu thông thường, hệ thống tự động ưu tiên kế thừa định dạng từ data row liền kề, không kế thừa kiểu chữ in đậm (`bold: false`) hay màu nền (`shading`) từ dòng tiêu đề (header) hoặc dòng tổng cộng (total/footer).
583
+ :::
584
+
576
585
  ### 10.4 Thay thế nhiều dòng dữ liệu một lần (`editor.replaceTableRows()`)
577
586
 
578
587
  Cập nhật hàng loạt dòng dữ liệu trong một transaction nguyên tử:
@@ -622,9 +631,49 @@ await editor.executeHostTableAction("mergeCells", {
622
631
  await editor.executeHostTableAction("deleteTable", "tbl_invoice");
623
632
  ```
624
633
 
634
+ ### 10.6 Giải phóng Cache Layout thủ công (`editor.invalidateLayout()`)
635
+
636
+ Nếu cần ép buộc làm mới cache đo đạc và vẽ lại một bảng hoặc toàn bộ tài liệu:
637
+
638
+ ```ts
639
+ // Xóa cache đo đạc của bảng cụ thể và repaint
640
+ await editor.invalidateLayout("tbl_invoice");
641
+
642
+ // Hoặc làm mới toàn bộ layout cache
643
+ await editor.invalidateLayout();
644
+ ```
645
+
646
+ ---
647
+
648
+ ## 11. Tối Ưu Hiệu Năng: Nhập Liệu Liên Tục Không Gây Giật
649
+
650
+ ::: warning Tuyệt đối không gọi `setDocument()` khi người dùng đang nhập Form
651
+ Phương thức `setDocument()` thực hiện hủy và tái tạo toàn bộ DOM của Editor (`editor.destroy()` + mount lại). Nếu gọi `setDocument()` trên mỗi sự kiện `input` / `change` của form, canvas sẽ bị nhấp nháy trắng, tụt FPS và nhảy vị trí cuộn.
652
+
653
+ **Hãy dùng `setTableCellValue()` kết hợp gom frame bằng `requestAnimationFrame`:**
654
+ :::
655
+
656
+ ```ts
657
+ let pendingRaf: number | null = null;
658
+ let pendingValue = "";
659
+
660
+ function onFormCellInput(newValue: string) {
661
+ pendingValue = newValue;
662
+ if (pendingRaf !== null) return;
663
+
664
+ pendingRaf = requestAnimationFrame(async () => {
665
+ pendingRaf = null;
666
+ await editor.setTableCellValue("tbl_invoice", 1, 2, pendingValue);
667
+ });
668
+ }
669
+ ```
670
+ Nhờ cơ chế này:
671
+ - Trình duyệt chỉ cập nhật cell và repaint 1 lần mỗi khung hình (60/120 FPS).
672
+ - Trải nghiệm nhập liệu ở Form ngoài sang Canvas đạt độ mượt mà tối đa.
673
+
625
674
  ---
626
675
 
627
- ## 11. Trải Nghiệm Trang Demo Trực Quan
676
+ ## 12. Trải Nghiệm Trang Demo Trực Quan
628
677
 
629
678
  Kindy Editor cung cấp sẵn trang demo tương tác đầy đủ các tính năng trên:
630
679
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kindy-editor",
3
- "version": "3.2.7",
3
+ "version": "3.2.9",
4
4
  "type": "module",
5
5
  "description": "Trình soạn thảo tài liệu Word chính xác, vẽ bằng canvas",
6
6
  "license": "MIT",
@@ -991,6 +991,8 @@ export interface EditorHandle {
991
991
  options?: ReplaceTableRowsOptions,
992
992
  ): boolean;
993
993
  getTables(): TableSummary[];
994
+ /** Invalidate layout cache (for a specific table or full relayout) and repaint. */
995
+ invalidateLayout(blockId?: string): void;
994
996
  // ---- review layer (track changes + comments) ----------------------------
995
997
  /** The current editor mode. */
996
998
  getMode(): EditMode;
@@ -1173,6 +1175,8 @@ export declare class KindyEditor {
1173
1175
  options?: ReplaceTableRowsOptions,
1174
1176
  ): Promise<boolean>;
1175
1177
  getTables(): TableSummary[];
1178
+ /** Invalidate layout cache (for a specific table or full relayout) and repaint. */
1179
+ invalidateLayout(blockId?: string): Promise<void>;
1176
1180
  getDocId(): string | null;
1177
1181
  getShareLink(): string | null;
1178
1182
  /** Render ephemeral highlight decorations for external comments/annotations.
@@ -1,376 +0,0 @@
1
- import { t as T } from "./qrcode-B-JKix2T.js";
2
- function y(c) {
3
- if (c.length === 0) return [];
4
- const e = /* @__PURE__ */ new Map();
5
- for (const s of c) {
6
- let t = e.get(s.blockId);
7
- t || (t = [], e.set(s.blockId, t)), t.push({ ...s });
8
- }
9
- const i = [];
10
- for (const [s, t] of e) {
11
- if (t.length === 0) continue;
12
- const r = [];
13
- for (const n of t) {
14
- if (r.length === 0) {
15
- r.push(n);
16
- continue;
17
- }
18
- const o = r[r.length - 1];
19
- if (o.action === "delete" && n.action === "insert" && o.offset === n.offset) {
20
- o.action = "replace", o.toText = n.toText;
21
- continue;
22
- }
23
- if (o.action === "replace" && n.action === "insert" && n.offset === o.offset + o.toText.length) {
24
- o.toText += n.toText;
25
- continue;
26
- }
27
- if (o.action === "insert" && n.action === "insert" && n.offset === o.offset + o.toText.length) {
28
- o.toText += n.toText;
29
- continue;
30
- }
31
- if (o.action === "delete" && n.action === "delete" && n.offset === o.offset) {
32
- o.fromText += n.fromText;
33
- continue;
34
- }
35
- if (o.action === "delete" && n.action === "delete" && n.offset + n.fromText.length === o.offset) {
36
- o.offset = n.offset, o.fromText = n.fromText + o.fromText;
37
- continue;
38
- }
39
- r.push(n);
40
- }
41
- for (const n of r)
42
- n.action === "replace" && n.fromText === n.toText || n.action === "insert" && n.toText.length === 0 || n.action === "delete" && n.fromText.length === 0 || i.push({
43
- action: n.action,
44
- blockId: s,
45
- offset: n.offset,
46
- fromText: n.fromText,
47
- toText: n.toText
48
- });
49
- }
50
- return i;
51
- }
52
- function v(c, e) {
53
- const i = new Map(Object.entries(e)), s = [];
54
- for (const t of c)
55
- if (t.type === "deleteRange") {
56
- const r = i.get(t.blockId) ?? "", n = Math.max(0, Math.min(t.start, r.length)), o = Math.max(n, Math.min(t.end, r.length)), l = r.slice(n, o);
57
- l.length > 0 && s.push({
58
- action: "delete",
59
- blockId: t.blockId,
60
- offset: n,
61
- fromText: l,
62
- toText: ""
63
- }), i.set(t.blockId, r.slice(0, n) + r.slice(o));
64
- } else if (t.type === "insertText") {
65
- const r = i.get(t.at.blockId) ?? "", n = Math.max(0, Math.min(t.at.offset, r.length));
66
- t.text.length > 0 && s.push({
67
- action: "insert",
68
- blockId: t.at.blockId,
69
- offset: n,
70
- fromText: "",
71
- toText: t.text
72
- }), i.set(
73
- t.at.blockId,
74
- r.slice(0, n) + t.text + r.slice(n)
75
- );
76
- } else if (t.type === "insertRuns") {
77
- const r = T(t.runs), n = i.get(t.at.blockId) ?? "", o = Math.max(0, Math.min(t.at.offset, n.length));
78
- r.length > 0 && s.push({
79
- action: "insert",
80
- blockId: t.at.blockId,
81
- offset: o,
82
- fromText: "",
83
- toText: r
84
- }), i.set(
85
- t.at.blockId,
86
- n.slice(0, o) + r + n.slice(o)
87
- );
88
- } else if (t.type === "setRuns") {
89
- const r = i.get(t.blockId) ?? "", n = T(t.runs);
90
- r !== n && s.push({
91
- action: "replace",
92
- blockId: t.blockId,
93
- offset: 0,
94
- fromText: r,
95
- toText: n
96
- }), i.set(t.blockId, n);
97
- } else if (t.type === "splitParagraph") {
98
- const r = i.get(t.at.blockId) ?? "", n = Math.max(0, Math.min(t.at.offset, r.length)), o = r.slice(0, n), l = r.slice(n);
99
- i.set(t.at.blockId, o), i.set(t.newBlockId, l);
100
- } else if (t.type === "removeBlock") {
101
- const r = i.get(t.blockId) ?? "";
102
- r.length > 0 && s.push({
103
- action: "delete",
104
- blockId: t.blockId,
105
- offset: 0,
106
- fromText: r,
107
- toText: ""
108
- }), i.set(t.blockId, "");
109
- }
110
- return y(s);
111
- }
112
- function b(c, e, i, s = 0) {
113
- if (c === e) return [];
114
- let t = 0;
115
- const r = Math.min(c.length, e.length);
116
- for (; t < r && c[t] === e[t]; )
117
- t++;
118
- let n = 0;
119
- const o = Math.min(c.length - t, e.length - t);
120
- for (; n < o && c[c.length - 1 - n] === e[e.length - 1 - n]; )
121
- n++;
122
- const l = c.slice(t, c.length - n), f = e.slice(t, e.length - n), d = s + t;
123
- return l.length > 0 && f.length === 0 ? [{ action: "delete", blockId: i, offset: d, fromText: l, toText: "" }] : l.length === 0 && f.length > 0 ? [{ action: "insert", blockId: i, offset: d, fromText: "", toText: f }] : l.length > 0 && f.length > 0 ? [{ action: "replace", blockId: i, offset: d, fromText: l, toText: f }] : [];
124
- }
125
- class S {
126
- detail;
127
- includeSelection;
128
- handlers = /* @__PURE__ */ new Map();
129
- anyHandlers = /* @__PURE__ */ new Set();
130
- sink;
131
- redact;
132
- onError;
133
- disposed = !1;
134
- constructor(e = {}) {
135
- this.detail = e.detail ?? "metadata", this.includeSelection = e.includeSelection ?? !1, this.sink = e.sink, this.redact = e.redact, this.onError = e.onError ?? ((i) => console.error("[kindy-editor:event]", i));
136
- }
137
- on(e, i, s = {}) {
138
- if (this.disposed || s.signal?.aborted) return () => {
139
- };
140
- let t = this.handlers.get(e);
141
- t || this.handlers.set(e, t = /* @__PURE__ */ new Set()), t.add(i);
142
- const r = () => {
143
- t?.delete(i), t?.size === 0 && this.handlers.delete(e);
144
- };
145
- return s.signal?.addEventListener("abort", r, { once: !0 }), r;
146
- }
147
- onAny(e, i = {}) {
148
- if (this.disposed || i.signal?.aborted) return () => {
149
- };
150
- this.anyHandlers.add(e);
151
- const s = () => {
152
- this.anyHandlers.delete(e);
153
- };
154
- return i.signal?.addEventListener("abort", s, { once: !0 }), s;
155
- }
156
- off(e, i) {
157
- this.handlers.get(e)?.delete(i);
158
- }
159
- /** Called by the editor runtime after state is already consistent. Public only
160
- * for custom bridges; normal integrations subscribe with on/onAny. */
161
- dispatch(e) {
162
- if (this.disposed) return;
163
- const i = this.redact ? this.redact(e) : e;
164
- if (i) {
165
- for (const s of this.handlers.get(i.type) ?? []) this.safeCall(s, i);
166
- for (const s of this.anyHandlers) this.safeCall(s, i);
167
- if (this.sink)
168
- try {
169
- Promise.resolve(this.sink(i)).catch((s) => this.reportError(s, i));
170
- } catch (s) {
171
- this.reportError(s, i);
172
- }
173
- }
174
- }
175
- destroy() {
176
- this.disposed = !0, this.handlers.clear(), this.anyHandlers.clear();
177
- }
178
- safeCall(e, i) {
179
- try {
180
- e(i);
181
- } catch (s) {
182
- this.reportError(s, i);
183
- }
184
- }
185
- reportError(e, i) {
186
- try {
187
- this.onError(e, i);
188
- } catch (s) {
189
- console.error("[kindy-editor:event:onError]", s);
190
- }
191
- }
192
- }
193
- function w(c) {
194
- const e = c.fetch ?? globalThis.fetch;
195
- if (!e) throw new Error("createHttpEventSink requires fetch");
196
- const i = Math.max(1, c.batchSize ?? 25), s = Math.max(10, c.flushIntervalMs ?? 1e3), t = Math.max(1, c.maxAttempts ?? 3);
197
- let r = [], n = null, o = Promise.resolve(), l = !1;
198
- const f = () => {
199
- n && clearTimeout(n), n = null;
200
- }, d = async () => {
201
- const a = typeof c.headers == "function" ? await c.headers() : c.headers, h = new Headers(a);
202
- return h.has("content-type") || h.set("content-type", "application/json"), h;
203
- }, p = async (a) => {
204
- let h;
205
- for (let g = 1; g <= t; g++)
206
- try {
207
- const m = await e(c.endpoint, {
208
- method: "POST",
209
- headers: await d(),
210
- body: JSON.stringify({ schemaVersion: a[0]?.schemaVersion ?? "1.0", events: a })
211
- });
212
- if (!m.ok) throw new Error(`event sink returned HTTP ${m.status}`);
213
- return;
214
- } catch (m) {
215
- h = m, g < t && await new Promise((I) => setTimeout(I, 100 * 2 ** (g - 1)));
216
- }
217
- c.onDeliveryError?.(h, a);
218
- }, u = async () => {
219
- if (f(), r.length === 0) return o;
220
- const a = r;
221
- r = [], o = o.then(() => p(a)), await o;
222
- }, x = ((a) => {
223
- l || c.eventTypes && !c.eventTypes.includes(a.type) || (r.push(a), r.length >= i ? u() : n || (n = setTimeout(() => void u(), s)));
224
- });
225
- return x.flush = u, x.destroy = async () => {
226
- l = !0, await u();
227
- }, x;
228
- }
229
- class k {
230
- idleMs;
231
- selectionJumpThreshold;
232
- constructor(e = {}) {
233
- this.idleMs = Math.max(100, e.idleMs ?? 1e3), this.selectionJumpThreshold = Math.max(1, e.selectionJumpThreshold ?? 2);
234
- }
235
- /**
236
- * Evaluates if a selection movement constitutes a boundary (e.g. jumped to another block
237
- * or moved far away from the active typing position).
238
- */
239
- shouldCommitOnSelectionChange(e, i, s, t) {
240
- return !e || s === null || t === null ? !1 : e !== s || i !== null && Math.abs(t - i) > this.selectionJumpThreshold;
241
- }
242
- }
243
- class B {
244
- policy;
245
- emit;
246
- getVersion;
247
- idGenerator;
248
- currentSession = null;
249
- idleTimer = null;
250
- disposed = !1;
251
- nextGroupId = 1;
252
- constructor(e) {
253
- this.policy = e.policy instanceof k ? e.policy : new k({
254
- ...typeof e.idleMs == "number" ? { idleMs: e.idleMs } : {},
255
- ...e.policy
256
- }), this.emit = e.emit, this.getVersion = e.getVersion ?? (() => 0), this.idGenerator = e.idGenerator ?? (() => `chg-${Date.now()}-${this.nextGroupId++}`);
257
- }
258
- /**
259
- * Tracks a raw applied change. Starts a new session or extends the active session.
260
- */
261
- trackChange(e) {
262
- if (this.disposed) return;
263
- this.currentSession && this.currentSession.origin !== e.origin && this.flush("origin-change");
264
- const i = e.version ?? this.getVersion();
265
- if (!this.currentSession) {
266
- const t = this.getVersion(), r = e.version ?? t;
267
- this.currentSession = {
268
- changeGroupId: this.idGenerator(),
269
- origin: e.origin,
270
- ...e.intent !== void 0 ? { intent: e.intent } : {},
271
- beforeVersion: t,
272
- afterVersion: r,
273
- lastTransactionId: e.transactionId,
274
- initialBlockTexts: /* @__PURE__ */ new Map(),
275
- currentBlockTexts: /* @__PURE__ */ new Map(),
276
- diffs: [],
277
- activeBlockId: e.selectionAfter?.focus.blockId ?? null,
278
- lastOffset: e.selectionAfter?.focus.offset ?? null
279
- };
280
- }
281
- const s = this.currentSession;
282
- if (s) {
283
- s.afterVersion = i, s.lastTransactionId = e.transactionId, e.intent !== void 0 && s.intent === void 0 && (s.intent = e.intent);
284
- for (const t of e.affectedBlockIds)
285
- if (!s.initialBlockTexts.has(t)) {
286
- const r = e.blockTextBefore?.[t] ?? "";
287
- s.initialBlockTexts.set(t, r), s.currentBlockTexts.set(t, r);
288
- }
289
- if (this.applyOpsToCurrentTexts(s.currentBlockTexts, e.ops), e.textDiffs && e.textDiffs.length > 0 && s.diffs.push(...e.textDiffs), e.selectionAfter && (s.activeBlockId = e.selectionAfter.focus.blockId, s.lastOffset = e.selectionAfter.focus.offset), e.origin === "paste" || e.origin === "command") {
290
- this.flush("explicit");
291
- return;
292
- }
293
- this.restartIdleTimer();
294
- }
295
- }
296
- /**
297
- * Signals a semantic boundary from the editor environment (blur, save, selection change, etc.).
298
- */
299
- notifyBoundary(e, i) {
300
- if (!(this.disposed || !this.currentSession)) {
301
- if (e === "selection-jump") {
302
- this.policy.shouldCommitOnSelectionChange(
303
- this.currentSession.activeBlockId,
304
- this.currentSession.lastOffset,
305
- i?.newBlockId ?? null,
306
- i?.newOffset ?? null
307
- ) && this.flush("selection-jump");
308
- return;
309
- }
310
- this.flush(e);
311
- }
312
- }
313
- /**
314
- * Flushes and commits the active session if one exists and contains non-trivial changes.
315
- */
316
- flush(e) {
317
- this.clearIdleTimer();
318
- const i = this.currentSession;
319
- if (!i) return;
320
- this.currentSession = null;
321
- const s = [];
322
- for (const [t, r] of i.initialBlockTexts) {
323
- const n = i.currentBlockTexts.get(t) ?? r;
324
- if (r !== n) {
325
- const o = b(r, n, t);
326
- s.push(...o);
327
- }
328
- }
329
- s.length !== 0 && this.emit({
330
- transactionId: i.lastTransactionId,
331
- changeGroupId: i.changeGroupId,
332
- beforeVersion: i.beforeVersion,
333
- afterVersion: i.afterVersion,
334
- origin: i.origin,
335
- textDiffs: s,
336
- ...i.intent ? { intent: i.intent } : {},
337
- affectedBlockIds: Array.from(i.initialBlockTexts.keys())
338
- });
339
- }
340
- destroy() {
341
- this.disposed || (this.flush("destroy"), this.disposed = !0);
342
- }
343
- applyOpsToCurrentTexts(e, i) {
344
- for (const s of i)
345
- if (s.type === "deleteRange") {
346
- const t = e.get(s.blockId) ?? "", r = Math.max(0, Math.min(s.start, t.length)), n = Math.max(r, Math.min(s.end, t.length));
347
- e.set(s.blockId, t.slice(0, r) + t.slice(n));
348
- } else if (s.type === "insertText") {
349
- const t = e.get(s.at.blockId) ?? "", r = Math.max(0, Math.min(s.at.offset, t.length));
350
- e.set(s.at.blockId, t.slice(0, r) + s.text + t.slice(r));
351
- } else if (s.type === "insertRuns") {
352
- const t = T(s.runs), r = e.get(s.at.blockId) ?? "", n = Math.max(0, Math.min(s.at.offset, r.length));
353
- e.set(s.at.blockId, r.slice(0, n) + t + r.slice(n));
354
- } else if (s.type === "setRuns")
355
- e.set(s.blockId, T(s.runs));
356
- else if (s.type === "splitParagraph") {
357
- const t = e.get(s.at.blockId) ?? "", r = Math.max(0, Math.min(s.at.offset, t.length));
358
- e.set(s.at.blockId, t.slice(0, r)), e.set(s.newBlockId, t.slice(r));
359
- } else s.type === "removeBlock" && e.set(s.blockId, "");
360
- }
361
- restartIdleTimer() {
362
- this.clearIdleTimer(), this.idleTimer = setTimeout(() => {
363
- this.flush("idle");
364
- }, this.policy.idleMs);
365
- }
366
- clearIdleTimer() {
367
- this.idleTimer && (clearTimeout(this.idleTimer), this.idleTimer = null);
368
- }
369
- }
370
- export {
371
- B as C,
372
- S as E,
373
- k as a,
374
- v as b,
375
- w as c
376
- };