ct-rich-text-editor 1.3.7 → 1.3.8

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 (26) hide show
  1. package/dist/api/featureSuggestion.d.ts +21 -0
  2. package/dist/assets/style.css +186 -81
  3. package/dist/components/FeatureSuggestionDialog/index.d.ts +6 -0
  4. package/dist/components/ImageComparisonDialog/index.d.ts +11 -0
  5. package/dist/components/ImageGenerationDialog/ImageGenerationManager.d.ts +2 -1
  6. package/dist/components/ImageGenerationDialog/index.d.ts +2 -1
  7. package/dist/components/ImageView/index.d.ts +2 -1
  8. package/dist/{html2pdf.bundle-40cc5697.js → html2pdf.bundle-6d32d085.js} +2 -2
  9. package/dist/{html2pdf.bundle-40cc5697.js.map → html2pdf.bundle-6d32d085.js.map} +1 -1
  10. package/dist/{html2pdf.bundle.min-bb81d5dc.js → html2pdf.bundle.min-b3120e0c.js} +2 -2
  11. package/dist/{html2pdf.bundle.min-bb81d5dc.js.map → html2pdf.bundle.min-b3120e0c.js.map} +1 -1
  12. package/dist/{index-a8476eee.js → index-158a9bd4.js} +2284 -1003
  13. package/dist/index-158a9bd4.js.map +1 -0
  14. package/dist/{index-308e13ae.js → index-42136c92.js} +254 -7
  15. package/dist/index-42136c92.js.map +1 -0
  16. package/dist/{index-f0d8f7a8.js → index-9548fdb4.js} +2 -2
  17. package/dist/{index-f0d8f7a8.js.map → index-9548fdb4.js.map} +1 -1
  18. package/dist/index.js +5 -5
  19. package/dist/nodes/ImageNode.d.ts +8 -2
  20. package/dist/plugins/LinkPreviewPlugin/index.d.ts +2 -0
  21. package/dist/plugins/TableHoverActionsPlugin/index.d.ts +2 -11
  22. package/dist/plugins/TableHoverActionsPlugin/index_old_backup.d.ts +17 -0
  23. package/dist/plugins/TablePlugin.d.ts +1 -1
  24. package/package.json +2 -1
  25. package/dist/index-308e13ae.js.map +0 -1
  26. package/dist/index-a8476eee.js.map +0 -1
@@ -6,7 +6,7 @@ var __publicField = (obj, key, value) => {
6
6
  };
7
7
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
8
8
  import * as React$1 from "react";
9
- import React__default, { createContext, useContext, useState as useState$1, forwardRef, createElement, useImperativeHandle, useRef, useEffect as useEffect$1, useMemo, useCallback, useLayoutEffect as useLayoutEffect$1, Suspense, Component } from "react";
9
+ import React__default, { createContext, useContext, useState as useState$1, Suspense, useEffect as useEffect$1, forwardRef, createElement, useImperativeHandle, useRef, useMemo, useCallback, useLayoutEffect as useLayoutEffect$1, Component } from "react";
10
10
  import axios from "axios";
11
11
  import styled from "@emotion/styled";
12
12
  import { $generateNodesFromDOM, $generateHtmlFromNodes } from "@lexical/html";
@@ -21,10 +21,10 @@ 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 { TableNode, TableCellNode, TableRowNode, $createTableNodeWithDimensions, $isTableRowNode, $isTableCellNode, TableCellHeaderStates, $isTableNode, $isTableSelection, $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, getTableElement, getTableObserverFromTableElement, $insertTableRow__EXPERIMENTAL, $insertTableColumn__EXPERIMENTAL, $getNodeTriplet, $deleteTableRow__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL, $getTableRowIndexFromTableCellNode, $getTableColumnIndexFromTableCellNode, $unmergeCell, $computeTableMapSkipCellCheck, getDOMCellFromTarget, $getTableAndElementByKey } from "@lexical/table";
25
- import { $findMatchingParent, $getNearestNodeOfType, mergeRegister, $getNearestBlockElementAncestorOrThrow, $insertNodeToNearestRoot, $wrapNodeInElement, $isEditorIsNestedEditor, mediaFileReader, isMimeType, calculateZoomLevel, CAN_USE_DOM } from "@lexical/utils";
24
+ import { TableNode, TableCellNode, TableRowNode, $createTableNodeWithDimensions, $isTableRowNode, $isTableCellNode, TableCellHeaderStates, $isTableNode, $isTableSelection, $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, getTableElement, getTableObserverFromTableElement, $getNodeTriplet, $getTableRowIndexFromTableCellNode, $insertTableRow__EXPERIMENTAL, $getTableColumnIndexFromTableCellNode, $insertTableColumn__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL, $unmergeCell, $computeTableMapSkipCellCheck, getDOMCellFromTarget, $getTableAndElementByKey } from "@lexical/table";
25
+ import { mergeRegister, $wrapNodeInElement, $findMatchingParent, $getNearestNodeOfType, $getNearestBlockElementAncestorOrThrow, $insertNodeToNearestRoot, $isEditorIsNestedEditor, mediaFileReader, isMimeType, calculateZoomLevel, CAN_USE_DOM } from "@lexical/utils";
26
26
  import Stack from "@mui/material/Stack";
27
- 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, getDOMSelection, CLICK_COMMAND, COMMAND_PRIORITY_HIGH, $isLineBreakNode, PASTE_COMMAND, isDOMNode } from "lexical";
27
+ import { createCommand, DecoratorNode, createEditor, $applyNodeReplacement, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $getNearestNodeFromDOMNode, $setSelection, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $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, getDOMSelection, CLICK_COMMAND, COMMAND_PRIORITY_HIGH, $isLineBreakNode, PASTE_COMMAND, isDOMNode } from "lexical";
28
28
  import * as ReactDOM from "react-dom";
29
29
  import ReactDOM__default, { createPortal } from "react-dom";
30
30
  import { $isCodeNode, CodeNode, normalizeCodeLang, getLanguageFriendlyName, CodeHighlightNode, CODE_LANGUAGE_MAP, $createCodeNode, registerCodeHighlighting, $isCodeHighlightNode } from "@lexical/code";
@@ -1463,6 +1463,236 @@ const GetUserInfo = async ({ apiKey }) => {
1463
1463
  const AI_ACTION_COMMAND = createCommand(
1464
1464
  "AI_ACTION_COMMAND"
1465
1465
  );
1466
+ const ImageView = React__default.lazy(() => import("./index-42136c92.js"));
1467
+ function isGoogleDocCheckboxImg(img) {
1468
+ return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
1469
+ }
1470
+ function $convertImageElement(domNode) {
1471
+ const img = domNode;
1472
+ if (img.src.startsWith("file:///") || isGoogleDocCheckboxImg(img)) {
1473
+ return null;
1474
+ }
1475
+ const { alt: altText, src, width, height } = img;
1476
+ const node = $createImageNode({ altText, height, src, width });
1477
+ return { node };
1478
+ }
1479
+ class ImageNode extends DecoratorNode {
1480
+ constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, key) {
1481
+ super(key);
1482
+ __publicField(this, "__src");
1483
+ __publicField(this, "__altText");
1484
+ __publicField(this, "__width");
1485
+ __publicField(this, "__height");
1486
+ __publicField(this, "__maxWidth");
1487
+ __publicField(this, "__showCaption");
1488
+ __publicField(this, "__caption");
1489
+ // Captions cannot yet be used within editor cells
1490
+ __publicField(this, "__captionsEnabled");
1491
+ __publicField(this, "__originalPrompt");
1492
+ this.__src = src;
1493
+ this.__altText = altText;
1494
+ this.__maxWidth = maxWidth;
1495
+ this.__width = width || "inherit";
1496
+ this.__height = height || "inherit";
1497
+ this.__showCaption = showCaption || false;
1498
+ this.__caption = caption || createEditor({
1499
+ nodes: []
1500
+ });
1501
+ this.__captionsEnabled = captionsEnabled || captionsEnabled === void 0;
1502
+ this.__originalPrompt = originalPrompt || "";
1503
+ }
1504
+ // to identify the image node and must unique too
1505
+ static getType() {
1506
+ return "image";
1507
+ }
1508
+ // Clones the ImageNode when needed (during editor updates)
1509
+ static clone(node) {
1510
+ return new ImageNode(
1511
+ node.__src,
1512
+ node.__altText,
1513
+ node.__maxWidth,
1514
+ node.__width,
1515
+ node.__height,
1516
+ node.__showCaption,
1517
+ node.__caption,
1518
+ node.__captionsEnabled,
1519
+ node.__originalPrompt,
1520
+ node.__key
1521
+ );
1522
+ }
1523
+ // importing to json format
1524
+ static importJSON(serializedNode) {
1525
+ const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt } = serializedNode;
1526
+ const node = $createImageNode({
1527
+ altText,
1528
+ height,
1529
+ maxWidth,
1530
+ showCaption,
1531
+ src,
1532
+ width,
1533
+ originalPrompt: originalPrompt || ""
1534
+ // Default to empty string if undefined
1535
+ });
1536
+ const nestedEditor = node.__caption;
1537
+ const editorState = nestedEditor.parseEditorState(caption.editorState);
1538
+ if (!editorState.isEmpty()) {
1539
+ nestedEditor.setEditorState(editorState);
1540
+ }
1541
+ return node;
1542
+ }
1543
+ // Exports this node as an actual <img> tag in the DOM when needed
1544
+ exportDOM() {
1545
+ const element = document.createElement("img");
1546
+ element.setAttribute("src", this.__src);
1547
+ element.setAttribute("alt", this.__altText);
1548
+ element.setAttribute("width", this.__width.toString());
1549
+ element.setAttribute("height", this.__height.toString());
1550
+ return { element };
1551
+ }
1552
+ // convert img tag into image node in the editor using convertImageElement func
1553
+ static importDOM() {
1554
+ return {
1555
+ img: (node) => ({
1556
+ conversion: $convertImageElement,
1557
+ priority: 0
1558
+ })
1559
+ };
1560
+ }
1561
+ exportJSON() {
1562
+ return {
1563
+ altText: this.getAltText(),
1564
+ caption: this.__caption.toJSON(),
1565
+ height: this.__height === "inherit" ? 0 : this.__height,
1566
+ maxWidth: this.__maxWidth,
1567
+ showCaption: this.__showCaption,
1568
+ src: this.getSrc(),
1569
+ type: "image",
1570
+ version: 1,
1571
+ width: this.__width === "inherit" ? 0 : this.__width,
1572
+ originalPrompt: this.__originalPrompt
1573
+ };
1574
+ }
1575
+ // setting width and height when resizing
1576
+ setWidthAndHeight(width, height) {
1577
+ const writable = this.getWritable();
1578
+ writable.__width = width;
1579
+ writable.__height = height;
1580
+ }
1581
+ // state to update to show the caption
1582
+ setShowCaption(showCaption) {
1583
+ const writable = this.getWritable();
1584
+ writable.__showCaption = showCaption;
1585
+ }
1586
+ // To create a dom representation of image view
1587
+ createDOM(config) {
1588
+ const span = document.createElement("span");
1589
+ const theme2 = config.theme;
1590
+ const className = theme2.image;
1591
+ if (className !== void 0) {
1592
+ span.className = className;
1593
+ }
1594
+ return span;
1595
+ }
1596
+ updateDOM() {
1597
+ return false;
1598
+ }
1599
+ // to get the image src
1600
+ getSrc() {
1601
+ return this.__src;
1602
+ }
1603
+ // to set the image src (for image refinement)
1604
+ setSrc(src) {
1605
+ const writable = this.getWritable();
1606
+ writable.__src = src;
1607
+ }
1608
+ getAltText() {
1609
+ return this.__altText;
1610
+ }
1611
+ // to get the original prompt
1612
+ getOriginalPrompt() {
1613
+ return this.__originalPrompt;
1614
+ }
1615
+ // to set/update the original prompt (when refining)
1616
+ setOriginalPrompt(prompt) {
1617
+ const writable = this.getWritable();
1618
+ writable.__originalPrompt = prompt;
1619
+ }
1620
+ // to render the image tag
1621
+ decorate() {
1622
+ return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
1623
+ ImageView,
1624
+ {
1625
+ src: this.__src,
1626
+ altText: this.__altText,
1627
+ width: this.__width,
1628
+ height: this.__height,
1629
+ maxWidth: this.__maxWidth,
1630
+ nodeKey: this.getKey(),
1631
+ showCaption: this.__showCaption,
1632
+ caption: this.__caption,
1633
+ captionsEnabled: this.__captionsEnabled,
1634
+ resizable: true,
1635
+ originalPrompt: this.__originalPrompt
1636
+ }
1637
+ ) });
1638
+ }
1639
+ }
1640
+ function $createImageNode({
1641
+ altText,
1642
+ height,
1643
+ maxWidth = 500,
1644
+ captionsEnabled,
1645
+ src,
1646
+ width,
1647
+ showCaption,
1648
+ caption,
1649
+ key,
1650
+ originalPrompt
1651
+ }) {
1652
+ return $applyNodeReplacement(
1653
+ new ImageNode(
1654
+ src,
1655
+ altText,
1656
+ maxWidth,
1657
+ width,
1658
+ height,
1659
+ showCaption,
1660
+ caption,
1661
+ captionsEnabled,
1662
+ originalPrompt,
1663
+ key
1664
+ )
1665
+ );
1666
+ }
1667
+ function $isImageNode(node) {
1668
+ return node instanceof ImageNode;
1669
+ }
1670
+ const INSERT_IMAGE_COMMAND = createCommand("INSERT_IMAGE_COMMAND");
1671
+ const ImagePlugin = ({
1672
+ captionsEnabled
1673
+ }) => {
1674
+ const [editor] = useLexicalComposerContext();
1675
+ useEffect$1(() => {
1676
+ if (!editor.hasNodes([ImageNode])) {
1677
+ throw new Error("ImagesPlugin: ImageNode not registered on editor");
1678
+ }
1679
+ return mergeRegister(
1680
+ editor.registerCommand(
1681
+ INSERT_IMAGE_COMMAND,
1682
+ (payload) => {
1683
+ const imageNode = $createImageNode(payload);
1684
+ $insertNodes([imageNode]);
1685
+ if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
1686
+ $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
1687
+ }
1688
+ return true;
1689
+ },
1690
+ COMMAND_PRIORITY_EDITOR
1691
+ )
1692
+ );
1693
+ }, [captionsEnabled, editor]);
1694
+ return null;
1695
+ };
1466
1696
  function setRef(ref, value) {
1467
1697
  if (typeof ref === "function") {
1468
1698
  return ref(value);
@@ -7769,6 +7999,7 @@ const ImageGenerationDialog = ({
7769
7999
  open,
7770
8000
  onOpenChange,
7771
8001
  onGenerate,
8002
+ onInsertImage,
7772
8003
  isGenerating,
7773
8004
  initialText
7774
8005
  }) => {
@@ -7778,11 +8009,29 @@ const ImageGenerationDialog = ({
7778
8009
  setPrompt(initialText);
7779
8010
  }
7780
8011
  }, [open, initialText]);
8012
+ React__default.useEffect(() => {
8013
+ if (!open) {
8014
+ setPrompt("");
8015
+ }
8016
+ }, [open]);
7781
8017
  const handleGenerate = async () => {
7782
8018
  if (!prompt.trim())
7783
8019
  return;
7784
- await onGenerate(prompt.trim());
7785
- setPrompt("");
8020
+ try {
8021
+ const trimmedPrompt = prompt.trim();
8022
+ const cleanPrompt = trimmedPrompt.replace(/^(generate|create|make|draw|paint)\s+(a|an|me|)\s*(image|picture|photo|drawing|illustration)\s+(of|with|showing|depicting)\s+/gi, "").replace(/^(generate|create|make|draw|paint)\s+(a|an|me|)\s*/gi, "").trim();
8023
+ const finalPrompt = cleanPrompt || trimmedPrompt;
8024
+ const imageUrl = await onGenerate(trimmedPrompt);
8025
+ if (!imageUrl || !imageUrl.includes("http")) {
8026
+ throw new Error("Invalid image URL received");
8027
+ }
8028
+ onInsertImage(imageUrl, finalPrompt);
8029
+ await new Promise((resolve) => setTimeout(resolve, 200));
8030
+ handleClose();
8031
+ } catch (error) {
8032
+ console.error("Error generating image:", error);
8033
+ throw error;
8034
+ }
7786
8035
  };
7787
8036
  const handleClose = () => {
7788
8037
  if (!isGenerating) {
@@ -7790,7 +8039,7 @@ const ImageGenerationDialog = ({
7790
8039
  onOpenChange(false);
7791
8040
  }
7792
8041
  };
7793
- return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[500px]", children: [
8042
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[500px] max-h-[90vh] overflow-y-auto", children: [
7794
8043
  /* @__PURE__ */ jsxs(DialogHeader, { children: [
7795
8044
  /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2 text-xl", children: [
7796
8045
  /* @__PURE__ */ jsx("span", { className: "text-2xl", children: "✨" }),
@@ -7800,12 +8049,12 @@ const ImageGenerationDialog = ({
7800
8049
  ] }),
7801
8050
  /* @__PURE__ */ jsxs("div", { className: "space-y-4 py-4", children: [
7802
8051
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
7803
- /* @__PURE__ */ jsx(Label$2, { htmlFor: "image-prompt", children: "Image Description" }),
8052
+ /* @__PURE__ */ jsx(Label$2, { htmlFor: "image-prompt", children: "What do you want to see?" }),
7804
8053
  /* @__PURE__ */ jsx(
7805
8054
  Input$1,
7806
8055
  {
7807
8056
  id: "image-prompt",
7808
- placeholder: "e.g., A beautiful sunset over mountains with a lake",
8057
+ placeholder: "Mountains and rivers with birds flying in the sky",
7809
8058
  value: prompt,
7810
8059
  onChange: (e) => setPrompt(e.target.value),
7811
8060
  disabled: isGenerating,
@@ -7817,7 +8066,7 @@ const ImageGenerationDialog = ({
7817
8066
  }
7818
8067
  }
7819
8068
  ),
7820
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Be specific and descriptive for best results" })
8069
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "💡 Just describe what you want - be specific and detailed for best results" })
7821
8070
  ] }),
7822
8071
  isGenerating && /* @__PURE__ */ jsx("div", { className: "p-4 rounded-lg bg-blue-50 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7823
8072
  /* @__PURE__ */ jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-blue-600 border-t-transparent" }),
@@ -7829,12 +8078,13 @@ const ImageGenerationDialog = ({
7829
8078
  !isGenerating && /* @__PURE__ */ jsx("div", { className: "p-3 rounded-lg bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
7830
8079
  /* @__PURE__ */ jsx("span", { className: "text-lg", children: "💡" }),
7831
8080
  /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-600 dark:text-gray-400", children: [
7832
- /* @__PURE__ */ jsx("p", { className: "font-medium mb-1", children: "Tips for better results:" }),
7833
- /* @__PURE__ */ jsxs("ul", { className: "list-disc list-inside space-y-0.5", children: [
7834
- /* @__PURE__ */ jsx("li", { children: "Be specific about style, colors, and mood" }),
7835
- /* @__PURE__ */ jsx("li", { children: "Mention key objects and their positions" }),
7836
- /* @__PURE__ */ jsx("li", { children: 'Add artistic style references (e.g., "oil painting")' })
7837
- ] })
8081
+ /* @__PURE__ */ jsx("p", { className: "font-medium mb-1.5", children: "Good examples:" }),
8082
+ /* @__PURE__ */ jsxs("ul", { className: "list-none space-y-1 ml-1", children: [
8083
+ /* @__PURE__ */ jsx("li", { children: '✅ "Mountains and rivers at sunset"' }),
8084
+ /* @__PURE__ */ jsx("li", { children: '✅ "A cat sitting on a windowsill"' }),
8085
+ /* @__PURE__ */ jsx("li", { children: ' "Modern city skyline at night"' })
8086
+ ] }),
8087
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-amber-600 dark:text-amber-400", children: `⚠️ Don't include "generate" or "create" - just describe!` })
7838
8088
  ] })
7839
8089
  ] }) })
7840
8090
  ] }),
@@ -7858,14 +8108,14 @@ const ImageGenerationDialog = ({
7858
8108
  "Generating..."
7859
8109
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7860
8110
  /* @__PURE__ */ jsx("span", { className: "mr-2", children: "✨" }),
7861
- "Generate Image"
8111
+ "Generate & Insert"
7862
8112
  ] })
7863
8113
  }
7864
8114
  )
7865
8115
  ] })
7866
8116
  ] }) });
7867
8117
  };
7868
- const ImageGenerationManager = forwardRef(({ onGenerate }, ref) => {
8118
+ const ImageGenerationManager = forwardRef(({ onGenerate, onInsertImage }, ref) => {
7869
8119
  const [open, setOpen] = useState$1(false);
7870
8120
  const [isGenerating, setIsGenerating] = useState$1(false);
7871
8121
  const [initialText, setInitialText] = useState$1(void 0);
@@ -7879,20 +8129,26 @@ const ImageGenerationManager = forwardRef(({ onGenerate }, ref) => {
7879
8129
  const handleGenerate = async (prompt) => {
7880
8130
  setIsGenerating(true);
7881
8131
  try {
7882
- await onGenerate(prompt);
7883
- setOpen(false);
8132
+ const imageUrl = await onGenerate(prompt);
8133
+ return imageUrl;
7884
8134
  } catch (error) {
7885
8135
  console.error("Error generating image:", error);
8136
+ throw error;
7886
8137
  } finally {
7887
8138
  setIsGenerating(false);
7888
8139
  }
7889
8140
  };
8141
+ const handleInsertImage = (imageUrl, prompt) => {
8142
+ onInsertImage(imageUrl, prompt);
8143
+ setOpen(false);
8144
+ };
7890
8145
  return /* @__PURE__ */ jsx(
7891
8146
  ImageGenerationDialog,
7892
8147
  {
7893
8148
  open,
7894
8149
  onOpenChange: setOpen,
7895
8150
  onGenerate: handleGenerate,
8151
+ onInsertImage: handleInsertImage,
7896
8152
  isGenerating,
7897
8153
  initialText
7898
8154
  }
@@ -8006,6 +8262,20 @@ const AIRephrasePlugin = () => {
8006
8262
  (_a = imageDialogRef.current) == null ? void 0 : _a.openDialog(selectedText);
8007
8263
  return true;
8008
8264
  };
8265
+ const extractImageUrlFromHtml = (htmlString) => {
8266
+ try {
8267
+ const parser = new DOMParser();
8268
+ const dom = parser.parseFromString(htmlString, "text/html");
8269
+ const imgElement = dom.querySelector("img");
8270
+ if (!imgElement || !imgElement.src) {
8271
+ throw new Error("No image element found in response");
8272
+ }
8273
+ return imgElement.src;
8274
+ } catch (error) {
8275
+ console.error("Error extracting image URL:", error);
8276
+ throw new Error("Failed to extract image URL from response");
8277
+ }
8278
+ };
8009
8279
  const generateImageFromPrompt = async (promptText) => {
8010
8280
  try {
8011
8281
  const response = await AiJsonResponse({ content: `Generate Image: ${promptText}` });
@@ -8014,21 +8284,26 @@ const AIRephrasePlugin = () => {
8014
8284
  console.warn("No HTML returned from agent for image generation");
8015
8285
  throw new Error("Failed to generate image via agent");
8016
8286
  }
8017
- editor.update(() => {
8018
- const currentSelection = $getSelection();
8019
- if (!currentSelection || !$isRangeSelection(currentSelection))
8020
- return;
8021
- const parser = new DOMParser();
8022
- const dom = parser.parseFromString(htmlString, "text/html");
8023
- const nodes = $generateNodesFromDOM(editor, dom);
8024
- currentSelection.insertText("");
8025
- $insertNodes(nodes);
8026
- });
8287
+ const imageUrl = extractImageUrlFromHtml(htmlString);
8288
+ return imageUrl;
8027
8289
  } catch (error) {
8028
8290
  console.error("Error generating image via agent:", error);
8029
8291
  throw error;
8030
8292
  }
8031
8293
  };
8294
+ const insertImageIntoEditor = (imageUrl, prompt) => {
8295
+ try {
8296
+ editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
8297
+ src: imageUrl,
8298
+ altText: "Generated image",
8299
+ originalPrompt: prompt
8300
+ // Store the prompt for refinement
8301
+ });
8302
+ } catch (error) {
8303
+ console.error("Error inserting image into editor:", error);
8304
+ throw error;
8305
+ }
8306
+ };
8032
8307
  useEffect$1(() => {
8033
8308
  return editor.registerCommand(
8034
8309
  AI_ACTION_COMMAND,
@@ -8065,7 +8340,8 @@ const AIRephrasePlugin = () => {
8065
8340
  ImageGenerationManager,
8066
8341
  {
8067
8342
  ref: imageDialogRef,
8068
- onGenerate: generateImageFromPrompt
8343
+ onGenerate: generateImageFromPrompt,
8344
+ onInsertImage: insertImageIntoEditor
8069
8345
  }
8070
8346
  );
8071
8347
  };
@@ -14395,7 +14671,7 @@ const EmbedComponent = ({ url, displayType, alignment, nodeKey }) => {
14395
14671
  }
14396
14672
  );
14397
14673
  };
14398
- const FileComponent = React$1.lazy(() => import("./index-f0d8f7a8.js"));
14674
+ const FileComponent = React$1.lazy(() => import("./index-9548fdb4.js"));
14399
14675
  function convertFileElement(domNode) {
14400
14676
  if (domNode instanceof HTMLDivElement) {
14401
14677
  const dataUrl = domNode.getAttribute("data-lexical-file-src");
@@ -14503,187 +14779,6 @@ function $createFileNode({ src, fileName, fileSize, key }) {
14503
14779
  function $isFileNode(node) {
14504
14780
  return node instanceof FileNode;
14505
14781
  }
14506
- const ImageView = React__default.lazy(() => import("./index-308e13ae.js"));
14507
- function isGoogleDocCheckboxImg(img) {
14508
- return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
14509
- }
14510
- function $convertImageElement(domNode) {
14511
- const img = domNode;
14512
- if (img.src.startsWith("file:///") || isGoogleDocCheckboxImg(img)) {
14513
- return null;
14514
- }
14515
- const { alt: altText, src, width, height } = img;
14516
- const node = $createImageNode({ altText, height, src, width });
14517
- return { node };
14518
- }
14519
- class ImageNode extends DecoratorNode {
14520
- constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, key) {
14521
- super(key);
14522
- __publicField(this, "__src");
14523
- __publicField(this, "__altText");
14524
- __publicField(this, "__width");
14525
- __publicField(this, "__height");
14526
- __publicField(this, "__maxWidth");
14527
- __publicField(this, "__showCaption");
14528
- __publicField(this, "__caption");
14529
- // Captions cannot yet be used within editor cells
14530
- __publicField(this, "__captionsEnabled");
14531
- this.__src = src;
14532
- this.__altText = altText;
14533
- this.__maxWidth = maxWidth;
14534
- this.__width = width || "inherit";
14535
- this.__height = height || "inherit";
14536
- this.__showCaption = showCaption || false;
14537
- this.__caption = caption || createEditor({
14538
- nodes: []
14539
- });
14540
- this.__captionsEnabled = captionsEnabled || captionsEnabled === void 0;
14541
- }
14542
- // to identify the image node and must unique too
14543
- static getType() {
14544
- return "image";
14545
- }
14546
- // Clones the ImageNode when needed (during editor updates)
14547
- static clone(node) {
14548
- return new ImageNode(
14549
- node.__src,
14550
- node.__altText,
14551
- node.__maxWidth,
14552
- node.__width,
14553
- node.__height,
14554
- node.__showCaption,
14555
- node.__caption,
14556
- node.__captionsEnabled,
14557
- node.__key
14558
- );
14559
- }
14560
- // importing to json format
14561
- static importJSON(serializedNode) {
14562
- const { altText, height, width, maxWidth, caption, src, showCaption } = serializedNode;
14563
- const node = $createImageNode({
14564
- altText,
14565
- height,
14566
- maxWidth,
14567
- showCaption,
14568
- src,
14569
- width
14570
- });
14571
- const nestedEditor = node.__caption;
14572
- const editorState = nestedEditor.parseEditorState(caption.editorState);
14573
- if (!editorState.isEmpty()) {
14574
- nestedEditor.setEditorState(editorState);
14575
- }
14576
- return node;
14577
- }
14578
- // Exports this node as an actual <img> tag in the DOM when needed
14579
- exportDOM() {
14580
- const element = document.createElement("img");
14581
- element.setAttribute("src", this.__src);
14582
- element.setAttribute("alt", this.__altText);
14583
- element.setAttribute("width", this.__width.toString());
14584
- element.setAttribute("height", this.__height.toString());
14585
- return { element };
14586
- }
14587
- // convert img tag into image node in the editor using convertImageElement func
14588
- static importDOM() {
14589
- return {
14590
- img: (node) => ({
14591
- conversion: $convertImageElement,
14592
- priority: 0
14593
- })
14594
- };
14595
- }
14596
- exportJSON() {
14597
- return {
14598
- altText: this.getAltText(),
14599
- caption: this.__caption.toJSON(),
14600
- height: this.__height === "inherit" ? 0 : this.__height,
14601
- maxWidth: this.__maxWidth,
14602
- showCaption: this.__showCaption,
14603
- src: this.getSrc(),
14604
- type: "image",
14605
- version: 1,
14606
- width: this.__width === "inherit" ? 0 : this.__width
14607
- };
14608
- }
14609
- // setting width and height when resizing
14610
- setWidthAndHeight(width, height) {
14611
- const writable = this.getWritable();
14612
- writable.__width = width;
14613
- writable.__height = height;
14614
- }
14615
- // state to update to show the caption
14616
- setShowCaption(showCaption) {
14617
- const writable = this.getWritable();
14618
- writable.__showCaption = showCaption;
14619
- }
14620
- // To create a dom representation of image view
14621
- createDOM(config) {
14622
- const span = document.createElement("span");
14623
- const theme2 = config.theme;
14624
- const className = theme2.image;
14625
- if (className !== void 0) {
14626
- span.className = className;
14627
- }
14628
- return span;
14629
- }
14630
- updateDOM() {
14631
- return false;
14632
- }
14633
- // to get the image src
14634
- getSrc() {
14635
- return this.__src;
14636
- }
14637
- getAltText() {
14638
- return this.__altText;
14639
- }
14640
- // to render the image tag
14641
- decorate() {
14642
- return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
14643
- ImageView,
14644
- {
14645
- src: this.__src,
14646
- altText: this.__altText,
14647
- width: this.__width,
14648
- height: this.__height,
14649
- maxWidth: this.__maxWidth,
14650
- nodeKey: this.getKey(),
14651
- showCaption: this.__showCaption,
14652
- caption: this.__caption,
14653
- captionsEnabled: this.__captionsEnabled,
14654
- resizable: true
14655
- }
14656
- ) });
14657
- }
14658
- }
14659
- function $createImageNode({
14660
- altText,
14661
- height,
14662
- maxWidth = 500,
14663
- captionsEnabled,
14664
- src,
14665
- width,
14666
- showCaption,
14667
- caption,
14668
- key
14669
- }) {
14670
- return $applyNodeReplacement(
14671
- new ImageNode(
14672
- src,
14673
- altText,
14674
- maxWidth,
14675
- width,
14676
- height,
14677
- showCaption,
14678
- caption,
14679
- captionsEnabled,
14680
- key
14681
- )
14682
- );
14683
- }
14684
- function $isImageNode(node) {
14685
- return node instanceof ImageNode;
14686
- }
14687
14782
  function $convertMentionElement(domNode) {
14688
14783
  const textContent = domNode.textContent;
14689
14784
  const mentionName = domNode.getAttribute("data-lexical-mention-name");
@@ -15618,24 +15713,6 @@ const BoldIcon = () => /* @__PURE__ */ jsx(
15618
15713
  )
15619
15714
  }
15620
15715
  );
15621
- const PlusIcon = () => /* @__PURE__ */ jsxs(
15622
- "svg",
15623
- {
15624
- xmlns: "http://www.w3.org/2000/svg",
15625
- width: "24",
15626
- height: "24",
15627
- viewBox: "0 0 24 24",
15628
- fill: "none",
15629
- stroke: "currentColor",
15630
- strokeWidth: "2",
15631
- strokeLinecap: "round",
15632
- strokeLinejoin: "round",
15633
- children: [
15634
- /* @__PURE__ */ jsx("path", { d: "M5 12h14" }),
15635
- /* @__PURE__ */ jsx("path", { d: "M12 5v14" })
15636
- ]
15637
- }
15638
- );
15639
15716
  const ChevronDownIcon = () => /* @__PURE__ */ jsx(
15640
15717
  "svg",
15641
15718
  {
@@ -16038,7 +16115,6 @@ const RecordingIcon = () => /* @__PURE__ */ jsx(
16038
16115
  }
16039
16116
  );
16040
16117
  const AddCommentIcon = () => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M19 14.3333C19 14.7459 18.8361 15.1416 18.5444 15.4333C18.2527 15.725 17.857 15.8889 17.4444 15.8889H8.11111L5 19V6.55556C5 6.143 5.16389 5.74733 5.45561 5.45561C5.74733 5.16389 6.143 5 6.55556 5H17.4444C17.857 5 18.2527 5.16389 18.5444 5.45561C18.8361 5.74733 19 6.143 19 6.55556V14.3333Z", stroke: "currentColor", strokeWidth: "1.33333", strokeLinecap: "round", strokeLinejoin: "round" }) });
16041
- const CheckIcon = () => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
16042
16118
  const QuoteIcon = () => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: [
16043
16119
  /* @__PURE__ */ jsx("path", { d: "M4.75 19C7 19 10 18.2222 10 12.7779V6.55575C10 5.58354 9.433 4.98699 8.5 5.00022H5.5C4.5625 5.00022 4 5.58354 4 6.53397V11.2223C4 12.1945 4.5625 12.7779 5.5 12.7779C6.25 12.7779 6.25 12.7779 6.25 13.5556V14.3334C6.25 15.1112 5.5 15.8889 4.75 15.8889C4 15.8889 4 15.8952 4 16.6908V18.2222C4 19 4 19 4.75 19Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
16044
16120
  /* @__PURE__ */ jsx("path", { d: "M14.75 19C17 19 20 18.2222 20 12.7779V6.55575C20 5.58354 19.4323 4.98699 18.5 5.00022H15.5C14.5625 5.00022 14 5.58354 14 6.53397V11.2223C14 12.1945 14.5625 12.7779 15.5 12.7779H16.0625C16.0625 14.5278 16.25 15.8889 14 15.8889V18.2222C14 19 14 19 14.75 19Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
@@ -16184,6 +16260,154 @@ const formatMenuItems = [
16184
16260
  }
16185
16261
  ];
16186
16262
  const LOWEST_PRIORITY = 1;
16263
+ class FeatureSuggestionAPI {
16264
+ static async createSuggestion(data, apiKey) {
16265
+ const response = await backendAPI.post(
16266
+ "/api/feature-suggestions",
16267
+ data,
16268
+ apiKey ? { headers: { "X-API-Key": apiKey } } : void 0
16269
+ );
16270
+ return response.data;
16271
+ }
16272
+ }
16273
+ function FeatureSuggestionDialog({
16274
+ open,
16275
+ onOpenChange
16276
+ }) {
16277
+ const { apiKey } = useEditor();
16278
+ const [title, setTitle] = useState$1("");
16279
+ const [description, setDescription] = useState$1("");
16280
+ const [isSubmitting, setIsSubmitting] = useState$1(false);
16281
+ const [errors, setErrors] = useState$1({});
16282
+ const validateForm = () => {
16283
+ const newErrors = {};
16284
+ if (!title.trim()) {
16285
+ newErrors.title = "Title is required";
16286
+ }
16287
+ if (!description.trim()) {
16288
+ newErrors.description = "Description is required";
16289
+ } else if (description.trim().length < 10) {
16290
+ newErrors.description = "Description must be at least 10 characters";
16291
+ }
16292
+ setErrors(newErrors);
16293
+ return Object.keys(newErrors).length === 0;
16294
+ };
16295
+ const handleSubmit = async (e) => {
16296
+ e.preventDefault();
16297
+ if (!validateForm()) {
16298
+ return;
16299
+ }
16300
+ setIsSubmitting(true);
16301
+ try {
16302
+ await FeatureSuggestionAPI.createSuggestion(
16303
+ {
16304
+ title: title.trim(),
16305
+ description: description.trim()
16306
+ },
16307
+ apiKey || void 0
16308
+ );
16309
+ toast.success("Success!", {
16310
+ description: "Your feature suggestion has been submitted successfully!"
16311
+ });
16312
+ setTitle("");
16313
+ setDescription("");
16314
+ setErrors({});
16315
+ onOpenChange(false);
16316
+ } catch (error) {
16317
+ console.error("Error submitting suggestion:", error);
16318
+ toast.error("Error", {
16319
+ description: "Failed to submit feature suggestion. Please try again."
16320
+ });
16321
+ } finally {
16322
+ setIsSubmitting(false);
16323
+ }
16324
+ };
16325
+ const handleCancel = () => {
16326
+ setTitle("");
16327
+ setDescription("");
16328
+ setErrors({});
16329
+ onOpenChange(false);
16330
+ };
16331
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[500px]", children: [
16332
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
16333
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: [
16334
+ /* @__PURE__ */ jsx(Lightbulb, { className: "cteditor-h-5 cteditor-w-5 cteditor-text-primary" }),
16335
+ "Suggest a Feature"
16336
+ ] }),
16337
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Help us improve by suggesting new features you'd like to see" })
16338
+ ] }),
16339
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
16340
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-4 cteditor-py-4", children: [
16341
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-2", children: [
16342
+ /* @__PURE__ */ jsx(Label$2, { htmlFor: "title", children: "Feature Name *" }),
16343
+ /* @__PURE__ */ jsx(
16344
+ Input$1,
16345
+ {
16346
+ id: "title",
16347
+ placeholder: "Enter a title for your feature suggestion",
16348
+ value: title,
16349
+ onChange: (e) => {
16350
+ setTitle(e.target.value);
16351
+ if (errors.title) {
16352
+ setErrors({ ...errors, title: void 0 });
16353
+ }
16354
+ },
16355
+ className: errors.title ? "cteditor-border-red-500 focus-visible:cteditor-ring-red-500" : ""
16356
+ }
16357
+ ),
16358
+ errors.title && /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-text-red-500", children: errors.title })
16359
+ ] }),
16360
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-2", children: [
16361
+ /* @__PURE__ */ jsx(Label$2, { htmlFor: "description", children: "Description *" }),
16362
+ /* @__PURE__ */ jsx(
16363
+ "textarea",
16364
+ {
16365
+ id: "description",
16366
+ placeholder: "Describe your feature suggestion in detail. What problem would it solve? How would it work?",
16367
+ value: description,
16368
+ onChange: (e) => {
16369
+ setDescription(e.target.value);
16370
+ if (errors.description) {
16371
+ setErrors({ ...errors, description: void 0 });
16372
+ }
16373
+ },
16374
+ className: `cteditor-flex cteditor-min-h-[120px] cteditor-w-full cteditor-rounded-md cteditor-border cteditor-border-input cteditor-bg-transparent cteditor-px-3 cteditor-py-2 cteditor-text-base cteditor-shadow-sm placeholder:cteditor-text-muted-foreground focus-visible:cteditor-outline-none focus-visible:cteditor-ring-1 focus-visible:cteditor-ring-ring disabled:cteditor-cursor-not-allowed disabled:cteditor-opacity-50 ${errors.description ? "cteditor-border-red-500 focus-visible:cteditor-ring-red-500" : ""}`
16375
+ }
16376
+ ),
16377
+ errors.description && /* @__PURE__ */ jsx("p", { className: "cteditor-text-sm cteditor-text-red-500", children: errors.description })
16378
+ ] }),
16379
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-p-3 cteditor-bg-muted/50 cteditor-rounded-lg", children: [
16380
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-1 cteditor-mb-2", children: [
16381
+ /* @__PURE__ */ jsx(Lightbulb, { className: "cteditor-h-4 cteditor-w-4" }),
16382
+ /* @__PURE__ */ jsx("h3", { className: "cteditor-text-sm cteditor-font-medium", children: "Tips for a great suggestion:" })
16383
+ ] }),
16384
+ /* @__PURE__ */ jsxs("ul", { className: "cteditor-text-xs cteditor-text-muted-foreground cteditor-space-y-1", children: [
16385
+ /* @__PURE__ */ jsx("li", { children: "• Be specific about what you want and why it would be useful" }),
16386
+ /* @__PURE__ */ jsx("li", { children: "• Explain the problem your suggestion would solve" }),
16387
+ /* @__PURE__ */ jsx("li", { children: "• Consider how other users might benefit from this feature" }),
16388
+ /* @__PURE__ */ jsx("li", { children: "• Include any relevant examples or use cases" })
16389
+ ] })
16390
+ ] })
16391
+ ] }),
16392
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
16393
+ /* @__PURE__ */ jsx(
16394
+ Button,
16395
+ {
16396
+ type: "button",
16397
+ variant: "outline",
16398
+ onClick: handleCancel,
16399
+ disabled: isSubmitting,
16400
+ children: "Cancel"
16401
+ }
16402
+ ),
16403
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSubmitting, children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
16404
+ /* @__PURE__ */ jsx(Loader2, { className: "cteditor-h-4 cteditor-w-4 cteditor-animate-spin cteditor-mr-2" }),
16405
+ "Submitting..."
16406
+ ] }) : "Submit Suggestion" })
16407
+ ] })
16408
+ ] })
16409
+ ] }) });
16410
+ }
16187
16411
  const DEFAULT_FONT_SIZE = 15;
16188
16412
  const INITIAL_TOOLBAR_STATE = {
16189
16413
  bgColor: "#fff",
@@ -17013,254 +17237,80 @@ function AIChatPlugin({
17013
17237
  const [editor] = useLexicalComposerContext();
17014
17238
  return useAIChatToolbar(editor, apiKey);
17015
17239
  }
17016
- const OPEN_TABLE_MODAL_COMMAND = createCommand();
17017
- const getContrastColor = (hexColor) => {
17018
- const hex = hexColor.replace("#", "");
17019
- const r2 = parseInt(hex.substr(0, 2), 16);
17020
- const g2 = parseInt(hex.substr(2, 2), 16);
17021
- const b2 = parseInt(hex.substr(4, 2), 16);
17022
- const luminance = (0.299 * r2 + 0.587 * g2 + 0.114 * b2) / 255;
17023
- return luminance > 0.5 ? "#000000" : "#FFFFFF";
17024
- };
17240
+ const CREATE_TABLE_COMMAND = createCommand();
17025
17241
  function TableOptionPlugin() {
17026
- const [isOpen, setIsOpen] = useState$1(false);
17027
- const [rows, setRows] = useState$1("");
17028
- const [columns, setColumns] = useState$1("");
17029
- const [includeHeaders, setIncludeHeaders] = useState$1(false);
17030
- const [columnHeadings, setColumnHeadings] = useState$1([]);
17031
- const [headerColor, setHeaderColor] = useState$1("#4A90E2");
17032
17242
  const [editor] = useLexicalComposerContext();
17033
- useEffect$1(() => {
17034
- return editor.registerCommand(
17035
- OPEN_TABLE_MODAL_COMMAND,
17036
- () => {
17037
- setIsOpen(true);
17038
- return true;
17039
- },
17040
- COMMAND_PRIORITY_EDITOR
17041
- );
17042
- }, [editor]);
17043
- const onAddTable = () => {
17044
- const rowCount = Number(rows);
17045
- const colCount = Number(columns);
17046
- if (!rowCount || !colCount)
17047
- return;
17243
+ const createInstantTable = React__default.useCallback(() => {
17244
+ const rowCount = 3;
17245
+ const colCount = 3;
17246
+ const headerColor = "#565656ff";
17048
17247
  editor.update(() => {
17049
- const tableNode = $createTableNodeWithDimensions(
17248
+ const selection = $getSelection();
17249
+ let shouldReplaceCurrentNode = false;
17250
+ if ($isRangeSelection(selection)) {
17251
+ const anchorNode = selection.anchor.getNode();
17252
+ const parent = anchorNode.getParent();
17253
+ if (parent) {
17254
+ try {
17255
+ const element = anchorNode.getTopLevelElementOrThrow();
17256
+ if ($isParagraphNode(element) && element.getTextContent().trim() === "") {
17257
+ shouldReplaceCurrentNode = true;
17258
+ }
17259
+ } catch (error) {
17260
+ shouldReplaceCurrentNode = false;
17261
+ }
17262
+ }
17263
+ }
17264
+ const tableNode = $createTableNodeWithDimensions(
17050
17265
  rowCount,
17051
17266
  colCount,
17052
17267
  false
17053
17268
  // Don't use built-in headers, we'll set them manually
17054
17269
  );
17055
- if (includeHeaders) {
17056
- const rowsNodes = tableNode.getChildren();
17057
- const headerRow = rowsNodes[0];
17058
- if ($isTableRowNode(headerRow)) {
17059
- const cells = headerRow.getChildren();
17060
- for (let i2 = 0; i2 < cells.length; i2++) {
17061
- const cellNode = cells[i2];
17062
- if ($isTableCellNode(cellNode)) {
17063
- cellNode.clear();
17064
- const headingText = (columnHeadings[i2] || "").trim();
17065
- if (headingText) {
17066
- cellNode.append($createTextNode(headingText));
17067
- }
17068
- cellNode.setHeaderStyles(TableCellHeaderStates.COLUMN);
17069
- cellNode.setBackgroundColor(headerColor);
17070
- }
17270
+ const rowsNodes = tableNode.getChildren();
17271
+ const headerRow = rowsNodes[0];
17272
+ if ($isTableRowNode(headerRow)) {
17273
+ const cells = headerRow.getChildren();
17274
+ for (let i2 = 0; i2 < cells.length; i2++) {
17275
+ const cellNode = cells[i2];
17276
+ if ($isTableCellNode(cellNode)) {
17277
+ cellNode.setHeaderStyles(TableCellHeaderStates.COLUMN);
17278
+ cellNode.setBackgroundColor(headerColor);
17279
+ const textNode = $createTextNode("");
17280
+ cellNode.append(textNode);
17071
17281
  }
17072
17282
  }
17073
17283
  }
17074
- $insertNodeToNearestRoot(tableNode);
17075
- });
17076
- if (includeHeaders) {
17077
- const textColor = getContrastColor(headerColor);
17078
- requestAnimationFrame(() => {
17079
- const applyStyles = () => {
17080
- const rootElement = editor.getRootElement();
17081
- if (!rootElement)
17082
- return false;
17083
- const tables = rootElement.querySelectorAll("table");
17084
- if (tables.length > 0) {
17085
- const latestTable = tables[tables.length - 1];
17086
- const rows2 = latestTable.querySelectorAll("tr");
17087
- if (rows2.length > 0) {
17088
- const firstRow = rows2[0];
17089
- const cells = firstRow.querySelectorAll("th, td");
17090
- cells.forEach((cell) => {
17091
- const htmlCell = cell;
17092
- htmlCell.style.setProperty("background-color", headerColor, "important");
17093
- htmlCell.style.setProperty("color", textColor, "important");
17094
- htmlCell.style.setProperty("font-weight", "bold", "important");
17095
- htmlCell.style.setProperty("padding", "8px", "important");
17096
- });
17097
- return true;
17098
- }
17099
- }
17100
- return false;
17101
- };
17102
- if (!applyStyles()) {
17103
- setTimeout(applyStyles, 100);
17284
+ if (shouldReplaceCurrentNode && $isRangeSelection(selection)) {
17285
+ try {
17286
+ const anchorNode = selection.anchor.getNode();
17287
+ const element = anchorNode.getTopLevelElementOrThrow();
17288
+ element.replace(tableNode);
17289
+ } catch (error) {
17290
+ $insertNodeToNearestRoot(tableNode);
17104
17291
  }
17105
- });
17106
- }
17107
- setRows("");
17108
- setColumns("");
17109
- setIncludeHeaders(false);
17110
- setColumnHeadings([]);
17111
- setHeaderColor("#4A90E2");
17112
- setIsOpen(false);
17113
- };
17114
- return /* @__PURE__ */ jsxs(Fragment, { children: [
17115
- /* @__PURE__ */ jsx(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: /* @__PURE__ */ jsxs(DialogContent, { children: [
17116
- /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: "Add Table" }) }),
17117
- /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-4 cteditor-py-4", children: [
17118
- /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-2", children: [
17119
- /* @__PURE__ */ jsx(Label$2, { htmlFor: "rows", children: "Rows" }),
17120
- /* @__PURE__ */ jsx(
17121
- Input$1,
17122
- {
17123
- id: "rows",
17124
- type: "number",
17125
- value: rows,
17126
- onChange: (e) => setRows(e.target.value),
17127
- autoFocus: true
17128
- }
17129
- )
17130
- ] }),
17131
- /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-2", children: [
17132
- /* @__PURE__ */ jsx(Label$2, { htmlFor: "columns", children: "Columns" }),
17133
- /* @__PURE__ */ jsx(
17134
- Input$1,
17135
- {
17136
- id: "columns",
17137
- type: "number",
17138
- value: columns,
17139
- onChange: (e) => {
17140
- const value = e.target.value;
17141
- setColumns(value);
17142
- const count2 = Number(value);
17143
- if (!Number.isNaN(count2) && includeHeaders) {
17144
- setColumnHeadings((prev) => {
17145
- const next = [...prev];
17146
- next.length = Math.max(0, count2);
17147
- for (let i2 = 0; i2 < count2; i2++) {
17148
- if (typeof next[i2] !== "string")
17149
- next[i2] = "";
17150
- }
17151
- return next;
17152
- });
17153
- }
17154
- }
17155
- }
17156
- )
17157
- ] }),
17158
- /* @__PURE__ */ jsx("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: /* @__PURE__ */ jsxs(
17159
- "label",
17160
- {
17161
- htmlFor: "include-headers",
17162
- className: "cteditor-flex cteditor-items-center cteditor-space-x-2 cteditor-cursor-pointer cteditor-select-none",
17163
- children: [
17164
- /* @__PURE__ */ jsxs("div", { className: "cteditor-relative cteditor-h-5", children: [
17165
- /* @__PURE__ */ jsx(
17166
- "input",
17167
- {
17168
- id: "include-headers",
17169
- type: "checkbox",
17170
- checked: includeHeaders,
17171
- onChange: (e) => {
17172
- const checked = e.target.checked;
17173
- setIncludeHeaders(checked);
17174
- const count2 = Number(columns);
17175
- if (checked && count2 > 0) {
17176
- setColumnHeadings((prev) => {
17177
- const next = [...prev];
17178
- next.length = count2;
17179
- for (let i2 = 0; i2 < count2; i2++) {
17180
- if (typeof next[i2] !== "string")
17181
- next[i2] = "";
17182
- }
17183
- return next;
17184
- });
17185
- }
17186
- if (!checked) {
17187
- setColumnHeadings([]);
17188
- }
17189
- },
17190
- className: "\n cteditor-peer\n cteditor-appearance-none\n cteditor-w-5 cteditor-h-5\n cteditor-border cteditor-border-gray-400 cteditor-rounded\n cteditor-transition-all cteditor-duration-200\n checked:cteditor-bg-blue-600 checked:cteditor-border-blue-600\n hover:cteditor-border-blue-500 [&>span]:checked:cteditor-opacity-100\n \n "
17191
- }
17192
- ),
17193
- /* @__PURE__ */ jsx("span", { className: "cteditor-absolute cteditor-top-1/2 cteditor-left-1/2 [&>svg]:cteditor-size-4 -cteditor-translate-x-1/2 -cteditor-translate-y-1/2 cteditor-opacity-0 peer-checked:cteditor-opacity-100", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
17194
- ] }),
17195
- /* @__PURE__ */ jsx("span", { className: "cteditor-text-sm cteditor-font-medium ", children: "Add column headers" })
17196
- ]
17197
- }
17198
- ) }),
17199
- includeHeaders && Number(columns) > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
17200
- /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-2 cteditor-space-y-1", children: [
17201
- /* @__PURE__ */ jsx(Label$2, { children: "Header titles" }),
17202
- /* @__PURE__ */ jsx(
17203
- "div",
17204
- {
17205
- className: "cteditor-grid cteditor-gap-2",
17206
- style: { gridTemplateColumns: "repeat(2, minmax(0, 1fr))" },
17207
- children: Array.from({ length: Number(columns) }).map((_, i2) => /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-1", children: [
17208
- /* @__PURE__ */ jsxs(
17209
- Label$2,
17210
- {
17211
- className: "cteditor-font-normal",
17212
- htmlFor: `col-heading-${i2}`,
17213
- children: [
17214
- "Column ",
17215
- i2 + 1
17216
- ]
17217
- }
17218
- ),
17219
- /* @__PURE__ */ jsx(
17220
- Input$1,
17221
- {
17222
- id: `col-heading-${i2}`,
17223
- type: "text",
17224
- value: columnHeadings[i2] ?? "",
17225
- onChange: (e) => {
17226
- const value = e.target.value;
17227
- setColumnHeadings((prev) => {
17228
- const next = [...prev];
17229
- next[i2] = value;
17230
- return next;
17231
- });
17232
- }
17233
- }
17234
- )
17235
- ] }, i2))
17236
- }
17237
- )
17238
- ] }),
17239
- /* @__PURE__ */ jsxs("div", { className: "cteditor-grid cteditor-gap-2", children: [
17240
- /* @__PURE__ */ jsx(Label$2, { htmlFor: "header-color", children: "Header color" }),
17241
- /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-3", children: [
17242
- /* @__PURE__ */ jsx("div", { className: "cteditor-size-9 cteditor-rounded-md cteditor-relative cteditor-overflow-hidden", children: /* @__PURE__ */ jsx(
17243
- "input",
17244
- {
17245
- id: "header-color",
17246
- type: "color",
17247
- value: headerColor,
17248
- onChange: (e) => setHeaderColor(e.target.value),
17249
- className: "cteditor-w-12 cteditor-h-10 cteditor-border cteditor-border-gray-300 cteditor-rounded cteditor-cursor-pointer cteditor-scale-150"
17250
- }
17251
- ) }),
17252
- /* @__PURE__ */ jsx("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: /* @__PURE__ */ jsx("span", { className: "cteditor-text-sm ", children: headerColor }) })
17253
- ] })
17254
- ] })
17255
- ] })
17256
- ] }),
17257
- /* @__PURE__ */ jsxs(DialogFooter, { children: [
17258
- /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setIsOpen(false), children: "Cancel" }),
17259
- /* @__PURE__ */ jsx(Button, { onClick: onAddTable, disabled: !rows || !columns, children: "Add" })
17260
- ] })
17261
- ] }) }),
17262
- /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: () => setIsOpen(true), size: "icon-sm", children: /* @__PURE__ */ jsx("span", { className: "[&_svg]:!cteditor-size-4", children: /* @__PURE__ */ jsx(PerspectiveIcon, {}) }) })
17263
- ] });
17292
+ } else {
17293
+ $insertNodeToNearestRoot(tableNode);
17294
+ }
17295
+ if ($isTableRowNode(headerRow)) {
17296
+ const cells = headerRow.getChildren();
17297
+ if (cells.length > 0 && $isTableCellNode(cells[0])) {
17298
+ cells[0].selectStart();
17299
+ }
17300
+ }
17301
+ });
17302
+ }, [editor]);
17303
+ useEffect$1(() => {
17304
+ return editor.registerCommand(
17305
+ CREATE_TABLE_COMMAND,
17306
+ () => {
17307
+ createInstantTable();
17308
+ return true;
17309
+ },
17310
+ COMMAND_PRIORITY_EDITOR
17311
+ );
17312
+ }, [editor, createInstantTable]);
17313
+ return /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: createInstantTable, size: "icon-sm", children: /* @__PURE__ */ jsx("span", { className: "[&_svg]:!cteditor-size-4", children: /* @__PURE__ */ jsx(PerspectiveIcon, {}) }) });
17264
17314
  }
17265
17315
  createCommand();
17266
17316
  const INSERT_TRANSCRIPT_COMMAND = createCommand();
@@ -17780,10 +17830,10 @@ const PDF_CONFIG = {
17780
17830
  };
17781
17831
  const loadHtml2Pdf = async () => {
17782
17832
  try {
17783
- const mod = await import("./html2pdf.bundle.min-bb81d5dc.js").then((n) => n.h);
17833
+ const mod = await import("./html2pdf.bundle.min-b3120e0c.js").then((n) => n.h);
17784
17834
  return (mod == null ? void 0 : mod.default) || mod;
17785
17835
  } catch {
17786
- const mod2 = await import("./html2pdf.bundle-40cc5697.js").then((n) => n.h);
17836
+ const mod2 = await import("./html2pdf.bundle-6d32d085.js").then((n) => n.h);
17787
17837
  return (mod2 == null ? void 0 : mod2.default) || mod2;
17788
17838
  }
17789
17839
  };
@@ -22132,32 +22182,6 @@ const HighlightColorPicker = ({
22132
22182
  )
22133
22183
  ] });
22134
22184
  };
22135
- const INSERT_IMAGE_COMMAND = createCommand("INSERT_IMAGE_COMMAND");
22136
- const ImagePlugin = ({
22137
- captionsEnabled
22138
- }) => {
22139
- const [editor] = useLexicalComposerContext();
22140
- useEffect$1(() => {
22141
- if (!editor.hasNodes([ImageNode])) {
22142
- throw new Error("ImagesPlugin: ImageNode not registered on editor");
22143
- }
22144
- return mergeRegister(
22145
- editor.registerCommand(
22146
- INSERT_IMAGE_COMMAND,
22147
- (payload) => {
22148
- const imageNode = $createImageNode(payload);
22149
- $insertNodes([imageNode]);
22150
- if ($isRootOrShadowRoot(imageNode.getParentOrThrow())) {
22151
- $wrapNodeInElement(imageNode, $createParagraphNode).selectEnd();
22152
- }
22153
- return true;
22154
- },
22155
- COMMAND_PRIORITY_EDITOR
22156
- )
22157
- );
22158
- }, [captionsEnabled, editor]);
22159
- return null;
22160
- };
22161
22185
  const useS3Uploader = (apiKey) => {
22162
22186
  const [uploadState, setUploadState] = useState$1({
22163
22187
  progress: 0,
@@ -23976,6 +24000,7 @@ const Toolbar = ({
23976
24000
  const contentRef = useRef(null);
23977
24001
  const [hiddenItemIds, setHiddenItemIds] = useState$1(/* @__PURE__ */ new Set());
23978
24002
  const [isImageDialogOpen, setIsImageDialogOpen] = useState$1(false);
24003
+ const [isFeatureSuggestionDialogOpen, setIsFeatureSuggestionDialogOpen] = useState$1(false);
23979
24004
  const classes = useStyles$1();
23980
24005
  const { hasFormat, isEditorEmpty, blockType, clearFormatting } = useEditorToolbar();
23981
24006
  const { clearEditorContent } = useCustomCommands();
@@ -25266,7 +25291,24 @@ const Toolbar = ({
25266
25291
  ] }) })
25267
25292
  ]
25268
25293
  }
25269
- )
25294
+ ),
25295
+ /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
25296
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
25297
+ Button,
25298
+ {
25299
+ "data-toolbar-item": "suggestFeature",
25300
+ variant: "ghost",
25301
+ size: "sm",
25302
+ onClick: () => setIsFeatureSuggestionDialogOpen(true),
25303
+ className: "cteditor-relative",
25304
+ children: [
25305
+ /* @__PURE__ */ jsx(Lightbulb, { className: "!cteditor-size-4" }),
25306
+ /* @__PURE__ */ jsx("span", {})
25307
+ ]
25308
+ }
25309
+ ) }),
25310
+ /* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: "Suggest a Feature" }) })
25311
+ ] }) })
25270
25312
  ]
25271
25313
  }
25272
25314
  ),
@@ -25276,6 +25318,13 @@ const Toolbar = ({
25276
25318
  activeEditor,
25277
25319
  onClose: closeImageDialog
25278
25320
  }
25321
+ ),
25322
+ /* @__PURE__ */ jsx(
25323
+ FeatureSuggestionDialog,
25324
+ {
25325
+ open: isFeatureSuggestionDialogOpen,
25326
+ onOpenChange: setIsFeatureSuggestionDialogOpen
25327
+ }
25279
25328
  )
25280
25329
  ] });
25281
25330
  };
@@ -27908,7 +27957,7 @@ function FloatingLinkEditor({
27908
27957
  return;
27909
27958
  }
27910
27959
  const rootElement = editor.getRootElement();
27911
- const isCreatingNewLink = isLinkEditMode && linkUrl === "https://";
27960
+ const isInEditMode = isLinkEditMode;
27912
27961
  if (selection !== null && nativeSelection !== null && rootElement !== null && rootElement.contains(nativeSelection.anchorNode) && editor.isEditable()) {
27913
27962
  const domRect = (_b = (_a = nativeSelection.focusNode) == null ? void 0 : _a.parentElement) == null ? void 0 : _b.getBoundingClientRect();
27914
27963
  if (domRect) {
@@ -27917,7 +27966,7 @@ function FloatingLinkEditor({
27917
27966
  }
27918
27967
  setLastSelection(selection);
27919
27968
  } else if (!activeElement || activeElement.className !== "link-input") {
27920
- if (!isCreatingNewLink) {
27969
+ if (!isInEditMode) {
27921
27970
  if (rootElement !== null) {
27922
27971
  setFloatingElemPositionForLinkEditor(null, editorElem, anchorElem);
27923
27972
  }
@@ -28047,7 +28096,7 @@ function FloatingLinkEditor({
28047
28096
  "div",
28048
28097
  {
28049
28098
  ref: editorRef,
28050
- className: "link-editor cteditor-border cteditor-border-background/20 cteditor-rounded-md cteditor-shadow-2xl cteditor-overflow-hidden cteditor-backdrop-blur-sm",
28099
+ className: "link-editor cteditor-bg-white cteditor-border cteditor-border-gray-200 cteditor-rounded-md cteditor-shadow-2xl cteditor-overflow-hidden",
28051
28100
  children: shouldShowEditMode ? (
28052
28101
  // EDIT MODE - Input to edit URL
28053
28102
  /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-p-1 cteditor-w-full", children: [
@@ -28055,7 +28104,7 @@ function FloatingLinkEditor({
28055
28104
  "input",
28056
28105
  {
28057
28106
  ref: inputRef,
28058
- className: "link-input cteditor-w-full cteditor-px-4 cteditor-py-2.5 cteditor-text-sm cteditor-border cteditor-border-background/20 cteditor-rounded-md cteditor-bg-transparent cteditor-transition-all cteditor-duration-200 cteditor-text-background placeholder:cteditor-text-background cteditor-font-medium cteditor-outline-background/30",
28107
+ className: "link-input cteditor-w-full cteditor-px-4 cteditor-py-2.5 cteditor-text-sm cteditor-border cteditor-border-gray-300 cteditor-rounded-md cteditor-bg-white cteditor-transition-all cteditor-duration-200 cteditor-text-gray-900 placeholder:cteditor-text-gray-500 cteditor-font-medium focus:cteditor-outline-none focus:cteditor-ring-2 focus:cteditor-ring-blue-500",
28059
28108
  value: editedLinkUrl,
28060
28109
  placeholder: "Enter URL (e.g., https://example.com)",
28061
28110
  onChange: (event) => setEditedLinkUrl(event.target.value),
@@ -28078,7 +28127,7 @@ function FloatingLinkEditor({
28078
28127
  /* @__PURE__ */ jsx(
28079
28128
  "button",
28080
28129
  {
28081
- className: "cteditor-p-2.5 cteditor-rounded-lg cteditor-bg-background hover:cteditor-bg-background/80 cteditor-text-foreground hover:cteditor-text-foreground cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-105 active:cteditor-scale-95",
28130
+ className: "cteditor-p-2.5 cteditor-rounded-lg cteditor-bg-green-500 hover:cteditor-bg-green-600 cteditor-text-white cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-105 active:cteditor-scale-95",
28082
28131
  onClick: handleLinkSubmission,
28083
28132
  title: "Save link",
28084
28133
  children: /* @__PURE__ */ jsx(Check, { className: "cteditor-size-4" })
@@ -28087,7 +28136,7 @@ function FloatingLinkEditor({
28087
28136
  /* @__PURE__ */ jsx(
28088
28137
  "button",
28089
28138
  {
28090
- className: "cteditor-p-2.5 cteditor-rounded-lg cteditor-bg-background hover:cteditor-bg-background/80 cteditor-text-foreground hover:cteditor-text-foreground cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-105 active:cteditor-scale-95",
28139
+ className: "cteditor-p-2.5 cteditor-rounded-lg cteditor-bg-gray-200 hover:cteditor-bg-gray-300 cteditor-text-gray-700 cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-105 active:cteditor-scale-95",
28091
28140
  onClick: () => {
28092
28141
  if (linkUrl === "https://") {
28093
28142
  editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
@@ -28104,15 +28153,15 @@ function FloatingLinkEditor({
28104
28153
  ) : showUrlView ? (
28105
28154
  // URL VIEW - Shows URL with edit and delete buttons
28106
28155
  /* @__PURE__ */ jsxs("div", { className: "cteditor-p-3 cteditor-space-y-2", children: [
28107
- /* @__PURE__ */ jsx("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: /* @__PURE__ */ jsxs("div", { className: "cteditor-flex-1 cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-px-3 cteditor-py-2 cteditor-bg-accent/30 cteditor-rounded-lg cteditor-border cteditor-border-border/30", children: [
28108
- /* @__PURE__ */ jsx(ExternalLink, { className: "cteditor-size-3.5 cteditor-text-primary cteditor-flex-shrink-0" }),
28156
+ /* @__PURE__ */ jsx("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: /* @__PURE__ */ jsxs("div", { className: "cteditor-flex-1 cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-px-3 cteditor-py-2 cteditor-bg-blue-50 cteditor-rounded-lg cteditor-border cteditor-border-blue-200", children: [
28157
+ /* @__PURE__ */ jsx(ExternalLink, { className: "cteditor-size-3.5 cteditor-text-blue-600 cteditor-flex-shrink-0" }),
28109
28158
  /* @__PURE__ */ jsx(
28110
28159
  "a",
28111
28160
  {
28112
28161
  href: sanitizeUrl(linkUrl),
28113
28162
  target: "_blank",
28114
28163
  rel: "noopener noreferrer",
28115
- className: "cteditor-flex-1 cteditor-text-xs cteditor-text-primary hover:cteditor-text-primary/80 cteditor-font-medium cteditor-truncate cteditor-transition-colors cteditor-no-underline",
28164
+ className: "cteditor-flex-1 cteditor-text-xs cteditor-text-blue-600 hover:cteditor-text-blue-800 cteditor-font-medium cteditor-truncate cteditor-transition-colors cteditor-no-underline",
28116
28165
  title: linkUrl,
28117
28166
  children: linkUrl
28118
28167
  }
@@ -28122,8 +28171,14 @@ function FloatingLinkEditor({
28122
28171
  /* @__PURE__ */ jsxs(
28123
28172
  "button",
28124
28173
  {
28125
- className: "cteditor-flex-1 cteditor-px-3 cteditor-py-2 cteditor-rounded-lg cteditor-bg-primary/10 hover:cteditor-bg-primary hover:cteditor-text-primary-foreground cteditor-text-primary cteditor-text-xs cteditor-font-medium cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-[1.02] active:cteditor-scale-95 cteditor-flex cteditor-items-center cteditor-justify-center cteditor-gap-1.5",
28126
- onClick: () => {
28174
+ className: "cteditor-flex-1 cteditor-px-3 cteditor-py-2 cteditor-rounded-lg cteditor-bg-blue-100 hover:cteditor-bg-blue-600 hover:cteditor-text-white cteditor-text-blue-700 cteditor-text-xs cteditor-font-medium cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-[1.02] active:cteditor-scale-95 cteditor-flex cteditor-items-center cteditor-justify-center cteditor-gap-1.5",
28175
+ onMouseDown: (e) => {
28176
+ e.preventDefault();
28177
+ e.stopPropagation();
28178
+ },
28179
+ onClick: (e) => {
28180
+ e.preventDefault();
28181
+ e.stopPropagation();
28127
28182
  setEditedLinkUrl(linkUrl);
28128
28183
  setIsLinkEditMode(true);
28129
28184
  setShowUrlView(false);
@@ -28138,8 +28193,14 @@ function FloatingLinkEditor({
28138
28193
  /* @__PURE__ */ jsxs(
28139
28194
  "button",
28140
28195
  {
28141
- className: "cteditor-flex-1 cteditor-px-3 cteditor-py-2 cteditor-rounded-lg cteditor-bg-destructive/10 hover:cteditor-bg-destructive hover:cteditor-text-destructive-foreground cteditor-text-destructive cteditor-text-xs cteditor-font-medium cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-[1.02] active:cteditor-scale-95 cteditor-flex cteditor-items-center cteditor-justify-center cteditor-gap-1.5",
28142
- onClick: () => {
28196
+ className: "cteditor-flex-1 cteditor-px-3 cteditor-py-2 cteditor-rounded-lg cteditor-bg-red-100 hover:cteditor-bg-red-600 hover:cteditor-text-white cteditor-text-red-700 cteditor-text-xs cteditor-font-medium cteditor-transition-all cteditor-duration-200 hover:cteditor-scale-[1.02] active:cteditor-scale-95 cteditor-flex cteditor-items-center cteditor-justify-center cteditor-gap-1.5",
28197
+ onMouseDown: (e) => {
28198
+ e.preventDefault();
28199
+ e.stopPropagation();
28200
+ },
28201
+ onClick: (e) => {
28202
+ e.preventDefault();
28203
+ e.stopPropagation();
28143
28204
  editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
28144
28205
  setShowUrlView(false);
28145
28206
  },
@@ -28157,13 +28218,21 @@ function FloatingLinkEditor({
28157
28218
  /* @__PURE__ */ jsxs(
28158
28219
  "button",
28159
28220
  {
28160
- className: "cteditor-w-full cteditor-px-4 cteditor-py-2.5 cteditor-text-sm cteditor-text-foreground cteditor-font-medium cteditor-truncate cteditor-transition-all cteditor-duration-200 hover:cteditor-bg-accent/50 cteditor-text-left cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-group",
28161
- onClick: () => setShowUrlView(true),
28221
+ className: "cteditor-w-full cteditor-px-4 cteditor-py-2.5 cteditor-text-sm cteditor-text-gray-900 cteditor-font-medium cteditor-truncate cteditor-transition-all cteditor-duration-200 hover:cteditor-bg-gray-100 cteditor-text-left cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-group",
28222
+ onMouseDown: (e) => {
28223
+ e.preventDefault();
28224
+ e.stopPropagation();
28225
+ },
28226
+ onClick: (e) => {
28227
+ e.preventDefault();
28228
+ e.stopPropagation();
28229
+ setShowUrlView(true);
28230
+ },
28162
28231
  title: "Click to view URL and options",
28163
28232
  children: [
28164
- /* @__PURE__ */ jsx(ExternalLink, { className: "cteditor-size-3.5 cteditor-text-muted-foreground group-hover:cteditor-text-primary cteditor-transition-colors cteditor-flex-shrink-0" }),
28233
+ /* @__PURE__ */ jsx(ExternalLink, { className: "cteditor-size-3.5 cteditor-text-gray-500 group-hover:cteditor-text-blue-600 cteditor-transition-colors cteditor-flex-shrink-0" }),
28165
28234
  /* @__PURE__ */ jsx("span", { className: "cteditor-truncate", children: linkText || "Link" }),
28166
- /* @__PURE__ */ jsx("span", { className: "cteditor-ml-auto cteditor-text-xs cteditor-text-muted-foreground group-hover:cteditor-text-foreground cteditor-transition-colors", children: "Click to view" })
28235
+ /* @__PURE__ */ jsx("span", { className: "cteditor-ml-auto cteditor-text-xs cteditor-text-gray-500 group-hover:cteditor-text-gray-700 cteditor-transition-colors", children: "Click to view" })
28167
28236
  ]
28168
28237
  }
28169
28238
  )
@@ -28813,77 +28882,366 @@ function LinkPlugin({
28813
28882
  }
28814
28883
  );
28815
28884
  }
28816
- const debounce = (fn, delay) => {
28817
- let timeoutID;
28818
- return function(...args) {
28819
- clearTimeout(timeoutID);
28820
- timeoutID = window.setTimeout(() => fn.apply(this, args), delay);
28821
- };
28822
- };
28823
- const LocalStoragePlugin = ({ namespace }) => {
28885
+ function LinkPreviewPlugin() {
28824
28886
  const [editor] = useLexicalComposerContext();
28825
- const saveContent = useCallback(
28826
- (content) => {
28827
- localStorage.setItem(namespace, content);
28828
- },
28829
- [namespace]
28830
- );
28831
- const debouncedSaveContent = debounce(saveContent, 500);
28887
+ const [hoveredLink, setHoveredLink] = useState$1(null);
28832
28888
  useEffect$1(() => {
28833
- return editor.registerUpdateListener(
28834
- ({ editorState, dirtyElements, dirtyLeaves }) => {
28835
- if (dirtyElements.size === 0 && dirtyLeaves.size === 0)
28836
- return;
28837
- const serializedState = JSON.stringify(editorState);
28838
- debouncedSaveContent(serializedState);
28889
+ const editorElement = editor.getRootElement();
28890
+ if (!editorElement)
28891
+ return;
28892
+ let showTimeout = null;
28893
+ let hideTimeout = null;
28894
+ let isOverPreview = false;
28895
+ const handleMouseOver = (event) => {
28896
+ const target = event.target;
28897
+ if (target.closest(".link-preview-card")) {
28898
+ isOverPreview = true;
28899
+ if (hideTimeout) {
28900
+ clearTimeout(hideTimeout);
28901
+ hideTimeout = null;
28902
+ }
28903
+ return;
28839
28904
  }
28840
- );
28841
- }, [debouncedSaveContent, editor]);
28842
- return null;
28843
- };
28844
- const LocalStoragePlugin$1 = LocalStoragePlugin;
28845
- const index$2 = "";
28846
- const PUNCTUATION = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_:;`;
28847
- const NAME = "\\b[A-Z][^\\s" + PUNCTUATION + "]";
28848
- const DocumentMentionsRegex = {
28849
- NAME,
28850
- PUNCTUATION
28851
- };
28852
- const PUNC = DocumentMentionsRegex.PUNCTUATION;
28853
- const TRIGGERS = ["@"].join("");
28854
- const VALID_CHARS = "[^" + TRIGGERS + PUNC + "\\s]";
28855
- const VALID_JOINS = "(?:\\.[ |$]| |[" + PUNC + "]|)";
28856
- const LENGTH_LIMIT = 75;
28857
- const AtSignMentionsRegex = new RegExp(
28858
- "(^|\\s|\\()([" + TRIGGERS + "]((?:" + VALID_CHARS + VALID_JOINS + "){0," + LENGTH_LIMIT + "}))$"
28859
- );
28860
- const SUGGESTION_LIST_LENGTH_LIMIT = 5;
28861
- const mentionsCache = /* @__PURE__ */ new Map();
28862
- const userLookupService = {
28863
- search(userList, string, callback) {
28864
- setTimeout(() => {
28865
- const results = userList.filter(
28866
- (mention) => mention.toLowerCase().includes(string.toLowerCase())
28867
- );
28868
- callback(results);
28869
- }, 500);
28905
+ const linkElement = target.closest("a");
28906
+ if (linkElement) {
28907
+ const href = linkElement.getAttribute("href");
28908
+ if (href && href !== "https://" && href !== "http://" && href !== "#") {
28909
+ if (showTimeout) {
28910
+ clearTimeout(showTimeout);
28911
+ }
28912
+ if (hideTimeout) {
28913
+ clearTimeout(hideTimeout);
28914
+ hideTimeout = null;
28915
+ }
28916
+ showTimeout = window.setTimeout(() => {
28917
+ const rect = linkElement.getBoundingClientRect();
28918
+ setHoveredLink({
28919
+ url: href,
28920
+ text: linkElement.textContent || "",
28921
+ rect
28922
+ });
28923
+ }, 500);
28924
+ }
28925
+ }
28926
+ };
28927
+ const handleMouseOut = (event) => {
28928
+ const target = event.target;
28929
+ const relatedTarget = event.relatedTarget;
28930
+ if (target.closest(".link-preview-card")) {
28931
+ isOverPreview = false;
28932
+ const movingToLink = relatedTarget == null ? void 0 : relatedTarget.closest("a");
28933
+ if (!movingToLink) {
28934
+ hideTimeout = window.setTimeout(() => {
28935
+ if (!isOverPreview) {
28936
+ setHoveredLink(null);
28937
+ }
28938
+ }, 300);
28939
+ }
28940
+ return;
28941
+ }
28942
+ const linkElement = target.closest("a");
28943
+ if (linkElement) {
28944
+ if (showTimeout) {
28945
+ clearTimeout(showTimeout);
28946
+ showTimeout = null;
28947
+ }
28948
+ const movingToPreview = relatedTarget == null ? void 0 : relatedTarget.closest(".link-preview-card");
28949
+ if (!movingToPreview) {
28950
+ hideTimeout = window.setTimeout(() => {
28951
+ if (!isOverPreview) {
28952
+ setHoveredLink(null);
28953
+ }
28954
+ }, 300);
28955
+ }
28956
+ }
28957
+ };
28958
+ editorElement.addEventListener("mouseover", handleMouseOver);
28959
+ editorElement.addEventListener("mouseout", handleMouseOut);
28960
+ document.body.addEventListener("mouseover", handleMouseOver);
28961
+ document.body.addEventListener("mouseout", handleMouseOut);
28962
+ return () => {
28963
+ if (showTimeout) {
28964
+ clearTimeout(showTimeout);
28965
+ }
28966
+ if (hideTimeout) {
28967
+ clearTimeout(hideTimeout);
28968
+ }
28969
+ editorElement.removeEventListener("mouseover", handleMouseOver);
28970
+ editorElement.removeEventListener("mouseout", handleMouseOut);
28971
+ document.body.removeEventListener("mouseover", handleMouseOver);
28972
+ document.body.removeEventListener("mouseout", handleMouseOut);
28973
+ };
28974
+ }, [editor]);
28975
+ if (!hoveredLink) {
28976
+ return null;
28870
28977
  }
28871
- };
28872
- function useMentionLookupService(userList = [], mentionString) {
28873
- const [results, setResults] = useState$1([]);
28978
+ return createPortal(
28979
+ /* @__PURE__ */ jsx(
28980
+ LinkPreview,
28981
+ {
28982
+ url: hoveredLink.url,
28983
+ rect: hoveredLink.rect,
28984
+ onClose: () => setHoveredLink(null)
28985
+ }
28986
+ ),
28987
+ document.body
28988
+ );
28989
+ }
28990
+ function LinkPreview({ url, rect, onClose }) {
28991
+ const [position, setPosition] = useState$1({ top: 0, left: 0 });
28874
28992
  useEffect$1(() => {
28875
- const cachedResults = mentionsCache.get(mentionString);
28876
- if (mentionString == null) {
28877
- setResults([]);
28878
- return;
28993
+ const previewWidth = 300;
28994
+ const previewHeight = 120;
28995
+ let top = rect.top + window.scrollY - previewHeight - 10;
28996
+ if (rect.top - previewHeight - 10 < 0) {
28997
+ top = rect.bottom + window.scrollY + 10;
28998
+ }
28999
+ let left = rect.left + window.scrollX + rect.width / 2 - previewWidth / 2;
29000
+ const viewportWidth = window.innerWidth;
29001
+ if (left < 10) {
29002
+ left = 10;
29003
+ } else if (left + previewWidth > viewportWidth - 10) {
29004
+ left = viewportWidth - previewWidth - 10;
29005
+ }
29006
+ setPosition({ top, left });
29007
+ }, [rect]);
29008
+ const getDomain = (urlString) => {
29009
+ try {
29010
+ const urlObj = new URL(urlString);
29011
+ return urlObj.hostname.replace("www.", "");
29012
+ } catch {
29013
+ return urlString;
28879
29014
  }
28880
- if (cachedResults === null) {
28881
- return;
28882
- } else if (cachedResults !== void 0) {
28883
- setResults(cachedResults);
28884
- return;
29015
+ };
29016
+ const domain = getDomain(url);
29017
+ const getProtocol = (urlString) => {
29018
+ try {
29019
+ const urlObj = new URL(urlString);
29020
+ return urlObj.protocol.replace(":", "").toUpperCase();
29021
+ } catch {
29022
+ return "HTTPS";
28885
29023
  }
28886
- mentionsCache.set(mentionString, null);
29024
+ };
29025
+ const protocol = getProtocol(url);
29026
+ return /* @__PURE__ */ jsxs(
29027
+ "div",
29028
+ {
29029
+ className: "link-preview-card",
29030
+ style: {
29031
+ position: "absolute",
29032
+ top: `${position.top}px`,
29033
+ left: `${position.left}px`,
29034
+ zIndex: 1e4,
29035
+ pointerEvents: "auto",
29036
+ animation: "fadeIn 0.2s ease-out"
29037
+ },
29038
+ children: [
29039
+ /* @__PURE__ */ jsxs(
29040
+ "div",
29041
+ {
29042
+ style: {
29043
+ width: "250px",
29044
+ backgroundColor: "#2d2d2d",
29045
+ borderRadius: "12px",
29046
+ boxShadow: "0 10px 40px rgba(0, 0, 0, 0.3)",
29047
+ overflow: "hidden",
29048
+ position: "relative"
29049
+ },
29050
+ children: [
29051
+ /* @__PURE__ */ jsx(
29052
+ "button",
29053
+ {
29054
+ onClick: (e) => {
29055
+ e.preventDefault();
29056
+ e.stopPropagation();
29057
+ onClose();
29058
+ },
29059
+ style: {
29060
+ position: "absolute",
29061
+ top: "8px",
29062
+ right: "8px",
29063
+ width: "20px",
29064
+ height: "20px",
29065
+ borderRadius: "4px",
29066
+ backgroundColor: "#404040",
29067
+ border: "none",
29068
+ cursor: "pointer",
29069
+ display: "flex",
29070
+ alignItems: "center",
29071
+ justifyContent: "center",
29072
+ transition: "background-color 0.2s",
29073
+ zIndex: 1
29074
+ },
29075
+ onMouseEnter: (e) => {
29076
+ e.currentTarget.style.backgroundColor = "#525252";
29077
+ },
29078
+ onMouseLeave: (e) => {
29079
+ e.currentTarget.style.backgroundColor = "#404040";
29080
+ },
29081
+ title: "Close preview",
29082
+ children: /* @__PURE__ */ jsx(
29083
+ "svg",
29084
+ {
29085
+ style: { width: "12px", height: "12px", color: "#9ca3af" },
29086
+ fill: "none",
29087
+ stroke: "currentColor",
29088
+ viewBox: "0 0 24 24",
29089
+ children: /* @__PURE__ */ jsx(
29090
+ "path",
29091
+ {
29092
+ strokeLinecap: "round",
29093
+ strokeLinejoin: "round",
29094
+ strokeWidth: 2,
29095
+ d: "M6 18L18 6M6 6l12 12"
29096
+ }
29097
+ )
29098
+ }
29099
+ )
29100
+ }
29101
+ ),
29102
+ /* @__PURE__ */ jsxs("div", { style: { padding: "16px 16px 12px 16px" }, children: [
29103
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }, children: [
29104
+ /* @__PURE__ */ jsx(
29105
+ "svg",
29106
+ {
29107
+ style: { width: "16px", height: "16px", color: "#ffffff" },
29108
+ fill: "none",
29109
+ stroke: "currentColor",
29110
+ viewBox: "0 0 24 24",
29111
+ children: /* @__PURE__ */ jsx(
29112
+ "path",
29113
+ {
29114
+ strokeLinecap: "round",
29115
+ strokeLinejoin: "round",
29116
+ strokeWidth: 2,
29117
+ d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
29118
+ }
29119
+ )
29120
+ }
29121
+ ),
29122
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "14px", fontWeight: "600", color: "#ffffff" }, children: domain })
29123
+ ] }),
29124
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "10px", color: "#9ca3af", marginLeft: "24px" }, children: protocol })
29125
+ ] }),
29126
+ /* @__PURE__ */ jsxs("div", { style: { padding: "0 16px 16px 16px" }, children: [
29127
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "10px", fontWeight: "500", color: "#9ca3af", textTransform: "uppercase", marginBottom: "8px" }, children: "LINK URL" }),
29128
+ /* @__PURE__ */ jsx("div", { style: { backgroundColor: "#1a1a1a", padding: "10px", borderRadius: "6px" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#ffffff", wordBreak: "break-all", lineHeight: "1.5" }, children: url }) })
29129
+ ] }),
29130
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "8px", padding: "12px", borderTop: "1px solid #404040" }, children: [
29131
+ /* @__PURE__ */ jsx(
29132
+ "div",
29133
+ {
29134
+ style: {
29135
+ width: "8px",
29136
+ height: "8px",
29137
+ borderRadius: "50%",
29138
+ backgroundColor: "#10b981",
29139
+ boxShadow: "0 0 8px rgba(16, 185, 129, 0.6)",
29140
+ animation: "pulse 2s ease-in-out infinite"
29141
+ }
29142
+ }
29143
+ ),
29144
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "10px", fontWeight: "500", color: "#a1a1aa" }, children: "Link Preview" })
29145
+ ] })
29146
+ ]
29147
+ }
29148
+ ),
29149
+ /* @__PURE__ */ jsx("style", { children: `
29150
+ @keyframes fadeIn {
29151
+ from {
29152
+ opacity: 0;
29153
+ transform: translateY(5px);
29154
+ }
29155
+ to {
29156
+ opacity: 1;
29157
+ transform: translateY(0);
29158
+ }
29159
+ }
29160
+
29161
+ @keyframes pulse {
29162
+ 0%, 100% {
29163
+ opacity: 1;
29164
+ }
29165
+ 50% {
29166
+ opacity: 0.6;
29167
+ }
29168
+ }
29169
+ ` })
29170
+ ]
29171
+ }
29172
+ );
29173
+ }
29174
+ const debounce = (fn, delay) => {
29175
+ let timeoutID;
29176
+ return function(...args) {
29177
+ clearTimeout(timeoutID);
29178
+ timeoutID = window.setTimeout(() => fn.apply(this, args), delay);
29179
+ };
29180
+ };
29181
+ const LocalStoragePlugin = ({ namespace }) => {
29182
+ const [editor] = useLexicalComposerContext();
29183
+ const saveContent = useCallback(
29184
+ (content) => {
29185
+ localStorage.setItem(namespace, content);
29186
+ },
29187
+ [namespace]
29188
+ );
29189
+ const debouncedSaveContent = debounce(saveContent, 500);
29190
+ useEffect$1(() => {
29191
+ return editor.registerUpdateListener(
29192
+ ({ editorState, dirtyElements, dirtyLeaves }) => {
29193
+ if (dirtyElements.size === 0 && dirtyLeaves.size === 0)
29194
+ return;
29195
+ const serializedState = JSON.stringify(editorState);
29196
+ debouncedSaveContent(serializedState);
29197
+ }
29198
+ );
29199
+ }, [debouncedSaveContent, editor]);
29200
+ return null;
29201
+ };
29202
+ const LocalStoragePlugin$1 = LocalStoragePlugin;
29203
+ const index$2 = "";
29204
+ const PUNCTUATION = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_:;`;
29205
+ const NAME = "\\b[A-Z][^\\s" + PUNCTUATION + "]";
29206
+ const DocumentMentionsRegex = {
29207
+ NAME,
29208
+ PUNCTUATION
29209
+ };
29210
+ const PUNC = DocumentMentionsRegex.PUNCTUATION;
29211
+ const TRIGGERS = ["@"].join("");
29212
+ const VALID_CHARS = "[^" + TRIGGERS + PUNC + "\\s]";
29213
+ const VALID_JOINS = "(?:\\.[ |$]| |[" + PUNC + "]|)";
29214
+ const LENGTH_LIMIT = 75;
29215
+ const AtSignMentionsRegex = new RegExp(
29216
+ "(^|\\s|\\()([" + TRIGGERS + "]((?:" + VALID_CHARS + VALID_JOINS + "){0," + LENGTH_LIMIT + "}))$"
29217
+ );
29218
+ const SUGGESTION_LIST_LENGTH_LIMIT = 5;
29219
+ const mentionsCache = /* @__PURE__ */ new Map();
29220
+ const userLookupService = {
29221
+ search(userList, string, callback) {
29222
+ setTimeout(() => {
29223
+ const results = userList.filter(
29224
+ (mention) => mention.toLowerCase().includes(string.toLowerCase())
29225
+ );
29226
+ callback(results);
29227
+ }, 500);
29228
+ }
29229
+ };
29230
+ function useMentionLookupService(userList = [], mentionString) {
29231
+ const [results, setResults] = useState$1([]);
29232
+ useEffect$1(() => {
29233
+ const cachedResults = mentionsCache.get(mentionString);
29234
+ if (mentionString == null) {
29235
+ setResults([]);
29236
+ return;
29237
+ }
29238
+ if (cachedResults === null) {
29239
+ return;
29240
+ } else if (cachedResults !== void 0) {
29241
+ setResults(cachedResults);
29242
+ return;
29243
+ }
29244
+ mentionsCache.set(mentionString, null);
28887
29245
  userLookupService.search(userList, mentionString, (newResults) => {
28888
29246
  mentionsCache.set(mentionString, newResults);
28889
29247
  setResults(newResults);
@@ -29412,7 +29770,7 @@ function SlashCommandPlugin() {
29412
29770
  });
29413
29771
  }, [makeBlock]);
29414
29772
  const insertTable = useCallback(() => {
29415
- editor.dispatchCommand(OPEN_TABLE_MODAL_COMMAND, void 0);
29773
+ editor.dispatchCommand(CREATE_TABLE_COMMAND, void 0);
29416
29774
  }, [editor]);
29417
29775
  const formatBold = useCallback(() => {
29418
29776
  editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
@@ -29466,9 +29824,6 @@ function SlashCommandPlugin() {
29466
29824
  const openAIChat = useCallback(() => {
29467
29825
  editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, void 0);
29468
29826
  }, [editor]);
29469
- const aiGenerateImage = useCallback(() => {
29470
- editor.dispatchCommand(AI_IMAGE_COMMAND, void 0);
29471
- }, [editor]);
29472
29827
  const baseOptions = useMemo(() => {
29473
29828
  return [
29474
29829
  // Block types
@@ -29522,8 +29877,8 @@ function SlashCommandPlugin() {
29522
29877
  // AI features
29523
29878
  new SlashMenuOption("__label__AI", () => {
29524
29879
  }),
29525
- new SlashMenuOption("AI Chat", openAIChat),
29526
- new SlashMenuOption("AI Generate image", aiGenerateImage)
29880
+ new SlashMenuOption("AI Chat", openAIChat)
29881
+ // new SlashMenuOption("AI Generate image", aiGenerateImage),
29527
29882
  ];
29528
29883
  }, [
29529
29884
  insertParagraph,
@@ -29549,8 +29904,7 @@ function SlashCommandPlugin() {
29549
29904
  handleClearFormatting,
29550
29905
  handleClearContent,
29551
29906
  addComment,
29552
- openAIChat,
29553
- aiGenerateImage
29907
+ openAIChat
29554
29908
  ]);
29555
29909
  const options = useMemo(() => {
29556
29910
  const query = searchQuery || queryString || "";
@@ -30153,10 +30507,12 @@ function TableActionMenu({
30153
30507
  columns: 1,
30154
30508
  rows: 1
30155
30509
  });
30510
+ const [selectionType, setSelectionType] = useState$1(null);
30156
30511
  const [canMergeCells, setCanMergeCells] = useState$1(false);
30157
30512
  const [canUnmergeCell, setCanUnmergeCell] = useState$1(false);
30158
30513
  const [backgroundColor, setBackgroundColor] = useState$1("");
30159
30514
  const [stripingColor, setStripingColor] = useState$1("");
30515
+ const [isHeaderCell, setIsHeaderCell] = useState$1(false);
30160
30516
  useEffect$1(() => {
30161
30517
  updateTableCellNode(_tableCellNode);
30162
30518
  }, [_tableCellNode]);
@@ -30184,10 +30540,43 @@ function TableActionMenu({
30184
30540
  setCanMergeCells(
30185
30541
  currentSelectionCounts.columns > 1 || currentSelectionCounts.rows > 1
30186
30542
  );
30543
+ const anchorNode = $getTableCellNodeFromLexicalNode(selection.anchor.getNode());
30544
+ if (anchorNode) {
30545
+ const tableNode = $getTableNodeFromLexicalNodeOrThrow(anchorNode);
30546
+ const tableRowCount = tableNode.getChildrenSize();
30547
+ const firstRow = tableNode.getFirstChild();
30548
+ const tableColumnCount = firstRow && $isTableRowNode(firstRow) ? firstRow.getChildrenSize() : 0;
30549
+ const nodes = selection.getNodes();
30550
+ const hasHeaderCell = nodes.some((node) => {
30551
+ if ($isTableCellNode(node)) {
30552
+ return node.getHeaderStyles() !== 0;
30553
+ }
30554
+ return false;
30555
+ });
30556
+ setIsHeaderCell(hasHeaderCell);
30557
+ if (currentSelectionCounts.rows === tableRowCount && currentSelectionCounts.columns < tableColumnCount) {
30558
+ setSelectionType("column");
30559
+ } else if (currentSelectionCounts.columns === tableColumnCount && currentSelectionCounts.rows < tableRowCount) {
30560
+ setSelectionType("row");
30561
+ } else {
30562
+ setSelectionType("cell");
30563
+ }
30564
+ } else {
30565
+ setSelectionType(null);
30566
+ setIsHeaderCell(false);
30567
+ }
30568
+ } else {
30569
+ setSelectionType(null);
30570
+ const node = $getTableCellNodeFromLexicalNode(tableCellNode);
30571
+ if (node && $isTableCellNode(node)) {
30572
+ setIsHeaderCell(node.getHeaderStyles() !== 0);
30573
+ } else {
30574
+ setIsHeaderCell(false);
30575
+ }
30187
30576
  }
30188
30577
  setCanUnmergeCell($canUnmerge());
30189
30578
  });
30190
- }, [editor]);
30579
+ }, [editor, tableCellNode]);
30191
30580
  useEffect$1(() => {
30192
30581
  const menuButtonElement = contextRef.current;
30193
30582
  const dropDownElement = dropDownRef.current;
@@ -30196,6 +30585,7 @@ function TableActionMenu({
30196
30585
  dropDownElement.style.opacity = "1";
30197
30586
  const dropDownElementRect = dropDownElement.getBoundingClientRect();
30198
30587
  const margin = 8;
30588
+ const viewportHeight = window.innerHeight;
30199
30589
  if (contextMenuPosition) {
30200
30590
  let leftPosition = contextMenuPosition.x + margin;
30201
30591
  let topPosition = contextMenuPosition.y + margin;
@@ -30211,6 +30601,12 @@ function TableActionMenu({
30211
30601
  if (topPosition < margin) {
30212
30602
  topPosition = margin;
30213
30603
  }
30604
+ const availableHeight = viewportHeight - topPosition - margin;
30605
+ if (availableHeight < dropDownElementRect.height) {
30606
+ dropDownElement.style.maxHeight = `${availableHeight}px`;
30607
+ } else {
30608
+ dropDownElement.style.maxHeight = "none";
30609
+ }
30214
30610
  dropDownElement.style.left = `${leftPosition}px`;
30215
30611
  dropDownElement.style.top = `${topPosition}px`;
30216
30612
  } else if (chevronPositionRef.current != null) {
@@ -30230,6 +30626,12 @@ function TableActionMenu({
30230
30626
  if (topPosition < margin) {
30231
30627
  topPosition = margin;
30232
30628
  }
30629
+ const availableHeight = viewportHeight - topPosition - margin;
30630
+ if (availableHeight < dropDownElementRect.height) {
30631
+ dropDownElement.style.maxHeight = `${availableHeight}px`;
30632
+ } else {
30633
+ dropDownElement.style.maxHeight = "none";
30634
+ }
30233
30635
  dropDownElement.style.top = `${topPosition}px`;
30234
30636
  } else if (menuButtonElement != null) {
30235
30637
  const menuButtonRect = menuButtonElement.getBoundingClientRect();
@@ -30248,6 +30650,12 @@ function TableActionMenu({
30248
30650
  if (topPosition < margin) {
30249
30651
  topPosition = margin;
30250
30652
  }
30653
+ const availableHeight = viewportHeight - topPosition - margin;
30654
+ if (availableHeight < dropDownElementRect.height) {
30655
+ dropDownElement.style.maxHeight = `${availableHeight}px`;
30656
+ } else {
30657
+ dropDownElement.style.maxHeight = "none";
30658
+ }
30251
30659
  dropDownElement.style.top = `${topPosition}px`;
30252
30660
  }
30253
30661
  }
@@ -30357,8 +30765,29 @@ function TableActionMenu({
30357
30765
  const insertTableRowAtSelection = useCallback(
30358
30766
  (shouldInsertAfter) => {
30359
30767
  editor.update(() => {
30768
+ const selection = $getSelection();
30769
+ if (!($isRangeSelection(selection) || $isTableSelection(selection))) {
30770
+ onClose();
30771
+ return;
30772
+ }
30773
+ const [cell] = $getNodeTriplet(selection.anchor);
30774
+ const tableNode = $getTableNodeFromLexicalNodeOrThrow(cell);
30775
+ const rowIndex = $getTableRowIndexFromTableCellNode(cell);
30360
30776
  for (let i2 = 0; i2 < selectionCounts.rows; i2++) {
30361
30777
  $insertTableRow__EXPERIMENTAL(shouldInsertAfter);
30778
+ const targetRowIndex = shouldInsertAfter ? rowIndex + i2 + 1 : rowIndex - i2;
30779
+ const rows = tableNode.getChildren();
30780
+ if (targetRowIndex >= 0 && targetRowIndex < rows.length) {
30781
+ const newRow = rows[targetRowIndex];
30782
+ if ($isTableRowNode(newRow)) {
30783
+ const cells = newRow.getChildren();
30784
+ cells.forEach((cellNode) => {
30785
+ if ($isTableCellNode(cellNode)) {
30786
+ cellNode.setHeaderStyles(TableCellHeaderStates.NO_STATUS);
30787
+ }
30788
+ });
30789
+ }
30790
+ }
30362
30791
  }
30363
30792
  onClose();
30364
30793
  });
@@ -30368,33 +30797,57 @@ function TableActionMenu({
30368
30797
  const insertTableColumnAtSelection = useCallback(
30369
30798
  (shouldInsertAfter) => {
30370
30799
  editor.update(() => {
30800
+ const selection = $getSelection();
30801
+ if (!($isRangeSelection(selection) || $isTableSelection(selection))) {
30802
+ onClose();
30803
+ return;
30804
+ }
30805
+ const [cell] = $getNodeTriplet(selection.anchor);
30806
+ if (!$isTableCellNode(cell)) {
30807
+ onClose();
30808
+ return;
30809
+ }
30810
+ const tableNode = $getTableNodeFromLexicalNodeOrThrow(cell);
30811
+ const rows = tableNode.getChildren();
30812
+ let hasColumnHeaders = false;
30813
+ let headerBackgroundColor = null;
30814
+ if (rows.length > 0 && $isTableRowNode(rows[0])) {
30815
+ const firstRow = rows[0];
30816
+ const cells = firstRow.getChildren();
30817
+ if (cells.length > 0 && $isTableCellNode(cells[0])) {
30818
+ const firstCell = cells[0];
30819
+ hasColumnHeaders = (firstCell.getHeaderStyles() & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN;
30820
+ headerBackgroundColor = firstCell.getBackgroundColor();
30821
+ }
30822
+ }
30823
+ const cellColumnIndex = $getTableColumnIndexFromTableCellNode(cell);
30371
30824
  for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
30372
30825
  $insertTableColumn__EXPERIMENTAL(shouldInsertAfter);
30373
30826
  }
30374
- const selection = $getSelection();
30375
- if ($isRangeSelection(selection) || $isTableSelection(selection)) {
30376
- const [cell] = $getNodeTriplet(selection.anchor);
30377
- if ($isTableCellNode(cell)) {
30378
- const tableNode = $getTableNodeFromLexicalNodeOrThrow(cell);
30379
- const rows = tableNode.getChildren();
30380
- if (rows.length > 0 && $isTableRowNode(rows[0])) {
30381
- const firstRow = rows[0];
30382
- const firstRowCells = firstRow.getChildren();
30383
- if (firstRowCells.length > 0 && $isTableCellNode(firstRowCells[0])) {
30384
- const firstCell = firstRowCells[0];
30385
- const hasColumnHeaders = (firstCell.getHeaderStyles() & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN;
30386
- if (hasColumnHeaders) {
30387
- const headerBackgroundColor = firstCell.getBackgroundColor();
30388
- for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
30389
- const newHeaderCellIndex = firstRowCells.length - 1 - i2;
30390
- if (newHeaderCellIndex >= 0) {
30391
- const newHeaderCell = firstRowCells[newHeaderCellIndex];
30392
- if ($isTableCellNode(newHeaderCell)) {
30393
- newHeaderCell.setHeaderStyles(TableCellHeaderStates.COLUMN);
30394
- if (headerBackgroundColor) {
30395
- newHeaderCell.setBackgroundColor(headerBackgroundColor);
30396
- }
30397
- }
30827
+ if (hasColumnHeaders) {
30828
+ const updatedFirstRow = tableNode.getChildren()[0];
30829
+ if ($isTableRowNode(updatedFirstRow)) {
30830
+ const updatedCells = updatedFirstRow.getChildren();
30831
+ const startIndex = shouldInsertAfter ? cellColumnIndex + 1 : cellColumnIndex;
30832
+ for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
30833
+ const newColumnIndex = startIndex + i2;
30834
+ if (newColumnIndex >= 0 && newColumnIndex < updatedCells.length) {
30835
+ const newHeaderCell = updatedCells[newColumnIndex];
30836
+ if ($isTableCellNode(newHeaderCell)) {
30837
+ newHeaderCell.setHeaderStyles(TableCellHeaderStates.COLUMN);
30838
+ if (headerBackgroundColor) {
30839
+ newHeaderCell.setBackgroundColor(headerBackgroundColor);
30840
+ }
30841
+ if (newHeaderCell.getChildrenSize() === 0) {
30842
+ const paragraph = $createParagraphNode();
30843
+ const textNode = $createTextNode("​");
30844
+ paragraph.append(textNode);
30845
+ newHeaderCell.append(paragraph);
30846
+ } else {
30847
+ const firstChild = newHeaderCell.getFirstChild();
30848
+ if ($isParagraphNode(firstChild) && firstChild.getTextContentSize() === 0) {
30849
+ const textNode = $createTextNode("​");
30850
+ firstChild.append(textNode);
30398
30851
  }
30399
30852
  }
30400
30853
  }
@@ -30404,46 +30857,6 @@ function TableActionMenu({
30404
30857
  }
30405
30858
  onClose();
30406
30859
  });
30407
- requestAnimationFrame(() => {
30408
- const applyHeaderStyles = () => {
30409
- const rootElement = editor.getRootElement();
30410
- if (!rootElement)
30411
- return false;
30412
- const tables = rootElement.querySelectorAll("table");
30413
- tables.forEach((table) => {
30414
- const rows = table.querySelectorAll("tr");
30415
- if (rows.length > 0) {
30416
- const firstRow = rows[0];
30417
- const cells = firstRow.querySelectorAll("th, td");
30418
- if (cells.length > 1) {
30419
- const firstHeaderCell = cells[0];
30420
- const headerColor = firstHeaderCell.getAttribute("data-header-color");
30421
- const textColor = firstHeaderCell.getAttribute("data-text-color");
30422
- if (headerColor && textColor) {
30423
- for (let i2 = 0; i2 < selectionCounts.columns; i2++) {
30424
- const cellIndex = cells.length - 1 - i2;
30425
- if (cellIndex >= 0) {
30426
- const newCell = cells[cellIndex];
30427
- newCell.setAttribute("data-header-color", headerColor);
30428
- newCell.setAttribute("data-text-color", textColor);
30429
- newCell.style.setProperty("background-color", headerColor, "important");
30430
- newCell.style.setProperty("color", textColor, "important");
30431
- newCell.style.setProperty("padding", "8px", "important");
30432
- newCell.style.setProperty("border", "1px solid #ddd", "important");
30433
- newCell.style.setProperty("font-weight", "bold", "important");
30434
- newCell.style.setProperty("white-space", "nowrap", "important");
30435
- }
30436
- }
30437
- }
30438
- }
30439
- }
30440
- });
30441
- return true;
30442
- };
30443
- if (!applyHeaderStyles()) {
30444
- setTimeout(applyHeaderStyles, 100);
30445
- }
30446
- });
30447
30860
  },
30448
30861
  [editor, onClose, selectionCounts.columns]
30449
30862
  );
@@ -30608,7 +31021,7 @@ function TableActionMenu({
30608
31021
  }, [editor, tableCellNode, $clearTableSelectionInline]);
30609
31022
  const handleCellBackgroundColor = useCallback(
30610
31023
  (value) => {
30611
- const getContrastColor2 = (hexColor) => {
31024
+ const getContrastColor = (hexColor) => {
30612
31025
  const hex = hexColor.replace("#", "");
30613
31026
  const r2 = parseInt(hex.substr(0, 2), 16);
30614
31027
  const g2 = parseInt(hex.substr(2, 2), 16);
@@ -30616,7 +31029,7 @@ function TableActionMenu({
30616
31029
  const luminance = (0.299 * r2 + 0.587 * g2 + 0.114 * b2) / 255;
30617
31030
  return luminance > 0.5 ? "#000000" : "#FFFFFF";
30618
31031
  };
30619
- const textColor = getContrastColor2(value);
31032
+ const textColor = getContrastColor(value);
30620
31033
  const cellKeysToStyle = [];
30621
31034
  editor.update(() => {
30622
31035
  if (tableCellNode.isAttached()) {
@@ -30641,6 +31054,7 @@ function TableActionMenu({
30641
31054
  if (cellElement instanceof HTMLElement) {
30642
31055
  cellElement.style.setProperty("background-color", value, "important");
30643
31056
  cellElement.style.setProperty("color", textColor, "important");
31057
+ cellElement.style.setProperty("border-color", "#bbb", "important");
30644
31058
  const nestedElements = cellElement.querySelectorAll("*");
30645
31059
  nestedElements.forEach((elem) => {
30646
31060
  if (elem instanceof HTMLElement) {
@@ -30720,7 +31134,7 @@ function TableActionMenu({
30720
31134
  children: /* @__PURE__ */ jsx("span", { className: "text", children: "Background color" })
30721
31135
  }
30722
31136
  ),
30723
- /* @__PURE__ */ jsx(
31137
+ selectionType !== "column" && /* @__PURE__ */ jsx(
30724
31138
  "button",
30725
31139
  {
30726
31140
  type: "button",
@@ -30745,7 +31159,7 @@ function TableActionMenu({
30745
31159
  }
30746
31160
  ),
30747
31161
  /* @__PURE__ */ jsx("div", { className: "cteditor-border-b cteditor-border-foreground/15 cteditor-my-1" }),
30748
- /* @__PURE__ */ jsx(
31162
+ !isHeaderCell && /* @__PURE__ */ jsx(
30749
31163
  "button",
30750
31164
  {
30751
31165
  type: "button",
@@ -30811,7 +31225,7 @@ function TableActionMenu({
30811
31225
  }
30812
31226
  ),
30813
31227
  /* @__PURE__ */ jsx("div", { className: "border-b border-foreground/15 my-1" }),
30814
- /* @__PURE__ */ jsx(
31228
+ selectionType !== "row" && /* @__PURE__ */ jsx(
30815
31229
  "button",
30816
31230
  {
30817
31231
  type: "button",
@@ -30821,7 +31235,7 @@ function TableActionMenu({
30821
31235
  children: /* @__PURE__ */ jsx("span", { className: "text", children: "Delete column" })
30822
31236
  }
30823
31237
  ),
30824
- /* @__PURE__ */ jsx(
31238
+ selectionType !== "column" && /* @__PURE__ */ jsx(
30825
31239
  "button",
30826
31240
  {
30827
31241
  type: "button",
@@ -30842,7 +31256,7 @@ function TableActionMenu({
30842
31256
  }
30843
31257
  ),
30844
31258
  /* @__PURE__ */ jsx("div", { className: "cteditor-border-b cteditor-border-foreground/15 cteditor-my-1" }),
30845
- /* @__PURE__ */ jsx(
31259
+ selectionType !== "column" && /* @__PURE__ */ jsx(
30846
31260
  "button",
30847
31261
  {
30848
31262
  type: "button",
@@ -30855,7 +31269,7 @@ function TableActionMenu({
30855
31269
  ] })
30856
31270
  }
30857
31271
  ),
30858
- /* @__PURE__ */ jsx(
31272
+ selectionType !== "row" && /* @__PURE__ */ jsx(
30859
31273
  "button",
30860
31274
  {
30861
31275
  type: "button",
@@ -30877,8 +31291,7 @@ function TableActionMenu({
30877
31291
  }
30878
31292
  function TableCellActionMenuContainer({
30879
31293
  anchorElem,
30880
- cellMerge,
30881
- isSmallWidthViewport
31294
+ cellMerge
30882
31295
  }) {
30883
31296
  const [editor] = useLexicalComposerContext();
30884
31297
  const menuButtonRef = useRef(null);
@@ -31001,6 +31414,15 @@ function TableCellActionMenuContainer({
31001
31414
  }
31002
31415
  return false;
31003
31416
  };
31417
+ const handleScroll2 = () => {
31418
+ editor.getEditorState().read($moveMenu);
31419
+ };
31420
+ const editorElement = editor.getRootElement();
31421
+ const scrollableParent = editorElement == null ? void 0 : editorElement.closest(".cteditor-content");
31422
+ if (scrollableParent) {
31423
+ scrollableParent.addEventListener("scroll", handleScroll2, { capture: true, passive: true });
31424
+ }
31425
+ window.addEventListener("scroll", handleScroll2, { capture: true, passive: true });
31004
31426
  const handleContextMenu = (event) => {
31005
31427
  event.stopPropagation();
31006
31428
  const target = event.target;
@@ -31070,7 +31492,15 @@ function TableCellActionMenuContainer({
31070
31492
  delayedCallback();
31071
31493
  }
31072
31494
  }),
31073
- () => clearTimeout(timeoutId)
31495
+ () => {
31496
+ clearTimeout(timeoutId);
31497
+ const editorElement2 = editor.getRootElement();
31498
+ const scrollableParent2 = editorElement2 == null ? void 0 : editorElement2.closest(".cteditor-content");
31499
+ if (scrollableParent2) {
31500
+ scrollableParent2.removeEventListener("scroll", handleScroll2);
31501
+ }
31502
+ window.removeEventListener("scroll", handleScroll2);
31503
+ }
31074
31504
  );
31075
31505
  });
31076
31506
  const prevTableCellDOM = useRef(tableCellNode);
@@ -31160,7 +31590,8 @@ function TableActionMenuPlugin({
31160
31590
  }
31161
31591
  const index = "";
31162
31592
  const MIN_ROW_HEIGHT = 33;
31163
- const MIN_COLUMN_WIDTH = 92;
31593
+ const MIN_COLUMN_WIDTH = 50;
31594
+ const DEFAULT_COLUMN_WIDTH = 80;
31164
31595
  function TableCellResizer({ editor }) {
31165
31596
  const targetRef = useRef(null);
31166
31597
  const resizerRef = useRef(null);
@@ -31168,10 +31599,13 @@ function TableCellResizer({ editor }) {
31168
31599
  const mouseStartPosRef = useRef(null);
31169
31600
  const [mouseCurrentPos, updateMouseCurrentPos] = useState$1(null);
31170
31601
  const [activeCell, updateActiveCell] = useState$1(null);
31171
- const [isMouseDown, updateIsMouseDown] = useState$1(false);
31602
+ const [_isMouseDown, updateIsMouseDown] = useState$1(false);
31172
31603
  const [draggingDirection, updateDraggingDirection] = useState$1(null);
31173
31604
  const [currentDimension, setCurrentDimension] = useState$1(null);
31174
31605
  const [hoveredDirection, setHoveredDirection] = useState$1(null);
31606
+ const [initialDimension, setInitialDimension] = useState$1(null);
31607
+ const updateColumnWidthToValueRef = useRef(null);
31608
+ const updateRowHeightToValueRef = useRef(null);
31175
31609
  const resetState = useCallback(() => {
31176
31610
  updateActiveCell(null);
31177
31611
  targetRef.current = null;
@@ -31180,6 +31614,7 @@ function TableCellResizer({ editor }) {
31180
31614
  tableRectRef.current = null;
31181
31615
  setCurrentDimension(null);
31182
31616
  setHoveredDirection(null);
31617
+ setInitialDimension(null);
31183
31618
  }, []);
31184
31619
  const isMouseDownOnEvent = (event) => {
31185
31620
  return (event.buttons & 1) === 1;
@@ -31187,54 +31622,41 @@ function TableCellResizer({ editor }) {
31187
31622
  useEffect$1(() => {
31188
31623
  return editor.registerNodeTransform(TableNode, (tableNode) => {
31189
31624
  const existingWidths = tableNode.getColWidths();
31190
- const numColumns = tableNode.getColumnCount();
31191
- const tableElement = editor.getElementByKey(tableNode.getKey());
31192
- if (existingWidths && existingWidths.length > 0) {
31193
- if (tableElement) {
31194
- const totalWidth = existingWidths.reduce((sum, w2) => sum + w2, 0);
31195
- const currentWidth = tableElement.style.width;
31196
- if (!currentWidth || parseInt(currentWidth) !== totalWidth) {
31197
- tableElement.style.setProperty("width", `${totalWidth}px`, "important");
31198
- }
31199
- }
31625
+ if (existingWidths) {
31200
31626
  return tableNode;
31201
31627
  }
31202
- if (tableElement) {
31203
- const firstRow = tableElement.querySelector("tr");
31204
- if (firstRow) {
31205
- const cells = Array.from(firstRow.querySelectorAll("th, td"));
31206
- const actualWidths = cells.map((cell) => {
31207
- const width = cell.offsetWidth;
31208
- return Math.max(width || MIN_COLUMN_WIDTH, MIN_COLUMN_WIDTH);
31209
- });
31210
- if (actualWidths.length === numColumns) {
31211
- tableNode.setColWidths(actualWidths);
31212
- const totalWidth = actualWidths.reduce((sum, w2) => sum + w2, 0);
31213
- tableElement.style.setProperty("width", `${totalWidth}px`, "important");
31214
- return tableNode;
31215
- }
31216
- }
31217
- }
31218
- const fallbackWidths = Array(numColumns).fill(MIN_COLUMN_WIDTH);
31219
- tableNode.setColWidths(fallbackWidths);
31220
- if (tableElement) {
31221
- const totalWidth = fallbackWidths.reduce((sum, w2) => sum + w2, 0);
31222
- tableElement.style.setProperty("width", `${totalWidth}px`, "important");
31223
- }
31628
+ const numColumns = tableNode.getColumnCount();
31629
+ const initialWidths = Array(numColumns).fill(DEFAULT_COLUMN_WIDTH);
31630
+ tableNode.setColWidths(initialWidths);
31224
31631
  return tableNode;
31225
31632
  });
31226
31633
  }, [editor]);
31227
31634
  useEffect$1(() => {
31228
31635
  const onMouseMove = (event) => {
31636
+ var _a, _b;
31229
31637
  const target = event.target;
31230
31638
  if (!isHTMLElement$1(target)) {
31231
31639
  return;
31232
31640
  }
31233
- if (draggingDirection) {
31234
- updateMouseCurrentPos({
31641
+ if (draggingDirection && mouseStartPosRef.current && initialDimension !== null) {
31642
+ const newPos = {
31235
31643
  x: event.clientX,
31236
31644
  y: event.clientY
31237
- });
31645
+ };
31646
+ updateMouseCurrentPos(newPos);
31647
+ const zoom = calculateZoomLevel(event.target);
31648
+ const { x: x2, y: y2 } = mouseStartPosRef.current;
31649
+ if (isHeightChanging(draggingDirection)) {
31650
+ const heightChange = (newPos.y - y2) / zoom;
31651
+ const newHeight = Math.max(initialDimension + heightChange, MIN_ROW_HEIGHT);
31652
+ setCurrentDimension(newHeight);
31653
+ (_a = updateRowHeightToValueRef.current) == null ? void 0 : _a.call(updateRowHeightToValueRef, newHeight);
31654
+ } else {
31655
+ const widthChange = (newPos.x - x2) / zoom;
31656
+ const newWidth = Math.max(initialDimension + widthChange, MIN_COLUMN_WIDTH);
31657
+ setCurrentDimension(newWidth);
31658
+ (_b = updateColumnWidthToValueRef.current) == null ? void 0 : _b.call(updateColumnWidthToValueRef, newWidth);
31659
+ }
31238
31660
  return;
31239
31661
  }
31240
31662
  updateIsMouseDown(isMouseDownOnEvent(event));
@@ -31270,10 +31692,10 @@ function TableCellResizer({ editor }) {
31270
31692
  }
31271
31693
  }
31272
31694
  };
31273
- const onMouseDown = (event) => {
31695
+ const onMouseDown = (_event) => {
31274
31696
  updateIsMouseDown(true);
31275
31697
  };
31276
- const onMouseUp = (event) => {
31698
+ const onMouseUp = (_event) => {
31277
31699
  updateIsMouseDown(false);
31278
31700
  if (draggingDirection) {
31279
31701
  updateDraggingDirection(null);
@@ -31294,52 +31716,44 @@ function TableCellResizer({ editor }) {
31294
31716
  return () => {
31295
31717
  removeRootListener();
31296
31718
  };
31297
- }, [activeCell, draggingDirection, editor, resetState, setCurrentDimension]);
31719
+ }, [activeCell, draggingDirection, editor, resetState, initialDimension]);
31298
31720
  const isHeightChanging = (direction) => {
31299
31721
  if (direction === "bottom") {
31300
31722
  return true;
31301
31723
  }
31302
31724
  return false;
31303
31725
  };
31304
- const updateRowHeight = useCallback(
31305
- (heightChange) => {
31726
+ const updateRowHeightToValue = useCallback(
31727
+ (newHeight) => {
31306
31728
  if (!activeCell) {
31307
- throw new Error("TableCellResizer: Expected active cell.");
31729
+ return;
31308
31730
  }
31309
31731
  editor.update(
31310
31732
  () => {
31311
31733
  const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
31312
31734
  if (!$isTableCellNode(tableCellNode)) {
31313
- throw new Error("TableCellResizer: Table cell node not found.");
31735
+ return;
31314
31736
  }
31315
31737
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
31316
31738
  const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode) + tableCellNode.getRowSpan() - 1;
31317
31739
  const tableRows = tableNode.getChildren();
31318
31740
  if (tableRowIndex >= tableRows.length || tableRowIndex < 0) {
31319
- throw new Error("Expected table cell to be inside of table row.");
31741
+ return;
31320
31742
  }
31321
31743
  const tableRow = tableRows[tableRowIndex];
31322
31744
  if (!$isTableRowNode(tableRow)) {
31323
- throw new Error("Expected table row");
31324
- }
31325
- let height = tableRow.getHeight();
31326
- if (height === void 0) {
31327
- const rowCells = tableRow.getChildren();
31328
- height = Math.min(
31329
- ...rowCells.map(
31330
- (cell) => getCellNodeHeight(cell, editor) ?? Infinity
31331
- )
31332
- );
31745
+ return;
31333
31746
  }
31334
- const newHeight = Math.max(height + heightChange, MIN_ROW_HEIGHT);
31335
- tableRow.setHeight(newHeight);
31336
- setCurrentDimension(newHeight);
31747
+ tableRow.setHeight(Math.max(newHeight, MIN_ROW_HEIGHT));
31337
31748
  },
31338
31749
  { tag: "skip-scroll-into-view" }
31339
31750
  );
31340
31751
  },
31341
31752
  [activeCell, editor]
31342
31753
  );
31754
+ useEffect$1(() => {
31755
+ updateRowHeightToValueRef.current = updateRowHeightToValue;
31756
+ }, [updateRowHeightToValue]);
31343
31757
  const autoFitRowHeight = useCallback(() => {
31344
31758
  if (!activeCell)
31345
31759
  return;
@@ -31375,16 +31789,16 @@ function TableCellResizer({ editor }) {
31375
31789
  }
31376
31790
  return void 0;
31377
31791
  };
31378
- const updateColumnWidth = useCallback(
31379
- (widthChange) => {
31792
+ const updateColumnWidthToValue = useCallback(
31793
+ (newWidth) => {
31380
31794
  if (!activeCell) {
31381
- throw new Error("TableCellResizer: Expected active cell.");
31795
+ return;
31382
31796
  }
31383
31797
  editor.update(
31384
31798
  () => {
31385
31799
  const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
31386
31800
  if (!$isTableCellNode(tableCellNode)) {
31387
- throw new Error("TableCellResizer: Table cell node not found.");
31801
+ return;
31388
31802
  }
31389
31803
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
31390
31804
  const [tableMap] = $computeTableMapSkipCellCheck(
@@ -31392,64 +31806,65 @@ function TableCellResizer({ editor }) {
31392
31806
  null,
31393
31807
  null
31394
31808
  );
31395
- let startColumnIndex;
31396
- for (let row = 0; row < tableMap.length; row++) {
31397
- for (let column = 0; column < tableMap[row].length; column++) {
31398
- if (tableMap[row][column].cell === tableCellNode) {
31399
- startColumnIndex = column;
31400
- break;
31401
- }
31402
- }
31403
- if (startColumnIndex !== void 0)
31404
- break;
31405
- }
31406
- if (startColumnIndex === void 0) {
31407
- throw new Error("TableCellResizer: Table column not found.");
31809
+ const columnIndex = getCellColumnIndex(tableCellNode, tableMap);
31810
+ if (columnIndex === void 0) {
31811
+ return;
31408
31812
  }
31409
- const colSpan = tableCellNode.getColSpan() || 1;
31410
- const columnIndex = startColumnIndex + colSpan - 1;
31411
31813
  const colWidths = tableNode.getColWidths();
31412
- if (!colWidths || columnIndex >= colWidths.length) {
31814
+ if (!colWidths) {
31413
31815
  return;
31414
31816
  }
31415
- const width = colWidths[columnIndex];
31416
- if (width === void 0) {
31817
+ const tableElement = editor.getElementByKey(tableNode.getKey());
31818
+ if (!tableElement) {
31417
31819
  return;
31418
31820
  }
31419
- const newWidth = Math.max(width + widthChange, MIN_COLUMN_WIDTH);
31420
- const newColWidths = colWidths.map((w2, i2) => {
31421
- if (i2 === columnIndex) {
31422
- return newWidth;
31423
- }
31424
- return w2;
31425
- });
31426
- tableNode.setColWidths(newColWidths);
31427
- setCurrentDimension(newWidth);
31428
- const totalWidth = newColWidths.reduce((sum, w2) => sum + w2, 0);
31429
- const tableElement = editor.getElementByKey(tableNode.getKey());
31430
- if (tableElement) {
31431
- tableElement.style.setProperty("width", `${totalWidth}px`, "important");
31821
+ const currentCellRect = activeCell.elem.getBoundingClientRect();
31822
+ const constrainedNewWidth = Math.max(newWidth, MIN_COLUMN_WIDTH);
31823
+ const oldWidth = currentCellRect.width;
31824
+ const oldLexicalWidth = colWidths[columnIndex];
31825
+ const widthRatio = constrainedNewWidth / oldWidth;
31826
+ const newLexicalWidth = oldLexicalWidth * widthRatio;
31827
+ const newColWidths = [...colWidths];
31828
+ const lexicalWidthDelta = newLexicalWidth - oldLexicalWidth;
31829
+ newColWidths[columnIndex] = newLexicalWidth;
31830
+ let nextColumnIndex = columnIndex + 1;
31831
+ while (nextColumnIndex < colWidths.length) {
31832
+ const nextColWidth = colWidths[nextColumnIndex];
31833
+ if (nextColWidth !== void 0 && nextColWidth > 0) {
31834
+ const potentialNewWidth = nextColWidth - lexicalWidthDelta;
31835
+ let nextColumnCell = null;
31836
+ for (let row = 0; row < tableMap.length; row++) {
31837
+ const cellInfo = tableMap[row][nextColumnIndex];
31838
+ if (cellInfo && cellInfo.cell) {
31839
+ nextColumnCell = cellInfo.cell;
31840
+ break;
31841
+ }
31842
+ }
31843
+ if (nextColumnCell) {
31844
+ const nextCellElement = editor.getElementByKey(nextColumnCell.getKey());
31845
+ if (nextCellElement) {
31846
+ const nextCellRect = nextCellElement.getBoundingClientRect();
31847
+ const nextCellWidthRatio = potentialNewWidth / nextColWidth;
31848
+ const nextCellPotentialPixelWidth = nextCellRect.width * nextCellWidthRatio;
31849
+ if (nextCellPotentialPixelWidth >= MIN_COLUMN_WIDTH) {
31850
+ newColWidths[nextColumnIndex] = potentialNewWidth;
31851
+ break;
31852
+ }
31853
+ }
31854
+ }
31855
+ }
31856
+ nextColumnIndex++;
31432
31857
  }
31858
+ tableNode.setColWidths(newColWidths);
31433
31859
  },
31434
31860
  { tag: "skip-scroll-into-view" }
31435
31861
  );
31436
- setTimeout(() => {
31437
- editor.getEditorState().read(() => {
31438
- const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
31439
- if (!$isTableCellNode(tableCellNode))
31440
- return;
31441
- const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
31442
- const tableElement = editor.getElementByKey(tableNode.getKey());
31443
- const colWidths = tableNode.getColWidths();
31444
- if (tableElement && colWidths) {
31445
- const totalWidth = colWidths.reduce((sum, w2) => sum + w2, 0);
31446
- tableElement.style.width = `${totalWidth}px`;
31447
- }
31448
- });
31449
- }, 0);
31450
31862
  },
31451
31863
  [activeCell, editor]
31452
31864
  );
31865
+ useEffect$1(() => {
31866
+ updateColumnWidthToValueRef.current = updateColumnWidthToValue;
31867
+ }, [updateColumnWidthToValue]);
31453
31868
  const autoFitColumnWidth = useCallback(() => {
31454
31869
  if (!activeCell)
31455
31870
  return;
@@ -31480,60 +31895,25 @@ function TableCellResizer({ editor }) {
31480
31895
  const newColWidths = [...colWidths];
31481
31896
  newColWidths[columnIndex] = Math.max(maxContentWidth, MIN_COLUMN_WIDTH);
31482
31897
  tableNode.setColWidths(newColWidths);
31483
- const totalWidth = newColWidths.reduce((sum, w2) => sum + w2, 0);
31484
- const tableElement = editor.getElementByKey(tableNode.getKey());
31485
- if (tableElement) {
31486
- tableElement.style.setProperty("width", `${totalWidth}px`, "important");
31487
- }
31488
31898
  },
31489
31899
  { tag: "skip-scroll-into-view" }
31490
31900
  );
31491
- setTimeout(() => {
31492
- editor.getEditorState().read(() => {
31493
- const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
31494
- if (!$isTableCellNode(tableCellNode))
31495
- return;
31496
- const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
31497
- const tableElement = editor.getElementByKey(tableNode.getKey());
31498
- const colWidths = tableNode.getColWidths();
31499
- if (tableElement && colWidths) {
31500
- const totalWidth = colWidths.reduce((sum, w2) => sum + w2, 0);
31501
- tableElement.style.setProperty("width", `${totalWidth}px`, "important");
31502
- }
31503
- });
31504
- }, 0);
31505
31901
  }, [activeCell, editor]);
31506
31902
  const mouseUpHandler = useCallback(
31507
- (direction) => {
31903
+ (_direction) => {
31508
31904
  const handler = (event) => {
31509
31905
  event.preventDefault();
31510
31906
  event.stopPropagation();
31511
- if (!activeCell) {
31512
- throw new Error("TableCellResizer: Expected active cell.");
31513
- }
31514
- if (mouseStartPosRef.current) {
31515
- const { x: x2, y: y2 } = mouseStartPosRef.current;
31516
- if (activeCell === null) {
31517
- return;
31518
- }
31519
- const zoom = calculateZoomLevel(event.target);
31520
- if (isHeightChanging(direction)) {
31521
- const heightChange = (event.clientY - y2) / zoom;
31522
- updateRowHeight(heightChange);
31523
- } else {
31524
- const widthChange = (event.clientX - x2) / zoom;
31525
- updateColumnWidth(widthChange);
31526
- }
31527
- updateDraggingDirection(null);
31528
- updateMouseCurrentPos(null);
31529
- mouseStartPosRef.current = null;
31530
- setCurrentDimension(null);
31531
- document.removeEventListener("mouseup", handler);
31532
- }
31907
+ updateDraggingDirection(null);
31908
+ updateMouseCurrentPos(null);
31909
+ mouseStartPosRef.current = null;
31910
+ setCurrentDimension(null);
31911
+ setInitialDimension(null);
31912
+ document.removeEventListener("mouseup", handler);
31533
31913
  };
31534
31914
  return handler;
31535
31915
  },
31536
- [activeCell, updateColumnWidth, updateRowHeight]
31916
+ []
31537
31917
  );
31538
31918
  const toggleResize = useCallback(
31539
31919
  (direction) => (event) => {
@@ -31542,6 +31922,36 @@ function TableCellResizer({ editor }) {
31542
31922
  if (!activeCell) {
31543
31923
  throw new Error("TableCellResizer: Expected active cell.");
31544
31924
  }
31925
+ editor.read(() => {
31926
+ const tableCellNode = $getNearestNodeFromDOMNode(activeCell.elem);
31927
+ if (!$isTableCellNode(tableCellNode)) {
31928
+ return;
31929
+ }
31930
+ const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
31931
+ if (isHeightChanging(direction)) {
31932
+ const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode) + tableCellNode.getRowSpan() - 1;
31933
+ const tableRows = tableNode.getChildren();
31934
+ if (tableRowIndex >= 0 && tableRowIndex < tableRows.length) {
31935
+ const tableRow = tableRows[tableRowIndex];
31936
+ if ($isTableRowNode(tableRow)) {
31937
+ let height = tableRow.getHeight();
31938
+ if (height === void 0) {
31939
+ const rowCells = tableRow.getChildren();
31940
+ height = Math.min(
31941
+ ...rowCells.map(
31942
+ (cell) => getCellNodeHeight(cell, editor) ?? Infinity
31943
+ )
31944
+ );
31945
+ }
31946
+ setInitialDimension(height || MIN_ROW_HEIGHT);
31947
+ }
31948
+ }
31949
+ } else {
31950
+ const cellRect = activeCell.elem.getBoundingClientRect();
31951
+ const actualWidth = cellRect.width;
31952
+ setInitialDimension(actualWidth);
31953
+ }
31954
+ });
31545
31955
  mouseStartPosRef.current = {
31546
31956
  x: event.clientX,
31547
31957
  y: event.clientY
@@ -31550,7 +31960,7 @@ function TableCellResizer({ editor }) {
31550
31960
  updateDraggingDirection(direction);
31551
31961
  document.addEventListener("mouseup", mouseUpHandler(direction));
31552
31962
  },
31553
- [activeCell, mouseUpHandler]
31963
+ [activeCell, editor, mouseUpHandler]
31554
31964
  );
31555
31965
  const handleDoubleClick = useCallback(
31556
31966
  (direction) => (event) => {
@@ -31590,15 +32000,16 @@ function TableCellResizer({ editor }) {
31590
32000
  }
31591
32001
  };
31592
32002
  const tableRect = tableRectRef.current;
31593
- if (draggingDirection && mouseCurrentPos && tableRect) {
32003
+ if (draggingDirection && mouseCurrentPos && tableRect && currentDimension !== null) {
31594
32004
  if (isHeightChanging(draggingDirection)) {
31595
32005
  styles[draggingDirection].left = `${window.pageXOffset + tableRect.left}px`;
31596
32006
  styles[draggingDirection].top = `${window.pageYOffset + mouseCurrentPos.y / zoom}px`;
31597
32007
  styles[draggingDirection].height = "3px";
31598
32008
  styles[draggingDirection].width = `${tableRect.width}px`;
31599
32009
  } else {
32010
+ const lineLeft = window.pageXOffset + left + currentDimension;
31600
32011
  styles[draggingDirection].top = `${window.pageYOffset + tableRect.top}px`;
31601
- styles[draggingDirection].left = `${window.pageXOffset + mouseCurrentPos.x / zoom}px`;
32012
+ styles[draggingDirection].left = `${lineLeft}px`;
31602
32013
  styles[draggingDirection].width = "3px";
31603
32014
  styles[draggingDirection].height = `${tableRect.height}px`;
31604
32015
  }
@@ -31613,7 +32024,7 @@ function TableCellResizer({ editor }) {
31613
32024
  right: null,
31614
32025
  top: null
31615
32026
  };
31616
- }, [activeCell, draggingDirection, mouseCurrentPos]);
32027
+ }, [activeCell, draggingDirection, mouseCurrentPos, currentDimension]);
31617
32028
  const resizerStyles = getResizers();
31618
32029
  return /* @__PURE__ */ jsxs("div", { ref: resizerRef, children: [
31619
32030
  activeCell != null && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -31688,127 +32099,695 @@ function useDebounce(fn, ms, maxWait) {
31688
32099
  [ms, maxWait]
31689
32100
  );
31690
32101
  }
31691
- const BUTTON_WIDTH_PX = 20;
32102
+ const DOT_SIZE = 8;
32103
+ const DOT_HOVER_SIZE = 16;
32104
+ const SELECTOR_BUTTON_SIZE = 12;
31692
32105
  function TableHoverActionsContainer({
31693
32106
  anchorElem
31694
32107
  }) {
31695
32108
  const [editor] = useLexicalComposerContext();
31696
32109
  const isEditable = useLexicalEditable();
31697
- const [isShownRow, setShownRow] = useState$1(false);
31698
- const [isShownColumn, setShownColumn] = useState$1(false);
31699
32110
  const [shouldListenMouseMove, setShouldListenMouseMove] = useState$1(false);
31700
- const [position, setPosition] = useState$1({});
32111
+ const [dots, setDots] = useState$1([]);
32112
+ const [selectorButtons, setSelectorButtons] = useState$1([]);
32113
+ const [hoveredDot, setHoveredDot] = useState$1(null);
32114
+ const [hoveredSelector, setHoveredSelector] = useState$1(null);
32115
+ const [hoveredRowColumn, setHoveredRowColumn] = useState$1({ row: null, column: null });
32116
+ const [activeTableDOM, setActiveTableDOM] = useState$1(null);
32117
+ const [dragState, setDragState] = useState$1(null);
32118
+ const [dragPreviewLine, setDragPreviewLine] = useState$1(null);
32119
+ const [highlightedRow, setHighlightedRow] = useState$1(null);
32120
+ const [highlightedColumn, setHighlightedColumn] = useState$1(null);
32121
+ const [targetHighlightedRow, setTargetHighlightedRow] = useState$1(null);
32122
+ const [targetHighlightedColumn, setTargetHighlightedColumn] = useState$1(null);
31701
32123
  const tableSetRef = useRef(/* @__PURE__ */ new Set());
31702
- const tableCellDOMNodeRef = useRef(null);
32124
+ const currentTableRef = useRef(null);
32125
+ const currentTableKeyRef = useRef(null);
32126
+ const calculateDotPositions = useCallback((tableDOMElement) => {
32127
+ const tableRect = tableDOMElement.getBoundingClientRect();
32128
+ const { left: editorLeft, top: editorTop } = anchorElem.getBoundingClientRect();
32129
+ const rows = tableDOMElement.querySelectorAll("tr");
32130
+ const newDots = [];
32131
+ const newSelectors = [];
32132
+ rows.forEach((row, index2) => {
32133
+ const rowRect = row.getBoundingClientRect();
32134
+ const dotTop = rowRect.bottom - editorTop - DOT_SIZE / 2;
32135
+ const dotLeft = tableRect.left - editorLeft - 20;
32136
+ newDots.push({
32137
+ left: dotLeft,
32138
+ top: dotTop,
32139
+ type: "row",
32140
+ index: index2 + 1,
32141
+ // This dot will insert at position index+1 (after current row)
32142
+ isHovered: false
32143
+ });
32144
+ });
32145
+ const lastRow = rows[rows.length - 1];
32146
+ if (lastRow) {
32147
+ const lastRowRect = lastRow.getBoundingClientRect();
32148
+ newDots.push({
32149
+ left: tableRect.left - editorLeft - 20,
32150
+ top: lastRowRect.bottom - editorTop - DOT_SIZE / 2,
32151
+ type: "row",
32152
+ index: rows.length,
32153
+ isHovered: false
32154
+ });
32155
+ }
32156
+ if (rows.length > 0) {
32157
+ const firstRow = rows[0];
32158
+ const cells = firstRow.querySelectorAll("td, th");
32159
+ cells.forEach((cell, index2) => {
32160
+ const cellRect = cell.getBoundingClientRect();
32161
+ const dotLeft = cellRect.right - editorLeft - DOT_SIZE / 2;
32162
+ const dotTop = tableRect.top - editorTop - 12;
32163
+ newDots.push({
32164
+ left: dotLeft,
32165
+ top: dotTop,
32166
+ type: "column",
32167
+ index: index2 + 1,
32168
+ // This dot will insert at position index+1 (after current column)
32169
+ isHovered: false
32170
+ });
32171
+ });
32172
+ const lastCell = cells[cells.length - 1];
32173
+ if (lastCell) {
32174
+ const lastCellRect = lastCell.getBoundingClientRect();
32175
+ newDots.push({
32176
+ left: lastCellRect.right - editorLeft - DOT_SIZE / 2,
32177
+ top: tableRect.top - editorTop - 12,
32178
+ type: "column",
32179
+ index: cells.length,
32180
+ isHovered: false
32181
+ });
32182
+ }
32183
+ }
32184
+ rows.forEach((row, index2) => {
32185
+ const rowRect = row.getBoundingClientRect();
32186
+ const buttonTop = rowRect.top - editorTop + (rowRect.height - SELECTOR_BUTTON_SIZE) / 2;
32187
+ const buttonLeft = tableRect.left - editorLeft - SELECTOR_BUTTON_SIZE / 2;
32188
+ newSelectors.push({
32189
+ left: buttonLeft,
32190
+ top: buttonTop,
32191
+ type: "row",
32192
+ index: index2,
32193
+ // The actual row index
32194
+ isHovered: false
32195
+ });
32196
+ });
32197
+ if (rows.length > 0) {
32198
+ const firstRow = rows[0];
32199
+ const cells = firstRow.querySelectorAll("td, th");
32200
+ cells.forEach((cell, index2) => {
32201
+ const cellRect = cell.getBoundingClientRect();
32202
+ const buttonLeft = cellRect.left - editorLeft + (cellRect.width - SELECTOR_BUTTON_SIZE) / 2;
32203
+ const buttonTop = tableRect.top - editorTop - SELECTOR_BUTTON_SIZE / 2;
32204
+ newSelectors.push({
32205
+ left: buttonLeft,
32206
+ top: buttonTop,
32207
+ type: "column",
32208
+ index: index2,
32209
+ // The actual column index
32210
+ isHovered: false
32211
+ });
32212
+ });
32213
+ }
32214
+ setDots(newDots);
32215
+ setSelectorButtons(newSelectors);
32216
+ }, [anchorElem]);
31703
32217
  const debouncedOnMouseMove = useDebounce(
31704
32218
  (event) => {
31705
- window.lastMouseX = event.clientX;
31706
- window.lastMouseY = event.clientY;
31707
32219
  const { isOutside, tableDOMNode } = getMouseInfo(event);
31708
- if (isOutside) {
31709
- setShownRow(false);
31710
- setShownColumn(false);
32220
+ if (isOutside || !tableDOMNode) {
32221
+ const hasFocusInTable = editor.getEditorState().read(() => {
32222
+ const selection = editor.getEditorState()._selection;
32223
+ if (!selection)
32224
+ return false;
32225
+ const nodes = selection.getNodes();
32226
+ for (const node of nodes) {
32227
+ const tableCell = $findMatchingParent(node, (n) => $isTableCellNode(n));
32228
+ if (tableCell && $isTableCellNode(tableCell)) {
32229
+ return true;
32230
+ }
32231
+ }
32232
+ return false;
32233
+ });
32234
+ if (!hasFocusInTable) {
32235
+ setDots([]);
32236
+ setSelectorButtons([]);
32237
+ setHoveredDot(null);
32238
+ setHoveredRowColumn({ row: null, column: null });
32239
+ currentTableRef.current = null;
32240
+ currentTableKeyRef.current = null;
32241
+ }
31711
32242
  return;
31712
32243
  }
31713
- if (!tableDOMNode) {
31714
- return;
32244
+ if (tableDOMNode && currentTableRef.current) {
32245
+ const tableElement = currentTableRef.current;
32246
+ const rows = tableElement.querySelectorAll("tr");
32247
+ const target = event.target;
32248
+ const cellElement = target.closest("td, th");
32249
+ if (cellElement) {
32250
+ const rowElement = cellElement.closest("tr");
32251
+ const rowIndex = Array.from(rows).indexOf(rowElement);
32252
+ const row = rowElement;
32253
+ const cells = row.querySelectorAll("td, th");
32254
+ const colIndex = Array.from(cells).indexOf(cellElement);
32255
+ setHoveredRowColumn({ row: rowIndex, column: colIndex });
32256
+ }
31715
32257
  }
31716
- tableCellDOMNodeRef.current = tableDOMNode;
31717
- let tableDOMElement = null;
31718
- editor.getEditorState().read(
31719
- () => {
31720
- const maybeTableCell = $getNearestNodeFromDOMNode(tableDOMNode);
31721
- if ($isTableCellNode(maybeTableCell)) {
31722
- const table = $findMatchingParent(
31723
- maybeTableCell,
31724
- (node) => $isTableNode(node)
31725
- );
31726
- if (!$isTableNode(table)) {
31727
- return;
32258
+ },
32259
+ 50,
32260
+ 250
32261
+ );
32262
+ const handleDotClick = (type, index2) => {
32263
+ if (!currentTableKeyRef.current)
32264
+ return;
32265
+ editor.update(() => {
32266
+ const tableNode = editor.getEditorState().read(() => {
32267
+ const nodeKey = currentTableKeyRef.current;
32268
+ if (!nodeKey)
32269
+ return null;
32270
+ const node = editor.getEditorState()._nodeMap.get(nodeKey);
32271
+ return $isTableNode(node) ? node : null;
32272
+ });
32273
+ if (!tableNode)
32274
+ return;
32275
+ if (type === "row") {
32276
+ const rows = tableNode.getChildren();
32277
+ const targetRowIndex = index2 - 1;
32278
+ if (targetRowIndex >= 0 && targetRowIndex < rows.length) {
32279
+ const targetRow = rows[targetRowIndex];
32280
+ if (targetRow) {
32281
+ const cells = targetRow.getChildren();
32282
+ if (cells.length > 0) {
32283
+ cells[0].selectEnd();
32284
+ $insertTableRow__EXPERIMENTAL(true);
32285
+ const updatedRows = tableNode.getChildren();
32286
+ const newRowIndex = targetRowIndex + 1;
32287
+ if (newRowIndex < updatedRows.length) {
32288
+ const newRow = updatedRows[newRowIndex];
32289
+ const newCells = newRow.getChildren();
32290
+ newCells.forEach((cell) => {
32291
+ cell.setHeaderStyles(TableCellHeaderStates.NO_STATUS);
32292
+ if (cell.getChildrenSize() === 0) {
32293
+ const paragraph = $createParagraphNode();
32294
+ cell.append(paragraph);
32295
+ }
32296
+ });
32297
+ }
31728
32298
  }
31729
- tableDOMElement = getTableElement(
31730
- table,
31731
- editor.getElementByKey(table.getKey())
31732
- );
31733
32299
  }
31734
- },
31735
- { editor }
31736
- );
31737
- if (tableDOMElement) {
31738
- const {
31739
- width: tableElemWidth,
31740
- y: tableElemY,
31741
- left: tableElemLeft,
31742
- bottom: tableElemBottom,
31743
- height: tableElemHeight
31744
- } = tableDOMElement.getBoundingClientRect();
31745
- const { y: editorElemY, left: editorElemLeft } = anchorElem.getBoundingClientRect();
31746
- setShownRow(true);
31747
- setShownColumn(true);
31748
- let actualTableWidth = tableElemWidth;
31749
- const firstRow = tableDOMElement.querySelector("tr");
31750
- if (firstRow) {
31751
- const cells = firstRow.querySelectorAll("td, th");
32300
+ }
32301
+ } else {
32302
+ const rows = tableNode.getChildren();
32303
+ if (rows.length > 0) {
32304
+ const firstRow = rows[0];
32305
+ const cells = firstRow.getChildren();
32306
+ const targetCellIndex = index2 - 1;
32307
+ if (targetCellIndex >= 0 && targetCellIndex < cells.length) {
32308
+ const targetCell = cells[targetCellIndex];
32309
+ if (targetCell) {
32310
+ targetCell.selectEnd();
32311
+ $insertTableColumn__EXPERIMENTAL(true);
32312
+ const hasColumnHeaders = (cells[0].getHeaderStyles() & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN;
32313
+ if (hasColumnHeaders) {
32314
+ const updatedFirstRow = tableNode.getChildren()[0];
32315
+ const updatedCells = updatedFirstRow.getChildren();
32316
+ const newHeaderCell = updatedCells[index2];
32317
+ if (newHeaderCell && $isTableCellNode(newHeaderCell)) {
32318
+ newHeaderCell.setHeaderStyles(TableCellHeaderStates.COLUMN);
32319
+ const headerBackgroundColor = cells[0].getBackgroundColor();
32320
+ if (headerBackgroundColor) {
32321
+ newHeaderCell.setBackgroundColor(headerBackgroundColor);
32322
+ }
32323
+ if (newHeaderCell.getChildrenSize() === 0) {
32324
+ const paragraph = $createParagraphNode();
32325
+ const textNode = $createTextNode("​");
32326
+ paragraph.append(textNode);
32327
+ newHeaderCell.append(paragraph);
32328
+ } else {
32329
+ const firstChild = newHeaderCell.getFirstChild();
32330
+ if ($isParagraphNode(firstChild) && firstChild.getTextContentSize() === 0) {
32331
+ const textNode = $createTextNode("​");
32332
+ firstChild.append(textNode);
32333
+ }
32334
+ }
32335
+ }
32336
+ }
32337
+ }
32338
+ }
32339
+ }
32340
+ }
32341
+ });
32342
+ setTimeout(() => {
32343
+ if (currentTableRef.current) {
32344
+ calculateDotPositions(currentTableRef.current);
32345
+ }
32346
+ }, 100);
32347
+ };
32348
+ const handleSelectorClick = (type, index2) => {
32349
+ if (!currentTableKeyRef.current)
32350
+ return;
32351
+ console.log(`[HoverPlugin] Selector clicked - Type: ${type}, Index: ${index2}`);
32352
+ editor.update(() => {
32353
+ const { tableNode } = $getTableAndElementByKey(currentTableKeyRef.current);
32354
+ if (!tableNode || !$isTableNode(tableNode)) {
32355
+ console.log("[HoverPlugin] Table node not found");
32356
+ return;
32357
+ }
32358
+ console.log("[HoverPlugin] Table node found, creating selection");
32359
+ if (type === "row") {
32360
+ const rows = tableNode.getChildren();
32361
+ if (index2 >= 0 && index2 < rows.length) {
32362
+ const targetRow = rows[index2];
32363
+ const cells = targetRow.getChildren();
31752
32364
  if (cells.length > 0) {
31753
- let sumWidth = 0;
31754
- cells.forEach((cell) => {
31755
- sumWidth += cell.offsetWidth;
31756
- });
31757
- if (sumWidth > 0 && sumWidth < tableElemWidth) {
31758
- actualTableWidth = sumWidth;
32365
+ const firstCell = cells[0];
32366
+ const lastCell = cells[cells.length - 1];
32367
+ console.log(`[HoverPlugin] Selecting row ${index2}, cells: ${cells.length}`);
32368
+ firstCell.selectEnd();
32369
+ const selection = firstCell.select();
32370
+ if (selection) {
32371
+ selection.focus.set(lastCell.getKey(), lastCell.getChildrenSize(), "element");
32372
+ console.log("[HoverPlugin] Row selection created");
32373
+ setTimeout(() => {
32374
+ const firstCellDOM = editor.getElementByKey(firstCell.getKey());
32375
+ if (firstCellDOM) {
32376
+ const event = new MouseEvent("contextmenu", {
32377
+ bubbles: true,
32378
+ cancelable: true,
32379
+ view: window,
32380
+ button: 2,
32381
+ clientX: firstCellDOM.getBoundingClientRect().left + 10,
32382
+ clientY: firstCellDOM.getBoundingClientRect().top + 10
32383
+ });
32384
+ firstCellDOM.dispatchEvent(event);
32385
+ console.log("[HoverPlugin] Context menu triggered");
32386
+ }
32387
+ }, 50);
31759
32388
  }
31760
32389
  }
31761
32390
  }
31762
- const tableRelativeLeft = tableElemLeft - editorElemLeft;
31763
- const tableRelativeRight = tableRelativeLeft + actualTableWidth;
31764
- setPosition({
31765
- row: {
31766
- height: BUTTON_WIDTH_PX,
31767
- left: tableRelativeLeft,
31768
- top: tableElemBottom - editorElemY + 5,
31769
- width: actualTableWidth
31770
- },
31771
- column: {
31772
- height: tableElemHeight,
31773
- left: tableRelativeRight + 5,
31774
- top: tableElemY - editorElemY,
31775
- width: BUTTON_WIDTH_PX
32391
+ } else {
32392
+ const rows = tableNode.getChildren();
32393
+ if (rows.length > 0) {
32394
+ const firstRow = rows[0];
32395
+ const firstRowCells = firstRow.getChildren();
32396
+ if (index2 >= 0 && index2 < firstRowCells.length) {
32397
+ const firstCell = firstRowCells[index2];
32398
+ const lastRow = rows[rows.length - 1];
32399
+ const lastRowCells = lastRow.getChildren();
32400
+ const lastCell = lastRowCells[index2];
32401
+ console.log(`[HoverPlugin] Selecting column ${index2}, rows: ${rows.length}`);
32402
+ if (firstCell && lastCell) {
32403
+ firstCell.selectEnd();
32404
+ const selection = firstCell.select();
32405
+ if (selection) {
32406
+ selection.focus.set(lastCell.getKey(), lastCell.getChildrenSize(), "element");
32407
+ console.log("[HoverPlugin] Column selection created");
32408
+ setTimeout(() => {
32409
+ const firstCellDOM = editor.getElementByKey(firstCell.getKey());
32410
+ if (firstCellDOM) {
32411
+ const event = new MouseEvent("contextmenu", {
32412
+ bubbles: true,
32413
+ cancelable: true,
32414
+ view: window,
32415
+ button: 2,
32416
+ clientX: firstCellDOM.getBoundingClientRect().left + 10,
32417
+ clientY: firstCellDOM.getBoundingClientRect().top + 10
32418
+ });
32419
+ firstCellDOM.dispatchEvent(event);
32420
+ console.log("[HoverPlugin] Context menu triggered");
32421
+ }
32422
+ }, 50);
32423
+ }
32424
+ }
31776
32425
  }
32426
+ }
32427
+ }
32428
+ });
32429
+ };
32430
+ const handleDragStart = (e, type, index2) => {
32431
+ e.stopPropagation();
32432
+ setTimeout(() => {
32433
+ setDragState({ type, sourceIndex: index2, targetIndex: null });
32434
+ }, 0);
32435
+ setTimeout(() => {
32436
+ if (type === "row") {
32437
+ setHighlightedRow(index2);
32438
+ } else {
32439
+ setHighlightedColumn(index2);
32440
+ }
32441
+ }, 0);
32442
+ e.dataTransfer.effectAllowed = "move";
32443
+ e.dataTransfer.dropEffect = "move";
32444
+ e.dataTransfer.setData("application/x-table-dnd", JSON.stringify({ type, index: index2 }));
32445
+ if (currentTableRef.current) {
32446
+ const dragPreview = document.createElement("div");
32447
+ dragPreview.style.position = "absolute";
32448
+ dragPreview.style.top = "-1000px";
32449
+ dragPreview.style.padding = "8px 16px";
32450
+ dragPreview.style.backgroundColor = "#3b82f6";
32451
+ dragPreview.style.color = "white";
32452
+ dragPreview.style.borderRadius = "6px";
32453
+ dragPreview.style.fontSize = "14px";
32454
+ dragPreview.style.fontWeight = "600";
32455
+ dragPreview.style.boxShadow = "0 4px 12px rgba(0,0,0,0.3)";
32456
+ dragPreview.style.pointerEvents = "none";
32457
+ dragPreview.textContent = `${type === "row" ? "↕" : "↔"} Moving ${type} ${index2 + 1}`;
32458
+ document.body.appendChild(dragPreview);
32459
+ e.dataTransfer.setDragImage(dragPreview, dragPreview.offsetWidth / 2, dragPreview.offsetHeight / 2);
32460
+ setTimeout(() => {
32461
+ if (document.body.contains(dragPreview)) {
32462
+ document.body.removeChild(dragPreview);
32463
+ }
32464
+ }, 0);
32465
+ }
32466
+ };
32467
+ const handleDragOver = (e, type, targetIndex) => {
32468
+ e.preventDefault();
32469
+ e.dataTransfer.dropEffect = "move";
32470
+ if (!dragState || dragState.type !== type) {
32471
+ return;
32472
+ }
32473
+ if (dragState.targetIndex !== targetIndex) {
32474
+ setDragState((prev) => prev ? { ...prev, targetIndex } : null);
32475
+ }
32476
+ if (type === "row") {
32477
+ setTargetHighlightedRow(targetIndex);
32478
+ setTargetHighlightedColumn(null);
32479
+ } else {
32480
+ setTargetHighlightedColumn(targetIndex);
32481
+ setTargetHighlightedRow(null);
32482
+ }
32483
+ if (currentTableRef.current) {
32484
+ const tableRect = currentTableRef.current.getBoundingClientRect();
32485
+ const { left: editorLeft, top: editorTop } = anchorElem.getBoundingClientRect();
32486
+ if (type === "row") {
32487
+ const rows = currentTableRef.current.querySelectorAll("tr");
32488
+ if (targetIndex >= 0 && targetIndex < rows.length) {
32489
+ const targetRow = rows[targetIndex];
32490
+ const rowRect = targetRow.getBoundingClientRect();
32491
+ const sourceIndex = dragState.sourceIndex;
32492
+ if (sourceIndex < targetIndex) {
32493
+ setDragPreviewLine({
32494
+ top: rowRect.bottom - editorTop,
32495
+ left: tableRect.left - editorLeft,
32496
+ width: tableRect.width,
32497
+ height: 3,
32498
+ isHorizontal: true
32499
+ });
32500
+ } else {
32501
+ setDragPreviewLine({
32502
+ top: rowRect.top - editorTop,
32503
+ left: tableRect.left - editorLeft,
32504
+ width: tableRect.width,
32505
+ height: 3,
32506
+ isHorizontal: true
32507
+ });
32508
+ }
32509
+ }
32510
+ } else {
32511
+ const rows = currentTableRef.current.querySelectorAll("tr");
32512
+ if (rows.length > 0) {
32513
+ const firstRow = rows[0];
32514
+ const cells = firstRow.querySelectorAll("td, th");
32515
+ if (targetIndex >= 0 && targetIndex < cells.length) {
32516
+ const targetCell = cells[targetIndex];
32517
+ const cellRect = targetCell.getBoundingClientRect();
32518
+ const sourceIndex = dragState.sourceIndex;
32519
+ if (sourceIndex < targetIndex) {
32520
+ setDragPreviewLine({
32521
+ top: tableRect.top - editorTop,
32522
+ left: cellRect.right - editorLeft,
32523
+ width: 3,
32524
+ height: tableRect.height,
32525
+ isHorizontal: false
32526
+ });
32527
+ } else {
32528
+ setDragPreviewLine({
32529
+ top: tableRect.top - editorTop,
32530
+ left: cellRect.left - editorLeft,
32531
+ width: 3,
32532
+ height: tableRect.height,
32533
+ isHorizontal: false
32534
+ });
32535
+ }
32536
+ }
32537
+ }
32538
+ }
32539
+ }
32540
+ };
32541
+ const handleDrop = (e) => {
32542
+ e.preventDefault();
32543
+ if (!dragState) {
32544
+ setDragPreviewLine(null);
32545
+ setHighlightedRow(null);
32546
+ setHighlightedColumn(null);
32547
+ setTargetHighlightedRow(null);
32548
+ setTargetHighlightedColumn(null);
32549
+ return;
32550
+ }
32551
+ const targetIndex = dragState.targetIndex;
32552
+ if (targetIndex === null) {
32553
+ setDragState(null);
32554
+ setDragPreviewLine(null);
32555
+ setHighlightedRow(null);
32556
+ setHighlightedColumn(null);
32557
+ setTargetHighlightedRow(null);
32558
+ setTargetHighlightedColumn(null);
32559
+ return;
32560
+ }
32561
+ if (dragState.sourceIndex === targetIndex) {
32562
+ setDragState(null);
32563
+ setDragPreviewLine(null);
32564
+ setHighlightedRow(null);
32565
+ setHighlightedColumn(null);
32566
+ setTargetHighlightedRow(null);
32567
+ setTargetHighlightedColumn(null);
32568
+ return;
32569
+ }
32570
+ const { type, sourceIndex } = dragState;
32571
+ let actualColWidths = [];
32572
+ let tableActualWidth = 0;
32573
+ if (currentTableRef.current) {
32574
+ tableActualWidth = currentTableRef.current.getBoundingClientRect().width;
32575
+ const firstRow = currentTableRef.current.querySelector("tr");
32576
+ if (firstRow) {
32577
+ const cells = firstRow.querySelectorAll("td, th");
32578
+ actualColWidths = Array.from(cells).map((cell) => {
32579
+ return cell.getBoundingClientRect().width;
31777
32580
  });
31778
32581
  }
31779
- },
31780
- 50,
31781
- 250
31782
- );
32582
+ }
32583
+ console.log("[TABLE-DND] BEFORE DROP:");
32584
+ console.log(" - Table actual width:", tableActualWidth);
32585
+ console.log(" - Captured DOM column widths:", actualColWidths);
32586
+ console.log(" - Source index:", sourceIndex, "Target index:", targetIndex, "Type:", type);
32587
+ editor.update(() => {
32588
+ if (!currentTableKeyRef.current) {
32589
+ return;
32590
+ }
32591
+ try {
32592
+ const result = $getTableAndElementByKey(currentTableKeyRef.current);
32593
+ const tableNode = result.tableNode;
32594
+ if (!tableNode || !$isTableNode(tableNode)) {
32595
+ return;
32596
+ }
32597
+ const preservedColWidths = tableNode.getColWidths();
32598
+ console.log("[TABLE-DND] Lexical stored column widths:", preservedColWidths);
32599
+ if (type === "row") {
32600
+ const rows = tableNode.getChildren();
32601
+ if (sourceIndex >= 0 && sourceIndex < rows.length && targetIndex >= 0 && targetIndex < rows.length) {
32602
+ const sourceRow = rows[sourceIndex];
32603
+ sourceRow.remove();
32604
+ const updatedRows = tableNode.getChildren();
32605
+ let movedRow = null;
32606
+ if (sourceIndex < targetIndex) {
32607
+ const adjustedTargetIndex = targetIndex - 1;
32608
+ if (adjustedTargetIndex >= 0 && adjustedTargetIndex < updatedRows.length) {
32609
+ const adjustedTarget = updatedRows[adjustedTargetIndex];
32610
+ adjustedTarget.insertAfter(sourceRow);
32611
+ movedRow = adjustedTarget.getNextSibling();
32612
+ } else {
32613
+ tableNode.append(sourceRow);
32614
+ movedRow = tableNode.getLastChild();
32615
+ }
32616
+ } else {
32617
+ if (targetIndex < updatedRows.length) {
32618
+ const adjustedTarget = updatedRows[targetIndex];
32619
+ adjustedTarget.insertBefore(sourceRow);
32620
+ movedRow = adjustedTarget.getPreviousSibling();
32621
+ } else {
32622
+ tableNode.append(sourceRow);
32623
+ movedRow = tableNode.getLastChild();
32624
+ }
32625
+ }
32626
+ if (movedRow && movedRow.getChildrenSize() > 0) {
32627
+ const firstCell = movedRow.getFirstChild();
32628
+ if (firstCell && $isTableCellNode(firstCell)) {
32629
+ firstCell.select();
32630
+ }
32631
+ }
32632
+ }
32633
+ } else {
32634
+ const rows = tableNode.getChildren();
32635
+ rows.forEach((row) => {
32636
+ const cells = row.getChildren();
32637
+ if (sourceIndex >= 0 && sourceIndex < cells.length && targetIndex >= 0 && targetIndex < cells.length) {
32638
+ const sourceCell = cells[sourceIndex];
32639
+ sourceCell.remove();
32640
+ const updatedCells = row.getChildren();
32641
+ if (sourceIndex < targetIndex) {
32642
+ const adjustedTargetIndex = targetIndex - 1;
32643
+ if (adjustedTargetIndex >= 0 && adjustedTargetIndex < updatedCells.length) {
32644
+ const adjustedTarget = updatedCells[adjustedTargetIndex];
32645
+ adjustedTarget.insertAfter(sourceCell);
32646
+ } else {
32647
+ row.append(sourceCell);
32648
+ }
32649
+ } else {
32650
+ if (targetIndex < updatedCells.length) {
32651
+ const adjustedTarget = updatedCells[targetIndex];
32652
+ adjustedTarget.insertBefore(sourceCell);
32653
+ } else {
32654
+ row.append(sourceCell);
32655
+ }
32656
+ }
32657
+ }
32658
+ });
32659
+ }
32660
+ const widthsToRestore = actualColWidths.length > 0 ? actualColWidths : preservedColWidths;
32661
+ console.log("[TABLE-DND] Widths to restore:", widthsToRestore);
32662
+ if (widthsToRestore && widthsToRestore.length > 0) {
32663
+ tableNode.setColWidths(widthsToRestore);
32664
+ console.log("[TABLE-DND] Column widths restored");
32665
+ } else {
32666
+ console.log("[TABLE-DND] WARNING: No widths available to restore!");
32667
+ }
32668
+ } catch (error) {
32669
+ console.error(`[TABLE-DND] ERROR during swap:`, error);
32670
+ }
32671
+ });
32672
+ setTimeout(() => {
32673
+ if (currentTableRef.current) {
32674
+ const newTableWidth = currentTableRef.current.getBoundingClientRect().width;
32675
+ const firstRow = currentTableRef.current.querySelector("tr");
32676
+ let newColWidths = [];
32677
+ if (firstRow) {
32678
+ const cells = firstRow.querySelectorAll("td, th");
32679
+ newColWidths = Array.from(cells).map((cell) => {
32680
+ return cell.getBoundingClientRect().width;
32681
+ });
32682
+ }
32683
+ console.log("[TABLE-DND] AFTER DROP:");
32684
+ console.log(" - Table actual width:", newTableWidth);
32685
+ console.log(" - New DOM column widths:", newColWidths);
32686
+ console.log(" - Width changed:", tableActualWidth !== newTableWidth);
32687
+ }
32688
+ }, 100);
32689
+ setDragState(null);
32690
+ setDragPreviewLine(null);
32691
+ setHighlightedRow(null);
32692
+ setHighlightedColumn(null);
32693
+ setTargetHighlightedRow(null);
32694
+ setTargetHighlightedColumn(null);
32695
+ setTimeout(() => {
32696
+ if (currentTableRef.current) {
32697
+ calculateDotPositions(currentTableRef.current);
32698
+ }
32699
+ }, 50);
32700
+ };
32701
+ const handleDragEnd = (_e) => {
32702
+ setTimeout(() => {
32703
+ setDragState(null);
32704
+ setDragPreviewLine(null);
32705
+ setHighlightedRow(null);
32706
+ setHighlightedColumn(null);
32707
+ setTargetHighlightedRow(null);
32708
+ setTargetHighlightedColumn(null);
32709
+ }, 50);
32710
+ };
31783
32711
  const tableResizeObserver = useMemo(() => {
31784
32712
  return new ResizeObserver(() => {
31785
- const lastX = window.lastMouseX || 0;
31786
- const lastY = window.lastMouseY || 0;
31787
- const mouseEvent = new MouseEvent("mousemove", {
31788
- clientX: lastX,
31789
- clientY: lastY
31790
- });
31791
- const { isOutside } = getMouseInfo(mouseEvent);
31792
- if (isOutside) {
31793
- setShownRow(false);
31794
- setShownColumn(false);
32713
+ if (currentTableRef.current) {
32714
+ calculateDotPositions(currentTableRef.current);
31795
32715
  }
31796
32716
  });
31797
- }, []);
32717
+ }, [calculateDotPositions]);
31798
32718
  useEffect$1(() => {
31799
32719
  if (!shouldListenMouseMove) {
31800
32720
  return;
31801
32721
  }
31802
32722
  document.addEventListener("mousemove", debouncedOnMouseMove);
31803
32723
  return () => {
31804
- setShownRow(false);
31805
- setShownColumn(false);
32724
+ setDots([]);
32725
+ setSelectorButtons([]);
32726
+ setHoveredDot(null);
31806
32727
  debouncedOnMouseMove.cancel();
31807
32728
  document.removeEventListener("mousemove", debouncedOnMouseMove);
31808
32729
  };
31809
32730
  }, [shouldListenMouseMove, debouncedOnMouseMove]);
32731
+ useEffect$1(() => {
32732
+ if (!activeTableDOM)
32733
+ return;
32734
+ const handleScroll2 = () => {
32735
+ requestAnimationFrame(() => {
32736
+ calculateDotPositions(activeTableDOM);
32737
+ });
32738
+ };
32739
+ window.addEventListener("scroll", handleScroll2, { capture: true, passive: true });
32740
+ window.addEventListener("resize", handleScroll2);
32741
+ return () => {
32742
+ window.removeEventListener("scroll", handleScroll2, { capture: true });
32743
+ window.removeEventListener("resize", handleScroll2);
32744
+ };
32745
+ }, [activeTableDOM, calculateDotPositions]);
31810
32746
  useEffect$1(() => {
31811
32747
  return mergeRegister(
32748
+ editor.registerUpdateListener(({ editorState }) => {
32749
+ editorState.read(() => {
32750
+ const selection = editorState._selection;
32751
+ if (!selection) {
32752
+ setDots([]);
32753
+ setSelectorButtons([]);
32754
+ setHoveredDot(null);
32755
+ currentTableRef.current = null;
32756
+ currentTableKeyRef.current = null;
32757
+ return;
32758
+ }
32759
+ const nodes = selection.getNodes();
32760
+ let foundTable = false;
32761
+ for (const node of nodes) {
32762
+ const tableCell = $findMatchingParent(node, (n) => $isTableCellNode(n));
32763
+ if (tableCell && $isTableCellNode(tableCell)) {
32764
+ const table = $findMatchingParent(tableCell, (n) => $isTableNode(n));
32765
+ if (table && $isTableNode(table)) {
32766
+ const tableElement = getTableElement(
32767
+ table,
32768
+ editor.getElementByKey(table.getKey())
32769
+ );
32770
+ if (tableElement) {
32771
+ currentTableRef.current = tableElement;
32772
+ currentTableKeyRef.current = table.getKey();
32773
+ setActiveTableDOM(tableElement);
32774
+ calculateDotPositions(tableElement);
32775
+ foundTable = true;
32776
+ }
32777
+ return;
32778
+ }
32779
+ }
32780
+ }
32781
+ if (!foundTable) {
32782
+ setDots([]);
32783
+ setSelectorButtons([]);
32784
+ setHoveredDot(null);
32785
+ currentTableRef.current = null;
32786
+ currentTableKeyRef.current = null;
32787
+ setActiveTableDOM(null);
32788
+ }
32789
+ });
32790
+ }),
31812
32791
  editor.registerMutationListener(
31813
32792
  TableNode,
31814
32793
  (mutations) => {
@@ -31844,109 +32823,404 @@ function TableHoverActionsContainer({
31844
32823
  { skipInitialization: false }
31845
32824
  )
31846
32825
  );
31847
- }, [editor, tableResizeObserver]);
31848
- const insertAction = (insertRow) => {
31849
- editor.update(() => {
31850
- if (tableCellDOMNodeRef.current) {
31851
- const maybeTableNode = $getNearestNodeFromDOMNode(
31852
- tableCellDOMNodeRef.current
31853
- );
31854
- maybeTableNode == null ? void 0 : maybeTableNode.selectEnd();
31855
- if (insertRow) {
31856
- $insertTableRow__EXPERIMENTAL();
31857
- setShownRow(false);
31858
- } else {
31859
- $insertTableColumn__EXPERIMENTAL();
31860
- setShownColumn(false);
31861
- const tableCellNode = $getNearestNodeFromDOMNode(tableCellDOMNodeRef.current);
31862
- if ($isTableCellNode(tableCellNode)) {
31863
- const tableNode = $findMatchingParent(
31864
- tableCellNode,
31865
- (node) => $isTableNode(node)
31866
- );
31867
- if ($isTableNode(tableNode)) {
31868
- const rows = tableNode.getChildren();
31869
- if (rows.length > 0) {
31870
- const firstRow = rows[0];
31871
- const firstRowCells = firstRow.getChildren();
31872
- if (firstRowCells.length > 0) {
31873
- const firstCell = firstRowCells[0];
31874
- const hasColumnHeaders = (firstCell.getHeaderStyles() & TableCellHeaderStates.COLUMN) === TableCellHeaderStates.COLUMN;
31875
- if (hasColumnHeaders) {
31876
- const newHeaderCell = firstRowCells[firstRowCells.length - 1];
31877
- newHeaderCell.setHeaderStyles(TableCellHeaderStates.COLUMN);
31878
- const headerBackgroundColor = firstCell.getBackgroundColor();
31879
- if (headerBackgroundColor) {
31880
- newHeaderCell.setBackgroundColor(headerBackgroundColor);
31881
- }
31882
- }
32826
+ }, [editor, tableResizeObserver, calculateDotPositions]);
32827
+ if (!isEditable) {
32828
+ return null;
32829
+ }
32830
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
32831
+ dots.map((dot, idx) => {
32832
+ const isHovered = (hoveredDot == null ? void 0 : hoveredDot.type) === dot.type && (hoveredDot == null ? void 0 : hoveredDot.index) === dot.index;
32833
+ const size2 = isHovered ? DOT_HOVER_SIZE : DOT_SIZE;
32834
+ return /* @__PURE__ */ jsx(
32835
+ "div",
32836
+ {
32837
+ style: {
32838
+ position: "absolute",
32839
+ left: `${dot.left - 12}px`,
32840
+ // Center hover zone on dot position
32841
+ top: `${dot.top - 12}px`,
32842
+ width: `${DOT_HOVER_SIZE + 16}px`,
32843
+ // Fixed larger hover zone
32844
+ height: `${DOT_HOVER_SIZE + 16}px`,
32845
+ display: "flex",
32846
+ alignItems: "center",
32847
+ justifyContent: "center",
32848
+ zIndex: 1e3
32849
+ },
32850
+ onMouseEnter: () => setHoveredDot({ type: dot.type, index: dot.index }),
32851
+ onMouseLeave: () => setHoveredDot(null),
32852
+ children: /* @__PURE__ */ jsx(
32853
+ "button",
32854
+ {
32855
+ className: `table-insert-dot ${isHovered ? "hovered" : ""}`,
32856
+ style: {
32857
+ width: `${size2}px`,
32858
+ height: `${size2}px`,
32859
+ borderRadius: "50%",
32860
+ backgroundColor: isHovered ? "white" : "transparent",
32861
+ border: `2px solid ${isHovered ? "#4b5563" : "#9ca3af"}`,
32862
+ cursor: "pointer",
32863
+ display: "flex",
32864
+ alignItems: "center",
32865
+ justifyContent: "center",
32866
+ transition: "all 0.2s ease",
32867
+ padding: 0,
32868
+ position: "relative",
32869
+ transform: isHovered ? "scale(1)" : "scale(1)"
32870
+ // Keep centered while scaling
32871
+ },
32872
+ onClick: () => handleDotClick(dot.type, dot.index),
32873
+ "aria-label": `Insert ${dot.type} ${dot.type === "row" ? "here" : "here"}`,
32874
+ role: "button",
32875
+ tabIndex: 0,
32876
+ children: isHovered && /* @__PURE__ */ jsxs(
32877
+ "svg",
32878
+ {
32879
+ width: "10",
32880
+ height: "10",
32881
+ viewBox: "0 0 10 10",
32882
+ style: {
32883
+ position: "absolute",
32884
+ top: "50%",
32885
+ left: "50%",
32886
+ transform: "translate(-50%, -50%)"
32887
+ },
32888
+ children: [
32889
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "1", x2: "5", y2: "9", stroke: "#4b5563", strokeWidth: "1.5", strokeLinecap: "round" }),
32890
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "5", x2: "9", y2: "5", stroke: "#4b5563", strokeWidth: "1.5", strokeLinecap: "round" })
32891
+ ]
31883
32892
  }
31884
- }
32893
+ )
31885
32894
  }
32895
+ )
32896
+ },
32897
+ `${dot.type}-${dot.index}-${idx}`
32898
+ );
32899
+ }),
32900
+ selectorButtons.map((selector, idx) => {
32901
+ const isDirectHover = (hoveredSelector == null ? void 0 : hoveredSelector.type) === selector.type && (hoveredSelector == null ? void 0 : hoveredSelector.index) === selector.index;
32902
+ const isRowColumnHovered = selector.type === "row" && hoveredRowColumn.row === selector.index || selector.type === "column" && hoveredRowColumn.column === selector.index;
32903
+ const shouldShow = isDirectHover || isRowColumnHovered;
32904
+ const isDragging = (dragState == null ? void 0 : dragState.type) === selector.type && (dragState == null ? void 0 : dragState.sourceIndex) === selector.index;
32905
+ const isDropTarget = (dragState == null ? void 0 : dragState.type) === selector.type && (dragState == null ? void 0 : dragState.targetIndex) === selector.index;
32906
+ return /* @__PURE__ */ jsx(
32907
+ "div",
32908
+ {
32909
+ style: {
32910
+ position: "absolute",
32911
+ left: `${selector.left - (isDirectHover ? 4 : 0)}px`,
32912
+ // Expand left when hovered
32913
+ top: `${selector.top - (isDirectHover ? 4 : 0)}px`,
32914
+ // Expand top when hovered
32915
+ width: `${isDirectHover ? SELECTOR_BUTTON_SIZE + 8 : SELECTOR_BUTTON_SIZE}px`,
32916
+ // Expand to ~20px when hovered
32917
+ height: `${isDirectHover ? SELECTOR_BUTTON_SIZE + 8 : SELECTOR_BUTTON_SIZE}px`,
32918
+ zIndex: 1e3,
32919
+ opacity: isDragging ? 0.5 : 1
32920
+ },
32921
+ onMouseEnter: () => {
32922
+ setHoveredSelector({ type: selector.type, index: selector.index });
32923
+ if (selector.type === "row") {
32924
+ setHighlightedRow(selector.index);
32925
+ } else {
32926
+ setHighlightedColumn(selector.index);
32927
+ }
32928
+ },
32929
+ onMouseLeave: () => {
32930
+ setHoveredSelector(null);
32931
+ if (!dragState) {
32932
+ setHighlightedRow(null);
32933
+ setHighlightedColumn(null);
32934
+ }
32935
+ },
32936
+ children: /* @__PURE__ */ jsx(
32937
+ "button",
32938
+ {
32939
+ className: "table-selector-button",
32940
+ draggable: shouldShow,
32941
+ onDragStart: (e) => {
32942
+ if (!shouldShow) {
32943
+ e.preventDefault();
32944
+ return;
32945
+ }
32946
+ handleDragStart(e, selector.type, selector.index);
32947
+ },
32948
+ onDragEnd: handleDragEnd,
32949
+ style: {
32950
+ width: "100%",
32951
+ height: "100%",
32952
+ borderRadius: "3px",
32953
+ backgroundColor: isDropTarget ? "#22c55e" : isDirectHover ? "#3b82f6" : isRowColumnHovered ? "#6b7280" : "transparent",
32954
+ border: "none",
32955
+ cursor: isDragging ? "grabbing" : isDirectHover ? "grab" : "pointer",
32956
+ display: "flex",
32957
+ alignItems: "center",
32958
+ justifyContent: "center",
32959
+ transition: "all 0.15s ease",
32960
+ padding: 0,
32961
+ opacity: shouldShow ? isDirectHover ? 1 : 0.6 : 0,
32962
+ boxShadow: isDirectHover ? "0 2px 4px rgba(0,0,0,0.2)" : "none"
32963
+ },
32964
+ onClick: () => {
32965
+ if (!dragState) {
32966
+ handleSelectorClick(selector.type, selector.index);
32967
+ }
32968
+ },
32969
+ "aria-label": `Drag to move or click to select ${selector.type} ${selector.index + 1}`,
32970
+ role: "button",
32971
+ tabIndex: 0,
32972
+ children: isDirectHover && /* @__PURE__ */ jsxs(
32973
+ "svg",
32974
+ {
32975
+ width: "16",
32976
+ height: "16",
32977
+ viewBox: "0 0 16 16",
32978
+ fill: "none",
32979
+ xmlns: "http://www.w3.org/2000/svg",
32980
+ style: { pointerEvents: "none" },
32981
+ children: [
32982
+ /* @__PURE__ */ jsx("circle", { cx: "5.5", cy: "3.5", r: "1.2", fill: "white" }),
32983
+ /* @__PURE__ */ jsx("circle", { cx: "10.5", cy: "3.5", r: "1.2", fill: "white" }),
32984
+ /* @__PURE__ */ jsx("circle", { cx: "5.5", cy: "8", r: "1.2", fill: "white" }),
32985
+ /* @__PURE__ */ jsx("circle", { cx: "10.5", cy: "8", r: "1.2", fill: "white" }),
32986
+ /* @__PURE__ */ jsx("circle", { cx: "5.5", cy: "12.5", r: "1.2", fill: "white" }),
32987
+ /* @__PURE__ */ jsx("circle", { cx: "10.5", cy: "12.5", r: "1.2", fill: "white" })
32988
+ ]
32989
+ }
32990
+ )
32991
+ }
32992
+ )
32993
+ },
32994
+ `selector-${selector.type}-${selector.index}-${idx}`
32995
+ );
32996
+ }),
32997
+ dragState && currentTableRef.current && /* @__PURE__ */ jsx(
32998
+ "div",
32999
+ {
33000
+ style: {
33001
+ position: "absolute",
33002
+ left: `${currentTableRef.current.getBoundingClientRect().left - anchorElem.getBoundingClientRect().left}px`,
33003
+ top: `${currentTableRef.current.getBoundingClientRect().top - anchorElem.getBoundingClientRect().top}px`,
33004
+ width: `${currentTableRef.current.getBoundingClientRect().width}px`,
33005
+ height: `${currentTableRef.current.getBoundingClientRect().height}px`,
33006
+ zIndex: 1e3,
33007
+ pointerEvents: "auto"
33008
+ },
33009
+ onDragOver: (e) => {
33010
+ e.preventDefault();
33011
+ e.stopPropagation();
33012
+ if (!dragState) {
33013
+ return;
31886
33014
  }
31887
- }
31888
- }
31889
- });
31890
- if (!insertRow) {
31891
- requestAnimationFrame(() => {
31892
- const applyHeaderStyles = () => {
31893
- const rootElement = editor.getRootElement();
31894
- if (!rootElement)
31895
- return false;
31896
- const tables = rootElement.querySelectorAll("table");
31897
- tables.forEach((table) => {
31898
- const rows = table.querySelectorAll("tr");
31899
- if (rows.length > 0) {
33015
+ e.dataTransfer.dropEffect = "move";
33016
+ if (!currentTableRef.current)
33017
+ return;
33018
+ if (dragState.type === "row") {
33019
+ const rows = currentTableRef.current.querySelectorAll("tr");
33020
+ const mouseY = e.clientY;
33021
+ let targetRowIndex = -1;
33022
+ for (let i2 = 0; i2 < rows.length; i2++) {
33023
+ const row = rows[i2];
33024
+ const rect = row.getBoundingClientRect();
33025
+ if (mouseY >= rect.top && mouseY <= rect.bottom) {
33026
+ targetRowIndex = i2;
33027
+ break;
33028
+ } else if (mouseY < rect.top && i2 === 0) {
33029
+ targetRowIndex = 0;
33030
+ break;
33031
+ } else if (i2 === rows.length - 1 && mouseY > rect.bottom) {
33032
+ targetRowIndex = rows.length - 1;
33033
+ break;
33034
+ }
33035
+ }
33036
+ if (targetRowIndex === 0) {
31900
33037
  const firstRow = rows[0];
31901
- const cells = firstRow.querySelectorAll("th, td");
31902
- if (cells.length > 1) {
31903
- const firstHeaderCell = cells[0];
31904
- const headerColor = firstHeaderCell.getAttribute("data-header-color");
31905
- const textColor = firstHeaderCell.getAttribute("data-text-color");
31906
- if (headerColor && textColor) {
31907
- const lastCell = cells[cells.length - 1];
31908
- lastCell.setAttribute("data-header-color", headerColor);
31909
- lastCell.setAttribute("data-text-color", textColor);
31910
- lastCell.style.setProperty("background-color", headerColor, "important");
31911
- lastCell.style.setProperty("color", textColor, "important");
31912
- lastCell.style.setProperty("padding", "8px", "important");
31913
- lastCell.style.setProperty("border", "1px solid #ddd", "important");
31914
- lastCell.style.setProperty("font-weight", "bold", "important");
31915
- lastCell.style.setProperty("white-space", "nowrap", "important");
33038
+ const firstCell = firstRow == null ? void 0 : firstRow.querySelector("th");
33039
+ if (firstCell) {
33040
+ e.dataTransfer.dropEffect = "none";
33041
+ setDragPreviewLine(null);
33042
+ setTargetHighlightedRow(null);
33043
+ return;
33044
+ }
33045
+ }
33046
+ if (targetRowIndex !== -1 && targetRowIndex !== dragState.sourceIndex) {
33047
+ handleDragOver(e, "row", targetRowIndex);
33048
+ } else if (targetRowIndex === dragState.sourceIndex) {
33049
+ setDragPreviewLine(null);
33050
+ setTargetHighlightedRow(dragState.sourceIndex);
33051
+ }
33052
+ } else {
33053
+ const rows = currentTableRef.current.querySelectorAll("tr");
33054
+ if (rows.length > 0) {
33055
+ const cells = rows[0].querySelectorAll("td, th");
33056
+ const mouseX = e.clientX;
33057
+ let targetColIndex = -1;
33058
+ for (let i2 = 0; i2 < cells.length; i2++) {
33059
+ const cell = cells[i2];
33060
+ const rect = cell.getBoundingClientRect();
33061
+ if (mouseX >= rect.left && mouseX <= rect.right) {
33062
+ targetColIndex = i2;
33063
+ break;
33064
+ } else if (mouseX < rect.left && i2 === 0) {
33065
+ targetColIndex = 0;
33066
+ break;
33067
+ } else if (i2 === cells.length - 1 && mouseX > rect.right) {
33068
+ targetColIndex = cells.length - 1;
33069
+ break;
31916
33070
  }
31917
33071
  }
33072
+ if (targetColIndex !== -1 && targetColIndex !== dragState.sourceIndex) {
33073
+ handleDragOver(e, "column", targetColIndex);
33074
+ } else if (targetColIndex === dragState.sourceIndex) {
33075
+ setDragPreviewLine(null);
33076
+ setTargetHighlightedColumn(dragState.sourceIndex);
33077
+ }
31918
33078
  }
31919
- });
31920
- return true;
31921
- };
31922
- if (!applyHeaderStyles()) {
31923
- setTimeout(applyHeaderStyles, 100);
33079
+ }
33080
+ },
33081
+ onDrop: (e) => {
33082
+ e.preventDefault();
33083
+ e.stopPropagation();
33084
+ handleDrop(e);
31924
33085
  }
31925
- });
31926
- }
31927
- };
31928
- if (!isEditable) {
31929
- return null;
31930
- }
31931
- return /* @__PURE__ */ jsxs(Fragment, { children: [
31932
- isShownRow && position.row && /* @__PURE__ */ jsx(
31933
- "button",
31934
- {
31935
- className: "PlaygroundEditorTheme__tableAddRows ",
31936
- style: { ...position.row },
31937
- onClick: () => insertAction(true),
31938
- children: /* @__PURE__ */ jsx(PlusIcon, {})
31939
33086
  }
31940
33087
  ),
31941
- isShownColumn && position.column && /* @__PURE__ */ jsx(
31942
- "button",
33088
+ dragPreviewLine && /* @__PURE__ */ jsx(
33089
+ "div",
31943
33090
  {
31944
- className: "PlaygroundEditorTheme__tableAddColumns",
31945
- style: { ...position.column },
31946
- onClick: () => insertAction(false),
31947
- children: /* @__PURE__ */ jsx(PlusIcon, {})
33091
+ style: {
33092
+ position: "absolute",
33093
+ left: `${dragPreviewLine.left}px`,
33094
+ top: `${dragPreviewLine.top}px`,
33095
+ width: dragPreviewLine.isHorizontal ? `${dragPreviewLine.width}px` : `${dragPreviewLine.width}px`,
33096
+ height: dragPreviewLine.isHorizontal ? `${dragPreviewLine.height}px` : `${dragPreviewLine.height}px`,
33097
+ backgroundColor: "#22c55e",
33098
+ zIndex: 1001,
33099
+ pointerEvents: "none",
33100
+ boxShadow: "0 0 8px rgba(34, 197, 94, 0.6)"
33101
+ }
31948
33102
  }
31949
- )
33103
+ ),
33104
+ highlightedRow !== null && currentTableRef.current && (() => {
33105
+ const tableRect = currentTableRef.current.getBoundingClientRect();
33106
+ const { left: editorLeft, top: editorTop } = anchorElem.getBoundingClientRect();
33107
+ const rows = currentTableRef.current.querySelectorAll("tr");
33108
+ if (highlightedRow >= 0 && highlightedRow < rows.length) {
33109
+ const row = rows[highlightedRow];
33110
+ const rowRect = row.getBoundingClientRect();
33111
+ return /* @__PURE__ */ jsx(
33112
+ "div",
33113
+ {
33114
+ style: {
33115
+ position: "absolute",
33116
+ left: `${tableRect.left - editorLeft}px`,
33117
+ top: `${rowRect.top - editorTop}px`,
33118
+ width: `${tableRect.width}px`,
33119
+ height: `${rowRect.height}px`,
33120
+ backgroundColor: dragState ? "rgba(59, 130, 246, 0.2)" : "rgba(59, 130, 246, 0.15)",
33121
+ zIndex: 999,
33122
+ pointerEvents: "none",
33123
+ border: "2px solid rgba(59, 130, 246, 0.5)",
33124
+ boxSizing: "border-box",
33125
+ transition: "all 0.15s ease"
33126
+ }
33127
+ }
33128
+ );
33129
+ }
33130
+ return null;
33131
+ })(),
33132
+ targetHighlightedRow !== null && dragState && currentTableRef.current && (() => {
33133
+ const tableRect = currentTableRef.current.getBoundingClientRect();
33134
+ const { left: editorLeft, top: editorTop } = anchorElem.getBoundingClientRect();
33135
+ const rows = currentTableRef.current.querySelectorAll("tr");
33136
+ if (targetHighlightedRow >= 0 && targetHighlightedRow < rows.length) {
33137
+ const row = rows[targetHighlightedRow];
33138
+ const rowRect = row.getBoundingClientRect();
33139
+ return /* @__PURE__ */ jsx(
33140
+ "div",
33141
+ {
33142
+ style: {
33143
+ position: "absolute",
33144
+ left: `${tableRect.left - editorLeft}px`,
33145
+ top: `${rowRect.top - editorTop}px`,
33146
+ width: `${tableRect.width}px`,
33147
+ height: `${rowRect.height}px`,
33148
+ backgroundColor: "rgba(34, 197, 94, 0.25)",
33149
+ zIndex: 1e3,
33150
+ pointerEvents: "none",
33151
+ border: "2px solid rgba(34, 197, 94, 0.6)",
33152
+ boxSizing: "border-box",
33153
+ transition: "all 0.15s ease"
33154
+ }
33155
+ }
33156
+ );
33157
+ }
33158
+ return null;
33159
+ })(),
33160
+ highlightedColumn !== null && currentTableRef.current && (() => {
33161
+ const tableRect = currentTableRef.current.getBoundingClientRect();
33162
+ const { left: editorLeft, top: editorTop } = anchorElem.getBoundingClientRect();
33163
+ const rows = currentTableRef.current.querySelectorAll("tr");
33164
+ if (rows.length > 0) {
33165
+ const firstRow = rows[0];
33166
+ const cells = firstRow.querySelectorAll("td, th");
33167
+ if (highlightedColumn >= 0 && highlightedColumn < cells.length) {
33168
+ const cell = cells[highlightedColumn];
33169
+ const cellRect = cell.getBoundingClientRect();
33170
+ return /* @__PURE__ */ jsx(
33171
+ "div",
33172
+ {
33173
+ style: {
33174
+ position: "absolute",
33175
+ left: `${cellRect.left - editorLeft}px`,
33176
+ top: `${tableRect.top - editorTop}px`,
33177
+ width: `${cellRect.width}px`,
33178
+ height: `${tableRect.height}px`,
33179
+ backgroundColor: dragState ? "rgba(59, 130, 246, 0.2)" : "rgba(59, 130, 246, 0.15)",
33180
+ zIndex: 999,
33181
+ pointerEvents: "none",
33182
+ border: "2px solid rgba(59, 130, 246, 0.5)",
33183
+ boxSizing: "border-box",
33184
+ transition: "all 0.15s ease"
33185
+ }
33186
+ }
33187
+ );
33188
+ }
33189
+ }
33190
+ return null;
33191
+ })(),
33192
+ targetHighlightedColumn !== null && dragState && currentTableRef.current && (() => {
33193
+ const tableRect = currentTableRef.current.getBoundingClientRect();
33194
+ const { left: editorLeft, top: editorTop } = anchorElem.getBoundingClientRect();
33195
+ const rows = currentTableRef.current.querySelectorAll("tr");
33196
+ if (rows.length > 0) {
33197
+ const firstRow = rows[0];
33198
+ const cells = firstRow.querySelectorAll("td, th");
33199
+ if (targetHighlightedColumn >= 0 && targetHighlightedColumn < cells.length) {
33200
+ const cell = cells[targetHighlightedColumn];
33201
+ const cellRect = cell.getBoundingClientRect();
33202
+ return /* @__PURE__ */ jsx(
33203
+ "div",
33204
+ {
33205
+ style: {
33206
+ position: "absolute",
33207
+ left: `${cellRect.left - editorLeft}px`,
33208
+ top: `${tableRect.top - editorTop}px`,
33209
+ width: `${cellRect.width}px`,
33210
+ height: `${tableRect.height}px`,
33211
+ backgroundColor: "rgba(34, 197, 94, 0.25)",
33212
+ zIndex: 1e3,
33213
+ pointerEvents: "none",
33214
+ border: "2px solid rgba(34, 197, 94, 0.6)",
33215
+ boxSizing: "border-box",
33216
+ transition: "all 0.15s ease"
33217
+ }
33218
+ }
33219
+ );
33220
+ }
33221
+ }
33222
+ return null;
33223
+ })()
31950
33224
  ] });
31951
33225
  }
31952
33226
  function getMouseInfo(event) {
@@ -31955,11 +33229,7 @@ function getMouseInfo(event) {
31955
33229
  const tableDOMNode = target.closest(
31956
33230
  "td.PlaygroundEditorTheme__tableCell, th.PlaygroundEditorTheme__tableCell"
31957
33231
  );
31958
- const isOutside = !(tableDOMNode || target.closest(
31959
- "button.PlaygroundEditorTheme__tableAddRows"
31960
- ) || target.closest(
31961
- "button.PlaygroundEditorTheme__tableAddColumns"
31962
- ) || target.closest("div.TableCellResizer__resizer"));
33232
+ const isOutside = !(tableDOMNode || target.closest("button.table-insert-dot") || target.closest("button.table-selector-button") || target.closest("div.TableCellResizer__resizer"));
31963
33233
  return { isOutside, tableDOMNode };
31964
33234
  } else {
31965
33235
  return { isOutside: true, tableDOMNode: null };
@@ -32181,6 +33451,7 @@ const CellBackgroundPersistencePlugin = () => {
32181
33451
  const textColor = luminance > 0.5 ? "#000000" : "#FFFFFF";
32182
33452
  htmlCell.style.setProperty("background-color", bgColor, "important");
32183
33453
  htmlCell.style.setProperty("color", textColor, "important");
33454
+ htmlCell.style.setProperty("border-color", "#bbb", "important");
32184
33455
  const nestedElements = htmlCell.querySelectorAll("*");
32185
33456
  nestedElements.forEach((elem) => {
32186
33457
  if (elem instanceof HTMLElement) {
@@ -32189,8 +33460,7 @@ const CellBackgroundPersistencePlugin = () => {
32189
33460
  });
32190
33461
  const hasHeaderStyles = cellNode.getHeaderStyles();
32191
33462
  if (hasHeaderStyles) {
32192
- htmlCell.style.setProperty("font-weight", "bold", "important");
32193
- htmlCell.style.setProperty("padding", "8px", "important");
33463
+ htmlCell.style.setProperty("font-weight", "600", "important");
32194
33464
  }
32195
33465
  }
32196
33466
  }
@@ -32313,6 +33583,7 @@ const ConfigurableEditor = ({
32313
33583
  /* @__PURE__ */ jsx(LocalStoragePlugin$1, { namespace: initialConfig.namespace }),
32314
33584
  /* @__PURE__ */ jsx(ListPlugin, {}),
32315
33585
  /* @__PURE__ */ jsx(LinkPlugin, { hasLinkAttributes: false }),
33586
+ /* @__PURE__ */ jsx(LinkPreviewPlugin, {}),
32316
33587
  /* @__PURE__ */ jsx(DragDropPaste, {}),
32317
33588
  /* @__PURE__ */ jsx(RichTextPastePlugin, {}),
32318
33589
  /* @__PURE__ */ jsx(FilePlugin, {}),
@@ -32485,22 +33756,32 @@ const ConfigurableEditorWithAuth = ({
32485
33756
  };
32486
33757
  export {
32487
33758
  $isFileNode as $,
33759
+ AiJsonResponse as A,
33760
+ Button as B,
32488
33761
  ConfigurableEditorWithAuth as C,
32489
33762
  Download as D,
32490
33763
  ExternalLink as E,
32491
33764
  HtmlViewProvider as H,
32492
33765
  LocalStoragePlugin$1 as L,
33766
+ Sparkles as S,
32493
33767
  Trash2 as T,
32494
33768
  createLucideIcon as a,
32495
- $isImageNode as b,
33769
+ Dialog as b,
32496
33770
  commonjsGlobal as c,
32497
- EditorProvider as d,
32498
- useEditor as e,
32499
- ConfigurableEditor as f,
33771
+ DialogContent as d,
33772
+ DialogHeader as e,
33773
+ DialogTitle as f,
32500
33774
  getDefaultExportFromCjs as g,
32501
- editorConfig as h,
33775
+ DialogDescription as h,
32502
33776
  initialConfig as i,
33777
+ DialogFooter as j,
33778
+ $isImageNode as k,
33779
+ EditorProvider as l,
33780
+ useEditor as m,
33781
+ ConfigurableEditor as n,
33782
+ editorConfig as o,
33783
+ toast as t,
32503
33784
  useHtmlView as u,
32504
33785
  verifyApiKey as v
32505
33786
  };
32506
- //# sourceMappingURL=index-a8476eee.js.map
33787
+ //# sourceMappingURL=index-158a9bd4.js.map