ct-rich-text-editor 1.3.0 → 1.3.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.
Files changed (41) hide show
  1. package/dist/assets/style.css +372 -187
  2. package/dist/{babel-d155920e.js → babel-d3085146.js} +3565 -3292
  3. package/dist/babel-d3085146.js.map +1 -0
  4. package/dist/components/CodeActionMenuPlugin/utils.d.ts +1 -1
  5. package/dist/{estree-b1fff53b.js → estree-164983f6.js} +1763 -1778
  6. package/dist/estree-164983f6.js.map +1 -0
  7. package/dist/hooks/useDebounce.d.ts +1 -1
  8. package/dist/{html-f95ee5dc.js → html-5586dbf6.js} +701 -656
  9. package/dist/html-5586dbf6.js.map +1 -0
  10. package/dist/{html2pdf.bundle-0fecc54c.js → html2pdf.bundle-f23e1b00.js} +2 -2
  11. package/dist/html2pdf.bundle-f23e1b00.js.map +1 -0
  12. package/dist/{html2pdf.bundle.min-d9d93bc1.js → html2pdf.bundle.min-daf952fb.js} +2 -2
  13. package/dist/html2pdf.bundle.min-daf952fb.js.map +1 -0
  14. package/dist/{index-113e3eb2.js → index-10f9d057.js} +7 -11
  15. package/dist/index-10f9d057.js.map +1 -0
  16. package/dist/{index-7aab7b5a.js → index-8d147c36.js} +1041 -602
  17. package/dist/index-8d147c36.js.map +1 -0
  18. package/dist/index.js +1 -1
  19. package/dist/{markdown-1d9e6c3f.js → markdown-d513479b.js} +1836 -1789
  20. package/dist/markdown-d513479b.js.map +1 -0
  21. package/dist/plugins/CombinedAutocompletGrammarPlugin.d.ts +22 -0
  22. package/dist/{postcss-c2592f3f.js → postcss-f084f74d.js} +1378 -1357
  23. package/dist/postcss-f084f74d.js.map +1 -0
  24. package/dist/standalone-5a8c6b7e.js +2518 -0
  25. package/dist/standalone-5a8c6b7e.js.map +1 -0
  26. package/dist/typescript-b1005db4.js +13705 -0
  27. package/dist/typescript-b1005db4.js.map +1 -0
  28. package/package.json +1 -1
  29. package/dist/babel-d155920e.js.map +0 -1
  30. package/dist/estree-b1fff53b.js.map +0 -1
  31. package/dist/html-f95ee5dc.js.map +0 -1
  32. package/dist/html2pdf.bundle-0fecc54c.js.map +0 -1
  33. package/dist/html2pdf.bundle.min-d9d93bc1.js.map +0 -1
  34. package/dist/index-113e3eb2.js.map +0 -1
  35. package/dist/index-7aab7b5a.js.map +0 -1
  36. package/dist/markdown-1d9e6c3f.js.map +0 -1
  37. package/dist/postcss-c2592f3f.js.map +0 -1
  38. package/dist/standalone-bcc7f37a.js +0 -2649
  39. package/dist/standalone-bcc7f37a.js.map +0 -1
  40. package/dist/typescript-48c10f50.js +0 -13601
  41. package/dist/typescript-48c10f50.js.map +0 -1
@@ -21,17 +21,17 @@ import { ListPlugin } from "@lexical/react/LexicalListPlugin";
21
21
  import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
22
22
  import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
23
23
  import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
24
- import { $findMatchingParent, $getNearestNodeOfType, mergeRegister, $getNearestBlockElementAncestorOrThrow, $insertNodeToNearestRoot, $wrapNodeInElement, $isEditorIsNestedEditor, calculateZoomLevel, CAN_USE_DOM } from "@lexical/utils";
24
+ import { $findMatchingParent, $getNearestNodeOfType, mergeRegister, $getNearestBlockElementAncestorOrThrow, $insertNodeToNearestRoot, $wrapNodeInElement, $isEditorIsNestedEditor, mediaFileReader, isMimeType, calculateZoomLevel, CAN_USE_DOM } from "@lexical/utils";
25
25
  import Stack from "@mui/material/Stack";
26
- import { createCommand, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $insertNodes, $getNearestNodeFromDOMNode, $setSelection, isHTMLElement as isHTMLElement$1, TextNode, $applyNodeReplacement, $getRoot, $createTextNode, $getNodeByKey, DecoratorNode, createEditor, COMMAND_PRIORITY_EDITOR, $createParagraphNode, $isRootOrShadowRoot, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, UNDO_COMMAND, REDO_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, CLICK_COMMAND, getDOMSelection, COMMAND_PRIORITY_HIGH, $isLineBreakNode, isDOMNode } from "lexical";
26
+ import { createCommand, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $insertNodes, $getNearestNodeFromDOMNode, $setSelection, isHTMLElement as isHTMLElement$1, TextNode, $applyNodeReplacement, $getRoot, $createTextNode, $getNodeByKey, DecoratorNode, createEditor, COMMAND_PRIORITY_EDITOR, $createParagraphNode, $isRootOrShadowRoot, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, UNDO_COMMAND, REDO_COMMAND, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, CLICK_COMMAND, getDOMSelection, COMMAND_PRIORITY_HIGH, $isLineBreakNode, PASTE_COMMAND, isDOMNode } from "lexical";
27
27
  import * as ReactDOM from "react-dom";
28
28
  import ReactDOM__default, { createPortal } from "react-dom";
29
29
  import { $isCodeNode, CodeNode, normalizeCodeLang, getLanguageFriendlyName, CodeHighlightNode, CODE_LANGUAGE_MAP, $createCodeNode, registerCodeHighlighting, $isCodeHighlightNode } from "@lexical/code";
30
30
  import { LinkNode, $isLinkNode, TOGGLE_LINK_COMMAND, $createLinkNode, $isAutoLinkNode } from "@lexical/link";
31
- import { ListNode, ListItemNode, $isListNode, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND } from "@lexical/list";
32
- import { HeadingNode, QuoteNode, $isHeadingNode, $createHeadingNode, $createQuoteNode } from "@lexical/rich-text";
31
+ import { ListNode, ListItemNode, $isListNode, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, $createListNode, $createListItemNode } from "@lexical/list";
32
+ import { HeadingNode, QuoteNode, $isHeadingNode, $createHeadingNode, $createQuoteNode, DRAG_DROP_PASTE } from "@lexical/rich-text";
33
33
  import { $isAtNodeEnd, $selectAll, $patchStyleText, $setBlocksType, $isParentElementRTL, $getSelectionStyleValueForProperty } from "@lexical/selection";
34
- import { TableNode, TableCellNode, TableRowNode, $createTableNodeWithDimensions, TableCellHeaderStates, $isTableNode, $isTableSelection, $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, getTableElement, getTableObserverFromTableElement, $isTableCellNode, $insertTableRow__EXPERIMENTAL, $insertTableColumn__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL, $getTableRowIndexFromTableCellNode, $isTableRowNode, $getTableColumnIndexFromTableCellNode, $getNodeTriplet, $unmergeCell, $computeTableMapSkipCellCheck, getDOMCellFromTarget, $getTableAndElementByKey } from "@lexical/table";
34
+ import { TableNode, TableCellNode, TableRowNode, $createTableNodeWithDimensions, TableCellHeaderStates, $isTableNode, $isTableSelection, $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, getTableElement, getTableObserverFromTableElement, $isTableCellNode, $insertTableRow__EXPERIMENTAL, $insertTableColumn__EXPERIMENTAL, $getNodeTriplet, $isTableRowNode, $deleteTableRow__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL, $getTableRowIndexFromTableCellNode, $getTableColumnIndexFromTableCellNode, $unmergeCell, $computeTableMapSkipCellCheck, getDOMCellFromTarget, $getTableAndElementByKey } from "@lexical/table";
35
35
  import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode";
36
36
  import DescriptionIcon from "@mui/icons-material/Description";
37
37
  import FolderZipIcon from "@mui/icons-material/FolderZip";
@@ -7822,16 +7822,16 @@ function CopyButton({ editor, getCodeDOMNode }) {
7822
7822
  }
7823
7823
  const index$4 = "";
7824
7824
  const PRETTIER_PARSER_MODULES = {
7825
- css: [() => import("./postcss-c2592f3f.js")],
7826
- html: [() => import("./html-f95ee5dc.js")],
7825
+ css: [() => import("./postcss-f084f74d.js")],
7826
+ html: [() => import("./html-5586dbf6.js")],
7827
7827
  js: [
7828
- () => import("./babel-d155920e.js"),
7829
- () => import("./estree-b1fff53b.js")
7828
+ () => import("./babel-d3085146.js"),
7829
+ () => import("./estree-164983f6.js")
7830
7830
  ],
7831
- markdown: [() => import("./markdown-1d9e6c3f.js")],
7831
+ markdown: [() => import("./markdown-d513479b.js")],
7832
7832
  typescript: [
7833
- () => import("./typescript-48c10f50.js"),
7834
- () => import("./estree-b1fff53b.js")
7833
+ () => import("./typescript-b1005db4.js"),
7834
+ () => import("./estree-164983f6.js")
7835
7835
  ]
7836
7836
  };
7837
7837
  async function loadPrettierParserByLang(lang) {
@@ -7842,7 +7842,7 @@ async function loadPrettierParserByLang(lang) {
7842
7842
  return modules;
7843
7843
  }
7844
7844
  async function loadPrettierFormat() {
7845
- const { format } = await import("./standalone-bcc7f37a.js");
7845
+ const { format } = await import("./standalone-5a8c6b7e.js");
7846
7846
  return format;
7847
7847
  }
7848
7848
  const PRETTIER_OPTIONS_BY_LANG = {
@@ -12717,10 +12717,10 @@ const PDF_CONFIG = {
12717
12717
  };
12718
12718
  const loadHtml2Pdf = async () => {
12719
12719
  try {
12720
- const mod = await import("./html2pdf.bundle.min-d9d93bc1.js").then((n) => n.h);
12720
+ const mod = await import("./html2pdf.bundle.min-daf952fb.js").then((n) => n.h);
12721
12721
  return (mod == null ? void 0 : mod.default) || mod;
12722
12722
  } catch {
12723
- const mod2 = await import("./html2pdf.bundle-0fecc54c.js").then((n) => n.h);
12723
+ const mod2 = await import("./html2pdf.bundle-f23e1b00.js").then((n) => n.h);
12724
12724
  return (mod2 == null ? void 0 : mod2.default) || mod2;
12725
12725
  }
12726
12726
  };
@@ -13927,7 +13927,7 @@ const EmbedComponent = ({ url, displayType, alignment, nodeKey }) => {
13927
13927
  }
13928
13928
  );
13929
13929
  };
13930
- const ImageView = React__default.lazy(() => import("./index-113e3eb2.js"));
13930
+ const ImageView = React__default.lazy(() => import("./index-10f9d057.js"));
13931
13931
  function isGoogleDocCheckboxImg(img) {
13932
13932
  return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
13933
13933
  }
@@ -16457,6 +16457,7 @@ function TableOptionPlugin() {
16457
16457
  htmlCell.style.setProperty("padding", "8px", "important");
16458
16458
  htmlCell.style.setProperty("border", "1px solid #ddd", "important");
16459
16459
  htmlCell.style.setProperty("font-weight", "bold", "important");
16460
+ htmlCell.style.setProperty("white-space", "nowrap", "important");
16460
16461
  }
16461
16462
  });
16462
16463
  }
@@ -16504,6 +16505,7 @@ function TableOptionPlugin() {
16504
16505
  for (let i2 = 0; i2 < cells.length; i2++) {
16505
16506
  const headingText = (columnHeadings[i2] || "").trim();
16506
16507
  const cellNode = cells[i2];
16508
+ cellNode.clear();
16507
16509
  if (headingText) {
16508
16510
  cellNode.append($createTextNode(headingText));
16509
16511
  }
@@ -16536,6 +16538,7 @@ function TableOptionPlugin() {
16536
16538
  htmlCell.style.setProperty("padding", "8px", "important");
16537
16539
  htmlCell.style.setProperty("border", "1px solid #ddd", "important");
16538
16540
  htmlCell.style.setProperty("font-weight", "bold", "important");
16541
+ htmlCell.style.setProperty("white-space", "nowrap", "important");
16539
16542
  });
16540
16543
  return true;
16541
16544
  }
@@ -21276,6 +21279,7 @@ const InsertImageUploadedDialogBody = ({
21276
21279
  const { uploadFileToS3, uploadedUrl, progress, uploading } = useS3Uploader(apiKey || void 0);
21277
21280
  const [tempSrc, setTempSrc] = useState$1("");
21278
21281
  const [fileToUpload, setFileToUpload] = useState$1(null);
21282
+ const [imageDimensions, setImageDimensions] = useState$1(null);
21279
21283
  const onChangeImage = async (event) => {
21280
21284
  const files = event.target.files;
21281
21285
  if (!files || files.length === 0)
@@ -21286,6 +21290,11 @@ const InsertImageUploadedDialogBody = ({
21286
21290
  reader.onload = () => {
21287
21291
  if (typeof reader.result === "string") {
21288
21292
  setTempSrc(reader.result);
21293
+ const img = new Image();
21294
+ img.onload = () => {
21295
+ setImageDimensions({ width: img.naturalWidth, height: img.naturalHeight });
21296
+ };
21297
+ img.src = reader.result;
21289
21298
  }
21290
21299
  };
21291
21300
  reader.readAsDataURL(file);
@@ -21295,9 +21304,19 @@ const InsertImageUploadedDialogBody = ({
21295
21304
  return;
21296
21305
  try {
21297
21306
  const uploadedUrl2 = await uploadFileToS3(fileToUpload);
21298
- onClick({ altText, src: uploadedUrl2 });
21307
+ console.log("Upload successful! URL:", uploadedUrl2);
21308
+ console.log("Image dimensions:", imageDimensions);
21309
+ const payload = {
21310
+ altText,
21311
+ src: uploadedUrl2,
21312
+ width: imageDimensions == null ? void 0 : imageDimensions.width,
21313
+ height: imageDimensions == null ? void 0 : imageDimensions.height
21314
+ };
21315
+ console.log("Inserting image with payload:", payload);
21316
+ onClick(payload);
21299
21317
  setTempSrc("");
21300
21318
  setFileToUpload(null);
21319
+ setImageDimensions(null);
21301
21320
  } catch (error) {
21302
21321
  console.error("Upload failed:", error);
21303
21322
  }
@@ -21379,6 +21398,7 @@ const InsertImageUrlDialogBody = ({
21379
21398
  const [altText, setAltText] = useState$1("");
21380
21399
  const [isValidUrl, setIsValidUrl] = useState$1(false);
21381
21400
  const [previewError, setPreviewError] = useState$1(null);
21401
+ const [imageDimensions, setImageDimensions] = useState$1(null);
21382
21402
  const validateUrl2 = (url) => {
21383
21403
  if (!url.trim())
21384
21404
  return false;
@@ -21414,6 +21434,7 @@ const InsertImageUrlDialogBody = ({
21414
21434
  img.onload = () => {
21415
21435
  setPreviewError(null);
21416
21436
  setIsValidUrl(true);
21437
+ setImageDimensions({ width: img.naturalWidth, height: img.naturalHeight });
21417
21438
  };
21418
21439
  img.onerror = () => {
21419
21440
  setPreviewError(
@@ -21426,7 +21447,12 @@ const InsertImageUrlDialogBody = ({
21426
21447
  const handleConfirmUrl = () => {
21427
21448
  if (!imageUrl || !isValidUrl)
21428
21449
  return;
21429
- onClick({ altText, src: imageUrl });
21450
+ onClick({
21451
+ altText,
21452
+ src: imageUrl,
21453
+ width: imageDimensions == null ? void 0 : imageDimensions.width,
21454
+ height: imageDimensions == null ? void 0 : imageDimensions.height
21455
+ });
21430
21456
  };
21431
21457
  return /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-4", children: [
21432
21458
  imageUrl && isValidUrl && !previewError && /* @__PURE__ */ jsx("div", { className: "cteditor-mb-4", children: /* @__PURE__ */ jsx(
@@ -22706,8 +22732,8 @@ const NotePanelMenu = ({ className }) => {
22706
22732
  ] });
22707
22733
  };
22708
22734
  const useStyles$1 = () => ({
22709
- root: "cteditor-p-2 cteditor-border-b cteditor-border-[#e0e0e0] cteditor-overflow-auto",
22710
- toolbar: "cteditor-p-2 cteditor-overflow-auto",
22735
+ root: "cteditor-p-2 cteditor-border-b cteditor-border-[#e0e0e0] cteditor-max-w-full cteditor-overflow-x-auto",
22736
+ toolbar: "cteditor-p-2 cteditor-max-w-full cteditor-overflow-x-auto cteditor-flex cteditor-flex-nowrap cteditor-gap-1",
22711
22737
  toolbarButton: "cteditor-p-1.5"
22712
22738
  });
22713
22739
  const useModal$1 = () => {
@@ -23220,14 +23246,17 @@ const Toolbar = ({
23220
23246
  "div",
23221
23247
  {
23222
23248
  ref: contentRef,
23223
- className: "cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-flex-1 cteditor-overflow-x-auto cteditor-scrollbar-hide",
23224
- style: { scrollbarWidth: "none", msOverflowStyle: "none" },
23249
+ className: "cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-flex-1 cteditor-overflow-x-auto cteditor-flex-nowrap",
23250
+ style: {
23251
+ scrollBehavior: "smooth",
23252
+ WebkitOverflowScrolling: "touch"
23253
+ },
23225
23254
  children: [
23226
23255
  enableUndoRedo && /* @__PURE__ */ jsxs(
23227
23256
  "div",
23228
23257
  {
23229
23258
  "data-toolbar-item": "undoRedo",
23230
- className: "cteditor-flex cteditor-items-center cteditor-gap-1.5",
23259
+ className: "cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-flex-shrink-0",
23231
23260
  children: [
23232
23261
  /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
23233
23262
  /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
@@ -24122,9 +24151,8 @@ function Skeleton({
24122
24151
  }
24123
24152
  );
24124
24153
  }
24125
- createCommand(
24126
- "AUTOCOMPLETE_COMMAND"
24127
- );
24154
+ const GrammarCheckPlugin = "";
24155
+ createCommand("AUTOCOMPLETE_COMMAND");
24128
24156
  const STATIC_SUGGESTIONS = [
24129
24157
  "javascript",
24130
24158
  "typescript",
@@ -24152,7 +24180,6 @@ class AIService {
24152
24180
  __publicField(this, "apiEndpoint");
24153
24181
  __publicField(this, "cache", /* @__PURE__ */ new Map());
24154
24182
  __publicField(this, "requestTimeout", 1e4);
24155
- // 10 seconds timeout for more reliable responses
24156
24183
  __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
24157
24184
  this.apiEndpoint = "https://api.cteditor.com/" + apiEndpoint;
24158
24185
  }
@@ -24174,19 +24201,9 @@ class AIService {
24174
24201
  }
24175
24202
  }
24176
24203
  async executeRequest(payload, cacheKey) {
24177
- var _a;
24178
24204
  try {
24179
24205
  const controller = new AbortController();
24180
- const timeoutId = setTimeout(
24181
- () => controller.abort(),
24182
- this.requestTimeout
24183
- );
24184
- console.log("🌐 AIService: Making request to:", this.apiEndpoint);
24185
- console.log("📦 AIService: Payload:", {
24186
- ...payload,
24187
- text: ((_a = payload.text) == null ? void 0 : _a.substring(0, 100)) + "..."
24188
- // Log only first 100 chars
24189
- });
24206
+ const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);
24190
24207
  const response = await fetch(this.apiEndpoint, {
24191
24208
  method: "POST",
24192
24209
  headers: {
@@ -24196,14 +24213,11 @@ class AIService {
24196
24213
  signal: controller.signal
24197
24214
  });
24198
24215
  clearTimeout(timeoutId);
24199
- console.log("📡 AIService: Response status:", response.status);
24200
24216
  if (!response.ok) {
24201
24217
  const errorText = await response.text();
24202
- console.error("❌ AIService: Error response:", errorText);
24203
24218
  throw new Error(`AI service error: ${response.status} - ${errorText}`);
24204
24219
  }
24205
24220
  const result = await response.json();
24206
- console.log("✅ AIService: Successful response received");
24207
24221
  this.cache.set(cacheKey, result.data);
24208
24222
  if (this.cache.size > 50) {
24209
24223
  const firstKey = this.cache.keys().next().value;
@@ -24213,15 +24227,7 @@ class AIService {
24213
24227
  }
24214
24228
  return result.data;
24215
24229
  } catch (error) {
24216
- if (error instanceof Error && error.name === "AbortError") {
24217
- console.warn(
24218
- "⏰ AIService: Request timed out after",
24219
- this.requestTimeout,
24220
- "ms"
24221
- );
24222
- } else {
24223
- console.error("❌ AIService: Request failed:", error);
24224
- }
24230
+ console.error("❌ AIService: Request failed:", error);
24225
24231
  return null;
24226
24232
  }
24227
24233
  }
@@ -24231,43 +24237,118 @@ class AIService {
24231
24237
  }
24232
24238
  const result = await this.makeRequest({
24233
24239
  text: text.trim(),
24234
- // Send the sentence/text for correction
24235
24240
  currentWord: currentWord == null ? void 0 : currentWord.trim(),
24236
- // Send current word being typed (optional)
24237
24241
  maxSuggestions
24238
24242
  });
24239
24243
  return result;
24240
24244
  }
24241
24245
  }
24242
- function AutocompletePlugin({
24246
+ class GrammarCheckService {
24247
+ constructor() {
24248
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
24249
+ __publicField(this, "apiEndpoint");
24250
+ __publicField(this, "pendingRequest", null);
24251
+ this.apiEndpoint = "https://api.cteditor.com/api/ai/process";
24252
+ }
24253
+ async check(text) {
24254
+ if (!text || text.trim().length < 3) {
24255
+ return [];
24256
+ }
24257
+ const cacheKey = text.trim();
24258
+ if (this.cache.has(cacheKey)) {
24259
+ return this.cache.get(cacheKey);
24260
+ }
24261
+ if (this.pendingRequest) {
24262
+ return this.pendingRequest;
24263
+ }
24264
+ this.pendingRequest = this.executeCheck(text);
24265
+ try {
24266
+ const result = await this.pendingRequest;
24267
+ return result;
24268
+ } finally {
24269
+ this.pendingRequest = null;
24270
+ }
24271
+ }
24272
+ async executeCheck(text) {
24273
+ var _a, _b, _c, _d, _e, _f;
24274
+ try {
24275
+ const response = await fetch(this.apiEndpoint, {
24276
+ method: "POST",
24277
+ headers: { "Content-Type": "application/json" },
24278
+ body: JSON.stringify({ text: text.trim(), maxSuggestions: 3 }),
24279
+ signal: AbortSignal.timeout(1e4)
24280
+ });
24281
+ if (!response.ok) {
24282
+ console.error("❌ GrammarCheck: API error:", response.status);
24283
+ return [];
24284
+ }
24285
+ const result = await response.json();
24286
+ const foundErrors = [];
24287
+ if ((_c = (_b = (_a = result.data) == null ? void 0 : _a.corrections) == null ? void 0 : _b.spelling) == null ? void 0 : _c.errors) {
24288
+ result.data.corrections.spelling.errors.forEach((err, idx) => {
24289
+ foundErrors.push({
24290
+ type: "spelling",
24291
+ original: err.original,
24292
+ suggestions: err.suggestions || [],
24293
+ index: idx
24294
+ });
24295
+ });
24296
+ }
24297
+ if ((_f = (_e = (_d = result.data) == null ? void 0 : _d.corrections) == null ? void 0 : _e.grammar) == null ? void 0 : _f.errors) {
24298
+ result.data.corrections.grammar.errors.forEach((err, idx) => {
24299
+ foundErrors.push({
24300
+ type: "grammar",
24301
+ original: err.original || text,
24302
+ suggestions: [err.suggestion],
24303
+ index: foundErrors.length + idx,
24304
+ issue: err.issue
24305
+ });
24306
+ });
24307
+ }
24308
+ this.cache.set(text.trim(), foundErrors);
24309
+ if (this.cache.size > 30) {
24310
+ const firstKey = this.cache.keys().next().value;
24311
+ if (firstKey) {
24312
+ this.cache.delete(firstKey);
24313
+ }
24314
+ }
24315
+ return foundErrors;
24316
+ } catch (error) {
24317
+ console.error("❌ GrammarCheck: Check failed:", error);
24318
+ return [];
24319
+ }
24320
+ }
24321
+ }
24322
+ function CombinedAutocompleteGrammarPlugin({
24243
24323
  onQueryChange,
24244
24324
  onSelectOption,
24245
24325
  minMatchLength = 2,
24246
24326
  maxSuggestions = 10,
24247
- // anchorClassName = "",
24248
- // menuClassName = "",
24249
- // itemClassName = "",
24250
- // selectedItemClassName = "",
24251
24327
  apiEndpoint = "api/ai/process",
24252
24328
  enableAI = true,
24253
24329
  debounceDelay = 200
24254
24330
  }) {
24255
24331
  const [editor] = useLexicalComposerContext();
24256
24332
  const { updateToolbarState } = useToolbarState();
24333
+ const [activeTab, setActiveTab] = useState$1("autocomplete");
24257
24334
  const [queryString, setQueryString] = useState$1(null);
24258
24335
  const [suggestions, setSuggestions] = useState$1([]);
24259
24336
  const [selectedIndex, setSelectedIndex] = useState$1(0);
24260
24337
  const [isLoading, setIsLoading] = useState$1(false);
24261
24338
  const menuRef = useRef(null);
24262
24339
  const anchorElementRef = useRef(null);
24263
- const [anchorElement, setAnchorElement] = useState$1(
24264
- null
24265
- );
24340
+ const [anchorElement, setAnchorElement] = useState$1(null);
24266
24341
  const aiService = useRef(new AIService(apiEndpoint));
24267
24342
  const debounceTimer = useRef(null);
24268
24343
  const justSelectedOption = useRef(false);
24269
24344
  const lastRequestTime = useRef(0);
24270
24345
  const requestThrottle = 100;
24346
+ const [errors, setErrors] = useState$1([]);
24347
+ const [userDismissed, setUserDismissed] = useState$1(false);
24348
+ const grammarService = useRef(new GrammarCheckService());
24349
+ const checkTimeout = useRef();
24350
+ const lastCheckedText = useRef("");
24351
+ const highlightElementsRef = useRef([]);
24271
24352
  const extractWordsFromEditor = useCallback(() => {
24272
24353
  const words = /* @__PURE__ */ new Set();
24273
24354
  STATIC_SUGGESTIONS.forEach((word) => words.add(word));
@@ -24292,17 +24373,12 @@ function AutocompletePlugin({
24292
24373
  return [];
24293
24374
  }
24294
24375
  if (justSelectedOption.current) {
24295
- console.log(
24296
- "🚫 AutocompletePlugin: Skipping AI request - just selected option"
24297
- );
24298
24376
  return [];
24299
24377
  }
24300
24378
  const now2 = Date.now();
24301
24379
  if (now2 - lastRequestTime.current < requestThrottle) {
24302
- console.log("🚫 AutocompletePlugin: Throttling AI request");
24303
24380
  return [];
24304
24381
  }
24305
- console.log("🤖 AutocompletePlugin: Getting AI suggestions for:", query);
24306
24382
  setIsLoading(true);
24307
24383
  lastRequestTime.current = now2;
24308
24384
  let lastSentence = "";
@@ -24341,11 +24417,8 @@ function AutocompletePlugin({
24341
24417
  try {
24342
24418
  const result = await aiService.current.getIntelligentSuggestions(
24343
24419
  query,
24344
- // currentWord
24345
24420
  lastSentence,
24346
- // text (the sentence to correct)
24347
24421
  maxSuggestions
24348
- // maxSuggestions
24349
24422
  );
24350
24423
  const aiOptions = [];
24351
24424
  if (result) {
@@ -24418,10 +24491,6 @@ function AutocompletePlugin({
24418
24491
  });
24419
24492
  }
24420
24493
  }
24421
- console.log(
24422
- "✅ AutocompletePlugin: AI sentence corrections received:",
24423
- aiOptions
24424
- );
24425
24494
  return aiOptions.slice(0, Math.floor(maxSuggestions * 0.8));
24426
24495
  } catch (error) {
24427
24496
  console.error("❌ AutocompletePlugin: AI suggestions failed:", error);
@@ -24430,7 +24499,7 @@ function AutocompletePlugin({
24430
24499
  setIsLoading(false);
24431
24500
  }
24432
24501
  },
24433
- [enableAI, minMatchLength, maxSuggestions]
24502
+ [enableAI, minMatchLength, maxSuggestions, editor]
24434
24503
  );
24435
24504
  const getTraditionalSuggestions = useCallback(
24436
24505
  (query) => {
@@ -24487,7 +24556,6 @@ function AutocompletePlugin({
24487
24556
  }, 100);
24488
24557
  return;
24489
24558
  }
24490
- console.log("🎯 AutocompletePlugin: Checking for autocomplete trigger");
24491
24559
  editor.update(() => {
24492
24560
  const selection = $getSelection();
24493
24561
  if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
@@ -24520,18 +24588,10 @@ function AutocompletePlugin({
24520
24588
  }
24521
24589
  if (queryString && !justSelectedOption.current) {
24522
24590
  debounceTimer.current = setTimeout(async () => {
24523
- console.log(
24524
- "🔄 AutocompletePlugin: Getting suggestions for:",
24525
- queryString
24526
- );
24527
24591
  const newSuggestions = await getCombinedSuggestions(queryString);
24528
24592
  setSuggestions(newSuggestions);
24529
24593
  setSelectedIndex(0);
24530
24594
  onQueryChange == null ? void 0 : onQueryChange(queryString);
24531
- console.log(
24532
- "🎯 AutocompletePlugin: Updated suggestions:",
24533
- newSuggestions
24534
- );
24535
24595
  }, debounceDelay);
24536
24596
  } else {
24537
24597
  setSuggestions([]);
@@ -24546,7 +24606,6 @@ function AutocompletePlugin({
24546
24606
  }, [queryString, getCombinedSuggestions, onQueryChange, debounceDelay]);
24547
24607
  const selectOption = useCallback(
24548
24608
  (option) => {
24549
- console.log("✅ AutocompletePlugin: Selecting option:", option);
24550
24609
  justSelectedOption.current = true;
24551
24610
  editor.update(() => {
24552
24611
  const selection = $getSelection();
@@ -24584,9 +24643,6 @@ function AutocompletePlugin({
24584
24643
  const newOffset = sentenceStart + option.displayText.length;
24585
24644
  selection.anchor.set(textNode.getKey(), newOffset, "text");
24586
24645
  selection.focus.set(textNode.getKey(), newOffset, "text");
24587
- console.log(
24588
- "✅ AutocompletePlugin: Sentence replaced successfully"
24589
- );
24590
24646
  }
24591
24647
  } else {
24592
24648
  let wordStart = anchorOffset;
@@ -24600,7 +24656,6 @@ function AutocompletePlugin({
24600
24656
  const newOffset = wordStart + option.displayText.length;
24601
24657
  selection.anchor.set(textNode.getKey(), newOffset, "text");
24602
24658
  selection.focus.set(textNode.getKey(), newOffset, "text");
24603
- console.log("✅ AutocompletePlugin: Word replaced successfully");
24604
24659
  }
24605
24660
  }
24606
24661
  });
@@ -24704,6 +24759,136 @@ function AutocompletePlugin({
24704
24759
  inputListener();
24705
24760
  };
24706
24761
  }, [editor, checkForAutocompleteTrigger]);
24762
+ const checkGrammar = useCallback(async () => {
24763
+ const isSlashActive = editor.getEditorState().read(() => {
24764
+ const selection = $getSelection();
24765
+ if (!$isRangeSelection(selection))
24766
+ return false;
24767
+ const anchor = selection.anchor;
24768
+ const anchorNode = anchor.getNode();
24769
+ const anchorOffset = anchor.offset;
24770
+ const textContent = anchorNode.getTextContent();
24771
+ let wordStart = anchorOffset;
24772
+ while (wordStart > 0 && /[a-zA-Z0-9_']/.test(textContent[wordStart - 1])) {
24773
+ wordStart--;
24774
+ }
24775
+ return wordStart > 0 && textContent[wordStart - 1] === "/";
24776
+ });
24777
+ if (isSlashActive) {
24778
+ setErrors([]);
24779
+ return;
24780
+ }
24781
+ const text = editor.getEditorState().read(() => $getRoot().getTextContent());
24782
+ if (text === lastCheckedText.current) {
24783
+ return;
24784
+ }
24785
+ if (Math.abs(text.length - lastCheckedText.current.length) > 20) {
24786
+ setUserDismissed(false);
24787
+ }
24788
+ lastCheckedText.current = text;
24789
+ if (!text || text.trim().length < 3) {
24790
+ setErrors([]);
24791
+ return;
24792
+ }
24793
+ const foundErrors = await grammarService.current.check(text);
24794
+ setErrors(foundErrors);
24795
+ }, [editor]);
24796
+ useEffect$1(() => {
24797
+ const unregister = editor.registerUpdateListener(() => {
24798
+ clearTimeout(checkTimeout.current);
24799
+ checkTimeout.current = window.setTimeout(checkGrammar, 2e3);
24800
+ });
24801
+ return () => {
24802
+ unregister();
24803
+ clearTimeout(checkTimeout.current);
24804
+ };
24805
+ }, [editor, checkGrammar]);
24806
+ useEffect$1(() => {
24807
+ highlightElementsRef.current.forEach((el) => {
24808
+ el.classList.remove("spelling-error", "grammar-error");
24809
+ });
24810
+ highlightElementsRef.current = [];
24811
+ if (errors.length === 0 || userDismissed)
24812
+ return;
24813
+ const timeoutId = setTimeout(() => {
24814
+ const editorElement = document.querySelector(".ContentEditable__root");
24815
+ if (!editorElement)
24816
+ return;
24817
+ const walker = document.createTreeWalker(
24818
+ editorElement,
24819
+ NodeFilter.SHOW_TEXT,
24820
+ null
24821
+ );
24822
+ const textNodes = [];
24823
+ let node;
24824
+ while (node = walker.nextNode()) {
24825
+ textNodes.push(node);
24826
+ }
24827
+ errors.forEach((error) => {
24828
+ textNodes.forEach((textNode) => {
24829
+ const nodeText = textNode.textContent || "";
24830
+ const errorIndex = nodeText.toLowerCase().indexOf(error.original.toLowerCase());
24831
+ if (errorIndex !== -1 && textNode.parentElement) {
24832
+ const className = error.type === "spelling" ? "spelling-error" : "grammar-error";
24833
+ if (textNode.parentElement.tagName === "SPAN") {
24834
+ textNode.parentElement.classList.add(className);
24835
+ highlightElementsRef.current.push(textNode.parentElement);
24836
+ } else if (textNode.parentElement) {
24837
+ const range = document.createRange();
24838
+ range.setStart(textNode, errorIndex);
24839
+ range.setEnd(textNode, Math.min(errorIndex + error.original.length, nodeText.length));
24840
+ const span = document.createElement("span");
24841
+ span.className = className;
24842
+ span.setAttribute("data-error-type", error.type);
24843
+ try {
24844
+ range.surroundContents(span);
24845
+ highlightElementsRef.current.push(span);
24846
+ } catch (e) {
24847
+ if (textNode.parentElement) {
24848
+ textNode.parentElement.classList.add(className);
24849
+ highlightElementsRef.current.push(textNode.parentElement);
24850
+ }
24851
+ }
24852
+ }
24853
+ }
24854
+ });
24855
+ });
24856
+ }, 100);
24857
+ return () => clearTimeout(timeoutId);
24858
+ }, [errors, userDismissed]);
24859
+ const applyCorrection = useCallback(
24860
+ (suggestion, original, errorType) => {
24861
+ editor.update(() => {
24862
+ const root2 = $getRoot();
24863
+ const currentText = root2.getTextContent();
24864
+ const isSpellingError = errorType === "spelling";
24865
+ let newText = currentText;
24866
+ if (isSpellingError) {
24867
+ const escapedOriginal = original.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24868
+ const regex = new RegExp(`\\b${escapedOriginal}\\b`, "gi");
24869
+ newText = currentText.replace(regex, suggestion);
24870
+ } else {
24871
+ const escapedOriginal = original.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24872
+ const regex = new RegExp(escapedOriginal, "gi");
24873
+ if (currentText.toLowerCase().includes(original.toLowerCase())) {
24874
+ newText = currentText.replace(regex, suggestion);
24875
+ } else {
24876
+ newText = suggestion;
24877
+ }
24878
+ }
24879
+ root2.clear();
24880
+ const paragraph = $createParagraphNode();
24881
+ const textNode = $createTextNode(newText);
24882
+ paragraph.append(textNode);
24883
+ root2.append(paragraph);
24884
+ });
24885
+ setTimeout(() => {
24886
+ lastCheckedText.current = "";
24887
+ checkGrammar();
24888
+ }, 100);
24889
+ },
24890
+ [editor, checkGrammar]
24891
+ );
24707
24892
  const calculateMenuPosition = useCallback(() => {
24708
24893
  if (!anchorElement)
24709
24894
  return { top: 0, left: 0 };
@@ -24736,10 +24921,7 @@ function AutocompletePlugin({
24736
24921
  try {
24737
24922
  document.body.removeChild(anchorElementRef.current);
24738
24923
  } catch (error) {
24739
- console.warn(
24740
- "🚨 AutocompletePlugin: Error removing existing anchor:",
24741
- error
24742
- );
24924
+ console.warn("Error removing existing anchor:", error);
24743
24925
  }
24744
24926
  }
24745
24927
  document.body.appendChild(anchor);
@@ -24750,7 +24932,7 @@ function AutocompletePlugin({
24750
24932
  try {
24751
24933
  document.body.removeChild(anchorElementRef.current);
24752
24934
  } catch (error) {
24753
- console.warn("🚨 AutocompletePlugin: Error during cleanup:", error);
24935
+ console.warn("Error during cleanup:", error);
24754
24936
  }
24755
24937
  }
24756
24938
  };
@@ -24779,76 +24961,171 @@ function AutocompletePlugin({
24779
24961
  return "outline";
24780
24962
  }
24781
24963
  };
24782
- if (!anchorElement || !queryString || suggestions.length === 0 && !isLoading) {
24964
+ useEffect$1(() => {
24965
+ const showAutocomplete2 = queryString && (suggestions.length > 0 || isLoading);
24966
+ const showGrammar2 = errors.length > 0 && !userDismissed;
24967
+ if (showAutocomplete2 && !showGrammar2) {
24968
+ setActiveTab("autocomplete");
24969
+ } else if (showGrammar2 && !showAutocomplete2) {
24970
+ setActiveTab("grammar");
24971
+ }
24972
+ }, [queryString, suggestions.length, isLoading, errors.length, userDismissed]);
24973
+ const showAutocomplete = queryString && (suggestions.length > 0 || isLoading);
24974
+ const showGrammar = errors.length > 0 && !userDismissed;
24975
+ if (!anchorElement || !showAutocomplete && !showGrammar) {
24783
24976
  return null;
24784
24977
  }
24785
24978
  return createPortal(
24786
- /* @__PURE__ */ jsx(
24979
+ /* @__PURE__ */ jsxs(
24787
24980
  Card,
24788
24981
  {
24789
24982
  ref: menuRef,
24790
- className: "cteditor-w-80 cteditor-max-h-64 cteditor-overflow-y-auto cteditor-shadow-lg cteditor-border cteditor-bg-background cteditor-rounded-md",
24791
- children: /* @__PURE__ */ jsxs(CardContent, { className: "cteditor-p-2", children: [
24792
- isLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-p-3 cteditor-text-sm cteditor-text-muted-foreground", children: [
24793
- /* @__PURE__ */ jsx(Skeleton, { className: "cteditor-h-4 cteditor-w-4 cteditor-rounded-full" }),
24794
- /* @__PURE__ */ jsx("span", { children: "Getting AI suggestions..." })
24795
- ] }),
24796
- /* @__PURE__ */ jsx("div", { className: "cteditor-space-y-1", children: suggestions.map((option, index2) => /* @__PURE__ */ jsxs(
24797
- "div",
24798
- {
24799
- className: cn$1(
24800
- "cteditor-flex cteditor-items-start cteditor-gap-3 cteditor-p-3 cteditor-rounded-md cteditor-cursor-pointer cteditor-transition-colors cteditor-text-sm",
24801
- index2 === selectedIndex ? "cteditor-bg-foreground/5" : "hover:cteditor-bg-red"
24802
- ),
24803
- onClick: () => selectOption(option),
24804
- onMouseEnter: () => setSelectedIndex(index2),
24805
- children: [
24806
- /* @__PURE__ */ jsx(
24807
- "div",
24808
- {
24809
- className: cn$1(
24810
- "cteditor-mt-0.5",
24811
- index2 === selectedIndex ? "cteditor-text-primary" : "cteditor-text-primary"
24812
- ),
24813
- children: getSuggestionIcon(option.type)
24814
- }
24983
+ className: "cteditor-w-80 cteditor-max-h-64 cteditor-overflow-hidden cteditor-shadow-lg cteditor-border cteditor-bg-background cteditor-rounded-md",
24984
+ children: [
24985
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-border-b cteditor-bg-muted/30", children: [
24986
+ /* @__PURE__ */ jsxs(
24987
+ "button",
24988
+ {
24989
+ onClick: () => setActiveTab("autocomplete"),
24990
+ className: cn$1(
24991
+ "cteditor-flex-1 cteditor-px-4 cteditor-py-2 cteditor-text-sm cteditor-font-medium cteditor-transition-colors",
24992
+ activeTab === "autocomplete" ? "cteditor-bg-background cteditor-text-foreground cteditor-border-b-2 cteditor-border-primary" : "cteditor-text-muted-foreground hover:cteditor-text-foreground"
24815
24993
  ),
24816
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex-1 cteditor-min-w-0", children: [
24817
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-mb-2", children: [
24994
+ children: [
24995
+ /* @__PURE__ */ jsx(Sparkles, { className: "cteditor-inline cteditor-size-4 cteditor-mr-2" }),
24996
+ "Autocomplete"
24997
+ ]
24998
+ }
24999
+ ),
25000
+ /* @__PURE__ */ jsxs(
25001
+ "button",
25002
+ {
25003
+ onClick: () => setActiveTab("grammar"),
25004
+ className: cn$1(
25005
+ "cteditor-flex-1 cteditor-px-4 cteditor-py-2 cteditor-text-sm cteditor-font-medium cteditor-transition-colors",
25006
+ activeTab === "grammar" ? "cteditor-bg-background cteditor-text-foreground cteditor-border-b-2 cteditor-border-primary" : "cteditor-text-muted-foreground hover:cteditor-text-foreground"
25007
+ ),
25008
+ children: [
25009
+ /* @__PURE__ */ jsx(CheckCircle, { className: "cteditor-inline cteditor-size-4 cteditor-mr-2" }),
25010
+ "Grammar & Spelling",
25011
+ errors.length > 0 && /* @__PURE__ */ jsx(Badge, { variant: "destructive", className: "cteditor-ml-2 cteditor-text-xs", children: errors.length })
25012
+ ]
25013
+ }
25014
+ )
25015
+ ] }),
25016
+ /* @__PURE__ */ jsxs(CardContent, { className: "cteditor-p-2 cteditor-max-h-56 cteditor-overflow-y-auto", children: [
25017
+ activeTab === "autocomplete" && /* @__PURE__ */ jsxs(Fragment, { children: [
25018
+ isLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-p-3 cteditor-text-sm cteditor-text-muted-foreground", children: [
25019
+ /* @__PURE__ */ jsx(Skeleton, { className: "cteditor-h-4 cteditor-w-4 cteditor-rounded-full" }),
25020
+ /* @__PURE__ */ jsx("span", { children: "Getting AI suggestions..." })
25021
+ ] }),
25022
+ /* @__PURE__ */ jsx("div", { className: "cteditor-space-y-1", children: suggestions.map((option, index2) => /* @__PURE__ */ jsxs(
25023
+ "div",
25024
+ {
25025
+ className: cn$1(
25026
+ "cteditor-flex cteditor-items-start cteditor-gap-3 cteditor-p-3 cteditor-rounded-md cteditor-cursor-pointer cteditor-transition-colors cteditor-text-sm",
25027
+ index2 === selectedIndex ? "cteditor-bg-foreground/5" : "hover:cteditor-bg-muted/50"
25028
+ ),
25029
+ onClick: () => selectOption(option),
25030
+ onMouseEnter: () => setSelectedIndex(index2),
25031
+ children: [
24818
25032
  /* @__PURE__ */ jsx(
24819
- Badge,
25033
+ "div",
24820
25034
  {
24821
- variant: index2 === selectedIndex ? "secondary" : getSuggestionVariant(option.type),
24822
- className: "cteditor-text-xs cteditor-border cteditor-border-foreground/20 cteditor-rounded-2xl !cteditor-font-normal ",
24823
- children: option.type
25035
+ className: cn$1(
25036
+ "cteditor-mt-0.5",
25037
+ index2 === selectedIndex ? "cteditor-text-primary" : "cteditor-text-primary"
25038
+ ),
25039
+ children: getSuggestionIcon(option.type)
24824
25040
  }
24825
25041
  ),
24826
- option.confidence && /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-px-2 cteditor-py-0.5 cteditor-rounded-md cteditor-bg-muted/50 cteditor-text-foreground", children: option.confidence })
24827
- ] }),
24828
- /* @__PURE__ */ jsx("p", { className: "cteditor-leading-relaxed cteditor-break-words", children: option.displayText })
24829
- ] })
24830
- ]
24831
- },
24832
- option.key
24833
- )) }),
24834
- /* @__PURE__ */ jsx("div", { className: "cteditor-mt-1 cteditor-pt-1 cteditor-border-t cteditor-sticky cteditor-bottom-0 cteditor-bg-background", children: /* @__PURE__ */ jsxs(
24835
- Button,
24836
- {
24837
- variant: "ghost",
24838
- size: "sm",
24839
- className: "cteditor-w-full cteditor-justify-start cteditor-gap-2 cteditor-text-muted-foreground hover:cteditor-text-foreground",
24840
- onClick: () => {
24841
- setQueryString(null);
24842
- setSuggestions([]);
24843
- updateToolbarState("isAutocompleteEnabled", false);
24844
- },
24845
- children: [
24846
- /* @__PURE__ */ jsx(Ban, { className: "!cteditor-size-3" }),
24847
- "Disable Autocorrection"
24848
- ]
24849
- }
24850
- ) })
24851
- ] })
25042
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex-1 cteditor-min-w-0", children: [
25043
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-mb-2", children: [
25044
+ /* @__PURE__ */ jsx(
25045
+ Badge,
25046
+ {
25047
+ variant: index2 === selectedIndex ? "secondary" : getSuggestionVariant(option.type),
25048
+ className: "cteditor-text-xs cteditor-border cteditor-border-foreground/20 cteditor-rounded-2xl !cteditor-font-normal",
25049
+ children: option.type
25050
+ }
25051
+ ),
25052
+ option.confidence && /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-px-2 cteditor-py-0.5 cteditor-rounded-md cteditor-bg-muted/50 cteditor-text-foreground", children: option.confidence })
25053
+ ] }),
25054
+ /* @__PURE__ */ jsx("p", { className: "cteditor-leading-relaxed cteditor-break-words", children: option.displayText })
25055
+ ] })
25056
+ ]
25057
+ },
25058
+ option.key
25059
+ )) }),
25060
+ /* @__PURE__ */ jsx("div", { className: "cteditor-mt-1 cteditor-pt-1 cteditor-border-t cteditor-sticky cteditor-bottom-0 cteditor-bg-background", children: /* @__PURE__ */ jsxs(
25061
+ Button,
25062
+ {
25063
+ variant: "ghost",
25064
+ size: "sm",
25065
+ className: "cteditor-w-full cteditor-justify-start cteditor-gap-2 cteditor-text-muted-foreground hover:cteditor-text-foreground",
25066
+ onClick: () => {
25067
+ setQueryString(null);
25068
+ setSuggestions([]);
25069
+ updateToolbarState("isAutocompleteEnabled", false);
25070
+ },
25071
+ children: [
25072
+ /* @__PURE__ */ jsx(Ban, { className: "!cteditor-size-3" }),
25073
+ "Disable Autocomplete & Grammar Check"
25074
+ ]
25075
+ }
25076
+ ) })
25077
+ ] }),
25078
+ activeTab === "grammar" && /* @__PURE__ */ jsxs(Fragment, { children: [
25079
+ /* @__PURE__ */ jsx("div", { className: "cteditor-space-y-2 cteditor-p-2", children: errors.map((error, idx) => /* @__PURE__ */ jsx(
25080
+ "div",
25081
+ {
25082
+ className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-p-3 cteditor-rounded-md cteditor-bg-muted/50 cteditor-border",
25083
+ children: /* @__PURE__ */ jsxs("div", { className: "cteditor-flex-1", children: [
25084
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-mb-1", children: [
25085
+ /* @__PURE__ */ jsx(
25086
+ Badge,
25087
+ {
25088
+ variant: error.type === "spelling" ? "destructive" : "default",
25089
+ className: "cteditor-text-xs",
25090
+ children: error.type
25091
+ }
25092
+ ),
25093
+ error.confidence && /* @__PURE__ */ jsx("span", { className: "cteditor-text-xs cteditor-text-muted-foreground", children: error.confidence })
25094
+ ] }),
25095
+ /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-line-through cteditor-text-red-600 cteditor-mb-1", children: error.original }),
25096
+ error.suggestions.length > 0 && /* @__PURE__ */ jsx("div", { className: "cteditor-space-y-1", children: error.suggestions.slice(0, 2).map((suggestion, sIdx) => /* @__PURE__ */ jsx(
25097
+ "button",
25098
+ {
25099
+ onClick: () => applyCorrection(suggestion, error.original, error.type),
25100
+ className: "cteditor-block cteditor-w-full cteditor-text-left cteditor-text-sm cteditor-text-green-600 hover:cteditor-text-green-700 cteditor-px-2 cteditor-py-1 cteditor-rounded cteditor-bg-green-50 hover:cteditor-bg-green-100",
25101
+ children: suggestion
25102
+ },
25103
+ sIdx
25104
+ )) })
25105
+ ] })
25106
+ },
25107
+ idx
25108
+ )) }),
25109
+ /* @__PURE__ */ jsx("div", { className: "cteditor-mt-1 cteditor-pt-1 cteditor-border-t cteditor-sticky cteditor-bottom-0 cteditor-bg-background", children: /* @__PURE__ */ jsxs(
25110
+ Button,
25111
+ {
25112
+ variant: "ghost",
25113
+ size: "sm",
25114
+ className: "cteditor-w-full cteditor-justify-start cteditor-gap-2 cteditor-text-muted-foreground hover:cteditor-text-foreground",
25115
+ onClick: () => {
25116
+ setUserDismissed(true);
25117
+ setErrors([]);
25118
+ updateToolbarState("isGrammarCheckEnabled", false);
25119
+ },
25120
+ children: [
25121
+ /* @__PURE__ */ jsx(Ban, { className: "!cteditor-size-3" }),
25122
+ "Disable Autocomplete & Grammar Check"
25123
+ ]
25124
+ }
25125
+ ) })
25126
+ ] })
25127
+ ] })
25128
+ ]
24852
25129
  }
24853
25130
  ),
24854
25131
  anchorElement
@@ -25048,6 +25325,174 @@ const CommentBubblePlugin = () => {
25048
25325
  }, [editor, getCommentById]);
25049
25326
  return null;
25050
25327
  };
25328
+ const ACCEPTABLE_IMAGE_TYPES = [
25329
+ "image/",
25330
+ "image/heic",
25331
+ "image/heif",
25332
+ "image/gif",
25333
+ "image/webp",
25334
+ "image/png",
25335
+ "image/jpg",
25336
+ "image/jpeg",
25337
+ "image/svg+xml"
25338
+ ];
25339
+ const ACCEPTABLE_APPLICATION_TYPES = [
25340
+ "application/pdf",
25341
+ "application/msword",
25342
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
25343
+ ];
25344
+ const fileToDataURL = (file) => {
25345
+ return new Promise((resolve, reject) => {
25346
+ const reader = new FileReader();
25347
+ reader.onload = () => resolve(reader.result);
25348
+ reader.onerror = reject;
25349
+ reader.readAsDataURL(file);
25350
+ });
25351
+ };
25352
+ function DragDropPaste() {
25353
+ const [editor] = useLexicalComposerContext();
25354
+ const [isDragging, setIsDragging] = useState$1(false);
25355
+ const apiKey = void 0;
25356
+ const { uploadFileToS3 } = useS3Uploader(apiKey);
25357
+ useEffect$1(() => {
25358
+ const handleDragEnter = (e) => {
25359
+ var _a, _b;
25360
+ e.preventDefault();
25361
+ e.stopPropagation();
25362
+ const hasFiles = (_a = e.dataTransfer) == null ? void 0 : _a.types.includes("Files");
25363
+ const hasImages = (_b = e.dataTransfer) == null ? void 0 : _b.types.some(
25364
+ (type) => type === "text/html" || type === "text/uri-list"
25365
+ );
25366
+ if (hasFiles || hasImages) {
25367
+ setIsDragging(true);
25368
+ const editorEl = editor.getRootElement();
25369
+ if (editorEl) {
25370
+ editorEl.style.backgroundColor = "rgba(59, 130, 246, 0.05)";
25371
+ editorEl.style.border = "2px dashed rgb(59, 130, 246)";
25372
+ editorEl.style.borderRadius = "8px";
25373
+ }
25374
+ }
25375
+ };
25376
+ const handleDragOver = (e) => {
25377
+ e.preventDefault();
25378
+ e.stopPropagation();
25379
+ if (e.dataTransfer) {
25380
+ e.dataTransfer.dropEffect = "copy";
25381
+ }
25382
+ };
25383
+ const handleDragLeave = (e) => {
25384
+ e.preventDefault();
25385
+ e.stopPropagation();
25386
+ const editorEl = editor.getRootElement();
25387
+ if (e.relatedTarget === null || editorEl && !editorEl.contains(e.relatedTarget)) {
25388
+ setIsDragging(false);
25389
+ if (editorEl) {
25390
+ editorEl.style.backgroundColor = "";
25391
+ editorEl.style.border = "";
25392
+ editorEl.style.borderRadius = "";
25393
+ }
25394
+ }
25395
+ };
25396
+ const handleDrop = (e) => {
25397
+ var _a, _b, _c;
25398
+ e.preventDefault();
25399
+ e.stopPropagation();
25400
+ setIsDragging(false);
25401
+ const editorEl = editor.getRootElement();
25402
+ if (editorEl) {
25403
+ editorEl.style.backgroundColor = "";
25404
+ editorEl.style.border = "";
25405
+ editorEl.style.borderRadius = "";
25406
+ }
25407
+ const files = (_a = e.dataTransfer) == null ? void 0 : _a.files;
25408
+ if (files && files.length > 0) {
25409
+ console.log("File drop detected, letting DRAG_DROP_PASTE command handle it");
25410
+ return;
25411
+ }
25412
+ const html = (_b = e.dataTransfer) == null ? void 0 : _b.getData("text/html");
25413
+ if (html) {
25414
+ const tempDiv = document.createElement("div");
25415
+ tempDiv.innerHTML = html;
25416
+ const img = tempDiv.querySelector("img");
25417
+ if (img && img.src) {
25418
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
25419
+ altText: img.alt || "Dragged image",
25420
+ src: img.src
25421
+ });
25422
+ console.log("Image from web browser inserted:", img.src);
25423
+ return;
25424
+ }
25425
+ }
25426
+ const uriList = (_c = e.dataTransfer) == null ? void 0 : _c.getData("text/uri-list");
25427
+ if (uriList) {
25428
+ const urls = uriList.split("\n").filter((url) => url.trim().length > 0);
25429
+ urls.forEach((url) => {
25430
+ if (/\.(jpg|jpeg|png|gif|webp|svg)$/i.test(url)) {
25431
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
25432
+ altText: "Dragged image",
25433
+ src: url.trim()
25434
+ });
25435
+ console.log("Image from URL inserted:", url);
25436
+ }
25437
+ });
25438
+ }
25439
+ };
25440
+ const editorElement = editor.getRootElement();
25441
+ if (editorElement) {
25442
+ editorElement.addEventListener("dragenter", handleDragEnter);
25443
+ editorElement.addEventListener("dragover", handleDragOver);
25444
+ editorElement.addEventListener("dragleave", handleDragLeave);
25445
+ editorElement.addEventListener("drop", handleDrop);
25446
+ return () => {
25447
+ editorElement.removeEventListener("dragenter", handleDragEnter);
25448
+ editorElement.removeEventListener("dragover", handleDragOver);
25449
+ editorElement.removeEventListener("dragleave", handleDragLeave);
25450
+ editorElement.removeEventListener("drop", handleDrop);
25451
+ };
25452
+ }
25453
+ }, [editor]);
25454
+ useEffect$1(() => {
25455
+ return editor.registerCommand(
25456
+ DRAG_DROP_PASTE,
25457
+ (files) => {
25458
+ (async () => {
25459
+ const filesResult = await mediaFileReader(files, [
25460
+ ...ACCEPTABLE_IMAGE_TYPES,
25461
+ ...ACCEPTABLE_APPLICATION_TYPES
25462
+ ]);
25463
+ for (const { file, result } of filesResult) {
25464
+ let fileUrl;
25465
+ try {
25466
+ if (apiKey)
25467
+ ;
25468
+ else {
25469
+ fileUrl = await fileToDataURL(file);
25470
+ console.log("Using local data URL (no S3 upload)");
25471
+ }
25472
+ } catch (error) {
25473
+ console.error("Upload failed, using local data URL:", error);
25474
+ fileUrl = await fileToDataURL(file);
25475
+ }
25476
+ if (isMimeType(file, ACCEPTABLE_IMAGE_TYPES)) {
25477
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
25478
+ altText: file.name,
25479
+ src: fileUrl
25480
+ });
25481
+ } else if (isMimeType(file, ACCEPTABLE_APPLICATION_TYPES)) {
25482
+ editor.dispatchCommand(INSERT_FILE_COMMAND, {
25483
+ linkText: file.name || "Download File",
25484
+ src: fileUrl
25485
+ });
25486
+ }
25487
+ }
25488
+ })();
25489
+ return true;
25490
+ },
25491
+ COMMAND_PRIORITY_LOW
25492
+ );
25493
+ }, [editor, apiKey, uploadFileToS3]);
25494
+ return null;
25495
+ }
25051
25496
  const FloatingEmbedMenuPlugin$1 = "";
25052
25497
  function FloatingEmbedMenu({
25053
25498
  editor,
@@ -27007,6 +27452,203 @@ function NewMentionsPlugin({
27007
27452
  }
27008
27453
  );
27009
27454
  }
27455
+ function RichTextPastePlugin() {
27456
+ const [editor] = useLexicalComposerContext();
27457
+ useEffect$1(() => {
27458
+ return editor.registerCommand(
27459
+ PASTE_COMMAND,
27460
+ (event) => {
27461
+ const clipboardData = event.clipboardData;
27462
+ if (!clipboardData)
27463
+ return false;
27464
+ const htmlContent = clipboardData.getData("text/html");
27465
+ const plainText = clipboardData.getData("text/plain");
27466
+ if (htmlContent) {
27467
+ event.preventDefault();
27468
+ handleHtmlPaste(htmlContent);
27469
+ return true;
27470
+ } else if (plainText) {
27471
+ event.preventDefault();
27472
+ handleMarkdownPaste(plainText);
27473
+ return true;
27474
+ }
27475
+ return false;
27476
+ },
27477
+ COMMAND_PRIORITY_LOW
27478
+ );
27479
+ }, [editor]);
27480
+ const handleHtmlPaste = (htmlContent) => {
27481
+ editor.update(() => {
27482
+ const selection = $getSelection();
27483
+ if ($isRangeSelection(selection)) {
27484
+ const tempDiv = document.createElement("div");
27485
+ tempDiv.innerHTML = htmlContent;
27486
+ const processNode = (node) => {
27487
+ if (node.nodeType === Node.TEXT_NODE) {
27488
+ const text = node.textContent || "";
27489
+ const textNode = $createTextNode(text);
27490
+ if (node.parentElement) {
27491
+ if (node.parentElement.tagName === "STRONG" || node.parentElement.tagName === "B") {
27492
+ textNode.setFormat("bold");
27493
+ }
27494
+ if (node.parentElement.tagName === "EM" || node.parentElement.tagName === "I") {
27495
+ textNode.setFormat("italic");
27496
+ }
27497
+ if (node.parentElement.tagName === "U") {
27498
+ textNode.setFormat("underline");
27499
+ }
27500
+ if (node.parentElement.tagName === "CODE") {
27501
+ textNode.setFormat("code");
27502
+ }
27503
+ if (node.parentElement.tagName === "STRIKE" || node.parentElement.tagName === "S") {
27504
+ textNode.setFormat("strikethrough");
27505
+ }
27506
+ if (node.parentElement.tagName === "SUB") {
27507
+ textNode.setFormat("subscript");
27508
+ }
27509
+ if (node.parentElement.tagName === "SUP") {
27510
+ textNode.setFormat("superscript");
27511
+ }
27512
+ }
27513
+ return textNode;
27514
+ }
27515
+ if (node.nodeType === Node.ELEMENT_NODE) {
27516
+ const element = node;
27517
+ if (element.tagName === "UL" || element.tagName === "OL") {
27518
+ const listNode = $createListNode(
27519
+ element.tagName === "UL" ? "bullet" : "number"
27520
+ );
27521
+ Array.from(element.childNodes).forEach((child) => {
27522
+ if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "LI") {
27523
+ const listItemNode = $createListItemNode();
27524
+ Array.from(child.childNodes).forEach((grandChild) => {
27525
+ const processedNode = processNode(grandChild);
27526
+ if (processedNode) {
27527
+ if (Array.isArray(processedNode)) {
27528
+ processedNode.forEach(
27529
+ (node2) => listItemNode.append(node2)
27530
+ );
27531
+ } else {
27532
+ listItemNode.append(processedNode);
27533
+ }
27534
+ }
27535
+ });
27536
+ listNode.append(listItemNode);
27537
+ }
27538
+ });
27539
+ return listNode;
27540
+ }
27541
+ if (element.tagName.match(/^H[1-6]$/)) {
27542
+ const headingNode = $createHeadingNode(
27543
+ element.tagName.toLowerCase()
27544
+ );
27545
+ Array.from(element.childNodes).forEach((child) => {
27546
+ const processedNode = processNode(child);
27547
+ if (processedNode) {
27548
+ if (Array.isArray(processedNode)) {
27549
+ processedNode.forEach((node2) => headingNode.append(node2));
27550
+ } else {
27551
+ headingNode.append(processedNode);
27552
+ }
27553
+ }
27554
+ });
27555
+ return headingNode;
27556
+ }
27557
+ if (element.tagName === "P") {
27558
+ const paragraphNode = $createParagraphNode();
27559
+ Array.from(element.childNodes).forEach((child) => {
27560
+ const processedNode = processNode(child);
27561
+ if (processedNode) {
27562
+ if (Array.isArray(processedNode)) {
27563
+ processedNode.forEach((node2) => paragraphNode.append(node2));
27564
+ } else {
27565
+ paragraphNode.append(processedNode);
27566
+ }
27567
+ }
27568
+ });
27569
+ return paragraphNode;
27570
+ }
27571
+ const nodes = [];
27572
+ Array.from(element.childNodes).forEach((child) => {
27573
+ const processedNode = processNode(child);
27574
+ if (processedNode) {
27575
+ if (Array.isArray(processedNode)) {
27576
+ nodes.push(...processedNode);
27577
+ } else {
27578
+ nodes.push(processedNode);
27579
+ }
27580
+ }
27581
+ });
27582
+ return nodes;
27583
+ }
27584
+ return null;
27585
+ };
27586
+ const processedNodes = processNode(tempDiv);
27587
+ if (processedNodes) {
27588
+ if (Array.isArray(processedNodes)) {
27589
+ selection.insertNodes(processedNodes);
27590
+ } else {
27591
+ selection.insertNodes([processedNodes]);
27592
+ }
27593
+ }
27594
+ }
27595
+ });
27596
+ };
27597
+ const handleMarkdownPaste = (text) => {
27598
+ editor.update(() => {
27599
+ const selection = $getSelection();
27600
+ if ($isRangeSelection(selection)) {
27601
+ const lines = text.split("\n");
27602
+ const nodes = [];
27603
+ lines.forEach((line) => {
27604
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
27605
+ if (headingMatch) {
27606
+ const level = headingMatch[1].length;
27607
+ const content = headingMatch[2];
27608
+ const headingNode = $createHeadingNode(
27609
+ `h${level}`
27610
+ );
27611
+ headingNode.append($createTextNode(content));
27612
+ nodes.push(headingNode);
27613
+ return;
27614
+ }
27615
+ const bulletMatch = line.match(/^-\s+(.+)$/);
27616
+ if (bulletMatch) {
27617
+ const listNode = $createListNode("bullet");
27618
+ const listItemNode = $createListItemNode();
27619
+ listItemNode.append($createTextNode(bulletMatch[1]));
27620
+ listNode.append(listItemNode);
27621
+ nodes.push(listNode);
27622
+ return;
27623
+ }
27624
+ const numberedMatch = line.match(/^\d+\.\s+(.+)$/);
27625
+ if (numberedMatch) {
27626
+ const listNode = $createListNode("number");
27627
+ const listItemNode = $createListItemNode();
27628
+ listItemNode.append($createTextNode(numberedMatch[1]));
27629
+ listNode.append(listItemNode);
27630
+ nodes.push(listNode);
27631
+ return;
27632
+ }
27633
+ const textNode = $createTextNode(line);
27634
+ if (line.includes("**") || line.includes("__")) {
27635
+ textNode.setFormat("bold");
27636
+ }
27637
+ if (line.includes("*") || line.includes("_")) {
27638
+ textNode.setFormat("italic");
27639
+ }
27640
+ if (line.includes("***") || line.includes("___")) {
27641
+ textNode.setFormat("bold");
27642
+ textNode.setFormat("italic");
27643
+ }
27644
+ nodes.push(textNode);
27645
+ });
27646
+ selection.insertNodes(nodes);
27647
+ }
27648
+ });
27649
+ };
27650
+ return null;
27651
+ }
27010
27652
  function useModal() {
27011
27653
  const [modalContent, setModalContent] = useState$1(null);
27012
27654
  const onClose = useCallback(() => {
@@ -27552,8 +28194,79 @@ function TableActionMenu({
27552
28194
  for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
27553
28195
  $insertTableColumn__EXPERIMENTAL(shouldInsertAfter);
27554
28196
  }
28197
+ const selection = $getSelection();
28198
+ if ($isRangeSelection(selection) || $isTableSelection(selection)) {
28199
+ const [cell] = $getNodeTriplet(selection.anchor);
28200
+ if ($isTableCellNode(cell)) {
28201
+ const tableNode = $getTableNodeFromLexicalNodeOrThrow(cell);
28202
+ const rows = tableNode.getChildren();
28203
+ if (rows.length > 0 && $isTableRowNode(rows[0])) {
28204
+ const firstRow = rows[0];
28205
+ const firstRowCells = firstRow.getChildren();
28206
+ if (firstRowCells.length > 0 && $isTableCellNode(firstRowCells[0])) {
28207
+ const firstCell = firstRowCells[0];
28208
+ const hasColumnHeaders = (firstCell.getHeaderStyles() & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN;
28209
+ if (hasColumnHeaders) {
28210
+ const headerBackgroundColor = firstCell.getBackgroundColor();
28211
+ for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
28212
+ const newHeaderCellIndex = firstRowCells.length - 1 - i2;
28213
+ if (newHeaderCellIndex >= 0) {
28214
+ const newHeaderCell = firstRowCells[newHeaderCellIndex];
28215
+ if ($isTableCellNode(newHeaderCell)) {
28216
+ newHeaderCell.setHeaderStyles(TableCellHeaderStates.COLUMN);
28217
+ if (headerBackgroundColor) {
28218
+ newHeaderCell.setBackgroundColor(headerBackgroundColor);
28219
+ }
28220
+ }
28221
+ }
28222
+ }
28223
+ }
28224
+ }
28225
+ }
28226
+ }
28227
+ }
27555
28228
  onClose();
27556
28229
  });
28230
+ requestAnimationFrame(() => {
28231
+ const applyHeaderStyles = () => {
28232
+ const rootElement = editor.getRootElement();
28233
+ if (!rootElement)
28234
+ return false;
28235
+ const tables = rootElement.querySelectorAll("table");
28236
+ tables.forEach((table) => {
28237
+ const rows = table.querySelectorAll("tr");
28238
+ if (rows.length > 0) {
28239
+ const firstRow = rows[0];
28240
+ const cells = firstRow.querySelectorAll("th, td");
28241
+ if (cells.length > 1) {
28242
+ const firstHeaderCell = cells[0];
28243
+ const headerColor = firstHeaderCell.getAttribute("data-header-color");
28244
+ const textColor = firstHeaderCell.getAttribute("data-text-color");
28245
+ if (headerColor && textColor) {
28246
+ for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
28247
+ const cellIndex = cells.length - 1 - i2;
28248
+ if (cellIndex >= 0) {
28249
+ const newCell = cells[cellIndex];
28250
+ newCell.setAttribute("data-header-color", headerColor);
28251
+ newCell.setAttribute("data-text-color", textColor);
28252
+ newCell.style.setProperty("background-color", headerColor, "important");
28253
+ newCell.style.setProperty("color", textColor, "important");
28254
+ newCell.style.setProperty("padding", "8px", "important");
28255
+ newCell.style.setProperty("border", "1px solid #ddd", "important");
28256
+ newCell.style.setProperty("font-weight", "bold", "important");
28257
+ newCell.style.setProperty("white-space", "nowrap", "important");
28258
+ }
28259
+ }
28260
+ }
28261
+ }
28262
+ }
28263
+ });
28264
+ return true;
28265
+ };
28266
+ if (!applyHeaderStyles()) {
28267
+ setTimeout(applyHeaderStyles, 100);
28268
+ }
28269
+ });
27557
28270
  },
27558
28271
  [editor, onClose, selectionCounts.columns]
27559
28272
  );
@@ -28550,21 +29263,84 @@ function TableHoverActionsContainer({
28550
29263
  } else {
28551
29264
  $insertTableColumn__EXPERIMENTAL();
28552
29265
  setShownColumn(false);
29266
+ const tableCellNode = $getNearestNodeFromDOMNode(tableCellDOMNodeRef.current);
29267
+ if ($isTableCellNode(tableCellNode)) {
29268
+ const tableNode = $findMatchingParent(
29269
+ tableCellNode,
29270
+ (node) => $isTableNode(node)
29271
+ );
29272
+ if ($isTableNode(tableNode)) {
29273
+ const rows = tableNode.getChildren();
29274
+ if (rows.length > 0) {
29275
+ const firstRow = rows[0];
29276
+ const firstRowCells = firstRow.getChildren();
29277
+ if (firstRowCells.length > 0) {
29278
+ const firstCell = firstRowCells[0];
29279
+ const hasColumnHeaders = (firstCell.getHeaderStyles() & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN;
29280
+ if (hasColumnHeaders) {
29281
+ const newHeaderCell = firstRowCells[firstRowCells.length - 1];
29282
+ newHeaderCell.setHeaderStyles(TableCellHeaderStates.COLUMN);
29283
+ const headerBackgroundColor = firstCell.getBackgroundColor();
29284
+ if (headerBackgroundColor) {
29285
+ newHeaderCell.setBackgroundColor(headerBackgroundColor);
29286
+ }
29287
+ }
29288
+ }
29289
+ }
29290
+ }
29291
+ }
28553
29292
  }
28554
29293
  }
28555
29294
  });
28556
- };
28557
- if (!isEditable) {
28558
- return null;
28559
- }
28560
- return /* @__PURE__ */ jsxs(Fragment, { children: [
28561
- isShownRow && /* @__PURE__ */ jsx(
28562
- "button",
28563
- {
28564
- className: "PlaygroundEditorTheme__tableAddRows ",
28565
- style: { ...position },
28566
- onClick: () => insertAction(true),
28567
- children: /* @__PURE__ */ jsx(PlusIcon, {})
29295
+ if (!insertRow) {
29296
+ requestAnimationFrame(() => {
29297
+ const applyHeaderStyles = () => {
29298
+ const rootElement = editor.getRootElement();
29299
+ if (!rootElement)
29300
+ return false;
29301
+ const tables = rootElement.querySelectorAll("table");
29302
+ tables.forEach((table) => {
29303
+ const rows = table.querySelectorAll("tr");
29304
+ if (rows.length > 0) {
29305
+ const firstRow = rows[0];
29306
+ const cells = firstRow.querySelectorAll("th, td");
29307
+ if (cells.length > 1) {
29308
+ const firstHeaderCell = cells[0];
29309
+ const headerColor = firstHeaderCell.getAttribute("data-header-color");
29310
+ const textColor = firstHeaderCell.getAttribute("data-text-color");
29311
+ if (headerColor && textColor) {
29312
+ const lastCell = cells[cells.length - 1];
29313
+ lastCell.setAttribute("data-header-color", headerColor);
29314
+ lastCell.setAttribute("data-text-color", textColor);
29315
+ lastCell.style.setProperty("background-color", headerColor, "important");
29316
+ lastCell.style.setProperty("color", textColor, "important");
29317
+ lastCell.style.setProperty("padding", "8px", "important");
29318
+ lastCell.style.setProperty("border", "1px solid #ddd", "important");
29319
+ lastCell.style.setProperty("font-weight", "bold", "important");
29320
+ lastCell.style.setProperty("white-space", "nowrap", "important");
29321
+ }
29322
+ }
29323
+ }
29324
+ });
29325
+ return true;
29326
+ };
29327
+ if (!applyHeaderStyles()) {
29328
+ setTimeout(applyHeaderStyles, 100);
29329
+ }
29330
+ });
29331
+ }
29332
+ };
29333
+ if (!isEditable) {
29334
+ return null;
29335
+ }
29336
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
29337
+ isShownRow && /* @__PURE__ */ jsx(
29338
+ "button",
29339
+ {
29340
+ className: "PlaygroundEditorTheme__tableAddRows ",
29341
+ style: { ...position },
29342
+ onClick: () => insertAction(true),
29343
+ children: /* @__PURE__ */ jsx(PlusIcon, {})
28568
29344
  }
28569
29345
  ),
28570
29346
  isShownColumn && /* @__PURE__ */ jsx(
@@ -28686,6 +29462,10 @@ function SlashMenuItem({
28686
29462
  function SlashCommandPlugin() {
28687
29463
  const [editor] = useLexicalComposerContext();
28688
29464
  const [queryString, setQueryString] = useState$1(null);
29465
+ const menuRef = useRef(null);
29466
+ const [menuPosition, setMenuPosition] = useState$1({ left: 0 });
29467
+ const anchorRef = useRef(null);
29468
+ const [isMenuOpen, setIsMenuOpen] = useState$1(false);
28689
29469
  const triggerFn = useBasicTypeaheadTriggerMatch("/", { minLength: 0 });
28690
29470
  const makeBlock = useCallback((cb) => {
28691
29471
  editor.update(() => {
@@ -28772,9 +29552,55 @@ function SlashCommandPlugin() {
28772
29552
  }
28773
29553
  });
28774
29554
  closeMenu();
29555
+ setIsMenuOpen(false);
28775
29556
  },
28776
29557
  [editor]
28777
29558
  );
29559
+ useEffect$1(() => {
29560
+ if (!isMenuOpen) {
29561
+ return;
29562
+ }
29563
+ const menu = menuRef.current;
29564
+ const anchor = anchorRef.current;
29565
+ if (!menu || !anchor) {
29566
+ return;
29567
+ }
29568
+ const updatePosition = () => {
29569
+ const menuRect = menu.getBoundingClientRect();
29570
+ const viewportHeight = window.innerHeight;
29571
+ const viewportWidth = window.innerWidth;
29572
+ const anchorRect = anchor.getBoundingClientRect();
29573
+ const spaceBelow = viewportHeight - anchorRect.bottom;
29574
+ const spaceAbove = anchorRect.top;
29575
+ const menuHeight = menuRect.height || 240;
29576
+ const menuWidth = menuRect.width || 288;
29577
+ let newPosition = { left: anchorRect.left };
29578
+ if (spaceBelow >= menuHeight || spaceBelow >= spaceAbove) {
29579
+ newPosition.top = anchorRect.bottom + 4;
29580
+ } else {
29581
+ newPosition.bottom = viewportHeight - anchorRect.top + 4;
29582
+ }
29583
+ if (anchorRect.left + menuWidth > viewportWidth) {
29584
+ newPosition.left = Math.max(8, viewportWidth - menuWidth - 8);
29585
+ } else {
29586
+ newPosition.left = Math.max(8, anchorRect.left);
29587
+ }
29588
+ setMenuPosition((prev) => {
29589
+ if (prev.top === newPosition.top && prev.bottom === newPosition.bottom && prev.left === newPosition.left) {
29590
+ return prev;
29591
+ }
29592
+ return newPosition;
29593
+ });
29594
+ };
29595
+ const timeoutId = setTimeout(updatePosition, 0);
29596
+ window.addEventListener("scroll", updatePosition, true);
29597
+ window.addEventListener("resize", updatePosition);
29598
+ return () => {
29599
+ clearTimeout(timeoutId);
29600
+ window.removeEventListener("scroll", updatePosition, true);
29601
+ window.removeEventListener("resize", updatePosition);
29602
+ };
29603
+ }, [isMenuOpen]);
28778
29604
  return /* @__PURE__ */ jsx(
28779
29605
  LexicalTypeaheadMenuPlugin,
28780
29606
  {
@@ -28782,31 +29608,52 @@ function SlashCommandPlugin() {
28782
29608
  onSelectOption,
28783
29609
  triggerFn,
28784
29610
  options,
28785
- menuRenderFn: (anchorElementRef, { selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }) => anchorElementRef.current ? ReactDOM.createPortal(
28786
- /* @__PURE__ */ jsxs("div", { className: "cteditor-w-72 cteditor-max-h-60 cteditor-overflow-y-auto no-scrollbar cteditor-backdrop-blur-md cteditor-shadow-xl cteditor-rounded-lg cteditor-border cteditor-border-border cteditor-p-1.5 cteditor-bg-background", style: { position: "absolute" }, children: [
28787
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-justify-between cteditor-px-2 cteditor-py-1 cteditor-text-[11px] cteditor-text-muted-foreground", children: [
28788
- /* @__PURE__ */ jsx("span", { children: queryString ? "Search results" : "Quick actions" }),
28789
- /* @__PURE__ */ jsx("span", { className: "cteditor-hidden sm:cteditor-inline", children: "Type to filter" })
28790
- ] }),
28791
- options.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "cteditor-space-y-1", children: options.map((option, i2) => /* @__PURE__ */ jsx(
28792
- SlashMenuItem,
29611
+ menuRenderFn: (anchorElementRef, { selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }) => {
29612
+ anchorRef.current = anchorElementRef.current;
29613
+ if (anchorElementRef.current && !isMenuOpen) {
29614
+ setIsMenuOpen(true);
29615
+ } else if (!anchorElementRef.current && isMenuOpen) {
29616
+ setIsMenuOpen(false);
29617
+ }
29618
+ return anchorElementRef.current ? ReactDOM.createPortal(
29619
+ /* @__PURE__ */ jsxs(
29620
+ "div",
28793
29621
  {
28794
- index: i2,
28795
- isSelected: selectedIndex === i2,
28796
- onClick: () => {
28797
- setHighlightedIndex(i2);
28798
- selectOptionAndCleanUp(option);
28799
- },
28800
- onMouseEnter: () => {
28801
- setHighlightedIndex(i2);
29622
+ ref: menuRef,
29623
+ className: "cteditor-w-72 cteditor-max-h-60 cteditor-overflow-y-auto no-scrollbar cteditor-backdrop-blur-md cteditor-shadow-xl cteditor-rounded-lg cteditor-border cteditor-border-border cteditor-p-1.5 cteditor-bg-background cteditor-z-50",
29624
+ style: {
29625
+ position: "fixed",
29626
+ top: menuPosition.top,
29627
+ bottom: menuPosition.bottom,
29628
+ left: menuPosition.left
28802
29629
  },
28803
- option
28804
- },
28805
- option.key
28806
- )) }) : /* @__PURE__ */ jsx("div", { className: "cteditor-text-[11px] cteditor-text-muted-foreground cteditor-px-3 cteditor-py-2", children: "No results" })
28807
- ] }),
28808
- anchorElementRef.current
28809
- ) : null
29630
+ children: [
29631
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-justify-between cteditor-px-2 cteditor-py-1 cteditor-text-[11px] cteditor-text-muted-foreground", children: [
29632
+ /* @__PURE__ */ jsx("span", { children: queryString ? "Search results" : "Quick actions" }),
29633
+ /* @__PURE__ */ jsx("span", { className: "cteditor-hidden sm:cteditor-inline", children: "Type to filter" })
29634
+ ] }),
29635
+ options.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "cteditor-space-y-1", children: options.map((option, i2) => /* @__PURE__ */ jsx(
29636
+ SlashMenuItem,
29637
+ {
29638
+ index: i2,
29639
+ isSelected: selectedIndex === i2,
29640
+ onClick: () => {
29641
+ setHighlightedIndex(i2);
29642
+ selectOptionAndCleanUp(option);
29643
+ },
29644
+ onMouseEnter: () => {
29645
+ setHighlightedIndex(i2);
29646
+ },
29647
+ option
29648
+ },
29649
+ option.key
29650
+ )) }) : /* @__PURE__ */ jsx("div", { className: "cteditor-text-[11px] cteditor-text-muted-foreground cteditor-px-3 cteditor-py-2", children: "No results" })
29651
+ ]
29652
+ }
29653
+ ),
29654
+ anchorElementRef.current
29655
+ ) : null;
29656
+ }
28810
29657
  }
28811
29658
  );
28812
29659
  }
@@ -28858,415 +29705,6 @@ const WordCountPlugin = () => {
28858
29705
  }
28859
29706
  );
28860
29707
  };
28861
- const GrammarCheckPlugin$1 = "";
28862
- class GrammarCheckService {
28863
- constructor() {
28864
- __publicField(this, "cache", /* @__PURE__ */ new Map());
28865
- __publicField(this, "apiEndpoint");
28866
- __publicField(this, "pendingRequest", null);
28867
- this.apiEndpoint = "https://api.cteditor.com/api/ai/process";
28868
- }
28869
- async check(text) {
28870
- if (!text || text.trim().length < 3) {
28871
- return [];
28872
- }
28873
- const cacheKey = text.trim();
28874
- if (this.cache.has(cacheKey)) {
28875
- return this.cache.get(cacheKey);
28876
- }
28877
- if (this.pendingRequest) {
28878
- return this.pendingRequest;
28879
- }
28880
- this.pendingRequest = this.executeCheck(text);
28881
- try {
28882
- const result = await this.pendingRequest;
28883
- return result;
28884
- } finally {
28885
- this.pendingRequest = null;
28886
- }
28887
- }
28888
- async executeCheck(text) {
28889
- var _a, _b, _c, _d, _e, _f;
28890
- try {
28891
- const response = await fetch(this.apiEndpoint, {
28892
- method: "POST",
28893
- headers: { "Content-Type": "application/json" },
28894
- body: JSON.stringify({ text: text.trim(), maxSuggestions: 3 }),
28895
- signal: AbortSignal.timeout(1e4)
28896
- });
28897
- if (!response.ok) {
28898
- console.error("❌ GrammarCheck: API error:", response.status);
28899
- return [];
28900
- }
28901
- const result = await response.json();
28902
- const foundErrors = [];
28903
- if ((_c = (_b = (_a = result.data) == null ? void 0 : _a.corrections) == null ? void 0 : _b.spelling) == null ? void 0 : _c.errors) {
28904
- result.data.corrections.spelling.errors.forEach((err, idx) => {
28905
- foundErrors.push({
28906
- type: "spelling",
28907
- original: err.original,
28908
- suggestions: err.suggestions || [],
28909
- index: idx
28910
- });
28911
- });
28912
- }
28913
- if ((_f = (_e = (_d = result.data) == null ? void 0 : _d.corrections) == null ? void 0 : _e.grammar) == null ? void 0 : _f.errors) {
28914
- result.data.corrections.grammar.errors.forEach((err, idx) => {
28915
- foundErrors.push({
28916
- type: "grammar",
28917
- original: err.original || text,
28918
- suggestions: [err.suggestion],
28919
- index: foundErrors.length + idx,
28920
- issue: err.issue
28921
- });
28922
- });
28923
- }
28924
- this.cache.set(text.trim(), foundErrors);
28925
- if (this.cache.size > 30) {
28926
- const firstKey = this.cache.keys().next().value;
28927
- if (firstKey) {
28928
- this.cache.delete(firstKey);
28929
- }
28930
- }
28931
- return foundErrors;
28932
- } catch (error) {
28933
- console.error("❌ GrammarCheck: Check failed:", error);
28934
- return [];
28935
- }
28936
- }
28937
- }
28938
- function GrammarCheckPlugin() {
28939
- const [editor] = useLexicalComposerContext();
28940
- const { updateToolbarState } = useToolbarState();
28941
- const [errors, setErrors] = useState$1([]);
28942
- const [tooltip, setTooltip] = useState$1(null);
28943
- const [userDismissed, setUserDismissed] = useState$1(false);
28944
- const grammarService = useRef(new GrammarCheckService());
28945
- const checkTimeout = useRef();
28946
- const lastCheckedText = useRef("");
28947
- const highlightElementsRef = useRef([]);
28948
- const checkGrammar = useCallback(async () => {
28949
- const isSlashActive = editor.getEditorState().read(() => {
28950
- const selection = $getSelection();
28951
- if (!$isRangeSelection(selection))
28952
- return false;
28953
- const anchor = selection.anchor;
28954
- const anchorNode = anchor.getNode();
28955
- const anchorOffset = anchor.offset;
28956
- const textContent = anchorNode.getTextContent();
28957
- let wordStart = anchorOffset;
28958
- while (wordStart > 0 && /[a-zA-Z0-9_']/.test(textContent[wordStart - 1])) {
28959
- wordStart--;
28960
- }
28961
- return wordStart > 0 && textContent[wordStart - 1] === "/";
28962
- });
28963
- if (isSlashActive) {
28964
- setErrors([]);
28965
- return;
28966
- }
28967
- const text = editor.getEditorState().read(() => $getRoot().getTextContent());
28968
- if (text === lastCheckedText.current) {
28969
- return;
28970
- }
28971
- if (Math.abs(text.length - lastCheckedText.current.length) > 20) {
28972
- setUserDismissed(false);
28973
- }
28974
- lastCheckedText.current = text;
28975
- if (!text || text.trim().length < 3) {
28976
- setErrors([]);
28977
- return;
28978
- }
28979
- const foundErrors = await grammarService.current.check(text);
28980
- setErrors(foundErrors);
28981
- }, [editor]);
28982
- useEffect$1(() => {
28983
- const unregister = editor.registerUpdateListener(() => {
28984
- clearTimeout(checkTimeout.current);
28985
- checkTimeout.current = window.setTimeout(checkGrammar, 2e3);
28986
- });
28987
- return () => {
28988
- unregister();
28989
- clearTimeout(checkTimeout.current);
28990
- };
28991
- }, [editor, checkGrammar]);
28992
- useEffect$1(() => {
28993
- highlightElementsRef.current.forEach((el) => {
28994
- el.classList.remove("spelling-error", "grammar-error");
28995
- });
28996
- highlightElementsRef.current = [];
28997
- if (errors.length === 0 || userDismissed)
28998
- return;
28999
- const timeoutId = setTimeout(() => {
29000
- const editorElement = document.querySelector(".ContentEditable__root");
29001
- if (!editorElement)
29002
- return;
29003
- const walker = document.createTreeWalker(
29004
- editorElement,
29005
- NodeFilter.SHOW_TEXT,
29006
- null
29007
- );
29008
- const textNodes = [];
29009
- let node;
29010
- while (node = walker.nextNode()) {
29011
- textNodes.push(node);
29012
- }
29013
- errors.forEach((error) => {
29014
- textNodes.forEach((textNode) => {
29015
- const nodeText = textNode.textContent || "";
29016
- const errorIndex = nodeText.toLowerCase().indexOf(error.original.toLowerCase());
29017
- if (errorIndex !== -1 && textNode.parentElement) {
29018
- const className = error.type === "spelling" ? "spelling-error" : "grammar-error";
29019
- if (textNode.parentElement.tagName === "SPAN") {
29020
- textNode.parentElement.classList.add(className);
29021
- highlightElementsRef.current.push(textNode.parentElement);
29022
- } else if (textNode.parentElement) {
29023
- const range = document.createRange();
29024
- range.setStart(textNode, errorIndex);
29025
- range.setEnd(textNode, Math.min(errorIndex + error.original.length, nodeText.length));
29026
- const span = document.createElement("span");
29027
- span.className = className;
29028
- span.setAttribute("data-error-type", error.type);
29029
- try {
29030
- range.surroundContents(span);
29031
- highlightElementsRef.current.push(span);
29032
- } catch (e) {
29033
- if (textNode.parentElement) {
29034
- textNode.parentElement.classList.add(className);
29035
- highlightElementsRef.current.push(textNode.parentElement);
29036
- }
29037
- }
29038
- }
29039
- }
29040
- });
29041
- });
29042
- }, 100);
29043
- return () => clearTimeout(timeoutId);
29044
- }, [errors, userDismissed]);
29045
- const getWordAtPoint = useCallback((x2, y2) => {
29046
- try {
29047
- let range = null;
29048
- if (document.caretRangeFromPoint) {
29049
- range = document.caretRangeFromPoint(x2, y2);
29050
- } else if (document.caretPositionFromPoint) {
29051
- const position = document.caretPositionFromPoint(x2, y2);
29052
- if (position) {
29053
- range = document.createRange();
29054
- range.setStart(position.offsetNode, position.offset);
29055
- }
29056
- }
29057
- if (!range)
29058
- return null;
29059
- const textNode = range.startContainer;
29060
- if (textNode.nodeType !== Node.TEXT_NODE)
29061
- return null;
29062
- const text = textNode.textContent || "";
29063
- let start = range.startOffset;
29064
- let end = range.startOffset;
29065
- while (start > 0 && /\w/.test(text[start - 1])) {
29066
- start--;
29067
- }
29068
- while (end < text.length && /\w/.test(text[end])) {
29069
- end++;
29070
- }
29071
- const word = text.substring(start, end).trim();
29072
- return word || null;
29073
- } catch (error) {
29074
- console.error("Error getting word at point:", error);
29075
- return null;
29076
- }
29077
- }, []);
29078
- useEffect$1(() => {
29079
- if (errors.length === 0)
29080
- return;
29081
- let hoverTimeout;
29082
- const handleMouseMove = (e) => {
29083
- clearTimeout(hoverTimeout);
29084
- hoverTimeout = window.setTimeout(() => {
29085
- const wordAtCursor = getWordAtPoint(e.clientX, e.clientY);
29086
- if (wordAtCursor) {
29087
- const matchedError = errors.find(
29088
- (err) => wordAtCursor.toLowerCase() === err.original.toLowerCase()
29089
- );
29090
- if (matchedError) {
29091
- setTooltip({
29092
- error: matchedError,
29093
- x: e.clientX,
29094
- y: e.clientY
29095
- });
29096
- }
29097
- }
29098
- }, 50);
29099
- };
29100
- const handleClick = () => {
29101
- setTooltip(null);
29102
- };
29103
- document.addEventListener("mousemove", handleMouseMove);
29104
- document.addEventListener("click", handleClick);
29105
- return () => {
29106
- clearTimeout(hoverTimeout);
29107
- document.removeEventListener("mousemove", handleMouseMove);
29108
- document.removeEventListener("click", handleClick);
29109
- };
29110
- }, [errors, getWordAtPoint]);
29111
- const applyCorrection = useCallback(
29112
- (suggestion, original, errorType) => {
29113
- editor.update(() => {
29114
- const root2 = $getRoot();
29115
- const currentText = root2.getTextContent();
29116
- const isSpellingError = errorType === "spelling";
29117
- let newText = currentText;
29118
- if (isSpellingError) {
29119
- const escapedOriginal = original.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29120
- const regex = new RegExp(`\\b${escapedOriginal}\\b`, "gi");
29121
- newText = currentText.replace(regex, suggestion);
29122
- } else {
29123
- const escapedOriginal = original.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29124
- const regex = new RegExp(escapedOriginal, "gi");
29125
- if (currentText.toLowerCase().includes(original.toLowerCase())) {
29126
- newText = currentText.replace(regex, suggestion);
29127
- } else {
29128
- newText = suggestion;
29129
- }
29130
- }
29131
- root2.clear();
29132
- const paragraph = $createParagraphNode();
29133
- const textNode = $createTextNode(newText);
29134
- paragraph.append(textNode);
29135
- root2.append(paragraph);
29136
- });
29137
- setTooltip(null);
29138
- setTimeout(() => {
29139
- lastCheckedText.current = "";
29140
- checkGrammar();
29141
- }, 100);
29142
- },
29143
- [editor, checkGrammar]
29144
- );
29145
- const showErrorTooltip = (error, event) => {
29146
- setTooltip({
29147
- error,
29148
- x: event.clientX,
29149
- y: event.clientY
29150
- });
29151
- };
29152
- return /* @__PURE__ */ jsxs(Fragment, { children: [
29153
- errors.length > 0 && !userDismissed && /* @__PURE__ */ jsx("div", { className: "grammar-error-panel", children: /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-bg-amber-50 cteditor-border cteditor-border-amber-200 cteditor-rounded-lg cteditor-px-3 cteditor-py-2 cteditor-shadow-sm", children: [
29154
- /* @__PURE__ */ jsx(AlertCircle, { className: "cteditor-h-4 cteditor-w-4 cteditor-text-amber-600 cteditor-flex-shrink-0" }),
29155
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-flex-1 cteditor-overflow-x-auto cteditor-max-w-2xl", children: [
29156
- /* @__PURE__ */ jsxs("span", { className: "cteditor-text-xs cteditor-font-semibold cteditor-text-amber-800 cteditor-whitespace-nowrap", children: [
29157
- errors.length,
29158
- " ",
29159
- errors.length === 1 ? "issue" : "issues",
29160
- ":"
29161
- ] }),
29162
- /* @__PURE__ */ jsx("div", { className: "cteditor-flex cteditor-gap-2 cteditor-items-center", children: errors.map((error, idx) => /* @__PURE__ */ jsxs(
29163
- "div",
29164
- {
29165
- className: "cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-bg-white cteditor-border cteditor-border-gray-200 cteditor-rounded cteditor-px-2 cteditor-py-1 cteditor-whitespace-nowrap cteditor-cursor-pointer hover:cteditor-bg-gray-50 cteditor-transition-colors",
29166
- onClick: (e) => showErrorTooltip(error, e),
29167
- children: [
29168
- /* @__PURE__ */ jsx("span", { className: "cteditor-text-xs cteditor-line-through cteditor-text-red-600 cteditor-max-w-24 cteditor-truncate", title: error.original, children: error.original }),
29169
- /* @__PURE__ */ jsx("span", { className: "cteditor-text-xs cteditor-text-gray-400", children: "→" }),
29170
- /* @__PURE__ */ jsx(
29171
- "button",
29172
- {
29173
- onClick: (e) => {
29174
- e.stopPropagation();
29175
- applyCorrection(error.suggestions[0], error.original, error.type);
29176
- },
29177
- className: "cteditor-text-xs cteditor-text-green-600 hover:cteditor-text-green-700 cteditor-font-medium cteditor-max-w-24 cteditor-truncate",
29178
- title: error.suggestions[0],
29179
- children: error.suggestions[0]
29180
- }
29181
- )
29182
- ]
29183
- },
29184
- idx
29185
- )) })
29186
- ] }),
29187
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-1 cteditor-flex-shrink-0", children: [
29188
- /* @__PURE__ */ jsx(
29189
- Button,
29190
- {
29191
- variant: "link",
29192
- size: "sm",
29193
- onClick: () => {
29194
- setUserDismissed(true);
29195
- setErrors([]);
29196
- updateToolbarState("isGrammarCheckEnabled", false);
29197
- },
29198
- className: "cteditor-h-7 cteditor-px-2 cteditor-text-xs !cteditor-text-amber-700 ",
29199
- title: "Disable Grammar Check",
29200
- children: "Disable"
29201
- }
29202
- ),
29203
- /* @__PURE__ */ jsx(
29204
- "button",
29205
- {
29206
- onClick: () => setUserDismissed(true),
29207
- className: "cteditor-p-1 hover:cteditor-bg-amber-100 cteditor-rounded cteditor-transition-colors",
29208
- title: "Dismiss grammar suggestions",
29209
- children: /* @__PURE__ */ jsx(X$1, { className: "cteditor-h-3.5 cteditor-w-3.5 cteditor-text-amber-600" })
29210
- }
29211
- )
29212
- ] })
29213
- ] }) }),
29214
- tooltip && createPortal(
29215
- /* @__PURE__ */ jsx(
29216
- "div",
29217
- {
29218
- className: "grammar-tooltip ",
29219
- style: {
29220
- position: "fixed",
29221
- left: tooltip.x,
29222
- top: tooltip.y + 20,
29223
- zIndex: 1e4
29224
- },
29225
- onMouseEnter: () => {
29226
- },
29227
- onMouseLeave: () => {
29228
- setTooltip(null);
29229
- },
29230
- children: /* @__PURE__ */ jsx(Card, { className: "cteditor-w-72 cteditor-shadow-xl cteditor-border-2 cteditor-bg-background cteditor-rounded-xl", children: /* @__PURE__ */ jsxs(CardContent, { className: "cteditor-p-3", children: [
29231
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-mb-3", children: [
29232
- tooltip.error.type === "spelling" ? /* @__PURE__ */ jsx(AlertCircle, { className: "cteditor-h-4 cteditor-w-4 cteditor-text-red-500" }) : /* @__PURE__ */ jsx(CheckCircle, { className: "cteditor-h-4 cteditor-w-4 cteditor-text-blue-500" }),
29233
- /* @__PURE__ */ jsx(
29234
- Badge,
29235
- {
29236
- variant: tooltip.error.type === "spelling" ? "destructive" : "default",
29237
- className: "cteditor-text-xs",
29238
- children: tooltip.error.type === "spelling" ? "Spelling Error" : "Grammar Issue"
29239
- }
29240
- )
29241
- ] }),
29242
- tooltip.error.issue && /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-text-muted-foreground cteditor-mb-2 cteditor-italic", children: tooltip.error.issue }),
29243
- /* @__PURE__ */ jsxs("div", { className: "cteditor-mb-2", children: [
29244
- /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-font-semibold cteditor-text-muted-foreground", children: "Original:" }),
29245
- /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-line-through cteditor-text-red-600", children: tooltip.error.original })
29246
- ] }),
29247
- tooltip.error.suggestions.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
29248
- /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-font-semibold cteditor-text-muted-foreground cteditor-mb-1", children: "Suggestions:" }),
29249
- /* @__PURE__ */ jsx("div", { className: "cteditor-space-y-1", children: tooltip.error.suggestions.map((suggestion, idx) => /* @__PURE__ */ jsxs(
29250
- "button",
29251
- {
29252
- onClick: () => applyCorrection(suggestion, tooltip.error.original, tooltip.error.type),
29253
- className: "cteditor-w-full cteditor-text-left cteditor-p-2 cteditor-text-sm cteditor-rounded-md cteditor-bg-accent/50 hover:cteditor-bg-accent cteditor-transition-colors cteditor-border cteditor-border-transparent hover:cteditor-border-primary",
29254
- children: [
29255
- "✓ ",
29256
- suggestion
29257
- ]
29258
- },
29259
- idx
29260
- )) })
29261
- ] }),
29262
- tooltip.error.suggestions.length === 0 && /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-text-muted-foreground cteditor-italic", children: "No suggestions available" })
29263
- ] }) })
29264
- }
29265
- ),
29266
- document.body
29267
- )
29268
- ] });
29269
- }
29270
29708
  const useStyles = () => ({
29271
29709
  // container: "cteditor-relative cteditor-w-full cteditor-bg-white cteditor-text-black cteditor-font-normal cteditor-text-left cteditor-border cteditor-border-red-500",
29272
29710
  contentEditable: cn$1(
@@ -29360,12 +29798,12 @@ const ToolbarWithEditor = (props) => {
29360
29798
  }
29361
29799
  );
29362
29800
  };
29363
- const AutocompleteWrapper = () => {
29801
+ const CombinedPluginWrapper = () => {
29364
29802
  const { toolbarState } = useToolbarState();
29365
- if (!toolbarState.isAutocompleteEnabled) {
29803
+ if (!toolbarState.isAutocompleteEnabled && !toolbarState.isGrammarCheckEnabled) {
29366
29804
  return null;
29367
29805
  }
29368
- return /* @__PURE__ */ jsx(AutocompletePlugin, { minMatchLength: 2, maxSuggestions: 10 });
29806
+ return /* @__PURE__ */ jsx(CombinedAutocompleteGrammarPlugin, { minMatchLength: 2, maxSuggestions: 10, enableAI: true });
29369
29807
  };
29370
29808
  const OnChangeWrapper = ({ onChange }) => {
29371
29809
  const [editor] = useLexicalComposerContext();
@@ -29492,14 +29930,15 @@ const ConfigurableEditor = ({
29492
29930
  /* @__PURE__ */ jsx(HtmlSyncPlugin, {}),
29493
29931
  /* @__PURE__ */ jsx(CodeHighlightPlugin, {}),
29494
29932
  /* @__PURE__ */ jsx(SlashCommandPlugin, {}),
29495
- /* @__PURE__ */ jsx(AutocompleteWrapper, {}),
29496
- /* @__PURE__ */ jsx(GrammarCheckPlugin, {}),
29933
+ /* @__PURE__ */ jsx(CombinedPluginWrapper, {}),
29497
29934
  /* @__PURE__ */ jsx(OnChangeWrapper, { onChange }),
29498
29935
  /* @__PURE__ */ jsx(InitialContentPlugin, { initialContent }),
29499
29936
  /* @__PURE__ */ jsx(HistoryPlugin, {}),
29500
29937
  /* @__PURE__ */ jsx(LocalStoragePlugin$1, { namespace: initialConfig.namespace }),
29501
29938
  /* @__PURE__ */ jsx(ListPlugin, {}),
29502
29939
  /* @__PURE__ */ jsx(LinkPlugin, { hasLinkAttributes: false }),
29940
+ /* @__PURE__ */ jsx(DragDropPaste, {}),
29941
+ /* @__PURE__ */ jsx(RichTextPastePlugin, {}),
29503
29942
  /* @__PURE__ */ jsx(FilePlugin, {}),
29504
29943
  /* @__PURE__ */ jsx(HorizontalRulePlugin, {}),
29505
29944
  /* @__PURE__ */ jsx(CustomHorizontalRulePlugin, {}),
@@ -29561,7 +30000,7 @@ const ScopedEditorWrapper = ({
29561
30000
  className = "",
29562
30001
  darkMode = false
29563
30002
  }) => {
29564
- return /* @__PURE__ */ jsx("div", { id: "ct-editor-f47ac10b", children: /* @__PURE__ */ jsx("div", { className: "cteditor-p-2 ", children }) });
30003
+ return /* @__PURE__ */ jsx("div", { id: "ct-editor-f47ac10b", className: "cteditor-max-w-full cteditor-overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "cteditor-p-2 cteditor-w-full", children }) });
29565
30004
  };
29566
30005
  const MessageContainer = styled.div`
29567
30006
  display: flex;
@@ -29685,4 +30124,4 @@ export {
29685
30124
  useHtmlView as u,
29686
30125
  verifyApiKey as v
29687
30126
  };
29688
- //# sourceMappingURL=index-7aab7b5a.js.map
30127
+ //# sourceMappingURL=index-8d147c36.js.map