dishui 0.0.72 β†’ 0.0.73

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.
Files changed (93) hide show
  1. package/dist/components/Button/index.d.ts +4 -4
  2. package/dist/components/Button/index.js +18 -17
  3. package/dist/components/Button/index.js.map +1 -1
  4. package/dist/components/Card/Metric.d.ts +17 -0
  5. package/dist/components/Card/Metric2.js +50 -0
  6. package/dist/components/Card/Metric2.js.map +1 -0
  7. package/dist/components/Card/index.d.ts +3 -0
  8. package/dist/components/Card/index.js +118 -117
  9. package/dist/components/Card/index.js.map +1 -1
  10. package/dist/components/Group/index.d.ts +2 -0
  11. package/dist/components/GroupButton/index.d.ts +16 -0
  12. package/dist/components/GroupButton/index.js +41 -0
  13. package/dist/components/GroupButton/index.js.map +1 -0
  14. package/dist/components/GroupedTable/index.d.ts +38 -0
  15. package/dist/components/GroupedTable/index.js +92 -0
  16. package/dist/components/GroupedTable/index.js.map +1 -0
  17. package/dist/components/Layout/index.d.ts +4 -2
  18. package/dist/components/Layout/index.js +1 -1
  19. package/dist/components/Layout/index.js.map +1 -1
  20. package/dist/components/NavigationList/index.d.ts +17 -0
  21. package/dist/components/NavigationList/index.js +48 -0
  22. package/dist/components/NavigationList/index.js.map +1 -0
  23. package/dist/components/Section/index.d.ts +28 -0
  24. package/dist/components/Section/index.js +58 -0
  25. package/dist/components/Section/index.js.map +1 -0
  26. package/dist/components/Select/index.d.ts +2 -0
  27. package/dist/components/Select/index.js +83 -82
  28. package/dist/components/Select/index.js.map +1 -1
  29. package/dist/components/SidebarToggleButton/index.d.ts +16 -1
  30. package/dist/components/SidebarToggleButton/index.js +90 -30
  31. package/dist/components/SidebarToggleButton/index.js.map +1 -1
  32. package/dist/components/Skeleton/index.d.ts +7 -0
  33. package/dist/components/Skeleton/index.js +21 -0
  34. package/dist/components/Skeleton/index.js.map +1 -0
  35. package/dist/components/Tree/Tree.js +5 -2
  36. package/dist/components/Tree/Tree.js.map +1 -1
  37. package/dist/components/pro/RichTextEditor/AIRewrite.js +114 -72
  38. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  39. package/dist/components/pro/RichTextEditor/BlockHandle.js +315 -196
  40. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  41. package/dist/components/pro/RichTextEditor/BubbleToolbar.d.ts +1 -1
  42. package/dist/components/pro/RichTextEditor/BubbleToolbar.js +69 -33
  43. package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
  44. package/dist/components/pro/RichTextEditor/CommentPanel.d.ts +2 -1
  45. package/dist/components/pro/RichTextEditor/CommentPanel.js +100 -81
  46. package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
  47. package/dist/components/pro/RichTextEditor/CommentPopover.d.ts +2 -1
  48. package/dist/components/pro/RichTextEditor/CommentPopover.js +92 -68
  49. package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
  50. package/dist/components/pro/RichTextEditor/RichTextEditor.js +24 -22
  51. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  52. package/dist/components/pro/RichTextEditor/SearchReplace.d.ts +7 -0
  53. package/dist/components/pro/RichTextEditor/SlashMenu.js +136 -73
  54. package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
  55. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.d.ts +1 -1
  56. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js +346 -313
  57. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  58. package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js +114 -146
  59. package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
  60. package/dist/components/pro/RichTextEditor/extensions/CommentMark.js +2 -2
  61. package/dist/components/pro/RichTextEditor/extensions/CommentMark.js.map +1 -1
  62. package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js +178 -163
  63. package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
  64. package/dist/components/pro/RichTextEditor/extensions/FontSize.js +8 -5
  65. package/dist/components/pro/RichTextEditor/extensions/FontSize.js.map +1 -1
  66. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.d.ts +6 -0
  67. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js +85 -74
  68. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
  69. package/dist/components/pro/RichTextEditor/searchUtils.d.ts +23 -0
  70. package/dist/contexts/AppContext.js +47 -45
  71. package/dist/contexts/AppContext.js.map +1 -1
  72. package/dist/dishui.css +1 -1
  73. package/dist/index-nostyled.d.ts +11 -1
  74. package/dist/index.d.ts +11 -1
  75. package/dist/index.js +119 -114
  76. package/dist/layouts/MainLayout.js +9 -10
  77. package/dist/layouts/MainLayout.js.map +1 -1
  78. package/dist/layouts/Sidebar.d.ts +9 -0
  79. package/dist/layouts/Sidebar.js +99 -80
  80. package/dist/layouts/Sidebar.js.map +1 -1
  81. package/dist/layouts/headbar/Headbar.d.ts +1 -1
  82. package/dist/layouts/headbar/Headbar.js +2 -2
  83. package/dist/layouts/headbar/Headbar.js.map +1 -1
  84. package/dist/lite.d.ts +19 -1
  85. package/dist/lite.js +17 -8
  86. package/dist/styles/themeStyles.js +6 -6
  87. package/dist/styles/themeStyles.js.map +1 -1
  88. package/dist/utils/i18n.d.ts +3 -0
  89. package/dist/utils/i18n.js +78 -0
  90. package/dist/utils/i18n.js.map +1 -1
  91. package/dist/utils/menu.js +23 -6
  92. package/dist/utils/menu.js.map +1 -1
  93. package/package.json +8 -2
@@ -56,7 +56,32 @@ function l(e, t) {
56
56
  casual: "Rewrite the following text in a casual, friendly tone. Return only the rewritten text."
57
57
  }[e];
58
58
  }
59
- async function* u(e, t, n, r) {
59
+ async function* u(e) {
60
+ let t = e.body?.getReader();
61
+ if (!t) throw Error("No response body");
62
+ let n = new TextDecoder(), r = "", i = [];
63
+ try {
64
+ for (;;) {
65
+ let { done: e, value: a } = await t.read();
66
+ r += e ? n.decode() : n.decode(a, { stream: !0 });
67
+ let o;
68
+ for (; (o = r.indexOf("\n")) !== -1;) {
69
+ let e = r.slice(0, o).replace(/\r$/, "");
70
+ r = r.slice(o + 1), e ? e.startsWith("data:") && i.push(e.slice(5).replace(/^ /, "")) : (i.length && (yield i.join("\n")), i = []);
71
+ }
72
+ if (e) {
73
+ r.startsWith("data:") && i.push(r.slice(5).replace(/^ /, "").replace(/\r$/, "")), i.length && (yield i.join("\n"));
74
+ return;
75
+ }
76
+ }
77
+ } finally {
78
+ try {
79
+ await t.cancel();
80
+ } catch {}
81
+ t.releaseLock();
82
+ }
83
+ }
84
+ async function* d(e, t, n, r) {
60
85
  let i = JSON.stringify({
61
86
  model: e.model,
62
87
  messages: [{
@@ -78,25 +103,20 @@ async function* u(e, t, n, r) {
78
103
  signal: r
79
104
  });
80
105
  if (!a.ok) throw Error(`AI API error: ${a.status} ${a.statusText}`);
81
- let o = a.body?.getReader();
82
- if (!o) throw Error("No response body");
83
- let s = new TextDecoder(), c = "";
84
- for (;;) {
85
- let { done: e, value: t } = await o.read();
86
- if (e) break;
87
- c += s.decode(t, { stream: !0 });
88
- let n = c.split("\n");
89
- c = n.pop() || "";
90
- for (let e of n) {
91
- let t = e.trim();
92
- if (t && t !== "data: [DONE]" && t.startsWith("data: ")) try {
93
- let e = JSON.parse(t.slice(6)).choices?.[0]?.delta?.content;
94
- e && (yield e);
95
- } catch {}
106
+ for await (let e of u(a)) {
107
+ if (e.trim() === "[DONE]") return;
108
+ let t;
109
+ try {
110
+ t = JSON.parse(e);
111
+ } catch {
112
+ continue;
96
113
  }
114
+ if (t?.error) throw Error(t.error.message || "AI stream error");
115
+ let n = t?.choices?.[0]?.delta?.content;
116
+ typeof n == "string" && (yield n);
97
117
  }
98
118
  }
99
- async function* d(e, t, n, r) {
119
+ async function* f(e, t, n, r) {
100
120
  let i = JSON.stringify({
101
121
  model: e.model,
102
122
  max_tokens: 4096,
@@ -118,41 +138,59 @@ async function* d(e, t, n, r) {
118
138
  signal: r
119
139
  });
120
140
  if (!a.ok) throw Error(`AI API error: ${a.status} ${a.statusText}`);
121
- let o = a.body?.getReader();
122
- if (!o) throw Error("No response body");
123
- let s = new TextDecoder(), c = "";
124
- for (;;) {
125
- let { done: e, value: t } = await o.read();
126
- if (e) break;
127
- c += s.decode(t, { stream: !0 });
128
- let n = c.split("\n");
129
- c = n.pop() || "";
130
- for (let e of n) {
131
- let t = e.trim();
132
- if (t.startsWith("data: ")) try {
133
- let e = JSON.parse(t.slice(6));
134
- e.type === "content_block_delta" && e.delta?.text && (yield e.delta.text);
135
- } catch {}
141
+ for await (let e of u(a)) {
142
+ let t;
143
+ try {
144
+ t = JSON.parse(e);
145
+ } catch {
146
+ continue;
136
147
  }
148
+ if (t?.type === "error") throw Error(t.error?.message || "AI stream error");
149
+ if (t?.type === "message_stop") return;
150
+ t?.type === "content_block_delta" && typeof t.delta?.text == "string" && (yield t.delta.text);
137
151
  }
138
152
  }
139
- function f(e, t, n, r, i) {
140
- return e.protocol === "custom" && e.customHandler ? e.customHandler({
141
- text: t,
142
- action: r === "custom" ? "rewrite" : r,
143
- signal: i
144
- }) : e.protocol === "anthropic" ? d(e, t, n, i) : u(e, t, n, i);
153
+ function p(e, t, n, r, i) {
154
+ if (e.protocol === "custom") {
155
+ if (!e.customHandler) throw Error("Custom AI protocol requires customHandler");
156
+ return e.customHandler({
157
+ text: t,
158
+ action: r === "custom" ? "rewrite" : r,
159
+ signal: i
160
+ });
161
+ }
162
+ return e.protocol === "anthropic" ? f(e, t, n, i) : d(e, t, n, i);
145
163
  }
146
- var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRange: h, onClose: g }) => {
164
+ var m = ({ editor: u, aiConfig: d, labels: f, initialSelection: m, selectionRange: h, onClose: g }) => {
147
165
  let _ = {
148
166
  ...e,
149
- ...p
150
- }, [v, y] = i(""), [b, x] = i(!1), [S, C] = i(""), [w, T] = i(null), E = r(null), D = r(null), O = m;
167
+ ...f
168
+ }, [v, y] = i(""), [b, x] = i(!1), [S, C] = i(""), [w, T] = i(null), E = r(null), D = r(null), [O, k] = i(() => !u.isDestroyed && u.isEditable), [A, j] = i(!1), M = r(u.state.doc), N = r(!1), P = t(() => {
169
+ let e = E.current;
170
+ E.current = null, e?.abort();
171
+ }, []);
172
+ n(() => {
173
+ M.current = u.state.doc, N.current = !1, j(!1), C(""), x(!1), T(null);
174
+ let e = () => {
175
+ k(!u.isDestroyed && u.isEditable), (u.isDestroyed || !u.isEditable || u.state.doc !== M.current) && (N.current = !0, j(!0), P(), x(!1), C(""), T("The document or editing permissions changed. Close and reopen AI Assistant."));
176
+ };
177
+ return e(), u.on("update", e), u.on("transaction", e), u.on("destroy", e), () => {
178
+ P(), u.off("update", e), u.off("transaction", e), u.off("destroy", e);
179
+ };
180
+ }, [
181
+ u,
182
+ m,
183
+ h.from,
184
+ h.to,
185
+ P
186
+ ]);
187
+ let F = m;
151
188
  n(() => {
152
189
  D.current && D.current.focus();
153
190
  }, []);
154
- let k = t(async (e = "custom", t) => {
155
- let n = O || u.state.doc.textContent;
191
+ let I = t(async (e = "custom", t) => {
192
+ if (u.isDestroyed || !u.isEditable || N.current || E.current) return;
193
+ let n = F || u.state.doc.textContent;
156
194
  if (!n.trim() && !v.trim()) return;
157
195
  let r = e === "custom" ? v || "Improve the following text. Return only the improved text." : l(e, t), i = e === "custom" && v ? `Instructions: ${v}\n\nText:\n${n}` : n;
158
196
  x(!0), C(""), T(null);
@@ -160,38 +198,39 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
160
198
  E.current = a;
161
199
  try {
162
200
  let t = "";
163
- for await (let n of f(d, i, r, e, a.signal)) {
164
- if (a.signal.aborted) break;
201
+ for await (let n of p(d, i, r, e, a.signal)) {
202
+ if (a.signal.aborted || E.current !== a) break;
165
203
  t += n, C(t);
166
204
  }
167
205
  } catch (e) {
168
- if (e instanceof DOMException && e.name === "AbortError") return;
169
- T(String(e instanceof Error ? e.message : e));
206
+ if (a.signal.aborted || E.current !== a) return;
207
+ C(""), T(String(e instanceof Error ? e.message : e));
170
208
  } finally {
171
- x(!1);
209
+ E.current === a && (E.current = null, x(!1));
172
210
  }
173
211
  }, [
174
212
  u,
175
213
  d,
176
- O,
214
+ F,
177
215
  v
178
- ]), A = t(() => {
179
- if (!S) return;
216
+ ]), L = t(() => {
217
+ if (!S || E.current || u.isDestroyed || !u.isEditable || N.current) return;
180
218
  let { from: e, to: t } = h;
181
- e === t ? u.chain().focus().insertContent(S).run() : u.chain().focus().deleteRange({
182
- from: e,
183
- to: t
184
- }).insertContentAt(e, S).run(), C(""), y(""), g();
219
+ if (u.state.doc !== M.current || !Number.isInteger(e) || !Number.isInteger(t) || e < 0 || t < e || t > u.state.doc.content.size) {
220
+ T("The original selection is no longer valid. Close and reopen AI Assistant.");
221
+ return;
222
+ }
223
+ u.view.dispatch(u.state.tr.insertText(S, e, t)), C(""), y(""), g();
185
224
  }, [
186
225
  u,
187
226
  S,
188
227
  h,
189
228
  g
190
- ]), j = t(() => {
191
- E.current?.abort(), C(""), x(!1), T(null);
192
- }, []), M = t((e) => {
193
- e.key === "Enter" && (e.metaKey || e.ctrlKey) && (e.preventDefault(), k());
194
- }, [k]);
229
+ ]), R = t(() => {
230
+ P(), C(""), x(!1), T(null);
231
+ }, [P]), z = t((e) => {
232
+ e.key === "Enter" && (e.metaKey || e.ctrlKey) && (e.preventDefault(), I());
233
+ }, [I]);
195
234
  return /* @__PURE__ */ s("div", {
196
235
  className: "rte-ai-panel-v2",
197
236
  children: [
@@ -203,7 +242,9 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
203
242
  }), /* @__PURE__ */ o("button", {
204
243
  type: "button",
205
244
  className: "rte-ai-panel-v2__close-btn",
206
- onClick: g,
245
+ onClick: () => {
246
+ P(), g();
247
+ },
207
248
  title: "Close",
208
249
  children: /* @__PURE__ */ s("svg", {
209
250
  width: "14",
@@ -238,10 +279,10 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
238
279
  className: "rte-ai-panel-v2__prompt-input",
239
280
  value: v,
240
281
  onChange: (e) => y(e.target.value),
241
- onKeyDown: M,
282
+ onKeyDown: z,
242
283
  placeholder: "Describe what AI should do... (Ctrl+Enter to generate)",
243
284
  rows: 3,
244
- disabled: b
285
+ disabled: b || !O || A
245
286
  })]
246
287
  }),
247
288
  /* @__PURE__ */ s("div", {
@@ -251,7 +292,7 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
251
292
  children: "Selected Text"
252
293
  }), /* @__PURE__ */ o("div", {
253
294
  className: "rte-ai-panel-v2__selection-box",
254
- children: O ? /* @__PURE__ */ o("span", { children: O.length > 300 ? O.slice(0, 300) + "..." : O }) : /* @__PURE__ */ o("span", {
295
+ children: F ? /* @__PURE__ */ o("span", { children: F.length > 300 ? F.slice(0, 300) + "..." : F }) : /* @__PURE__ */ o("span", {
255
296
  className: "rte-ai-panel-v2__empty",
256
297
  children: "No text selected (will use all content)"
257
298
  })
@@ -262,8 +303,8 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
262
303
  children: c.map(({ key: e, labelKey: t, icon: n }) => /* @__PURE__ */ s("button", {
263
304
  type: "button",
264
305
  className: "rte-ai-panel-v2__quick-btn",
265
- onClick: () => k(e),
266
- disabled: b,
306
+ onClick: () => I(e),
307
+ disabled: b || !O || A,
267
308
  title: _[t],
268
309
  children: [/* @__PURE__ */ o("span", { children: n }), /* @__PURE__ */ o("span", { children: _[t] })]
269
310
  }, e))
@@ -273,8 +314,8 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
273
314
  children: [/* @__PURE__ */ o("button", {
274
315
  type: "button",
275
316
  className: "rte-ai-panel-v2__generate-btn",
276
- onClick: () => k(),
277
- disabled: b || !v.trim() && !O.trim(),
317
+ onClick: () => I(),
318
+ disabled: b || !O || A || !v.trim() && !F.trim(),
278
319
  children: b ? /* @__PURE__ */ s(a, { children: [
279
320
  /* @__PURE__ */ o("div", { className: "rte-ai-panel__spinner" }),
280
321
  " ",
@@ -283,7 +324,7 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
283
324
  }), b && /* @__PURE__ */ o("button", {
284
325
  type: "button",
285
326
  className: "rte-ai-panel-v2__cancel-btn",
286
- onClick: j,
327
+ onClick: R,
287
328
  children: "Cancel"
288
329
  })]
289
330
  }),
@@ -303,12 +344,13 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
303
344
  children: [/* @__PURE__ */ o("button", {
304
345
  type: "button",
305
346
  className: "rte-ai-panel-v2__accept-btn",
306
- onClick: A,
347
+ disabled: b || !O || A,
348
+ onClick: L,
307
349
  children: _.aiAccept
308
350
  }), /* @__PURE__ */ o("button", {
309
351
  type: "button",
310
352
  className: "rte-ai-panel-v2__reject-btn",
311
- onClick: j,
353
+ onClick: R,
312
354
  children: _.aiReject
313
355
  })]
314
356
  })
@@ -326,6 +368,6 @@ var p = ({ editor: u, aiConfig: d, labels: p, initialSelection: m, selectionRang
326
368
  });
327
369
  };
328
370
  //#endregion
329
- export { p as default };
371
+ export { m as default };
330
372
 
331
373
  //# sourceMappingURL=AIRewrite.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AIRewrite.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/AIRewrite.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { AIConfig, AIAction, RichTextEditorLabels } from './types';\nimport { defaultLabels } from './types';\n\ninterface AIRewriteProps {\n editor: Editor;\n aiConfig: AIConfig;\n labels?: RichTextEditorLabels;\n initialSelection: string;\n selectionRange: { from: number; to: number };\n onClose: () => void;\n}\n\nconst QUICK_ACTIONS: { key: AIAction; labelKey: keyof RichTextEditorLabels; icon: string }[] = [\n { key: 'rewrite', labelKey: 'aiRewrite', icon: '✏' },\n { key: 'shorten', labelKey: 'aiShorten', icon: 'πŸ“' },\n { key: 'expand', labelKey: 'aiExpand', icon: 'πŸ“„' },\n { key: 'fix_grammar', labelKey: 'aiFixGrammar', icon: 'βœ“' },\n { key: 'translate_en', labelKey: 'aiTranslateEn', icon: 'EN' },\n { key: 'translate_zh', labelKey: 'aiTranslateZh', icon: 'δΈ­' },\n { key: 'professional', labelKey: 'aiProfessional', icon: 'πŸ’Ό' },\n { key: 'casual', labelKey: 'aiCasual', icon: 'πŸ’¬' },\n];\n\nfunction getSystemPrompt(action: AIAction | 'custom', customPrompt?: string): string {\n if (action === 'custom') return customPrompt || 'Follow the user instructions.';\n const prompts: Record<AIAction, string> = {\n rewrite: 'Rewrite the following text to improve clarity and readability. Keep the same meaning and tone. Return only the rewritten text.',\n shorten: 'Shorten the following text while preserving its key meaning. Be concise. Return only the shortened text.',\n expand: 'Expand the following text with more details and examples while keeping the same tone. Return only the expanded text.',\n fix_grammar: 'Fix any grammar, spelling, and punctuation errors in the following text. Return only the corrected text.',\n translate_en: 'Translate the following text to English. Return only the translated text.',\n translate_zh: 'Translate the following text to Chinese. Return only the translated text.',\n professional: 'Rewrite the following text in a professional, formal tone. Return only the rewritten text.',\n casual: 'Rewrite the following text in a casual, friendly tone. Return only the rewritten text.',\n };\n return customPrompt || prompts[action];\n}\n\nasync function* streamOpenAI(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: text },\n ],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]' || !trimmed.startsWith('data: ')) continue;\n try {\n const data = JSON.parse(trimmed.slice(6));\n const content = data.choices?.[0]?.delta?.content;\n if (content) yield content;\n } catch { /* skip */ }\n }\n }\n}\n\nasync function* streamAnthropic(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: text }],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith('data: ')) continue;\n try {\n const data = JSON.parse(trimmed.slice(6));\n if (data.type === 'content_block_delta' && data.delta?.text) yield data.delta.text;\n } catch { /* skip */ }\n }\n }\n}\n\nfunction getStream(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n action: AIAction | 'custom',\n signal: AbortSignal,\n): AsyncIterable<string> {\n if (config.protocol === 'custom' && config.customHandler) {\n return config.customHandler({ text, action: action === 'custom' ? 'rewrite' : action, signal });\n }\n if (config.protocol === 'anthropic') return streamAnthropic(config, text, systemPrompt, signal);\n return streamOpenAI(config, text, systemPrompt, signal);\n}\n\nconst AIRewrite: React.FC<AIRewriteProps> = ({ editor, aiConfig, labels: propsLabels, initialSelection, selectionRange, onClose }) => {\n const labels = { ...defaultLabels, ...propsLabels };\n const [prompt, setPrompt] = useState('');\n const [isProcessing, setIsProcessing] = useState(false);\n const [streamedText, setStreamedText] = useState('');\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const promptRef = useRef<HTMLTextAreaElement>(null);\n\n const selectedText = initialSelection;\n\n useEffect(() => {\n if (promptRef.current) promptRef.current.focus();\n }, []);\n\n const handleGenerate = useCallback(async (action: AIAction | 'custom' = 'custom', customPromptOverride?: string) => {\n const text = selectedText || editor.state.doc.textContent;\n if (!text.trim() && !prompt.trim()) return;\n\n const systemPrompt = action === 'custom'\n ? (prompt || 'Improve the following text. Return only the improved text.')\n : getSystemPrompt(action, customPromptOverride);\n\n const userText = action === 'custom' && prompt\n ? `Instructions: ${prompt}\\n\\nText:\\n${text}`\n : text;\n\n setIsProcessing(true);\n setStreamedText('');\n setError(null);\n\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n let result = '';\n for await (const chunk of getStream(aiConfig, userText, systemPrompt, action, abort.signal)) {\n if (abort.signal.aborted) break;\n result += chunk;\n setStreamedText(result);\n }\n } catch (err: unknown) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n setError(String(err instanceof Error ? err.message : err));\n } finally {\n setIsProcessing(false);\n }\n }, [editor, aiConfig, selectedText, prompt]);\n\n const handleAccept = useCallback(() => {\n if (!streamedText) return;\n const { from, to } = selectionRange;\n if (from !== to) {\n editor.chain().focus().deleteRange({ from, to }).insertContentAt(from, streamedText).run();\n } else {\n editor.chain().focus().insertContent(streamedText).run();\n }\n setStreamedText('');\n setPrompt('');\n onClose();\n }, [editor, streamedText, selectionRange, onClose]);\n\n const handleReject = useCallback(() => {\n abortRef.current?.abort();\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n }, []);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleGenerate();\n }\n }, [handleGenerate]);\n\n return (\n <div className=\"rte-ai-panel-v2\">\n <div className=\"rte-ai-panel-v2__header\">\n <span className=\"rte-ai-panel-v2__title\">✨ {labels.ai || 'AI Assistant'}</span>\n <button type=\"button\" className=\"rte-ai-panel-v2__close-btn\" onClick={onClose} title=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n {/* Prompt input */}\n <div className=\"rte-ai-panel-v2__prompt-section\">\n <label className=\"rte-ai-panel-v2__label\">Prompt</label>\n <textarea\n ref={promptRef}\n className=\"rte-ai-panel-v2__prompt-input\"\n value={prompt}\n onChange={(e) => setPrompt(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Describe what AI should do... (Ctrl+Enter to generate)\"\n rows={3}\n disabled={isProcessing}\n />\n </div>\n\n {/* Selected text display */}\n <div className=\"rte-ai-panel-v2__selection-section\">\n <label className=\"rte-ai-panel-v2__label\">Selected Text</label>\n <div className=\"rte-ai-panel-v2__selection-box\">\n {selectedText ? (\n <span>{selectedText.length > 300 ? selectedText.slice(0, 300) + '...' : selectedText}</span>\n ) : (\n <span className=\"rte-ai-panel-v2__empty\">No text selected (will use all content)</span>\n )}\n </div>\n </div>\n\n {/* Quick actions */}\n <div className=\"rte-ai-panel-v2__quick-actions\">\n {QUICK_ACTIONS.map(({ key, labelKey, icon }) => (\n <button\n key={key}\n type=\"button\"\n className=\"rte-ai-panel-v2__quick-btn\"\n onClick={() => handleGenerate(key)}\n disabled={isProcessing}\n title={labels[labelKey]}\n >\n <span>{icon}</span>\n <span>{labels[labelKey]}</span>\n </button>\n ))}\n </div>\n\n {/* Generate button */}\n <div className=\"rte-ai-panel-v2__actions\">\n <button\n type=\"button\"\n className=\"rte-ai-panel-v2__generate-btn\"\n onClick={() => handleGenerate()}\n disabled={isProcessing || (!prompt.trim() && !selectedText.trim())}\n >\n {isProcessing ? (\n <><div className=\"rte-ai-panel__spinner\" /> {labels.aiProcessing}</>\n ) : (\n '✨ Generate'\n )}\n </button>\n {isProcessing && (\n <button type=\"button\" className=\"rte-ai-panel-v2__cancel-btn\" onClick={handleReject}>\n Cancel\n </button>\n )}\n </div>\n\n {/* Streaming result */}\n {streamedText && (\n <div className=\"rte-ai-panel-v2__result\">\n <label className=\"rte-ai-panel-v2__label\">Result</label>\n <div className=\"rte-ai-panel-v2__result-text\">{streamedText}</div>\n <div className=\"rte-ai-panel-v2__result-actions\">\n <button type=\"button\" className=\"rte-ai-panel-v2__accept-btn\" onClick={handleAccept}>\n {labels.aiAccept}\n </button>\n <button type=\"button\" className=\"rte-ai-panel-v2__reject-btn\" onClick={handleReject}>\n {labels.aiReject}\n </button>\n </div>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"rte-ai-panel-v2__error\">\n <span>{error}</span>\n <button type=\"button\" onClick={() => setError(null)}>Dismiss</button>\n </div>\n )}\n </div>\n );\n};\n\nexport default AIRewrite;\n"],"mappings":"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"}
1
+ {"version":3,"file":"AIRewrite.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/AIRewrite.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { AIConfig, AIAction, RichTextEditorLabels } from './types';\nimport { defaultLabels } from './types';\n\ninterface AIRewriteProps {\n editor: Editor;\n aiConfig: AIConfig;\n labels?: RichTextEditorLabels;\n initialSelection: string;\n selectionRange: { from: number; to: number };\n onClose: () => void;\n}\n\nconst QUICK_ACTIONS: { key: AIAction; labelKey: keyof RichTextEditorLabels; icon: string }[] = [\n { key: 'rewrite', labelKey: 'aiRewrite', icon: '✏' },\n { key: 'shorten', labelKey: 'aiShorten', icon: 'πŸ“' },\n { key: 'expand', labelKey: 'aiExpand', icon: 'πŸ“„' },\n { key: 'fix_grammar', labelKey: 'aiFixGrammar', icon: 'βœ“' },\n { key: 'translate_en', labelKey: 'aiTranslateEn', icon: 'EN' },\n { key: 'translate_zh', labelKey: 'aiTranslateZh', icon: 'δΈ­' },\n { key: 'professional', labelKey: 'aiProfessional', icon: 'πŸ’Ό' },\n { key: 'casual', labelKey: 'aiCasual', icon: 'πŸ’¬' },\n];\n\nfunction getSystemPrompt(action: AIAction | 'custom', customPrompt?: string): string {\n if (action === 'custom') return customPrompt || 'Follow the user instructions.';\n const prompts: Record<AIAction, string> = {\n rewrite: 'Rewrite the following text to improve clarity and readability. Keep the same meaning and tone. Return only the rewritten text.',\n shorten: 'Shorten the following text while preserving its key meaning. Be concise. Return only the shortened text.',\n expand: 'Expand the following text with more details and examples while keeping the same tone. Return only the expanded text.',\n fix_grammar: 'Fix any grammar, spelling, and punctuation errors in the following text. Return only the corrected text.',\n translate_en: 'Translate the following text to English. Return only the translated text.',\n translate_zh: 'Translate the following text to Chinese. Return only the translated text.',\n professional: 'Rewrite the following text in a professional, formal tone. Return only the rewritten text.',\n casual: 'Rewrite the following text in a casual, friendly tone. Return only the rewritten text.',\n };\n return customPrompt || prompts[action];\n}\n\nasync function* readSSE(response: Response): AsyncGenerator<string> {\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n const decoder = new TextDecoder();\n let buffer = '';\n let data: string[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n // Normalize CRLF only when the complete line is available (chunks may split it).\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newline).replace(/\\r$/, '');\n buffer = buffer.slice(newline + 1);\n if (!line) {\n if (data.length) yield data.join('\\n');\n data = [];\n } else if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (done) {\n if (buffer.startsWith('data:')) data.push(buffer.slice(5).replace(/^ /, '').replace(/\\r$/, ''));\n if (data.length) yield data.join('\\n');\n return;\n }\n }\n } finally {\n try { await reader.cancel(); } catch { /* The request may already be aborted. */ }\n reader.releaseLock();\n }\n}\n\nasync function* streamOpenAI(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: text },\n ],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n for await (const payload of readSSE(response)) {\n if (payload.trim() === '[DONE]') return;\n let data;\n try { data = JSON.parse(payload); } catch { continue; }\n if (data?.error) throw new Error(data.error.message || 'AI stream error');\n const content = data?.choices?.[0]?.delta?.content;\n if (typeof content === 'string') yield content;\n }\n}\n\nasync function* streamAnthropic(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: text }],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n for await (const payload of readSSE(response)) {\n let data;\n try { data = JSON.parse(payload); } catch { continue; }\n if (data?.type === 'error') throw new Error(data.error?.message || 'AI stream error');\n if (data?.type === 'message_stop') return;\n if (data?.type === 'content_block_delta' && typeof data.delta?.text === 'string') yield data.delta.text;\n }\n}\n\nfunction getStream(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n action: AIAction | 'custom',\n signal: AbortSignal,\n): AsyncIterable<string> {\n if (config.protocol === 'custom') {\n if (!config.customHandler) throw new Error('Custom AI protocol requires customHandler');\n return config.customHandler({ text, action: action === 'custom' ? 'rewrite' : action, signal });\n }\n if (config.protocol === 'anthropic') return streamAnthropic(config, text, systemPrompt, signal);\n return streamOpenAI(config, text, systemPrompt, signal);\n}\n\nconst AIRewrite: React.FC<AIRewriteProps> = ({ editor, aiConfig, labels: propsLabels, initialSelection, selectionRange, onClose }) => {\n const labels = { ...defaultLabels, ...propsLabels };\n const [prompt, setPrompt] = useState('');\n const [isProcessing, setIsProcessing] = useState(false);\n const [streamedText, setStreamedText] = useState('');\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const promptRef = useRef<HTMLTextAreaElement>(null);\n const [editable, setEditable] = useState(() => !editor.isDestroyed && editor.isEditable);\n const [invalid, setInvalid] = useState(false);\n const sourceDoc = useRef(editor.state.doc);\n const invalidRef = useRef(false);\n\n const cancelRequest = useCallback(() => {\n const request = abortRef.current;\n abortRef.current = null;\n request?.abort();\n }, []);\n\n useEffect(() => {\n sourceDoc.current = editor.state.doc;\n invalidRef.current = false;\n setInvalid(false);\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n const invalidate = () => {\n setEditable(!editor.isDestroyed && editor.isEditable);\n if (editor.isDestroyed || !editor.isEditable || editor.state.doc !== sourceDoc.current) {\n invalidRef.current = true;\n setInvalid(true);\n cancelRequest();\n setIsProcessing(false);\n setStreamedText('');\n setError('The document or editing permissions changed. Close and reopen AI Assistant.');\n }\n };\n invalidate();\n editor.on('update', invalidate);\n editor.on('transaction', invalidate);\n editor.on('destroy', invalidate);\n return () => {\n cancelRequest();\n editor.off('update', invalidate);\n editor.off('transaction', invalidate);\n editor.off('destroy', invalidate);\n };\n }, [editor, initialSelection, selectionRange.from, selectionRange.to, cancelRequest]);\n\n const selectedText = initialSelection;\n\n useEffect(() => {\n if (promptRef.current) promptRef.current.focus();\n }, []);\n\n const handleGenerate = useCallback(async (action: AIAction | 'custom' = 'custom', customPromptOverride?: string) => {\n if (editor.isDestroyed || !editor.isEditable || invalidRef.current || abortRef.current) return;\n const text = selectedText || editor.state.doc.textContent;\n if (!text.trim() && !prompt.trim()) return;\n\n const systemPrompt = action === 'custom'\n ? (prompt || 'Improve the following text. Return only the improved text.')\n : getSystemPrompt(action, customPromptOverride);\n\n const userText = action === 'custom' && prompt\n ? `Instructions: ${prompt}\\n\\nText:\\n${text}`\n : text;\n\n setIsProcessing(true);\n setStreamedText('');\n setError(null);\n\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n let result = '';\n for await (const chunk of getStream(aiConfig, userText, systemPrompt, action, abort.signal)) {\n if (abort.signal.aborted || abortRef.current !== abort) break;\n result += chunk;\n setStreamedText(result);\n }\n } catch (err: unknown) {\n if (abort.signal.aborted || abortRef.current !== abort) return;\n setStreamedText('');\n setError(String(err instanceof Error ? err.message : err));\n } finally {\n if (abortRef.current === abort) {\n abortRef.current = null;\n setIsProcessing(false);\n }\n }\n }, [editor, aiConfig, selectedText, prompt]);\n\n const handleAccept = useCallback(() => {\n if (!streamedText || abortRef.current || editor.isDestroyed || !editor.isEditable || invalidRef.current) return;\n const { from, to } = selectionRange;\n if (editor.state.doc !== sourceDoc.current || !Number.isInteger(from) || !Number.isInteger(to) || from < 0 || to < from || to > editor.state.doc.content.size) {\n setError('The original selection is no longer valid. Close and reopen AI Assistant.');\n return;\n }\n // AI output is plain text, never HTML. Use the captured range even if the cursor moved.\n editor.view.dispatch(editor.state.tr.insertText(streamedText, from, to));\n setStreamedText('');\n setPrompt('');\n onClose();\n }, [editor, streamedText, selectionRange, onClose]);\n\n const handleReject = useCallback(() => {\n cancelRequest();\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n }, [cancelRequest]);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleGenerate();\n }\n }, [handleGenerate]);\n\n return (\n <div className=\"rte-ai-panel-v2\">\n <div className=\"rte-ai-panel-v2__header\">\n <span className=\"rte-ai-panel-v2__title\">✨ {labels.ai || 'AI Assistant'}</span>\n <button type=\"button\" className=\"rte-ai-panel-v2__close-btn\" onClick={() => { cancelRequest(); onClose(); }} title=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n {/* Prompt input */}\n <div className=\"rte-ai-panel-v2__prompt-section\">\n <label className=\"rte-ai-panel-v2__label\">Prompt</label>\n <textarea\n ref={promptRef}\n className=\"rte-ai-panel-v2__prompt-input\"\n value={prompt}\n onChange={(e) => setPrompt(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Describe what AI should do... (Ctrl+Enter to generate)\"\n rows={3}\n disabled={isProcessing || !editable || invalid}\n />\n </div>\n\n {/* Selected text display */}\n <div className=\"rte-ai-panel-v2__selection-section\">\n <label className=\"rte-ai-panel-v2__label\">Selected Text</label>\n <div className=\"rte-ai-panel-v2__selection-box\">\n {selectedText ? (\n <span>{selectedText.length > 300 ? selectedText.slice(0, 300) + '...' : selectedText}</span>\n ) : (\n <span className=\"rte-ai-panel-v2__empty\">No text selected (will use all content)</span>\n )}\n </div>\n </div>\n\n {/* Quick actions */}\n <div className=\"rte-ai-panel-v2__quick-actions\">\n {QUICK_ACTIONS.map(({ key, labelKey, icon }) => (\n <button\n key={key}\n type=\"button\"\n className=\"rte-ai-panel-v2__quick-btn\"\n onClick={() => handleGenerate(key)}\n disabled={isProcessing || !editable || invalid}\n title={labels[labelKey]}\n >\n <span>{icon}</span>\n <span>{labels[labelKey]}</span>\n </button>\n ))}\n </div>\n\n {/* Generate button */}\n <div className=\"rte-ai-panel-v2__actions\">\n <button\n type=\"button\"\n className=\"rte-ai-panel-v2__generate-btn\"\n onClick={() => handleGenerate()}\n disabled={isProcessing || !editable || invalid || (!prompt.trim() && !selectedText.trim())}\n >\n {isProcessing ? (\n <><div className=\"rte-ai-panel__spinner\" /> {labels.aiProcessing}</>\n ) : (\n '✨ Generate'\n )}\n </button>\n {isProcessing && (\n <button type=\"button\" className=\"rte-ai-panel-v2__cancel-btn\" onClick={handleReject}>\n Cancel\n </button>\n )}\n </div>\n\n {/* Streaming result */}\n {streamedText && (\n <div className=\"rte-ai-panel-v2__result\">\n <label className=\"rte-ai-panel-v2__label\">Result</label>\n <div className=\"rte-ai-panel-v2__result-text\">{streamedText}</div>\n <div className=\"rte-ai-panel-v2__result-actions\">\n <button type=\"button\" className=\"rte-ai-panel-v2__accept-btn\" disabled={isProcessing || !editable || invalid} onClick={handleAccept}>\n {labels.aiAccept}\n </button>\n <button type=\"button\" className=\"rte-ai-panel-v2__reject-btn\" onClick={handleReject}>\n {labels.aiReject}\n </button>\n </div>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"rte-ai-panel-v2__error\">\n <span>{error}</span>\n <button type=\"button\" onClick={() => setError(null)}>Dismiss</button>\n </div>\n )}\n </div>\n );\n};\n\nexport default AIRewrite;\n"],"mappings":"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"}