ct-rich-text-editor 1.3.26 → 1.3.28

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.
@@ -24,15 +24,15 @@ import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
24
24
  import { TableNode, TableCellNode, TableRowNode, $createTableNodeWithDimensions, $isTableRowNode, $isTableCellNode, TableCellHeaderStates, $isTableNode, $isTableSelection, $getTableCellNodeFromLexicalNode, $getTableNodeFromLexicalNodeOrThrow, getTableElement, getTableObserverFromTableElement, $getTableRowIndexFromTableCellNode, $getNodeTriplet, $insertTableRow__EXPERIMENTAL, $getTableColumnIndexFromTableCellNode, $insertTableColumn__EXPERIMENTAL, $deleteTableRow__EXPERIMENTAL, $deleteTableColumn__EXPERIMENTAL, $unmergeCell, $computeTableMapSkipCellCheck, getDOMCellFromTarget, $getTableAndElementByKey } from "@lexical/table";
25
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, DecoratorNode, createEditor, $applyNodeReplacement, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $getNearestNodeFromDOMNode, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, KEY_DOWN_COMMAND, COMMAND_PRIORITY_CRITICAL, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_SPACE_COMMAND, $isLineBreakNode, $createRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, getDOMSelection, CLICK_COMMAND, PASTE_COMMAND, ParagraphNode, $createLineBreakNode, isDOMNode } from "lexical";
27
+ import { createCommand, DecoratorNode, createEditor, $applyNodeReplacement, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $getNearestNodeFromDOMNode, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, KEY_DOWN_COMMAND, COMMAND_PRIORITY_CRITICAL, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_SPACE_COMMAND, $isLineBreakNode, $createRangeSelection, $setSelection, COMMAND_PRIORITY_HIGH, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, getDOMSelection, CLICK_COMMAND, KEY_BACKSPACE_COMMAND, PASTE_COMMAND, ParagraphNode, $createLineBreakNode, 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";
31
31
  import { LinkNode, $isLinkNode, TOGGLE_LINK_COMMAND, $isAutoLinkNode, $createLinkNode } from "@lexical/link";
32
- import { ListNode, ListItemNode, $isListNode, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, $createListNode, $createListItemNode } from "@lexical/list";
32
+ import { ListNode, ListItemNode, $isListNode, INSERT_UNORDERED_LIST_COMMAND, REMOVE_LIST_COMMAND, INSERT_CHECK_LIST_COMMAND, INSERT_ORDERED_LIST_COMMAND, $isListItemNode, $createListNode, $createListItemNode } from "@lexical/list";
33
33
  import { HeadingNode, QuoteNode, $isHeadingNode, $createHeadingNode, $createQuoteNode, DRAG_DROP_PASTE } from "@lexical/rich-text";
34
34
  import { $isAtNodeEnd, $selectAll, $patchStyleText, $setBlocksType, $getSelectionStyleValueForProperty, $isParentElementRTL } from "@lexical/selection";
35
- import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode";
35
+ import { HorizontalRuleNode, INSERT_HORIZONTAL_RULE_COMMAND } from "@lexical/react/LexicalHorizontalRuleNode";
36
36
  import DescriptionIcon from "@mui/icons-material/Description";
37
37
  import FolderZipIcon from "@mui/icons-material/FolderZip";
38
38
  import InsertChartIcon from "@mui/icons-material/InsertChart";
@@ -1395,6 +1395,9 @@ const apiEndpoints = {
1395
1395
  },
1396
1396
  transcript: {
1397
1397
  voiceTranscript: "/api/transcript/get-assemblyai-token"
1398
+ },
1399
+ linkPreview: {
1400
+ getPreview: "/api/link-preview"
1398
1401
  }
1399
1402
  };
1400
1403
  const AiJsonResponse = async ({ content }) => {
@@ -1478,7 +1481,7 @@ const AiTextTransform = async ({ content, apiKey }) => {
1478
1481
  const AI_ACTION_COMMAND = createCommand(
1479
1482
  "AI_ACTION_COMMAND"
1480
1483
  );
1481
- const ImageView = React__default.lazy(() => import("./index-01a6d110.js"));
1484
+ const ImageView = React__default.lazy(() => import("./index-c26337f6.js"));
1482
1485
  function isGoogleDocCheckboxImg(img) {
1483
1486
  return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
1484
1487
  }
@@ -1490,14 +1493,14 @@ function $convertImageElement(domNode) {
1490
1493
  const { alt: altText, src, width, height } = img;
1491
1494
  const positionAttr = img.getAttribute("data-position");
1492
1495
  let position = "none";
1493
- if (positionAttr === "left" || positionAttr === "right" || positionAttr === "full") {
1496
+ if (positionAttr === "left" || positionAttr === "right" || positionAttr === "full" || positionAttr === "inline-left" || positionAttr === "inline-center" || positionAttr === "inline-right") {
1494
1497
  position = positionAttr;
1495
1498
  }
1496
1499
  const node = $createImageNode({ altText, height, src, width, position });
1497
1500
  return { node };
1498
1501
  }
1499
1502
  class ImageNode extends DecoratorNode {
1500
- constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, position, key) {
1503
+ constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, position, linkUrl, key) {
1501
1504
  super(key);
1502
1505
  __publicField(this, "__src");
1503
1506
  __publicField(this, "__altText");
@@ -1510,6 +1513,7 @@ class ImageNode extends DecoratorNode {
1510
1513
  __publicField(this, "__captionsEnabled");
1511
1514
  __publicField(this, "__originalPrompt");
1512
1515
  __publicField(this, "__position");
1516
+ __publicField(this, "__linkUrl");
1513
1517
  this.__src = src;
1514
1518
  this.__altText = altText;
1515
1519
  this.__maxWidth = maxWidth;
@@ -1522,6 +1526,7 @@ class ImageNode extends DecoratorNode {
1522
1526
  this.__captionsEnabled = captionsEnabled || captionsEnabled === void 0;
1523
1527
  this.__originalPrompt = originalPrompt || "";
1524
1528
  this.__position = position || "none";
1529
+ this.__linkUrl = linkUrl || "";
1525
1530
  }
1526
1531
  // to identify the image node and must unique too
1527
1532
  static getType() {
@@ -1540,12 +1545,13 @@ class ImageNode extends DecoratorNode {
1540
1545
  node.__captionsEnabled,
1541
1546
  node.__originalPrompt,
1542
1547
  node.__position,
1548
+ node.__linkUrl,
1543
1549
  node.__key
1544
1550
  );
1545
1551
  }
1546
1552
  // importing to json format
1547
1553
  static importJSON(serializedNode) {
1548
- const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt, position } = serializedNode;
1554
+ const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt, position, linkUrl } = serializedNode;
1549
1555
  const node = $createImageNode({
1550
1556
  altText,
1551
1557
  height,
@@ -1555,7 +1561,8 @@ class ImageNode extends DecoratorNode {
1555
1561
  width,
1556
1562
  originalPrompt: originalPrompt || "",
1557
1563
  // Default to empty string if undefined
1558
- position: position || "none"
1564
+ position: position || "none",
1565
+ linkUrl: linkUrl || ""
1559
1566
  });
1560
1567
  const nestedEditor = node.__caption;
1561
1568
  const editorState = nestedEditor.parseEditorState(caption.editorState);
@@ -1597,7 +1604,8 @@ class ImageNode extends DecoratorNode {
1597
1604
  version: 1,
1598
1605
  width: this.__width === "inherit" ? 0 : this.__width,
1599
1606
  originalPrompt: this.__originalPrompt,
1600
- position: this.__position
1607
+ position: this.__position,
1608
+ linkUrl: this.__linkUrl
1601
1609
  };
1602
1610
  }
1603
1611
  // setting width and height when resizing
@@ -1611,6 +1619,26 @@ class ImageNode extends DecoratorNode {
1611
1619
  const writable = this.getWritable();
1612
1620
  writable.__showCaption = showCaption;
1613
1621
  }
1622
+ // Helper to get position-based CSS styles
1623
+ getPositionStyles() {
1624
+ const cursorStyle = "cursor: pointer;";
1625
+ switch (this.__position) {
1626
+ case "left":
1627
+ return `float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block; ${cursorStyle}`;
1628
+ case "right":
1629
+ return `float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block; ${cursorStyle}`;
1630
+ case "full":
1631
+ return `display: block; width: 100%; margin: 1em 0; text-align: center; ${cursorStyle}`;
1632
+ case "inline-left":
1633
+ return `display: block; margin: 1em 0; text-align: left; ${cursorStyle}`;
1634
+ case "inline-center":
1635
+ return `display: block; margin: 1em 0; text-align: center; ${cursorStyle}`;
1636
+ case "inline-right":
1637
+ return `display: block; margin: 1em 0; text-align: right; ${cursorStyle}`;
1638
+ default:
1639
+ return "";
1640
+ }
1641
+ }
1614
1642
  // To create a dom representation of image view
1615
1643
  createDOM(config) {
1616
1644
  const span = document.createElement("span");
@@ -1619,24 +1647,18 @@ class ImageNode extends DecoratorNode {
1619
1647
  if (className !== void 0) {
1620
1648
  span.className = className;
1621
1649
  }
1622
- if (this.__position === "left") {
1623
- span.style.cssText = "float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1624
- } else if (this.__position === "right") {
1625
- span.style.cssText = "float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1626
- } else if (this.__position === "full") {
1627
- span.style.cssText = "display: block; width: 100%; margin: 1em 0;";
1650
+ const positionStyles = this.getPositionStyles();
1651
+ if (positionStyles) {
1652
+ span.style.cssText = positionStyles;
1628
1653
  }
1629
1654
  return span;
1630
1655
  }
1631
1656
  updateDOM(prevNode, dom) {
1632
1657
  if (prevNode.__position !== this.__position) {
1633
1658
  dom.style.cssText = "";
1634
- if (this.__position === "left") {
1635
- dom.style.cssText = "float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1636
- } else if (this.__position === "right") {
1637
- dom.style.cssText = "float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1638
- } else if (this.__position === "full") {
1639
- dom.style.cssText = "display: block; width: 100%; margin: 1em 0;";
1659
+ const positionStyles = this.getPositionStyles();
1660
+ if (positionStyles) {
1661
+ dom.style.cssText = positionStyles;
1640
1662
  }
1641
1663
  }
1642
1664
  return false;
@@ -1671,6 +1693,15 @@ class ImageNode extends DecoratorNode {
1671
1693
  const writable = this.getWritable();
1672
1694
  writable.__position = position;
1673
1695
  }
1696
+ // to get the link URL (if image was wrapped in a link)
1697
+ getLinkUrl() {
1698
+ return this.__linkUrl;
1699
+ }
1700
+ // to set the link URL
1701
+ setLinkUrl(linkUrl) {
1702
+ const writable = this.getWritable();
1703
+ writable.__linkUrl = linkUrl;
1704
+ }
1674
1705
  // to render the image tag
1675
1706
  decorate() {
1676
1707
  return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
@@ -1687,7 +1718,8 @@ class ImageNode extends DecoratorNode {
1687
1718
  captionsEnabled: this.__captionsEnabled,
1688
1719
  resizable: true,
1689
1720
  originalPrompt: this.__originalPrompt,
1690
- position: this.__position
1721
+ position: this.__position,
1722
+ linkUrl: this.__linkUrl
1691
1723
  }
1692
1724
  ) });
1693
1725
  }
@@ -1703,7 +1735,8 @@ function $createImageNode({
1703
1735
  caption,
1704
1736
  key,
1705
1737
  originalPrompt,
1706
- position
1738
+ position,
1739
+ linkUrl
1707
1740
  }) {
1708
1741
  return $applyNodeReplacement(
1709
1742
  new ImageNode(
@@ -1717,6 +1750,7 @@ function $createImageNode({
1717
1750
  captionsEnabled,
1718
1751
  originalPrompt,
1719
1752
  position,
1753
+ linkUrl,
1720
1754
  key
1721
1755
  )
1722
1756
  );
@@ -2111,20 +2145,20 @@ const createLruCache = (maxCacheSize) => {
2111
2145
  };
2112
2146
  }
2113
2147
  let cacheSize = 0;
2114
- let cache = /* @__PURE__ */ Object.create(null);
2148
+ let cache2 = /* @__PURE__ */ Object.create(null);
2115
2149
  let previousCache = /* @__PURE__ */ Object.create(null);
2116
2150
  const update = (key, value) => {
2117
- cache[key] = value;
2151
+ cache2[key] = value;
2118
2152
  cacheSize++;
2119
2153
  if (cacheSize > maxCacheSize) {
2120
2154
  cacheSize = 0;
2121
- previousCache = cache;
2122
- cache = /* @__PURE__ */ Object.create(null);
2155
+ previousCache = cache2;
2156
+ cache2 = /* @__PURE__ */ Object.create(null);
2123
2157
  }
2124
2158
  };
2125
2159
  return {
2126
2160
  get(key) {
2127
- let value = cache[key];
2161
+ let value = cache2[key];
2128
2162
  if (value !== void 0) {
2129
2163
  return value;
2130
2164
  }
@@ -2134,8 +2168,8 @@ const createLruCache = (maxCacheSize) => {
2134
2168
  }
2135
2169
  },
2136
2170
  set(key, value) {
2137
- if (key in cache) {
2138
- cache[key] = value;
2171
+ if (key in cache2) {
2172
+ cache2[key] = value;
2139
2173
  } else {
2140
2174
  update(key, value);
2141
2175
  }
@@ -7311,6 +7345,19 @@ const FileSearch = createLucideIcon("FileSearch", [
7311
7345
  ["circle", { cx: "5", cy: "14", r: "3", key: "ufru5t" }],
7312
7346
  ["path", { d: "m9 18-1.5-1.5", key: "1j6qii" }]
7313
7347
  ]);
7348
+ /**
7349
+ * @license lucide-react v0.344.0 - ISC
7350
+ *
7351
+ * This source code is licensed under the ISC license.
7352
+ * See the LICENSE file in the root directory of this source tree.
7353
+ */
7354
+ const FileText = createLucideIcon("FileText", [
7355
+ ["path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z", key: "1rqfz7" }],
7356
+ ["path", { d: "M14 2v4a2 2 0 0 0 2 2h4", key: "tnqrlb" }],
7357
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
7358
+ ["path", { d: "M16 13H8", key: "t4e002" }],
7359
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
7360
+ ]);
7314
7361
  /**
7315
7362
  * @license lucide-react v0.344.0 - ISC
7316
7363
  *
@@ -7322,6 +7369,18 @@ const Globe = createLucideIcon("Globe", [
7322
7369
  ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
7323
7370
  ["path", { d: "M2 12h20", key: "9i4pu4" }]
7324
7371
  ]);
7372
+ /**
7373
+ * @license lucide-react v0.344.0 - ISC
7374
+ *
7375
+ * This source code is licensed under the ISC license.
7376
+ * See the LICENSE file in the root directory of this source tree.
7377
+ */
7378
+ const Hash = createLucideIcon("Hash", [
7379
+ ["line", { x1: "4", x2: "20", y1: "9", y2: "9", key: "4lhtct" }],
7380
+ ["line", { x1: "4", x2: "20", y1: "15", y2: "15", key: "vyu0kd" }],
7381
+ ["line", { x1: "10", x2: "8", y1: "3", y2: "21", key: "1ggp8o" }],
7382
+ ["line", { x1: "16", x2: "14", y1: "3", y2: "21", key: "weycgp" }]
7383
+ ]);
7325
7384
  /**
7326
7385
  * @license lucide-react v0.344.0 - ISC
7327
7386
  *
@@ -12665,8 +12724,8 @@ function hasFixedPositionAncestor(element, stopNode) {
12665
12724
  }
12666
12725
  return getComputedStyle$1(parentNode).position === "fixed" || hasFixedPositionAncestor(parentNode, stopNode);
12667
12726
  }
12668
- function getClippingElementAncestors(element, cache) {
12669
- const cachedResult = cache.get(element);
12727
+ function getClippingElementAncestors(element, cache2) {
12728
+ const cachedResult = cache2.get(element);
12670
12729
  if (cachedResult) {
12671
12730
  return cachedResult;
12672
12731
  }
@@ -12688,7 +12747,7 @@ function getClippingElementAncestors(element, cache) {
12688
12747
  }
12689
12748
  currentNode = getParentNode(currentNode);
12690
12749
  }
12691
- cache.set(element, result);
12750
+ cache2.set(element, result);
12692
12751
  return result;
12693
12752
  }
12694
12753
  function getClippingRect(_ref) {
@@ -12986,14 +13045,14 @@ const hide$1 = hide$2;
12986
13045
  const arrow$2 = arrow$3;
12987
13046
  const limitShift$1 = limitShift$2;
12988
13047
  const computePosition = (reference, floating, options) => {
12989
- const cache = /* @__PURE__ */ new Map();
13048
+ const cache2 = /* @__PURE__ */ new Map();
12990
13049
  const mergedOptions = {
12991
13050
  platform,
12992
13051
  ...options
12993
13052
  };
12994
13053
  const platformWithCache = {
12995
13054
  ...mergedOptions.platform,
12996
- _c: cache
13055
+ _c: cache2
12997
13056
  };
12998
13057
  return computePosition$1(reference, floating, {
12999
13058
  ...mergedOptions,
@@ -15370,7 +15429,7 @@ const EmbedComponent = ({ url, displayType, alignment, nodeKey }) => {
15370
15429
  }
15371
15430
  );
15372
15431
  };
15373
- const FileComponent = React$1.lazy(() => import("./index-9b519a99.js"));
15432
+ const FileComponent = React$1.lazy(() => import("./index-03cae849.js"));
15374
15433
  function convertFileElement(domNode) {
15375
15434
  if (domNode instanceof HTMLDivElement) {
15376
15435
  const dataUrl = domNode.getAttribute("data-lexical-file-src");
@@ -19160,6 +19219,7 @@ function AIChatDialog({
19160
19219
  selectedTextForInline
19161
19220
  }) {
19162
19221
  const [inputValue, setInputValue] = useState$1("");
19222
+ const [selectedText, setSelectedText] = useState$1("");
19163
19223
  const [isLoading, setIsLoading] = useState$1(false);
19164
19224
  const [errorMessage, setErrorMessage] = useState$1(null);
19165
19225
  const [provider, setProvider] = useState$1("chatgpt");
@@ -19168,7 +19228,11 @@ function AIChatDialog({
19168
19228
  const [purchasedCredits, setPurchasedCredits] = useState$1(0);
19169
19229
  useEffect$1(() => {
19170
19230
  if (open && initialText) {
19171
- setInputValue(initialText);
19231
+ setSelectedText(initialText);
19232
+ setInputValue("");
19233
+ } else if (!open) {
19234
+ setSelectedText("");
19235
+ setInputValue("");
19172
19236
  }
19173
19237
  }, [open, initialText]);
19174
19238
  const {
@@ -19243,8 +19307,26 @@ function AIChatDialog({
19243
19307
  setIsLoading(true);
19244
19308
  setErrorMessage(null);
19245
19309
  const isImageRequest = isImageGenerationRequest(inputValue);
19310
+ let finalPrompt;
19311
+ const hasSelectedText = selectedText && selectedText.trim() !== "";
19312
+ if (isImageRequest) {
19313
+ if (hasSelectedText) {
19314
+ finalPrompt = `${inputValue}: ${selectedText}`;
19315
+ } else {
19316
+ finalPrompt = inputValue;
19317
+ }
19318
+ } else if (hasSelectedText) {
19319
+ finalPrompt = `${inputValue}
19320
+
19321
+ IMPORTANT: Return ONLY the modified/transformed text. Do NOT include any labels, prefixes, explanations, or formatting like "Simplified:", "Result:", "Here is", etc. Just return the pure result text.
19322
+
19323
+ Text to transform:
19324
+ "${selectedText}"`;
19325
+ } else {
19326
+ finalPrompt = inputValue;
19327
+ }
19246
19328
  try {
19247
- const response = await AiEditorAction({ content: inputValue, provider, apiKey });
19329
+ const response = await AiEditorAction({ content: finalPrompt, provider, apiKey });
19248
19330
  const htmlString = response.data;
19249
19331
  const parser = new DOMParser();
19250
19332
  const dom = parser.parseFromString(htmlString.trim(), "text/html");
@@ -19281,6 +19363,7 @@ function AIChatDialog({
19281
19363
  const handleClose = () => {
19282
19364
  if (!isLoading) {
19283
19365
  setInputValue("");
19366
+ setSelectedText("");
19284
19367
  setErrorMessage(null);
19285
19368
  onOpenChange(false);
19286
19369
  }
@@ -19345,9 +19428,26 @@ function AIChatDialog({
19345
19428
  ] })
19346
19429
  ] }) }),
19347
19430
  /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-4 ", children: [
19431
+ selectedText && selectedText.trim() !== "" && /* @__PURE__ */ jsxs("div", { className: "cteditor-space-y-2", children: [
19432
+ /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-justify-between", children: [
19433
+ /* @__PURE__ */ jsx(Label$2, { className: "cteditor-text-sm cteditor-font-medium cteditor-text-muted-foreground", children: "Selected Text" }),
19434
+ /* @__PURE__ */ jsx(
19435
+ "button",
19436
+ {
19437
+ type: "button",
19438
+ onClick: () => setSelectedText(""),
19439
+ className: "cteditor-text-xs cteditor-text-muted-foreground hover:cteditor-text-foreground cteditor-transition-colors",
19440
+ title: "Clear selected text",
19441
+ children: /* @__PURE__ */ jsx(X$1, { size: 14 })
19442
+ }
19443
+ )
19444
+ ] }),
19445
+ /* @__PURE__ */ jsx("div", { className: "cteditor-p-3 cteditor-rounded-md cteditor-bg-accent/50 cteditor-border cteditor-border-foreground/10 cteditor-max-h-24 cteditor-overflow-y-auto", children: /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-text-foreground/80 cteditor-whitespace-pre-wrap cteditor-break-words", children: selectedText.length > 300 ? selectedText.substring(0, 300) + "..." : selectedText }) }),
19446
+ /* @__PURE__ */ jsx("p", { className: "cteditor-text-xs cteditor-text-muted-foreground", children: "Your prompt will be applied to this selected text" })
19447
+ ] }),
19348
19448
  /* @__PURE__ */ jsxs("div", { children: [
19349
19449
  /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-justify-between cteditor-gap-1 cteditor-min-h-8 cteditor-items-center", children: [
19350
- /* @__PURE__ */ jsx(Label$2, { htmlFor: "ai-prompt", className: "cteditor-text-sm cteditor-font-medium cteditor-mb-0 cteditor-block", children: "Your Question" }),
19450
+ /* @__PURE__ */ jsx(Label$2, { htmlFor: "ai-prompt", className: "cteditor-text-sm cteditor-font-medium cteditor-mb-0 cteditor-block", children: selectedText && selectedText.trim() !== "" ? "Your Instruction" : "Your Question" }),
19351
19451
  !isRecording && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
19352
19452
  "button",
19353
19453
  {
@@ -19368,7 +19468,7 @@ function AIChatDialog({
19368
19468
  {
19369
19469
  ref: textareaRef,
19370
19470
  id: "ai-prompt",
19371
- placeholder: isVoiceLoading ? "Initializing microphone..." : isRecording ? isPaused ? "Paused..." : "Listening..." : "e.g., Improve this text, translate to Spanish, or explain this concept",
19471
+ placeholder: isVoiceLoading ? "Initializing microphone..." : isRecording ? isPaused ? "Paused..." : "Listening..." : selectedText && selectedText.trim() !== "" ? "e.g., Improve this, translate to Spanish, summarize, fix grammar..." : "e.g., Write a paragraph about..., Generate an image of...",
19372
19472
  value: inputValue,
19373
19473
  onChange: (e) => setInputValue(e.target.value),
19374
19474
  disabled: isLoading || isRecording || isVoiceLoading,
@@ -19423,7 +19523,7 @@ function AIChatDialog({
19423
19523
  ] }),
19424
19524
  !isRecording && !voiceError && !isVoiceLoading && /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-text-xs cteditor-text-muted-foreground", children: [
19425
19525
  /* @__PURE__ */ jsx("svg", { className: "cteditor-w-4 cteditor-h-4 cteditor-opacity-60", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
19426
- /* @__PURE__ */ jsx("span", { children: "Type your question or click the microphone icon to use voice input" })
19526
+ /* @__PURE__ */ jsx("span", { children: selectedText && selectedText.trim() !== "" ? "Enter what you want to do with the selected text, or use voice input" : "Type your question or click the microphone icon to use voice input" })
19427
19527
  ] })
19428
19528
  ] }),
19429
19529
  isVoiceLoading && /* @__PURE__ */ jsx("div", { className: "cteditor-p-3 cteditor-rounded-lg cteditor-bg-gray-100 dark:cteditor-bg-gray-900/50 cteditor-border cteditor-border-gray-300 dark:cteditor-border-gray-700", children: /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-2", children: [
@@ -20486,10 +20586,10 @@ const PDF_CONFIG = {
20486
20586
  };
20487
20587
  const loadHtml2Pdf = async () => {
20488
20588
  try {
20489
- const mod = await import("./html2pdf.bundle.min-1f376935.js").then((n) => n.h);
20589
+ const mod = await import("./html2pdf.bundle.min-d2f5d9cb.js").then((n) => n.h);
20490
20590
  return (mod == null ? void 0 : mod.default) || mod;
20491
20591
  } catch {
20492
- const mod2 = await import("./html2pdf.bundle-41a72ab2.js").then((n) => n.h);
20592
+ const mod2 = await import("./html2pdf.bundle-0e71462c.js").then((n) => n.h);
20493
20593
  return (mod2 == null ? void 0 : mod2.default) || mod2;
20494
20594
  }
20495
20595
  };
@@ -27805,7 +27905,7 @@ const STATIC_SUGGESTIONS = [
27805
27905
  "programming"
27806
27906
  ];
27807
27907
  const CACHE_MAX_AGE = 5 * 60 * 1e3;
27808
- const MAX_CACHE_SIZE = 200;
27908
+ const MAX_CACHE_SIZE$1 = 200;
27809
27909
  const REQUEST_TIMEOUT = 3e4;
27810
27910
  const MENU_CONFIG = { width: 320, height: 200, padding: 8 };
27811
27911
  const TOOLTIP_CONFIG = {
@@ -27977,7 +28077,7 @@ class GrammarAIService {
27977
28077
  errors,
27978
28078
  checkedAt: Date.now()
27979
28079
  });
27980
- if (this.sentenceCache.size > MAX_CACHE_SIZE) {
28080
+ if (this.sentenceCache.size > MAX_CACHE_SIZE$1) {
27981
28081
  const oldestKey = this.sentenceCache.keys().next().value;
27982
28082
  if (oldestKey)
27983
28083
  this.sentenceCache.delete(oldestKey);
@@ -31361,7 +31461,51 @@ function LinkPlugin({
31361
31461
  }
31362
31462
  );
31363
31463
  }
31364
- function LinkPreviewPlugin() {
31464
+ const cache = /* @__PURE__ */ new Map();
31465
+ const CACHE_TTL = 30 * 60 * 1e3;
31466
+ const MAX_CACHE_SIZE = 100;
31467
+ function getCached(url) {
31468
+ const entry = cache.get(url);
31469
+ if (!entry)
31470
+ return null;
31471
+ if (Date.now() - entry.timestamp > CACHE_TTL) {
31472
+ cache.delete(url);
31473
+ return null;
31474
+ }
31475
+ return entry.data;
31476
+ }
31477
+ function setCache(url, data) {
31478
+ if (cache.size >= MAX_CACHE_SIZE) {
31479
+ const oldestKey = cache.keys().next().value;
31480
+ if (oldestKey)
31481
+ cache.delete(oldestKey);
31482
+ }
31483
+ cache.set(url, { data, timestamp: Date.now() });
31484
+ }
31485
+ async function fetchLinkPreview({
31486
+ url,
31487
+ apiKey
31488
+ }) {
31489
+ const cached = getCached(url);
31490
+ if (cached)
31491
+ return cached;
31492
+ try {
31493
+ const response = await backendAPI.post(
31494
+ apiEndpoints.linkPreview.getPreview,
31495
+ { url },
31496
+ apiKey ? { headers: { "X-API-Key": apiKey } } : void 0
31497
+ );
31498
+ if (response.data.success && response.data.data) {
31499
+ setCache(url, response.data.data);
31500
+ return response.data.data;
31501
+ }
31502
+ return null;
31503
+ } catch (error) {
31504
+ console.error("Error fetching link preview:", error);
31505
+ return null;
31506
+ }
31507
+ }
31508
+ function LinkPreviewPlugin({ apiKey }) {
31365
31509
  const [editor] = useLexicalComposerContext();
31366
31510
  const [hoveredLink, setHoveredLink] = useState$1(null);
31367
31511
  useEffect$1(() => {
@@ -31385,20 +31529,14 @@ function LinkPreviewPlugin() {
31385
31529
  if (linkElement && editorElement.contains(linkElement)) {
31386
31530
  const href = linkElement.getAttribute("href");
31387
31531
  if (href && href !== "https://" && href !== "http://" && href !== "#") {
31388
- if (showTimeout) {
31532
+ if (showTimeout)
31389
31533
  clearTimeout(showTimeout);
31390
- }
31391
31534
  if (hideTimeout) {
31392
31535
  clearTimeout(hideTimeout);
31393
31536
  hideTimeout = null;
31394
31537
  }
31395
31538
  showTimeout = window.setTimeout(() => {
31396
- const rect = linkElement.getBoundingClientRect();
31397
- setHoveredLink({
31398
- url: href,
31399
- text: linkElement.textContent || "",
31400
- rect
31401
- });
31539
+ setHoveredLink({ url: href, rect: linkElement.getBoundingClientRect() });
31402
31540
  }, 500);
31403
31541
  }
31404
31542
  }
@@ -31408,12 +31546,10 @@ function LinkPreviewPlugin() {
31408
31546
  const relatedTarget = event.relatedTarget;
31409
31547
  if (target.closest(".link-preview-card")) {
31410
31548
  isOverPreview = false;
31411
- const movingToLink = relatedTarget == null ? void 0 : relatedTarget.closest("a");
31412
- if (!movingToLink) {
31549
+ if (!(relatedTarget == null ? void 0 : relatedTarget.closest("a"))) {
31413
31550
  hideTimeout = window.setTimeout(() => {
31414
- if (!isOverPreview) {
31551
+ if (!isOverPreview)
31415
31552
  setHoveredLink(null);
31416
- }
31417
31553
  }, 300);
31418
31554
  }
31419
31555
  return;
@@ -31424,19 +31560,16 @@ function LinkPreviewPlugin() {
31424
31560
  clearTimeout(showTimeout);
31425
31561
  showTimeout = null;
31426
31562
  }
31427
- const movingToPreview = relatedTarget == null ? void 0 : relatedTarget.closest(".link-preview-card");
31428
- if (!movingToPreview) {
31563
+ if (!(relatedTarget == null ? void 0 : relatedTarget.closest(".link-preview-card"))) {
31429
31564
  hideTimeout = window.setTimeout(() => {
31430
- if (!isOverPreview) {
31565
+ if (!isOverPreview)
31431
31566
  setHoveredLink(null);
31432
- }
31433
31567
  }, 300);
31434
31568
  }
31435
31569
  }
31436
31570
  };
31437
31571
  const handlePreviewMouseOver = (event) => {
31438
- const target = event.target;
31439
- if (target.closest(".link-preview-card")) {
31572
+ if (event.target.closest(".link-preview-card")) {
31440
31573
  isOverPreview = true;
31441
31574
  if (hideTimeout) {
31442
31575
  clearTimeout(hideTimeout);
@@ -31449,12 +31582,10 @@ function LinkPreviewPlugin() {
31449
31582
  const relatedTarget = event.relatedTarget;
31450
31583
  if (target.closest(".link-preview-card")) {
31451
31584
  isOverPreview = false;
31452
- const movingToLink = relatedTarget == null ? void 0 : relatedTarget.closest("a");
31453
- if (!movingToLink || !editorElement.contains(movingToLink)) {
31585
+ if (!(relatedTarget == null ? void 0 : relatedTarget.closest("a")) || !editorElement.contains(relatedTarget)) {
31454
31586
  hideTimeout = window.setTimeout(() => {
31455
- if (!isOverPreview) {
31587
+ if (!isOverPreview)
31456
31588
  setHoveredLink(null);
31457
- }
31458
31589
  }, 300);
31459
31590
  }
31460
31591
  }
@@ -31464,216 +31595,241 @@ function LinkPreviewPlugin() {
31464
31595
  document.body.addEventListener("mouseover", handlePreviewMouseOver);
31465
31596
  document.body.addEventListener("mouseout", handlePreviewMouseOut);
31466
31597
  return () => {
31467
- if (showTimeout) {
31598
+ if (showTimeout)
31468
31599
  clearTimeout(showTimeout);
31469
- }
31470
- if (hideTimeout) {
31600
+ if (hideTimeout)
31471
31601
  clearTimeout(hideTimeout);
31472
- }
31473
31602
  editorElement.removeEventListener("mouseover", handleMouseOver);
31474
31603
  editorElement.removeEventListener("mouseout", handleMouseOut);
31475
31604
  document.body.removeEventListener("mouseover", handlePreviewMouseOver);
31476
31605
  document.body.removeEventListener("mouseout", handlePreviewMouseOut);
31477
31606
  };
31478
31607
  }, [editor]);
31479
- if (!hoveredLink) {
31608
+ if (!hoveredLink)
31480
31609
  return null;
31481
- }
31482
31610
  return createPortal(
31483
31611
  /* @__PURE__ */ jsx(
31484
31612
  LinkPreview,
31485
31613
  {
31486
31614
  url: hoveredLink.url,
31487
31615
  rect: hoveredLink.rect,
31616
+ apiKey,
31488
31617
  onClose: () => setHoveredLink(null)
31489
31618
  }
31490
31619
  ),
31491
31620
  document.body
31492
31621
  );
31493
31622
  }
31494
- function LinkPreview({ url, rect, onClose }) {
31623
+ const PREVIEW_WIDTH = 320;
31624
+ function LinkPreview({ url, rect, apiKey, onClose }) {
31495
31625
  const [position, setPosition] = useState$1({ top: 0, left: 0 });
31626
+ const [previewData, setPreviewData] = useState$1(null);
31627
+ const [isLoading, setIsLoading] = useState$1(true);
31628
+ const [hasError, setHasError] = useState$1(false);
31629
+ const fetchedRef = useRef(false);
31496
31630
  useEffect$1(() => {
31497
- const previewWidth = 300;
31498
- const previewHeight = 120;
31631
+ if (fetchedRef.current)
31632
+ return;
31633
+ fetchedRef.current = true;
31634
+ setIsLoading(true);
31635
+ setHasError(false);
31636
+ fetchLinkPreview({ url, apiKey }).then((data) => {
31637
+ if (data)
31638
+ setPreviewData(data);
31639
+ else
31640
+ setHasError(true);
31641
+ }).catch(() => setHasError(true)).finally(() => setIsLoading(false));
31642
+ }, [url, apiKey]);
31643
+ useEffect$1(() => {
31644
+ const previewHeight = (previewData == null ? void 0 : previewData.image) ? 280 : 160;
31499
31645
  let top = rect.top + window.scrollY - previewHeight - 10;
31500
31646
  if (rect.top - previewHeight - 10 < 0) {
31501
31647
  top = rect.bottom + window.scrollY + 10;
31502
31648
  }
31503
- let left = rect.left + window.scrollX + rect.width / 2 - previewWidth / 2;
31649
+ let left = rect.left + window.scrollX + rect.width / 2 - PREVIEW_WIDTH / 2;
31504
31650
  const viewportWidth = window.innerWidth;
31505
- if (left < 10) {
31651
+ if (left < 10)
31506
31652
  left = 10;
31507
- } else if (left + previewWidth > viewportWidth - 10) {
31508
- left = viewportWidth - previewWidth - 10;
31509
- }
31653
+ else if (left + PREVIEW_WIDTH > viewportWidth - 10)
31654
+ left = viewportWidth - PREVIEW_WIDTH - 10;
31510
31655
  setPosition({ top, left });
31511
- }, [rect]);
31656
+ }, [rect, previewData]);
31512
31657
  const getDomain = (urlString) => {
31513
31658
  try {
31514
- const urlObj = new URL(urlString);
31515
- return urlObj.hostname.replace("www.", "");
31659
+ return new URL(urlString).hostname.replace("www.", "");
31516
31660
  } catch {
31517
31661
  return urlString;
31518
31662
  }
31519
31663
  };
31520
31664
  const domain = getDomain(url);
31521
- const getProtocol = (urlString) => {
31522
- try {
31523
- const urlObj = new URL(urlString);
31524
- return urlObj.protocol.replace(":", "").toUpperCase();
31525
- } catch {
31526
- return "HTTPS";
31665
+ const TypeIcon = ({ type }) => {
31666
+ const iconProps = { style: { width: "14px", height: "14px" }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24" };
31667
+ const pathProps = { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2 };
31668
+ switch (type) {
31669
+ case "image":
31670
+ return /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { ...pathProps, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) });
31671
+ case "video":
31672
+ return /* @__PURE__ */ jsxs("svg", { ...iconProps, children: [
31673
+ /* @__PURE__ */ jsx("path", { ...pathProps, d: "M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" }),
31674
+ /* @__PURE__ */ jsx("path", { ...pathProps, d: "M21 12a9 9 0 11-18 0 9 9 0 0118 0z" })
31675
+ ] });
31676
+ case "pdf":
31677
+ return /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { ...pathProps, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) });
31678
+ default:
31679
+ return /* @__PURE__ */ jsx("svg", { ...iconProps, children: /* @__PURE__ */ jsx("path", { ...pathProps, d: "M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" }) });
31527
31680
  }
31528
31681
  };
31529
- const protocol = getProtocol(url);
31530
- return /* @__PURE__ */ jsxs(
31531
- "div",
31532
- {
31533
- className: "link-preview-card",
31534
- style: {
31535
- position: "absolute",
31536
- top: `${position.top}px`,
31537
- left: `${position.left}px`,
31538
- zIndex: 1e4,
31539
- pointerEvents: "auto",
31540
- animation: "fadeIn 0.2s ease-out"
31541
- },
31542
- children: [
31543
- /* @__PURE__ */ jsxs(
31544
- "div",
31545
- {
31546
- style: {
31547
- width: "250px",
31548
- backgroundColor: "#2d2d2d",
31549
- borderRadius: "12px",
31550
- boxShadow: "0 10px 40px rgba(0, 0, 0, 0.3)",
31551
- overflow: "hidden",
31552
- position: "relative"
31553
- },
31554
- children: [
31555
- /* @__PURE__ */ jsx(
31556
- "button",
31557
- {
31558
- onClick: (e) => {
31559
- e.preventDefault();
31560
- e.stopPropagation();
31561
- onClose();
31562
- },
31563
- style: {
31564
- position: "absolute",
31565
- top: "8px",
31566
- right: "8px",
31567
- width: "20px",
31568
- height: "20px",
31569
- borderRadius: "4px",
31570
- backgroundColor: "#404040",
31571
- border: "none",
31572
- cursor: "pointer",
31573
- display: "flex",
31574
- alignItems: "center",
31575
- justifyContent: "center",
31576
- transition: "background-color 0.2s",
31577
- zIndex: 1
31578
- },
31579
- onMouseEnter: (e) => {
31580
- e.currentTarget.style.backgroundColor = "#525252";
31581
- },
31582
- onMouseLeave: (e) => {
31583
- e.currentTarget.style.backgroundColor = "#404040";
31584
- },
31585
- title: "Close preview",
31586
- children: /* @__PURE__ */ jsx(
31587
- "svg",
31588
- {
31589
- style: { width: "12px", height: "12px", color: "#9ca3af" },
31590
- fill: "none",
31591
- stroke: "currentColor",
31592
- viewBox: "0 0 24 24",
31593
- children: /* @__PURE__ */ jsx(
31594
- "path",
31595
- {
31596
- strokeLinecap: "round",
31597
- strokeLinejoin: "round",
31598
- strokeWidth: 2,
31599
- d: "M6 18L18 6M6 6l12 12"
31600
- }
31601
- )
31602
- }
31603
- )
31682
+ const cardStyle = {
31683
+ position: "absolute",
31684
+ top: `${position.top}px`,
31685
+ left: `${position.left}px`,
31686
+ zIndex: 1e4,
31687
+ pointerEvents: "auto",
31688
+ animation: "linkPreviewFadeIn 0.2s ease-out"
31689
+ };
31690
+ const containerStyle = {
31691
+ width: `${PREVIEW_WIDTH}px`,
31692
+ backgroundColor: "#1e1e1e",
31693
+ borderRadius: "12px",
31694
+ boxShadow: "0 10px 40px rgba(0, 0, 0, 0.4)",
31695
+ overflow: "hidden",
31696
+ position: "relative",
31697
+ border: "1px solid #333"
31698
+ };
31699
+ const closeButtonStyle = {
31700
+ position: "absolute",
31701
+ top: "8px",
31702
+ right: "8px",
31703
+ width: "24px",
31704
+ height: "24px",
31705
+ borderRadius: "6px",
31706
+ backgroundColor: "rgba(0,0,0,0.5)",
31707
+ border: "none",
31708
+ cursor: "pointer",
31709
+ display: "flex",
31710
+ alignItems: "center",
31711
+ justifyContent: "center",
31712
+ zIndex: 10
31713
+ };
31714
+ return /* @__PURE__ */ jsxs("div", { className: "link-preview-card", style: cardStyle, children: [
31715
+ /* @__PURE__ */ jsxs("div", { style: containerStyle, children: [
31716
+ /* @__PURE__ */ jsx(
31717
+ "button",
31718
+ {
31719
+ onClick: (e) => {
31720
+ e.preventDefault();
31721
+ e.stopPropagation();
31722
+ onClose();
31723
+ },
31724
+ style: closeButtonStyle,
31725
+ onMouseEnter: (e) => {
31726
+ e.currentTarget.style.backgroundColor = "rgba(0,0,0,0.7)";
31727
+ },
31728
+ onMouseLeave: (e) => {
31729
+ e.currentTarget.style.backgroundColor = "rgba(0,0,0,0.5)";
31730
+ },
31731
+ title: "Close preview",
31732
+ children: /* @__PURE__ */ jsx("svg", { style: { width: "14px", height: "14px", color: "#fff" }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
31733
+ }
31734
+ ),
31735
+ isLoading && /* @__PURE__ */ jsxs("div", { style: { padding: "40px", textAlign: "center" }, children: [
31736
+ /* @__PURE__ */ jsx("div", { style: {
31737
+ width: "24px",
31738
+ height: "24px",
31739
+ border: "2px solid #444",
31740
+ borderTopColor: "#fff",
31741
+ borderRadius: "50%",
31742
+ animation: "linkPreviewSpin 1s linear infinite",
31743
+ margin: "0 auto 12px"
31744
+ } }),
31745
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#888" }, children: "Loading preview..." })
31746
+ ] }),
31747
+ !isLoading && hasError && /* @__PURE__ */ jsxs("div", { style: { padding: "16px" }, children: [
31748
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "12px" }, children: [
31749
+ /* @__PURE__ */ jsx("svg", { style: { width: "16px", height: "16px", color: "#fff" }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) }),
31750
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "14px", fontWeight: "600", color: "#fff" }, children: domain })
31751
+ ] }),
31752
+ /* @__PURE__ */ jsx("div", { style: { backgroundColor: "#2a2a2a", padding: "10px", borderRadius: "6px" }, children: /* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#ccc", wordBreak: "break-all", lineHeight: "1.5" }, children: url }) })
31753
+ ] }),
31754
+ !isLoading && !hasError && previewData && /* @__PURE__ */ jsxs(Fragment, { children: [
31755
+ previewData.image && /* @__PURE__ */ jsx("div", { style: {
31756
+ width: "100%",
31757
+ height: "140px",
31758
+ backgroundColor: "#2a2a2a",
31759
+ backgroundImage: `url(${previewData.image})`,
31760
+ backgroundSize: "cover",
31761
+ backgroundPosition: "center"
31762
+ } }),
31763
+ /* @__PURE__ */ jsxs("div", { style: { padding: "14px" }, children: [
31764
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "10px" }, children: [
31765
+ previewData.favicon ? /* @__PURE__ */ jsx(
31766
+ "img",
31767
+ {
31768
+ src: previewData.favicon,
31769
+ alt: "",
31770
+ style: { width: "16px", height: "16px", borderRadius: "2px", objectFit: "contain" },
31771
+ onError: (e) => {
31772
+ e.currentTarget.style.display = "none";
31604
31773
  }
31605
- ),
31606
- /* @__PURE__ */ jsxs("div", { style: { padding: "16px 16px 12px 16px" }, children: [
31607
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }, children: [
31608
- /* @__PURE__ */ jsx(
31609
- "svg",
31610
- {
31611
- style: { width: "16px", height: "16px", color: "#ffffff" },
31612
- fill: "none",
31613
- stroke: "currentColor",
31614
- viewBox: "0 0 24 24",
31615
- children: /* @__PURE__ */ jsx(
31616
- "path",
31617
- {
31618
- strokeLinecap: "round",
31619
- strokeLinejoin: "round",
31620
- strokeWidth: 2,
31621
- d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
31622
- }
31623
- )
31624
- }
31625
- ),
31626
- /* @__PURE__ */ jsx("span", { style: { fontSize: "14px", fontWeight: "600", color: "#ffffff" }, children: domain })
31627
- ] }),
31628
- /* @__PURE__ */ jsx("p", { style: { fontSize: "10px", color: "#9ca3af", marginLeft: "24px" }, children: protocol })
31629
- ] }),
31630
- /* @__PURE__ */ jsxs("div", { style: { padding: "0 16px 16px 16px" }, children: [
31631
- /* @__PURE__ */ jsx("p", { style: { fontSize: "10px", fontWeight: "500", color: "#9ca3af", textTransform: "uppercase", marginBottom: "8px" }, children: "LINK URL" }),
31632
- /* @__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 }) })
31633
- ] }),
31634
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "8px", padding: "12px", borderTop: "1px solid #404040" }, children: [
31635
- /* @__PURE__ */ jsx(
31636
- "div",
31637
- {
31638
- style: {
31639
- width: "8px",
31640
- height: "8px",
31641
- borderRadius: "50%",
31642
- backgroundColor: "#10b981",
31643
- boxShadow: "0 0 8px rgba(16, 185, 129, 0.6)",
31644
- animation: "pulse 2s ease-in-out infinite"
31645
- }
31646
- }
31647
- ),
31648
- /* @__PURE__ */ jsx("span", { style: { fontSize: "10px", fontWeight: "500", color: "#a1a1aa" }, children: "Link Preview" })
31649
- ] })
31650
- ]
31651
- }
31652
- ),
31653
- /* @__PURE__ */ jsx("style", { children: `
31654
- @keyframes fadeIn {
31655
- from {
31656
- opacity: 0;
31657
- transform: translateY(5px);
31658
- }
31659
- to {
31660
- opacity: 1;
31661
- transform: translateY(0);
31662
- }
31774
+ }
31775
+ ) : /* @__PURE__ */ jsx("span", { style: { color: "#888" }, children: /* @__PURE__ */ jsx(TypeIcon, { type: previewData.type }) }),
31776
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "12px", color: "#888", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: previewData.siteName || domain }),
31777
+ /* @__PURE__ */ jsx("span", { style: {
31778
+ fontSize: "10px",
31779
+ color: "#666",
31780
+ padding: "2px 6px",
31781
+ backgroundColor: "#333",
31782
+ borderRadius: "4px",
31783
+ textTransform: "uppercase"
31784
+ }, children: previewData.type })
31785
+ ] }),
31786
+ previewData.title && /* @__PURE__ */ jsx("h4", { style: {
31787
+ fontSize: "14px",
31788
+ fontWeight: "600",
31789
+ color: "#fff",
31790
+ marginBottom: "6px",
31791
+ lineHeight: "1.4",
31792
+ display: "-webkit-box",
31793
+ WebkitLineClamp: 2,
31794
+ WebkitBoxOrient: "vertical",
31795
+ overflow: "hidden"
31796
+ }, children: previewData.title }),
31797
+ previewData.description && /* @__PURE__ */ jsx("p", { style: {
31798
+ fontSize: "12px",
31799
+ color: "#999",
31800
+ lineHeight: "1.5",
31801
+ display: "-webkit-box",
31802
+ WebkitLineClamp: 2,
31803
+ WebkitBoxOrient: "vertical",
31804
+ overflow: "hidden",
31805
+ marginBottom: "10px"
31806
+ }, children: previewData.description }),
31807
+ /* @__PURE__ */ jsxs("div", { style: {
31808
+ display: "flex",
31809
+ alignItems: "center",
31810
+ gap: "6px",
31811
+ padding: "8px 10px",
31812
+ backgroundColor: "#252525",
31813
+ borderRadius: "6px",
31814
+ marginTop: "8px"
31815
+ }, children: [
31816
+ /* @__PURE__ */ jsx("svg", { style: { width: "12px", height: "12px", color: "#666", flexShrink: 0 }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" }) }),
31817
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "11px", color: "#888", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: url })
31818
+ ] })
31819
+ ] })
31820
+ ] })
31821
+ ] }),
31822
+ /* @__PURE__ */ jsx("style", { children: `
31823
+ @keyframes linkPreviewFadeIn {
31824
+ from { opacity: 0; transform: translateY(5px); }
31825
+ to { opacity: 1; transform: translateY(0); }
31663
31826
  }
31664
-
31665
- @keyframes pulse {
31666
- 0%, 100% {
31667
- opacity: 1;
31668
- }
31669
- 50% {
31670
- opacity: 0.6;
31671
- }
31827
+ @keyframes linkPreviewSpin {
31828
+ from { transform: rotate(0deg); }
31829
+ to { transform: rotate(360deg); }
31672
31830
  }
31673
31831
  ` })
31674
- ]
31675
- }
31676
- );
31832
+ ] });
31677
31833
  }
31678
31834
  const debounce = (fn, delay) => {
31679
31835
  let timeoutID;
@@ -31704,6 +31860,554 @@ const LocalStoragePlugin = ({ namespace }) => {
31704
31860
  return null;
31705
31861
  };
31706
31862
  const LocalStoragePlugin$1 = LocalStoragePlugin;
31863
+ const HORIZONTAL_RULE_PATTERNS = /^(---|___|\*\*\*)$/;
31864
+ const HEADING_PATTERN = /^(#{1,6})\s$/;
31865
+ const BULLET_LIST_PATTERN = /^(\*|-|\+)\s$/;
31866
+ const NUMBERED_LIST_PATTERN = /^(\d+)[\.\)]\s$/;
31867
+ const CHECKLIST_PATTERN = /^\[(x|\s)?\]\s$/i;
31868
+ const QUOTE_PATTERN = /^>\s$/;
31869
+ const CODE_BLOCK_PATTERN = /^```$/;
31870
+ function getLineTextBeforeCursor(editor) {
31871
+ let text = null;
31872
+ editor.getEditorState().read(() => {
31873
+ const selection = $getSelection();
31874
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
31875
+ return;
31876
+ }
31877
+ const anchor = selection.anchor;
31878
+ const anchorNode = anchor.getNode();
31879
+ if (!$isTextNode(anchorNode)) {
31880
+ return;
31881
+ }
31882
+ const textContent = anchorNode.getTextContent();
31883
+ const offset2 = anchor.offset;
31884
+ text = textContent.slice(0, offset2);
31885
+ });
31886
+ return text;
31887
+ }
31888
+ function isAtBlockStart(editor, triggerLength) {
31889
+ let result = false;
31890
+ editor.getEditorState().read(() => {
31891
+ const selection = $getSelection();
31892
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
31893
+ return;
31894
+ }
31895
+ const anchor = selection.anchor;
31896
+ const anchorNode = anchor.getNode();
31897
+ const parent = anchorNode.getParent();
31898
+ if (!parent || parent.getType() !== "paragraph") {
31899
+ return;
31900
+ }
31901
+ const children = parent.getChildren();
31902
+ if (children.length === 1 && children[0] === anchorNode) {
31903
+ const textContent = anchorNode.getTextContent();
31904
+ if (textContent.length === triggerLength) {
31905
+ result = true;
31906
+ }
31907
+ }
31908
+ });
31909
+ return result;
31910
+ }
31911
+ function isInsideListItem(node) {
31912
+ let current = node.getParent();
31913
+ while (current !== null) {
31914
+ if ($isListItemNode(current)) {
31915
+ return true;
31916
+ }
31917
+ current = current.getParent();
31918
+ }
31919
+ return false;
31920
+ }
31921
+ function handleHorizontalRule(editor) {
31922
+ const text = getLineTextBeforeCursor(editor);
31923
+ if (!text || !HORIZONTAL_RULE_PATTERNS.test(text)) {
31924
+ return false;
31925
+ }
31926
+ if (!isAtBlockStart(editor, text.length)) {
31927
+ return false;
31928
+ }
31929
+ editor.update(() => {
31930
+ const selection = $getSelection();
31931
+ if (!$isRangeSelection(selection))
31932
+ return;
31933
+ const anchorNode = selection.anchor.getNode();
31934
+ const parent = anchorNode.getParent();
31935
+ if (parent && parent.getType() === "paragraph") {
31936
+ editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, void 0);
31937
+ parent.remove();
31938
+ }
31939
+ });
31940
+ return true;
31941
+ }
31942
+ function handleHeading(editor) {
31943
+ const text = getLineTextBeforeCursor(editor);
31944
+ if (!text)
31945
+ return false;
31946
+ const match = text.match(HEADING_PATTERN);
31947
+ if (!match)
31948
+ return false;
31949
+ let isValidContext = false;
31950
+ editor.getEditorState().read(() => {
31951
+ const selection = $getSelection();
31952
+ if (!$isRangeSelection(selection))
31953
+ return;
31954
+ const anchorNode = selection.anchor.getNode();
31955
+ if (!$isTextNode(anchorNode))
31956
+ return;
31957
+ const parent = anchorNode.getParent();
31958
+ if (!parent || parent.getType() !== "paragraph")
31959
+ return;
31960
+ if (isInsideListItem(parent))
31961
+ return;
31962
+ const children = parent.getChildren();
31963
+ if (children.length !== 1 || children[0] !== anchorNode)
31964
+ return;
31965
+ const fullText = anchorNode.getTextContent();
31966
+ const headingMatch = fullText.match(HEADING_PATTERN);
31967
+ if (headingMatch && headingMatch.index === 0) {
31968
+ isValidContext = true;
31969
+ }
31970
+ });
31971
+ if (!isValidContext) {
31972
+ return false;
31973
+ }
31974
+ const level = match[1].length;
31975
+ const tag = `h${level}`;
31976
+ editor.update(() => {
31977
+ const selection = $getSelection();
31978
+ if (!$isRangeSelection(selection))
31979
+ return;
31980
+ const anchorNode = selection.anchor.getNode();
31981
+ if (!$isTextNode(anchorNode))
31982
+ return;
31983
+ const parent = anchorNode.getParent();
31984
+ if (parent && parent.getType() === "paragraph") {
31985
+ const fullText = anchorNode.getTextContent();
31986
+ const remainingText = fullText.slice(match[0].length);
31987
+ const headingNode = $createHeadingNode(tag);
31988
+ if (remainingText) {
31989
+ headingNode.append($createTextNode(remainingText));
31990
+ }
31991
+ parent.replace(headingNode);
31992
+ headingNode.selectEnd();
31993
+ }
31994
+ });
31995
+ return true;
31996
+ }
31997
+ function handleBulletList(editor) {
31998
+ const text = getLineTextBeforeCursor(editor);
31999
+ if (!text || !BULLET_LIST_PATTERN.test(text)) {
32000
+ return false;
32001
+ }
32002
+ let isValidContext = false;
32003
+ editor.getEditorState().read(() => {
32004
+ const selection = $getSelection();
32005
+ if (!$isRangeSelection(selection))
32006
+ return;
32007
+ const anchorNode = selection.anchor.getNode();
32008
+ if (!$isTextNode(anchorNode))
32009
+ return;
32010
+ const parent = anchorNode.getParent();
32011
+ if (!parent || parent.getType() !== "paragraph")
32012
+ return;
32013
+ if (isInsideListItem(parent))
32014
+ return;
32015
+ const children = parent.getChildren();
32016
+ if (children.length !== 1 || children[0] !== anchorNode)
32017
+ return;
32018
+ const fullText = anchorNode.getTextContent();
32019
+ const match = fullText.match(BULLET_LIST_PATTERN);
32020
+ if (match && match.index === 0) {
32021
+ isValidContext = true;
32022
+ }
32023
+ });
32024
+ if (!isValidContext) {
32025
+ return false;
32026
+ }
32027
+ editor.update(() => {
32028
+ const selection = $getSelection();
32029
+ if (!$isRangeSelection(selection))
32030
+ return;
32031
+ const anchorNode = selection.anchor.getNode();
32032
+ if (!$isTextNode(anchorNode))
32033
+ return;
32034
+ const parent = anchorNode.getParent();
32035
+ if (parent && parent.getType() === "paragraph") {
32036
+ const fullText = anchorNode.getTextContent();
32037
+ const match = text.match(BULLET_LIST_PATTERN);
32038
+ const remainingText = match ? fullText.slice(match[0].length) : "";
32039
+ const listNode = $createListNode("bullet");
32040
+ const listItemNode = $createListItemNode();
32041
+ if (remainingText) {
32042
+ listItemNode.append($createTextNode(remainingText));
32043
+ }
32044
+ listNode.append(listItemNode);
32045
+ parent.replace(listNode);
32046
+ listItemNode.selectEnd();
32047
+ }
32048
+ });
32049
+ return true;
32050
+ }
32051
+ function handleNumberedList(editor) {
32052
+ const text = getLineTextBeforeCursor(editor);
32053
+ if (!text || !NUMBERED_LIST_PATTERN.test(text)) {
32054
+ return false;
32055
+ }
32056
+ let isValidContext = false;
32057
+ editor.getEditorState().read(() => {
32058
+ const selection = $getSelection();
32059
+ if (!$isRangeSelection(selection))
32060
+ return;
32061
+ const anchorNode = selection.anchor.getNode();
32062
+ if (!$isTextNode(anchorNode))
32063
+ return;
32064
+ const parent = anchorNode.getParent();
32065
+ if (!parent || parent.getType() !== "paragraph")
32066
+ return;
32067
+ if (isInsideListItem(parent))
32068
+ return;
32069
+ const children = parent.getChildren();
32070
+ if (children.length !== 1 || children[0] !== anchorNode)
32071
+ return;
32072
+ const fullText = anchorNode.getTextContent();
32073
+ const match = fullText.match(NUMBERED_LIST_PATTERN);
32074
+ if (match && match.index === 0) {
32075
+ isValidContext = true;
32076
+ }
32077
+ });
32078
+ if (!isValidContext) {
32079
+ return false;
32080
+ }
32081
+ editor.update(() => {
32082
+ const selection = $getSelection();
32083
+ if (!$isRangeSelection(selection))
32084
+ return;
32085
+ const anchorNode = selection.anchor.getNode();
32086
+ if (!$isTextNode(anchorNode))
32087
+ return;
32088
+ const parent = anchorNode.getParent();
32089
+ if (parent && parent.getType() === "paragraph") {
32090
+ const fullText = anchorNode.getTextContent();
32091
+ const match = text.match(NUMBERED_LIST_PATTERN);
32092
+ const remainingText = match ? fullText.slice(match[0].length) : "";
32093
+ const listNode = $createListNode("number");
32094
+ const listItemNode = $createListItemNode();
32095
+ if (remainingText) {
32096
+ listItemNode.append($createTextNode(remainingText));
32097
+ }
32098
+ listNode.append(listItemNode);
32099
+ parent.replace(listNode);
32100
+ listItemNode.selectEnd();
32101
+ }
32102
+ });
32103
+ return true;
32104
+ }
32105
+ function handleChecklist(editor) {
32106
+ const text = getLineTextBeforeCursor(editor);
32107
+ if (!text || !CHECKLIST_PATTERN.test(text)) {
32108
+ return false;
32109
+ }
32110
+ let isValidContext = false;
32111
+ editor.getEditorState().read(() => {
32112
+ const selection = $getSelection();
32113
+ if (!$isRangeSelection(selection))
32114
+ return;
32115
+ const anchorNode = selection.anchor.getNode();
32116
+ if (!$isTextNode(anchorNode))
32117
+ return;
32118
+ const parent = anchorNode.getParent();
32119
+ if (!parent || parent.getType() !== "paragraph")
32120
+ return;
32121
+ if (isInsideListItem(parent))
32122
+ return;
32123
+ const children = parent.getChildren();
32124
+ if (children.length !== 1 || children[0] !== anchorNode)
32125
+ return;
32126
+ const fullText = anchorNode.getTextContent();
32127
+ const match = fullText.match(CHECKLIST_PATTERN);
32128
+ if (match && match.index === 0) {
32129
+ isValidContext = true;
32130
+ }
32131
+ });
32132
+ if (!isValidContext) {
32133
+ return false;
32134
+ }
32135
+ editor.update(() => {
32136
+ const selection = $getSelection();
32137
+ if (!$isRangeSelection(selection))
32138
+ return;
32139
+ const anchorNode = selection.anchor.getNode();
32140
+ if (!$isTextNode(anchorNode))
32141
+ return;
32142
+ const parent = anchorNode.getParent();
32143
+ if (parent && parent.getType() === "paragraph") {
32144
+ const fullText = anchorNode.getTextContent();
32145
+ const match = text.match(CHECKLIST_PATTERN);
32146
+ const remainingText = match ? fullText.slice(match[0].length) : "";
32147
+ const listNode = $createListNode("check");
32148
+ const listItemNode = $createListItemNode();
32149
+ if (remainingText) {
32150
+ listItemNode.append($createTextNode(remainingText));
32151
+ }
32152
+ listNode.append(listItemNode);
32153
+ parent.replace(listNode);
32154
+ listItemNode.selectEnd();
32155
+ }
32156
+ });
32157
+ return true;
32158
+ }
32159
+ function handleQuote(editor) {
32160
+ const text = getLineTextBeforeCursor(editor);
32161
+ if (!text || !QUOTE_PATTERN.test(text)) {
32162
+ return false;
32163
+ }
32164
+ let isValidContext = false;
32165
+ editor.getEditorState().read(() => {
32166
+ const selection = $getSelection();
32167
+ if (!$isRangeSelection(selection))
32168
+ return;
32169
+ const anchorNode = selection.anchor.getNode();
32170
+ if (!$isTextNode(anchorNode))
32171
+ return;
32172
+ const parent = anchorNode.getParent();
32173
+ if (!parent || parent.getType() !== "paragraph")
32174
+ return;
32175
+ if (isInsideListItem(parent))
32176
+ return;
32177
+ const children = parent.getChildren();
32178
+ if (children.length !== 1 || children[0] !== anchorNode)
32179
+ return;
32180
+ const fullText = anchorNode.getTextContent();
32181
+ const match = fullText.match(QUOTE_PATTERN);
32182
+ if (match && match.index === 0) {
32183
+ isValidContext = true;
32184
+ }
32185
+ });
32186
+ if (!isValidContext) {
32187
+ return false;
32188
+ }
32189
+ editor.update(() => {
32190
+ const selection = $getSelection();
32191
+ if (!$isRangeSelection(selection))
32192
+ return;
32193
+ const anchorNode = selection.anchor.getNode();
32194
+ if (!$isTextNode(anchorNode))
32195
+ return;
32196
+ const parent = anchorNode.getParent();
32197
+ if (parent && parent.getType() === "paragraph") {
32198
+ const fullText = anchorNode.getTextContent();
32199
+ const match = text.match(QUOTE_PATTERN);
32200
+ const remainingText = match ? fullText.slice(match[0].length) : "";
32201
+ const quoteNode = $createQuoteNode();
32202
+ if (remainingText) {
32203
+ quoteNode.append($createTextNode(remainingText));
32204
+ }
32205
+ parent.replace(quoteNode);
32206
+ quoteNode.selectEnd();
32207
+ }
32208
+ });
32209
+ return true;
32210
+ }
32211
+ function handleCodeBlock(editor) {
32212
+ const text = getLineTextBeforeCursor(editor);
32213
+ if (!text || !CODE_BLOCK_PATTERN.test(text)) {
32214
+ return false;
32215
+ }
32216
+ if (!isAtBlockStart(editor, text.length)) {
32217
+ return false;
32218
+ }
32219
+ editor.update(() => {
32220
+ const selection = $getSelection();
32221
+ if (!$isRangeSelection(selection))
32222
+ return;
32223
+ const anchorNode = selection.anchor.getNode();
32224
+ const parent = anchorNode.getParent();
32225
+ if (parent && parent.getType() === "paragraph") {
32226
+ const codeNode = $createCodeNode();
32227
+ parent.replace(codeNode);
32228
+ const paragraphNode = $createParagraphNode();
32229
+ codeNode.insertAfter(paragraphNode);
32230
+ codeNode.selectEnd();
32231
+ }
32232
+ });
32233
+ return true;
32234
+ }
32235
+ function handleMarkdownShortcuts(editor) {
32236
+ if (handleHorizontalRule(editor))
32237
+ return true;
32238
+ if (handleHeading(editor))
32239
+ return true;
32240
+ if (handleBulletList(editor))
32241
+ return true;
32242
+ if (handleNumberedList(editor))
32243
+ return true;
32244
+ if (handleChecklist(editor))
32245
+ return true;
32246
+ if (handleQuote(editor))
32247
+ return true;
32248
+ if (handleCodeBlock(editor))
32249
+ return true;
32250
+ return false;
32251
+ }
32252
+ function MarkdownShortcutsPlugin() {
32253
+ const [editor] = useLexicalComposerContext();
32254
+ useEffect$1(() => {
32255
+ const removeTextListener = editor.registerTextContentListener(() => {
32256
+ const text = getLineTextBeforeCursor(editor);
32257
+ if (text && HORIZONTAL_RULE_PATTERNS.test(text)) {
32258
+ setTimeout(() => {
32259
+ handleHorizontalRule(editor);
32260
+ }, 0);
32261
+ }
32262
+ });
32263
+ const removeEnterListener = editor.registerCommand(
32264
+ KEY_ENTER_COMMAND,
32265
+ (event) => {
32266
+ const handled = handleMarkdownShortcuts(editor);
32267
+ if (handled && event) {
32268
+ event.preventDefault();
32269
+ return true;
32270
+ }
32271
+ return false;
32272
+ },
32273
+ COMMAND_PRIORITY_HIGH
32274
+ );
32275
+ const removeBackspaceListener = editor.registerCommand(
32276
+ KEY_BACKSPACE_COMMAND,
32277
+ (event) => {
32278
+ const selection = $getSelection();
32279
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
32280
+ return false;
32281
+ }
32282
+ const anchor = selection.anchor;
32283
+ const anchorNode = anchor.getNode();
32284
+ if (anchor.offset !== 0) {
32285
+ return false;
32286
+ }
32287
+ let listItem = null;
32288
+ let current = anchorNode;
32289
+ while (current !== null) {
32290
+ if ($isListItemNode(current)) {
32291
+ listItem = current;
32292
+ break;
32293
+ }
32294
+ current = current.getParent();
32295
+ }
32296
+ if (!listItem) {
32297
+ return false;
32298
+ }
32299
+ const listItemChildren = listItem.getChildren();
32300
+ let isAtStart = false;
32301
+ if (listItemChildren.length === 0) {
32302
+ isAtStart = true;
32303
+ } else {
32304
+ const firstChild = listItemChildren[0];
32305
+ if (firstChild === anchorNode) {
32306
+ isAtStart = true;
32307
+ } else {
32308
+ const firstChildType = firstChild.getType();
32309
+ if (firstChildType === "paragraph" || firstChildType === "heading") {
32310
+ const parent = anchorNode.getParent();
32311
+ if (parent && parent === firstChild) {
32312
+ const siblings = parent.getChildren();
32313
+ if (siblings.length > 0 && siblings[0] === anchorNode) {
32314
+ isAtStart = true;
32315
+ } else if (siblings.length === 0) {
32316
+ isAtStart = true;
32317
+ }
32318
+ }
32319
+ }
32320
+ }
32321
+ }
32322
+ if (isAtStart) {
32323
+ const listNode = listItem.getParent();
32324
+ if (listNode && $isListNode(listNode)) {
32325
+ const paragraphNode = $createParagraphNode();
32326
+ const children = listItem.getChildren();
32327
+ for (const child of children) {
32328
+ const childType = child.getType();
32329
+ if (childType === "paragraph" || childType === "heading") {
32330
+ const elementChild = child;
32331
+ const innerChildren = elementChild.getChildren();
32332
+ for (const innerChild of innerChildren) {
32333
+ paragraphNode.append(innerChild);
32334
+ }
32335
+ } else {
32336
+ paragraphNode.append(child);
32337
+ }
32338
+ }
32339
+ const listChildren = listNode.getChildren();
32340
+ const isFirstItem = listChildren.length > 0 && listChildren[0] === listItem;
32341
+ if (isFirstItem) {
32342
+ listNode.insertBefore(paragraphNode);
32343
+ } else {
32344
+ listItem.insertBefore(paragraphNode);
32345
+ }
32346
+ listItem.remove();
32347
+ if (listNode.getChildrenSize() === 0) {
32348
+ listNode.remove();
32349
+ }
32350
+ paragraphNode.selectEnd();
32351
+ }
32352
+ if (event) {
32353
+ event.preventDefault();
32354
+ }
32355
+ return true;
32356
+ }
32357
+ return false;
32358
+ },
32359
+ COMMAND_PRIORITY_HIGH
32360
+ );
32361
+ const removeUpdateListener = editor.registerUpdateListener(
32362
+ ({ editorState, tags }) => {
32363
+ if (tags.has("history-merge"))
32364
+ return;
32365
+ editorState.read(() => {
32366
+ const selection = $getSelection();
32367
+ if (!$isRangeSelection(selection) || !selection.isCollapsed()) {
32368
+ return;
32369
+ }
32370
+ const text = getLineTextBeforeCursor(editor);
32371
+ if (!text)
32372
+ return;
32373
+ if (text.endsWith(" ")) {
32374
+ if (HEADING_PATTERN.test(text)) {
32375
+ setTimeout(() => handleHeading(editor), 0);
32376
+ return;
32377
+ }
32378
+ if (BULLET_LIST_PATTERN.test(text)) {
32379
+ setTimeout(() => handleBulletList(editor), 0);
32380
+ return;
32381
+ }
32382
+ if (NUMBERED_LIST_PATTERN.test(text)) {
32383
+ setTimeout(() => handleNumberedList(editor), 0);
32384
+ return;
32385
+ }
32386
+ if (CHECKLIST_PATTERN.test(text)) {
32387
+ setTimeout(() => handleChecklist(editor), 0);
32388
+ return;
32389
+ }
32390
+ if (QUOTE_PATTERN.test(text)) {
32391
+ setTimeout(() => handleQuote(editor), 0);
32392
+ return;
32393
+ }
32394
+ }
32395
+ if (CODE_BLOCK_PATTERN.test(text)) {
32396
+ setTimeout(() => handleCodeBlock(editor), 0);
32397
+ return;
32398
+ }
32399
+ });
32400
+ }
32401
+ );
32402
+ return () => {
32403
+ removeTextListener();
32404
+ removeEnterListener();
32405
+ removeBackspaceListener();
32406
+ removeUpdateListener();
32407
+ };
32408
+ }, [editor]);
32409
+ return null;
32410
+ }
31707
32411
  const index$2 = "";
31708
32412
  const PUNCTUATION = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_:;`;
31709
32413
  const NAME = "\\b[A-Z][^\\s" + PUNCTUATION + "]";
@@ -31882,6 +32586,11 @@ function detectCSSAlignment(element) {
31882
32586
  while (current && current !== document.body) {
31883
32587
  const style = current.style;
31884
32588
  const computedStyle = window.getComputedStyle(current);
32589
+ const floatValue = style.cssFloat || style.float || computedStyle.cssFloat || computedStyle.float;
32590
+ if (floatValue === "left")
32591
+ return "left";
32592
+ if (floatValue === "right")
32593
+ return "right";
31885
32594
  const textAlign = style.textAlign || computedStyle.textAlign;
31886
32595
  if (textAlign === "center")
31887
32596
  return "center";
@@ -31903,29 +32612,52 @@ function detectCSSAlignment(element) {
31903
32612
  }
31904
32613
  return null;
31905
32614
  }
32615
+ const DEFAULT_IMAGE_DIMENSIONS = {
32616
+ // For side-by-side/floated images - smaller default since they share space with text
32617
+ floated: { width: 300, height: 200 },
32618
+ // For centered/standalone images - larger default for prominence
32619
+ centered: { width: 600, height: 400 },
32620
+ // For inline images without explicit layout
32621
+ inline: { width: 400, height: 300 },
32622
+ // Maximum reasonable dimensions to cap oversized images
32623
+ maxWidth: 800,
32624
+ maxHeight: 600
32625
+ };
31906
32626
  function getImageDimensions(imgElement) {
31907
32627
  let width = parseInt(imgElement.getAttribute("width") || "0");
31908
32628
  let height = parseInt(imgElement.getAttribute("height") || "0");
31909
32629
  if (width === 0) {
31910
32630
  const styleWidth = imgElement.style.width;
31911
- if (styleWidth && styleWidth.endsWith("px")) {
31912
- width = parseInt(styleWidth);
32631
+ if (styleWidth) {
32632
+ const parsed = parseInt(styleWidth);
32633
+ if (!isNaN(parsed) && parsed > 0) {
32634
+ width = parsed;
32635
+ }
31913
32636
  }
31914
32637
  }
31915
32638
  if (height === 0) {
31916
32639
  const styleHeight = imgElement.style.height;
31917
- if (styleHeight && styleHeight.endsWith("px")) {
31918
- height = parseInt(styleHeight);
32640
+ if (styleHeight) {
32641
+ const parsed = parseInt(styleHeight);
32642
+ if (!isNaN(parsed) && parsed > 0) {
32643
+ height = parsed;
32644
+ }
31919
32645
  }
31920
32646
  }
31921
32647
  if (width === 0 || height === 0) {
31922
32648
  try {
31923
32649
  const computed = window.getComputedStyle(imgElement);
31924
32650
  if (width === 0 && computed.width && computed.width !== "auto") {
31925
- width = parseInt(computed.width);
32651
+ const parsed = parseInt(computed.width);
32652
+ if (!isNaN(parsed) && parsed > 0) {
32653
+ width = parsed;
32654
+ }
31926
32655
  }
31927
32656
  if (height === 0 && computed.height && computed.height !== "auto") {
31928
- height = parseInt(computed.height);
32657
+ const parsed = parseInt(computed.height);
32658
+ if (!isNaN(parsed) && parsed > 0) {
32659
+ height = parsed;
32660
+ }
31929
32661
  }
31930
32662
  } catch {
31931
32663
  }
@@ -31940,6 +32672,33 @@ function getImageDimensions(imgElement) {
31940
32672
  }
31941
32673
  return { width, height };
31942
32674
  }
32675
+ function getImageDimensionsWithDefaults(imgElement, layoutContext = "inline") {
32676
+ const { width, height } = getImageDimensions(imgElement);
32677
+ if (width > 0 && height > 0) {
32678
+ const aspectRatio = width / height;
32679
+ let finalWidth = width;
32680
+ let finalHeight = height;
32681
+ if (finalWidth > DEFAULT_IMAGE_DIMENSIONS.maxWidth) {
32682
+ finalWidth = DEFAULT_IMAGE_DIMENSIONS.maxWidth;
32683
+ finalHeight = Math.round(finalWidth / aspectRatio);
32684
+ }
32685
+ if (finalHeight > DEFAULT_IMAGE_DIMENSIONS.maxHeight) {
32686
+ finalHeight = DEFAULT_IMAGE_DIMENSIONS.maxHeight;
32687
+ finalWidth = Math.round(finalHeight * aspectRatio);
32688
+ }
32689
+ return { width: finalWidth, height: finalHeight };
32690
+ }
32691
+ if (width > 0) {
32692
+ const cappedWidth = Math.min(width, DEFAULT_IMAGE_DIMENSIONS.maxWidth);
32693
+ return { width: cappedWidth, height: Math.round(cappedWidth * 0.625) };
32694
+ }
32695
+ if (height > 0) {
32696
+ const cappedHeight = Math.min(height, DEFAULT_IMAGE_DIMENSIONS.maxHeight);
32697
+ return { width: Math.round(cappedHeight * 1.6), height: cappedHeight };
32698
+ }
32699
+ const defaults = DEFAULT_IMAGE_DIMENSIONS[layoutContext];
32700
+ return { width: defaults.width, height: defaults.height };
32701
+ }
31943
32702
  function shouldCenterImage(imgElement) {
31944
32703
  var _a;
31945
32704
  const { width, height } = getImageDimensions(imgElement);
@@ -32042,15 +32801,205 @@ function detectClassBasedAlignment(element) {
32042
32801
  }
32043
32802
  return null;
32044
32803
  }
32804
+ function isImageContainerClass(className) {
32805
+ const imagePatterns = [
32806
+ "media",
32807
+ "image",
32808
+ "img",
32809
+ "photo",
32810
+ "picture",
32811
+ "thumbnail",
32812
+ "thumb",
32813
+ "visual",
32814
+ "graphic",
32815
+ "illustration",
32816
+ "figure",
32817
+ "avatar",
32818
+ "hero",
32819
+ "banner",
32820
+ "cover",
32821
+ "poster",
32822
+ "artwork",
32823
+ "gallery",
32824
+ "featured",
32825
+ "wp-block-image",
32826
+ "wp-image",
32827
+ "attachment",
32828
+ "featured-image"
32829
+ ];
32830
+ const lowerClass = className.toLowerCase();
32831
+ return imagePatterns.some((pattern) => lowerClass.includes(pattern));
32832
+ }
32833
+ function detectWordPressAlignment(element) {
32834
+ const className = element.className || "";
32835
+ const lowerClass = className.toLowerCase();
32836
+ if (lowerClass.includes("alignleft") || lowerClass.includes("align-left")) {
32837
+ return "left";
32838
+ }
32839
+ if (lowerClass.includes("alignright") || lowerClass.includes("align-right")) {
32840
+ return "right";
32841
+ }
32842
+ if (lowerClass.includes("aligncenter") || lowerClass.includes("align-center")) {
32843
+ return "center";
32844
+ }
32845
+ if (lowerClass.includes("alignnone") || lowerClass.includes("align-none")) {
32846
+ return "left";
32847
+ }
32848
+ let parent = element.parentElement;
32849
+ let depth = 0;
32850
+ while (parent && depth < 5) {
32851
+ const parentClass = parent.className || "";
32852
+ const parentLower = parentClass.toLowerCase();
32853
+ if (parentLower.includes("alignleft") || parentLower.includes("align-left")) {
32854
+ return "left";
32855
+ }
32856
+ if (parentLower.includes("alignright") || parentLower.includes("align-right")) {
32857
+ return "right";
32858
+ }
32859
+ if (parentLower.includes("aligncenter") || parentLower.includes("align-center")) {
32860
+ return "center";
32861
+ }
32862
+ parent = parent.parentElement;
32863
+ depth++;
32864
+ }
32865
+ return null;
32866
+ }
32867
+ function isContentContainerClass(className) {
32868
+ const contentPatterns = [
32869
+ "content",
32870
+ "text",
32871
+ "body",
32872
+ "copy",
32873
+ "description",
32874
+ "details",
32875
+ "info",
32876
+ "meta",
32877
+ "caption",
32878
+ "excerpt",
32879
+ "summary",
32880
+ "article",
32881
+ "prose",
32882
+ "entry",
32883
+ "post",
32884
+ "main",
32885
+ "primary"
32886
+ ];
32887
+ const lowerClass = className.toLowerCase();
32888
+ return contentPatterns.some((pattern) => lowerClass.includes(pattern));
32889
+ }
32890
+ function containsImage(element) {
32891
+ return element.querySelector("img") !== null || element.tagName.toLowerCase() === "img";
32892
+ }
32893
+ function hasSubstantialTextContent(element) {
32894
+ var _a;
32895
+ const text = ((_a = element.textContent) == null ? void 0 : _a.trim()) || "";
32896
+ return text.length > 30;
32897
+ }
32898
+ function detectBootstrapColumn(element) {
32899
+ const className = element.className || "";
32900
+ const colMatch = className.match(/\bcol(-[a-z]{2})?(-\d+)?\b/);
32901
+ if (!colMatch)
32902
+ return null;
32903
+ const parent = element.parentElement;
32904
+ if (!parent)
32905
+ return null;
32906
+ const parentClass = parent.className || "";
32907
+ if (!parentClass.includes("row"))
32908
+ return null;
32909
+ const siblings = Array.from(parent.children).filter((child) => {
32910
+ const cls = child.className || "";
32911
+ return cls.match(/\bcol(-[a-z]{2})?(-\d+)?\b/);
32912
+ });
32913
+ const index2 = siblings.indexOf(element);
32914
+ if (index2 === -1)
32915
+ return null;
32916
+ return index2 < siblings.length / 2 ? "left" : "right";
32917
+ }
32918
+ function detectSideBySideLayout(imgElement) {
32919
+ const ancestors = [];
32920
+ let current = imgElement;
32921
+ while (current && current !== document.body && ancestors.length < 10) {
32922
+ ancestors.push(current);
32923
+ current = current.parentElement;
32924
+ }
32925
+ for (let i2 = 0; i2 < ancestors.length; i2++) {
32926
+ const ancestor = ancestors[i2];
32927
+ const parent = ancestor.parentElement;
32928
+ if (!parent || parent === document.body)
32929
+ continue;
32930
+ const bootstrapPos = detectBootstrapColumn(ancestor);
32931
+ if (bootstrapPos) {
32932
+ const siblings2 = Array.from(parent.children);
32933
+ const hasContentSibling = siblings2.some((sibling) => {
32934
+ if (sibling === ancestor)
32935
+ return false;
32936
+ return hasSubstantialTextContent(sibling) && !containsImage(sibling);
32937
+ });
32938
+ if (hasContentSibling) {
32939
+ return bootstrapPos;
32940
+ }
32941
+ }
32942
+ const ancestorClass = ancestor.className || "";
32943
+ const isMediaContainer = isImageContainerClass(ancestorClass);
32944
+ if (isMediaContainer) {
32945
+ const siblings2 = Array.from(parent.children).filter((child) => {
32946
+ var _a;
32947
+ const tag = (_a = child.tagName) == null ? void 0 : _a.toLowerCase();
32948
+ return tag !== "script" && tag !== "style" && tag !== "noscript";
32949
+ });
32950
+ if (siblings2.length >= 2) {
32951
+ const ancestorIndex = siblings2.indexOf(ancestor);
32952
+ const contentSiblingIndex = siblings2.findIndex((sibling, index2) => {
32953
+ if (index2 === ancestorIndex)
32954
+ return false;
32955
+ const siblingClass = sibling.className || "";
32956
+ const hasContentClass = isContentContainerClass(siblingClass);
32957
+ const hasText = hasSubstantialTextContent(sibling);
32958
+ const hasNoImage = !containsImage(sibling);
32959
+ return (hasContentClass || hasText) && hasNoImage;
32960
+ });
32961
+ if (contentSiblingIndex !== -1) {
32962
+ return ancestorIndex < contentSiblingIndex ? "left" : "right";
32963
+ }
32964
+ }
32965
+ }
32966
+ const siblings = Array.from(parent.children).filter((child) => {
32967
+ var _a;
32968
+ const tag = (_a = child.tagName) == null ? void 0 : _a.toLowerCase();
32969
+ return tag !== "script" && tag !== "style" && tag !== "noscript" && tag !== "br";
32970
+ });
32971
+ if (siblings.length === 2) {
32972
+ const ancestorIndex = siblings.indexOf(ancestor);
32973
+ if (ancestorIndex !== -1) {
32974
+ const otherSibling = siblings[1 - ancestorIndex];
32975
+ const ancestorHasImage = containsImage(ancestor);
32976
+ const otherHasImage = containsImage(otherSibling);
32977
+ const otherHasText = hasSubstantialTextContent(otherSibling);
32978
+ if (ancestorHasImage && !otherHasImage && otherHasText) {
32979
+ return ancestorIndex === 0 ? "left" : "right";
32980
+ }
32981
+ }
32982
+ }
32983
+ }
32984
+ return null;
32985
+ }
32045
32986
  function detectImageAlignment(imgElement) {
32046
32987
  const classAlignment = detectClassBasedAlignment(imgElement);
32047
32988
  if (classAlignment) {
32048
32989
  return classAlignment;
32049
32990
  }
32991
+ const wpAlignment = detectWordPressAlignment(imgElement);
32992
+ if (wpAlignment) {
32993
+ return wpAlignment;
32994
+ }
32050
32995
  const cssAlignment = detectCSSAlignment(imgElement);
32051
32996
  if (cssAlignment) {
32052
32997
  return cssAlignment;
32053
32998
  }
32999
+ const sideBySideAlignment = detectSideBySideLayout(imgElement);
33000
+ if (sideBySideAlignment) {
33001
+ return sideBySideAlignment;
33002
+ }
32054
33003
  if (shouldCenterImage(imgElement)) {
32055
33004
  return "center";
32056
33005
  }
@@ -32372,7 +33321,7 @@ const defaultPasteContext = {
32372
33321
  };
32373
33322
  let currentPasteContext = defaultPasteContext;
32374
33323
  function processNode(domNode, parentElement = null) {
32375
- var _a;
33324
+ var _a, _b, _c;
32376
33325
  const results = [];
32377
33326
  if (domNode.nodeType === Node.TEXT_NODE) {
32378
33327
  const text = domNode.textContent || "";
@@ -32398,17 +33347,22 @@ function processNode(domNode, parentElement = null) {
32398
33347
  const paragraph = $createParagraphNode();
32399
33348
  const styleInfo = getStyleInfoFromElement(element);
32400
33349
  const hasExplicitFontSize = styleInfo.fontSize && styleInfo.fontSize !== "16px";
33350
+ let overflowNodes = [];
32401
33351
  if (!hasExplicitFontSize && currentPasteContext.isCKEditor) {
32402
33352
  processChildrenWithStyle(element, paragraph, {
32403
33353
  fontSize: DEFAULT_PARAGRAPH_FONT_SIZE,
32404
33354
  lineHeight: DEFAULT_PARAGRAPH_LINE_HEIGHT
32405
33355
  });
32406
33356
  } else {
32407
- processChildren(element, paragraph);
33357
+ const result = processChildrenWithImageSeparation(element, paragraph);
33358
+ overflowNodes = result.overflowNodes;
32408
33359
  }
32409
33360
  if (paragraph.getChildrenSize() > 0 || tagName === "p") {
32410
33361
  results.push(paragraph);
32411
33362
  }
33363
+ if (overflowNodes.length > 0) {
33364
+ results.push(...overflowNodes);
33365
+ }
32412
33366
  break;
32413
33367
  }
32414
33368
  case "h1":
@@ -32471,7 +33425,41 @@ function processNode(domNode, parentElement = null) {
32471
33425
  }
32472
33426
  case "a": {
32473
33427
  const href = element.getAttribute("href") || "";
32474
- if (href) {
33428
+ const containedImg = element.querySelector("img");
33429
+ if (containedImg) {
33430
+ const src = containedImg.getAttribute("src") || "";
33431
+ if (src && !src.startsWith("file:///")) {
33432
+ const alt = containedImg.getAttribute("alt") || "";
33433
+ const alignment = detectImageAlignment(containedImg);
33434
+ const layoutContext = isFloatAlignment(alignment) ? "floated" : alignment === "center" ? "centered" : "inline";
33435
+ const { width, height } = getImageDimensionsWithDefaults(containedImg, layoutContext);
33436
+ const position = alignmentToPosition(alignment);
33437
+ const imageNode = $createImageNode({
33438
+ src,
33439
+ altText: alt,
33440
+ width,
33441
+ height,
33442
+ position: isFloatAlignment(alignment) ? position : "none",
33443
+ linkUrl: href
33444
+ // Store the original link URL
33445
+ });
33446
+ if (alignment === "center") {
33447
+ const paragraph = $createParagraphNode();
33448
+ paragraph.setFormat("center");
33449
+ paragraph.append(imageNode);
33450
+ results.push(paragraph);
33451
+ } else {
33452
+ results.push(imageNode);
33453
+ }
33454
+ }
33455
+ const textContent = (_a = element.textContent) == null ? void 0 : _a.replace(containedImg.alt || "", "").trim();
33456
+ if (textContent && textContent.length > 0) {
33457
+ const linkNode = $createLinkNode(href, { target: "_blank", rel: "noopener" });
33458
+ const textNode = $createTextNode(textContent);
33459
+ linkNode.append(textNode);
33460
+ results.push(linkNode);
33461
+ }
33462
+ } else if (href) {
32475
33463
  const linkNode = $createLinkNode(href, { target: "_blank", rel: "noopener" });
32476
33464
  processChildren(element, linkNode);
32477
33465
  results.push(linkNode);
@@ -32485,9 +33473,9 @@ function processNode(domNode, parentElement = null) {
32485
33473
  const src = element.getAttribute("src") || "";
32486
33474
  if (src && !src.startsWith("file:///")) {
32487
33475
  const alt = element.getAttribute("alt") || "";
32488
- const width = parseInt(element.getAttribute("width") || "0") || void 0;
32489
- const height = parseInt(element.getAttribute("height") || "0") || void 0;
32490
33476
  const alignment = detectImageAlignment(element);
33477
+ const layoutContext = isFloatAlignment(alignment) ? "floated" : alignment === "center" ? "centered" : "inline";
33478
+ const { width, height } = getImageDimensionsWithDefaults(element, layoutContext);
32491
33479
  const position = alignmentToPosition(alignment);
32492
33480
  const imageNode = $createImageNode({
32493
33481
  src,
@@ -32518,13 +33506,13 @@ function processNode(domNode, parentElement = null) {
32518
33506
  const position = alignmentToPosition(alignment);
32519
33507
  const isFloat = isFloatAlignment(alignment);
32520
33508
  const figcaption = element.querySelector("figcaption");
32521
- const captionText = ((_a = figcaption == null ? void 0 : figcaption.textContent) == null ? void 0 : _a.trim()) || "";
33509
+ const captionText = ((_b = figcaption == null ? void 0 : figcaption.textContent) == null ? void 0 : _b.trim()) || "";
32522
33510
  if (img) {
32523
33511
  const src = img.getAttribute("src") || "";
32524
33512
  if (src && !src.startsWith("file:///")) {
32525
33513
  const alt = img.getAttribute("alt") || "";
32526
- const width = parseInt(img.getAttribute("width") || "0") || void 0;
32527
- const height = parseInt(img.getAttribute("height") || "0") || void 0;
33514
+ const layoutContext = isFloat ? "floated" : alignment === "center" ? "centered" : "inline";
33515
+ const { width, height } = getImageDimensionsWithDefaults(img, layoutContext);
32528
33516
  const imageNode = $createImageNode({
32529
33517
  src,
32530
33518
  altText: alt,
@@ -32563,6 +33551,43 @@ function processNode(domNode, parentElement = null) {
32563
33551
  }
32564
33552
  break;
32565
33553
  }
33554
+ case "code": {
33555
+ const className = element.className || "";
33556
+ const isBlockCode = className.includes("PlaygroundEditorTheme__code") || className.includes("code-block") || element.hasAttribute("data-language") || element.hasAttribute("data-highlight-language");
33557
+ if (isBlockCode) {
33558
+ const language = element.getAttribute("data-language") || element.getAttribute("data-highlight-language") || void 0;
33559
+ const codeNode = $createCodeNode(language);
33560
+ const textContent = element.textContent || "";
33561
+ if (textContent) {
33562
+ codeNode.append($createTextNode(textContent));
33563
+ }
33564
+ results.push(codeNode);
33565
+ } else {
33566
+ const children = processChildren(element);
33567
+ results.push(...children);
33568
+ }
33569
+ break;
33570
+ }
33571
+ case "pre": {
33572
+ const codeChild = element.querySelector("code");
33573
+ if (codeChild) {
33574
+ const language = codeChild.getAttribute("data-language") || codeChild.getAttribute("data-highlight-language") || ((_c = codeChild.className.match(/language-(\w+)/)) == null ? void 0 : _c[1]) || void 0;
33575
+ const codeNode = $createCodeNode(language);
33576
+ const textContent = codeChild.textContent || "";
33577
+ if (textContent) {
33578
+ codeNode.append($createTextNode(textContent));
33579
+ }
33580
+ results.push(codeNode);
33581
+ } else {
33582
+ const codeNode = $createCodeNode();
33583
+ const textContent = element.textContent || "";
33584
+ if (textContent) {
33585
+ codeNode.append($createTextNode(textContent));
33586
+ }
33587
+ results.push(codeNode);
33588
+ }
33589
+ break;
33590
+ }
32566
33591
  case "strong":
32567
33592
  case "b":
32568
33593
  case "em":
@@ -32571,7 +33596,6 @@ function processNode(domNode, parentElement = null) {
32571
33596
  case "s":
32572
33597
  case "strike":
32573
33598
  case "del":
32574
- case "code":
32575
33599
  case "sub":
32576
33600
  case "sup":
32577
33601
  case "mark":
@@ -32619,6 +33643,60 @@ function processChildren(element, parentNode) {
32619
33643
  }
32620
33644
  return results;
32621
33645
  }
33646
+ function processChildrenWithImageSeparation(element, parentNode) {
33647
+ const overflowNodes = [];
33648
+ let hasTextContent = false;
33649
+ const childNodes = element.childNodes;
33650
+ for (let i2 = 0; i2 < childNodes.length; i2++) {
33651
+ const child = childNodes[i2];
33652
+ if (child.nodeType === Node.ELEMENT_NODE) {
33653
+ const childElement = child;
33654
+ const tagName = childElement.tagName.toLowerCase();
33655
+ if (tagName === "img") {
33656
+ if (hasTextContent) {
33657
+ const nodes2 = processNode(child, element);
33658
+ nodes2.forEach((node) => {
33659
+ if ($isImageNode(node)) {
33660
+ const imageParagraph = $createParagraphNode();
33661
+ imageParagraph.append(node);
33662
+ overflowNodes.push(imageParagraph);
33663
+ } else if (node instanceof ParagraphNode) {
33664
+ overflowNodes.push(node);
33665
+ } else {
33666
+ overflowNodes.push(node);
33667
+ }
33668
+ });
33669
+ continue;
33670
+ }
33671
+ }
33672
+ }
33673
+ const nodes = processNode(child, element);
33674
+ nodes.forEach((node) => {
33675
+ if ($isTextNode(node) && node.getTextContent().trim().length > 0) {
33676
+ hasTextContent = true;
33677
+ }
33678
+ if ($isImageNode(node) && hasTextContent) {
33679
+ const imageParagraph = $createParagraphNode();
33680
+ imageParagraph.append(node);
33681
+ overflowNodes.push(imageParagraph);
33682
+ } else if (node instanceof ParagraphNode && hasTextContent) {
33683
+ const children = node.getChildren();
33684
+ const hasOnlyImage = children.length === 1 && $isImageNode(children[0]);
33685
+ if (hasOnlyImage) {
33686
+ overflowNodes.push(node);
33687
+ } else {
33688
+ parentNode.append(node);
33689
+ }
33690
+ } else {
33691
+ parentNode.append(node);
33692
+ if ($isTextNode(node) && node.getTextContent().trim().length > 0) {
33693
+ hasTextContent = true;
33694
+ }
33695
+ }
33696
+ });
33697
+ }
33698
+ return { overflowNodes };
33699
+ }
32622
33700
  function processChildrenWithStyle(element, parentNode, defaultStyles) {
32623
33701
  const childNodes = element.childNodes;
32624
33702
  for (let i2 = 0; i2 < childNodes.length; i2++) {
@@ -32908,6 +33986,651 @@ function RichTextPastePlugin() {
32908
33986
  }, [editor]);
32909
33987
  return null;
32910
33988
  }
33989
+ function htmlContainsImages(html) {
33990
+ if (!html)
33991
+ return false;
33992
+ return /<img\s/i.test(html) || /data:image\//i.test(html);
33993
+ }
33994
+ function PasteOptionsMenu({
33995
+ position,
33996
+ currentMode,
33997
+ onSelectMode,
33998
+ onClose,
33999
+ hasHtml
34000
+ }) {
34001
+ const menuRef = useRef(null);
34002
+ const [isOpen, setIsOpen] = useState$1(false);
34003
+ const [menuPosition, setMenuPosition] = useState$1(position);
34004
+ useEffect$1(() => {
34005
+ setMenuPosition(position);
34006
+ }, [position]);
34007
+ useEffect$1(() => {
34008
+ const handleClickOutside = (e) => {
34009
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
34010
+ onClose();
34011
+ }
34012
+ };
34013
+ document.addEventListener("mousedown", handleClickOutside);
34014
+ return () => document.removeEventListener("mousedown", handleClickOutside);
34015
+ }, [onClose]);
34016
+ const allOptions = [
34017
+ {
34018
+ mode: "rich",
34019
+ label: "Use rich text",
34020
+ icon: /* @__PURE__ */ jsx(Type, { className: "cteditor-size-4" })
34021
+ },
34022
+ {
34023
+ mode: "markdown",
34024
+ label: "Use Markdown",
34025
+ icon: /* @__PURE__ */ jsx(Hash, { className: "cteditor-size-4" })
34026
+ },
34027
+ {
34028
+ mode: "plain",
34029
+ label: "Use plain text",
34030
+ icon: /* @__PURE__ */ jsx(FileText, { className: "cteditor-size-4" })
34031
+ }
34032
+ ];
34033
+ const options = hasHtml ? allOptions : allOptions.filter((option) => option.mode !== "rich");
34034
+ const currentOption = options.find((o) => o.mode === currentMode);
34035
+ const menuStyle = {
34036
+ position: "fixed",
34037
+ left: Math.min(menuPosition.x, window.innerWidth - 200),
34038
+ top: Math.min(menuPosition.y + 5, window.innerHeight - 150),
34039
+ zIndex: 1e3
34040
+ };
34041
+ return /* @__PURE__ */ jsxs("div", { ref: menuRef, style: menuStyle, className: "cteditor-relative", children: [
34042
+ /* @__PURE__ */ jsxs(
34043
+ "button",
34044
+ {
34045
+ onClick: () => setIsOpen(!isOpen),
34046
+ className: "cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-px-2 cteditor-py-1 cteditor-text-xs cteditor-bg-background cteditor-border cteditor-border-border cteditor-rounded-md cteditor-shadow-lg hover:cteditor-bg-accent cteditor-transition-colors",
34047
+ children: [
34048
+ currentOption == null ? void 0 : currentOption.icon,
34049
+ /* @__PURE__ */ jsx(
34050
+ ChevronDown,
34051
+ {
34052
+ className: `cteditor-size-3 cteditor-transition-transform ${isOpen ? "cteditor-rotate-180" : ""}`
34053
+ }
34054
+ )
34055
+ ]
34056
+ }
34057
+ ),
34058
+ isOpen && /* @__PURE__ */ jsx("div", { className: "cteditor-absolute cteditor-top-full cteditor-left-0 cteditor-mt-1 cteditor-w-44 cteditor-bg-background cteditor-border cteditor-border-border cteditor-rounded-md cteditor-shadow-xl cteditor-overflow-hidden", children: options.map((option) => /* @__PURE__ */ jsxs(
34059
+ "button",
34060
+ {
34061
+ onClick: () => {
34062
+ onSelectMode(option.mode);
34063
+ setIsOpen(false);
34064
+ },
34065
+ className: `cteditor-w-full cteditor-flex cteditor-items-center cteditor-gap-2 cteditor-px-3 cteditor-py-2 cteditor-text-xs hover:cteditor-bg-accent cteditor-transition-colors ${currentMode === option.mode ? "cteditor-bg-primary/10 cteditor-text-primary" : ""}`,
34066
+ children: [
34067
+ option.icon,
34068
+ /* @__PURE__ */ jsx("span", { className: "cteditor-flex-1 cteditor-text-left", children: option.label }),
34069
+ currentMode === option.mode && /* @__PURE__ */ jsx(Check, { className: "cteditor-size-3 cteditor-text-primary" })
34070
+ ]
34071
+ },
34072
+ option.mode
34073
+ )) })
34074
+ ] });
34075
+ }
34076
+ function processInlineMarkdown(text) {
34077
+ if (!text) {
34078
+ return [];
34079
+ }
34080
+ const nodes = [];
34081
+ const tripleBacktickPattern = /```([^`]+)```/g;
34082
+ if (tripleBacktickPattern.test(text)) {
34083
+ tripleBacktickPattern.lastIndex = 0;
34084
+ let lastIndex = 0;
34085
+ let match;
34086
+ while ((match = tripleBacktickPattern.exec(text)) !== null) {
34087
+ if (match.index > lastIndex) {
34088
+ const beforeText = text.slice(lastIndex, match.index);
34089
+ const beforeNodes = processSimpleInlineMarkdown(beforeText);
34090
+ nodes.push(...beforeNodes);
34091
+ }
34092
+ const codeContent = match[1];
34093
+ const codeNode = $createTextNode(codeContent);
34094
+ codeNode.toggleFormat("code");
34095
+ nodes.push(codeNode);
34096
+ lastIndex = match.index + match[0].length;
34097
+ }
34098
+ if (lastIndex < text.length) {
34099
+ const afterText = text.slice(lastIndex);
34100
+ const afterNodes = processSimpleInlineMarkdown(afterText);
34101
+ nodes.push(...afterNodes);
34102
+ }
34103
+ return nodes;
34104
+ }
34105
+ return processSimpleInlineMarkdown(text);
34106
+ }
34107
+ function processSimpleInlineMarkdown(text) {
34108
+ if (!text) {
34109
+ return [];
34110
+ }
34111
+ let processedText = text;
34112
+ let hasBold = false;
34113
+ let hasItalic = false;
34114
+ let hasCode = false;
34115
+ let hasStrikethrough = false;
34116
+ if (/\*\*(.+?)\*\*/.test(processedText)) {
34117
+ hasBold = true;
34118
+ processedText = processedText.replace(/\*\*(.+?)\*\*/g, "$1");
34119
+ }
34120
+ if (/__(.+?)__/.test(processedText)) {
34121
+ hasBold = true;
34122
+ processedText = processedText.replace(/__(.+?)__/g, "$1");
34123
+ }
34124
+ if (!hasBold && /^\*([^*]+)\*$/.test(processedText)) {
34125
+ hasItalic = true;
34126
+ processedText = processedText.replace(/^\*([^*]+)\*$/, "$1");
34127
+ } else if (/(?:^|[^*])\*([^*]+)\*(?:[^*]|$)/.test(processedText)) {
34128
+ hasItalic = true;
34129
+ processedText = processedText.replace(/\*([^*]+)\*/g, "$1");
34130
+ }
34131
+ if (!hasBold && /^_([^_]+)_$/.test(processedText)) {
34132
+ hasItalic = true;
34133
+ processedText = processedText.replace(/^_([^_]+)_$/, "$1");
34134
+ } else if (/(?:^|[^_])_([^_]+)_(?:[^_]|$)/.test(processedText)) {
34135
+ hasItalic = true;
34136
+ processedText = processedText.replace(/_([^_]+)_/g, "$1");
34137
+ }
34138
+ if (new RegExp("(?<!`)`([^`]+)`(?!`)").test(processedText)) {
34139
+ hasCode = true;
34140
+ processedText = processedText.replace(new RegExp("(?<!`)`([^`]+)`(?!`)", "g"), "$1");
34141
+ }
34142
+ if (/~~(.+?)~~/.test(processedText)) {
34143
+ hasStrikethrough = true;
34144
+ processedText = processedText.replace(/~~(.+?)~~/g, "$1");
34145
+ }
34146
+ processedText = processedText.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1");
34147
+ const textNode = $createTextNode(processedText);
34148
+ if (hasBold)
34149
+ textNode.toggleFormat("bold");
34150
+ if (hasItalic)
34151
+ textNode.toggleFormat("italic");
34152
+ if (hasCode)
34153
+ textNode.toggleFormat("code");
34154
+ if (hasStrikethrough)
34155
+ textNode.toggleFormat("strikethrough");
34156
+ return [textNode];
34157
+ }
34158
+ function convertMarkdownToNodes(text, editor) {
34159
+ const nodes = [];
34160
+ const lines = text.split("\n");
34161
+ let i2 = 0;
34162
+ while (i2 < lines.length) {
34163
+ const line = lines[i2];
34164
+ if (line.trim() === "") {
34165
+ i2++;
34166
+ continue;
34167
+ }
34168
+ if (/^(---|___|\*\*\*)$/.test(line.trim())) {
34169
+ const placeholder = $createParagraphNode();
34170
+ placeholder.append($createTextNode("___MARKDOWN_HR___"));
34171
+ nodes.push(placeholder);
34172
+ i2++;
34173
+ continue;
34174
+ }
34175
+ const singleLineCodeMatch = line.trim().match(/^```(.+?)```$/);
34176
+ if (singleLineCodeMatch) {
34177
+ const codeContent = singleLineCodeMatch[1];
34178
+ const codeNode = $createCodeNode();
34179
+ codeNode.append($createTextNode(codeContent));
34180
+ nodes.push(codeNode);
34181
+ const afterParagraph = $createParagraphNode();
34182
+ nodes.push(afterParagraph);
34183
+ i2++;
34184
+ continue;
34185
+ }
34186
+ if (line.trim().startsWith("```")) {
34187
+ const codeLines = [];
34188
+ const langMatch = line.trim().match(/^```(\w*)$/);
34189
+ i2++;
34190
+ while (i2 < lines.length && !lines[i2].trim().startsWith("```")) {
34191
+ codeLines.push(lines[i2]);
34192
+ i2++;
34193
+ }
34194
+ if (i2 < lines.length)
34195
+ i2++;
34196
+ const codeNode = $createCodeNode((langMatch == null ? void 0 : langMatch[1]) || void 0);
34197
+ codeNode.append($createTextNode(codeLines.join("\n")));
34198
+ nodes.push(codeNode);
34199
+ const afterParagraph = $createParagraphNode();
34200
+ nodes.push(afterParagraph);
34201
+ continue;
34202
+ }
34203
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
34204
+ if (headingMatch) {
34205
+ const level = headingMatch[1].length;
34206
+ const headingNode = $createHeadingNode(
34207
+ `h${level}`
34208
+ );
34209
+ const textNodes2 = processInlineMarkdown(headingMatch[2].trim());
34210
+ textNodes2.forEach((node) => headingNode.append(node));
34211
+ nodes.push(headingNode);
34212
+ i2++;
34213
+ continue;
34214
+ }
34215
+ if (/^[*\-+]\s+/.test(line)) {
34216
+ const listNode = $createListNode("bullet");
34217
+ while (i2 < lines.length && /^[*\-+]\s+/.test(lines[i2])) {
34218
+ const listItemNode = $createListItemNode();
34219
+ const itemText = lines[i2].replace(/^[*\-+]\s+/, "");
34220
+ if (itemText) {
34221
+ const textNodes2 = processInlineMarkdown(itemText);
34222
+ if (textNodes2.length > 0) {
34223
+ textNodes2.forEach((node) => listItemNode.append(node));
34224
+ } else {
34225
+ listItemNode.append($createTextNode(itemText));
34226
+ }
34227
+ }
34228
+ listNode.append(listItemNode);
34229
+ i2++;
34230
+ }
34231
+ nodes.push(listNode);
34232
+ continue;
34233
+ }
34234
+ if (/^\d+[.)]\s+/.test(line)) {
34235
+ const listNode = $createListNode("number");
34236
+ while (i2 < lines.length && /^\d+[.)]\s+/.test(lines[i2])) {
34237
+ const listItemNode = $createListItemNode();
34238
+ const itemText = lines[i2].replace(/^\d+[.)]\s+/, "");
34239
+ if (itemText) {
34240
+ const textNodes2 = processInlineMarkdown(itemText);
34241
+ if (textNodes2.length > 0) {
34242
+ textNodes2.forEach((node) => listItemNode.append(node));
34243
+ } else {
34244
+ listItemNode.append($createTextNode(itemText));
34245
+ }
34246
+ }
34247
+ listNode.append(listItemNode);
34248
+ i2++;
34249
+ }
34250
+ nodes.push(listNode);
34251
+ continue;
34252
+ }
34253
+ if (/^\[(x|\s)?\]\s+/i.test(line)) {
34254
+ const listNode = $createListNode("check");
34255
+ while (i2 < lines.length && /^\[(x|\s)?\]\s+/i.test(lines[i2])) {
34256
+ const listItemNode = $createListItemNode();
34257
+ const isChecked = /^\[x\]/i.test(lines[i2]);
34258
+ const itemText = lines[i2].replace(/^\[(x|\s)?\]\s+/i, "");
34259
+ if (itemText) {
34260
+ const textNodes2 = processInlineMarkdown(itemText);
34261
+ if (textNodes2.length > 0) {
34262
+ textNodes2.forEach((node) => listItemNode.append(node));
34263
+ } else {
34264
+ listItemNode.append($createTextNode(itemText));
34265
+ }
34266
+ }
34267
+ if (isChecked) {
34268
+ listItemNode.setChecked(true);
34269
+ }
34270
+ listNode.append(listItemNode);
34271
+ i2++;
34272
+ }
34273
+ nodes.push(listNode);
34274
+ continue;
34275
+ }
34276
+ if (/^>\s*/.test(line)) {
34277
+ const quoteNode = $createQuoteNode();
34278
+ const quoteLines = [];
34279
+ while (i2 < lines.length && /^>\s*/.test(lines[i2])) {
34280
+ quoteLines.push(lines[i2].replace(/^>\s*/, ""));
34281
+ i2++;
34282
+ }
34283
+ const quoteText = quoteLines.join("\n");
34284
+ if (quoteText) {
34285
+ const textNodes2 = processInlineMarkdown(quoteText);
34286
+ if (textNodes2.length > 0) {
34287
+ textNodes2.forEach((node) => quoteNode.append(node));
34288
+ } else {
34289
+ quoteNode.append($createTextNode(quoteText));
34290
+ }
34291
+ }
34292
+ nodes.push(quoteNode);
34293
+ continue;
34294
+ }
34295
+ const paragraph = $createParagraphNode();
34296
+ const textNodes = processInlineMarkdown(line);
34297
+ textNodes.forEach((node) => paragraph.append(node));
34298
+ nodes.push(paragraph);
34299
+ i2++;
34300
+ }
34301
+ return nodes;
34302
+ }
34303
+ function convertPlainTextToNodes(text) {
34304
+ const nodes = [];
34305
+ const paragraphs = text.split(/\n\n+/);
34306
+ for (const para of paragraphs) {
34307
+ if (para.trim() || para === "") {
34308
+ const paragraph = $createParagraphNode();
34309
+ const lines = para.split(/\n/);
34310
+ lines.forEach((line, index2) => {
34311
+ if (line) {
34312
+ paragraph.append($createTextNode(line));
34313
+ }
34314
+ if (index2 < lines.length - 1) {
34315
+ paragraph.append($createLineBreakNode());
34316
+ }
34317
+ });
34318
+ if (paragraph.getChildrenSize() > 0) {
34319
+ nodes.push(paragraph);
34320
+ }
34321
+ }
34322
+ }
34323
+ if (nodes.length === 0) {
34324
+ nodes.push($createParagraphNode());
34325
+ }
34326
+ return nodes;
34327
+ }
34328
+ function applyMarkdownToNodes(nodes, _editor) {
34329
+ const processTextNode = (node) => {
34330
+ const text = node.getTextContent();
34331
+ const style = node.getStyle();
34332
+ const format = node.getFormat();
34333
+ const markdownPattern = new RegExp("(```([^`]+)```)|(`([^`]+)`)|(\\*\\*(.+?)\\*\\*)|((?<!\\*)\\*([^*]+)\\*(?!\\*))|(~~(.+?)~~)", "g");
34334
+ if (!markdownPattern.test(text)) {
34335
+ return [node];
34336
+ }
34337
+ markdownPattern.lastIndex = 0;
34338
+ const resultNodes = [];
34339
+ let lastIndex = 0;
34340
+ let match;
34341
+ while ((match = markdownPattern.exec(text)) !== null) {
34342
+ if (match.index > lastIndex) {
34343
+ const beforeText = text.slice(lastIndex, match.index);
34344
+ const beforeNode = $createTextNode(beforeText);
34345
+ if (style)
34346
+ beforeNode.setStyle(style);
34347
+ if (format)
34348
+ beforeNode.setFormat(format);
34349
+ resultNodes.push(beforeNode);
34350
+ }
34351
+ let content = "";
34352
+ let nodeFormat = format;
34353
+ if (match[1]) {
34354
+ content = match[2];
34355
+ nodeFormat = format | 16;
34356
+ } else if (match[3]) {
34357
+ content = match[4];
34358
+ nodeFormat = format | 16;
34359
+ } else if (match[5]) {
34360
+ content = match[6];
34361
+ nodeFormat = format | 1;
34362
+ } else if (match[7]) {
34363
+ content = match[8];
34364
+ nodeFormat = format | 2;
34365
+ } else if (match[9]) {
34366
+ content = match[10];
34367
+ nodeFormat = format | 4;
34368
+ }
34369
+ if (content) {
34370
+ const formattedNode = $createTextNode(content);
34371
+ if (style)
34372
+ formattedNode.setStyle(style);
34373
+ formattedNode.setFormat(nodeFormat);
34374
+ resultNodes.push(formattedNode);
34375
+ }
34376
+ lastIndex = match.index + match[0].length;
34377
+ }
34378
+ if (lastIndex < text.length) {
34379
+ const afterText = text.slice(lastIndex);
34380
+ const afterNode = $createTextNode(afterText);
34381
+ if (style)
34382
+ afterNode.setStyle(style);
34383
+ if (format)
34384
+ afterNode.setFormat(format);
34385
+ resultNodes.push(afterNode);
34386
+ }
34387
+ return resultNodes.length > 0 ? resultNodes : [node];
34388
+ };
34389
+ const processNode2 = (node) => {
34390
+ if ($isElementNode(node)) {
34391
+ const children = node.getChildren();
34392
+ for (let i2 = children.length - 1; i2 >= 0; i2--) {
34393
+ const child = children[i2];
34394
+ if ($isTextNode(child)) {
34395
+ const replacementNodes = processTextNode(child);
34396
+ if (replacementNodes.length > 1 || replacementNodes[0] !== child) {
34397
+ for (const newNode of replacementNodes) {
34398
+ child.insertBefore(newNode);
34399
+ }
34400
+ child.remove();
34401
+ }
34402
+ } else if ($isElementNode(child)) {
34403
+ processNode2(child);
34404
+ }
34405
+ }
34406
+ }
34407
+ };
34408
+ nodes.forEach((node) => processNode2(node));
34409
+ return nodes;
34410
+ }
34411
+ function getNodeDOMPosition(editor) {
34412
+ const domSelection = window.getSelection();
34413
+ if (!domSelection || domSelection.rangeCount === 0) {
34414
+ return null;
34415
+ }
34416
+ const range = domSelection.getRangeAt(0);
34417
+ let rect = range.getBoundingClientRect();
34418
+ if (rect.width === 0 && rect.height === 0) {
34419
+ const anchorNode = domSelection.anchorNode;
34420
+ if (anchorNode) {
34421
+ const element = anchorNode.nodeType === Node.TEXT_NODE ? anchorNode.parentElement : anchorNode;
34422
+ if (element) {
34423
+ rect = element.getBoundingClientRect();
34424
+ }
34425
+ }
34426
+ }
34427
+ if (rect.right === 0 && rect.bottom === 0) {
34428
+ const rootElement = editor.getRootElement();
34429
+ if (rootElement) {
34430
+ const rootRect = rootElement.getBoundingClientRect();
34431
+ return {
34432
+ x: rootRect.left + 20,
34433
+ y: Math.min(rootRect.top + 100, window.innerHeight - 150)
34434
+ };
34435
+ }
34436
+ return null;
34437
+ }
34438
+ return {
34439
+ x: rect.right,
34440
+ y: rect.bottom
34441
+ };
34442
+ }
34443
+ function handleHorizontalRulePlaceholders(editor) {
34444
+ editor.update(
34445
+ () => {
34446
+ const root2 = $getRoot();
34447
+ const children = root2.getChildren();
34448
+ for (const child of children) {
34449
+ if ($isParagraphNode(child)) {
34450
+ const textContent = child.getTextContent();
34451
+ if (textContent === "___MARKDOWN_HR___") {
34452
+ editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, void 0);
34453
+ child.remove();
34454
+ }
34455
+ }
34456
+ }
34457
+ },
34458
+ { tag: "paste-options" }
34459
+ );
34460
+ }
34461
+ function PasteOptionsPlugin() {
34462
+ const [editor] = useLexicalComposerContext();
34463
+ const [pasteData, setPasteData] = useState$1(null);
34464
+ const [currentMode, setCurrentMode] = useState$1("rich");
34465
+ const [showMenu, setShowMenu] = useState$1(false);
34466
+ const [menuPosition, setMenuPosition] = useState$1({ x: 0, y: 0 });
34467
+ useEffect$1(() => {
34468
+ if (!showMenu)
34469
+ return;
34470
+ const handleScroll2 = () => {
34471
+ const newPosition = getNodeDOMPosition(editor);
34472
+ if (newPosition) {
34473
+ setMenuPosition(newPosition);
34474
+ setPasteData(
34475
+ (prev) => prev ? { ...prev, position: newPosition } : null
34476
+ );
34477
+ }
34478
+ };
34479
+ window.addEventListener("scroll", handleScroll2, true);
34480
+ return () => window.removeEventListener("scroll", handleScroll2, true);
34481
+ }, [editor, showMenu]);
34482
+ useEffect$1(() => {
34483
+ return editor.registerCommand(
34484
+ KEY_ESCAPE_COMMAND,
34485
+ () => {
34486
+ if (showMenu) {
34487
+ setShowMenu(false);
34488
+ setPasteData(null);
34489
+ return true;
34490
+ }
34491
+ return false;
34492
+ },
34493
+ COMMAND_PRIORITY_CRITICAL
34494
+ );
34495
+ }, [editor, showMenu]);
34496
+ useEffect$1(() => {
34497
+ if (!showMenu)
34498
+ return;
34499
+ const removeListener = editor.registerUpdateListener(
34500
+ ({ tags, dirtyElements, dirtyLeaves }) => {
34501
+ if (!tags.has("paste") && !tags.has("history-merge") && !tags.has("paste-options")) {
34502
+ if (dirtyElements.size > 0 || dirtyLeaves.size > 0) {
34503
+ setShowMenu(false);
34504
+ setPasteData(null);
34505
+ }
34506
+ }
34507
+ }
34508
+ );
34509
+ return removeListener;
34510
+ }, [editor, showMenu]);
34511
+ useEffect$1(() => {
34512
+ const handlePaste = (event) => {
34513
+ const clipboardData = event.clipboardData;
34514
+ if (!clipboardData)
34515
+ return;
34516
+ const html = clipboardData.getData("text/html");
34517
+ const plain = clipboardData.getData("text/plain");
34518
+ if (!html && !plain)
34519
+ return;
34520
+ if (htmlContainsImages(html)) {
34521
+ return;
34522
+ }
34523
+ const isPlainTextPaste = !html && plain;
34524
+ const initialMode = isPlainTextPaste ? "plain" : "rich";
34525
+ setTimeout(() => {
34526
+ editor.getEditorState().read(() => {
34527
+ const selection = $getSelection();
34528
+ if (!$isRangeSelection(selection))
34529
+ return;
34530
+ const position = getNodeDOMPosition(editor);
34531
+ if (!position)
34532
+ return;
34533
+ setPasteData({
34534
+ html,
34535
+ plain,
34536
+ position,
34537
+ initialMode
34538
+ });
34539
+ setCurrentMode(initialMode);
34540
+ setMenuPosition(position);
34541
+ setShowMenu(true);
34542
+ });
34543
+ }, 150);
34544
+ };
34545
+ const rootElement = editor.getRootElement();
34546
+ if (rootElement) {
34547
+ rootElement.addEventListener("paste", handlePaste);
34548
+ return () => rootElement.removeEventListener("paste", handlePaste);
34549
+ }
34550
+ }, [editor]);
34551
+ const handleSelectMode = useCallback(
34552
+ (mode) => {
34553
+ if (!pasteData) {
34554
+ return;
34555
+ }
34556
+ if (mode === currentMode) {
34557
+ setShowMenu(false);
34558
+ setPasteData(null);
34559
+ return;
34560
+ }
34561
+ editor.dispatchCommand(UNDO_COMMAND, void 0);
34562
+ setTimeout(() => {
34563
+ editor.update(
34564
+ () => {
34565
+ const selection = $getSelection();
34566
+ if (!$isRangeSelection(selection))
34567
+ return;
34568
+ let nodes = [];
34569
+ if (mode === "plain") {
34570
+ nodes = convertPlainTextToNodes(pasteData.plain);
34571
+ } else if (mode === "markdown") {
34572
+ if (pasteData.html) {
34573
+ nodes = convertHTMLToNodesWithStyles(pasteData.html, editor);
34574
+ nodes = applyMarkdownToNodes(nodes);
34575
+ } else {
34576
+ nodes = convertMarkdownToNodes(pasteData.plain);
34577
+ }
34578
+ } else if (mode === "rich") {
34579
+ if (pasteData.html) {
34580
+ const parser = new DOMParser();
34581
+ const doc = parser.parseFromString(pasteData.html, "text/html");
34582
+ nodes = $generateNodesFromDOM(editor, doc);
34583
+ } else {
34584
+ nodes = convertPlainTextToNodes(pasteData.plain);
34585
+ }
34586
+ }
34587
+ if (nodes.length > 0) {
34588
+ const filteredNodes = nodes.filter((node) => {
34589
+ const textContent = node.getTextContent();
34590
+ return textContent.trim().length > 0 || node.getType() !== "paragraph";
34591
+ });
34592
+ if (filteredNodes.length > 0) {
34593
+ selection.insertNodes(filteredNodes);
34594
+ } else if (nodes.length > 0) {
34595
+ selection.insertNodes(nodes);
34596
+ }
34597
+ }
34598
+ },
34599
+ { tag: "paste-options" }
34600
+ );
34601
+ if (mode === "markdown") {
34602
+ setTimeout(() => {
34603
+ handleHorizontalRulePlaceholders(editor);
34604
+ }, 50);
34605
+ }
34606
+ }, 50);
34607
+ setCurrentMode(mode);
34608
+ setShowMenu(false);
34609
+ setPasteData(null);
34610
+ },
34611
+ [editor, pasteData, currentMode]
34612
+ );
34613
+ const handleClose = useCallback(() => {
34614
+ setShowMenu(false);
34615
+ setPasteData(null);
34616
+ }, []);
34617
+ if (!showMenu || !pasteData) {
34618
+ return null;
34619
+ }
34620
+ return createPortal(
34621
+ /* @__PURE__ */ jsx(
34622
+ PasteOptionsMenu,
34623
+ {
34624
+ position: menuPosition,
34625
+ currentMode,
34626
+ onSelectMode: handleSelectMode,
34627
+ onClose: handleClose,
34628
+ hasHtml: Boolean(pasteData.html)
34629
+ }
34630
+ ),
34631
+ document.body
34632
+ );
34633
+ }
32911
34634
  function getOptionMeta(label) {
32912
34635
  const lower = label.toLowerCase();
32913
34636
  if (lower.startsWith("paragraph"))
@@ -34542,6 +36265,7 @@ function TableActionMenu({
34542
36265
  },
34543
36266
  [editor, tableCellNode]
34544
36267
  );
36268
+ const menuItemClass = " cteditor-group cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-px-2 cteditor-py-1 cteditor-rounded-sm cteditor-transition-all cteditor-duration-200 cteditor-cursor-pointer cteditor-text-xs hover:cteditor-bg-foreground/10";
34545
36269
  let mergeCellButton = null;
34546
36270
  if (cellMerge) {
34547
36271
  if (canMergeCells) {
@@ -34549,10 +36273,10 @@ function TableActionMenu({
34549
36273
  "button",
34550
36274
  {
34551
36275
  type: "button",
34552
- className: "item",
36276
+ className: menuItemClass,
34553
36277
  onClick: () => mergeTableCellsAtSelection(),
34554
36278
  "data-test-id": "table-merge-cells",
34555
- children: /* @__PURE__ */ jsx("span", { className: "cteditor-text-[11px] cteditor-text-muted-foreground cteditor-font-medium cteditor-tracking-wider cteditor-block cteditor-pb-1", children: "Merge cells" })
36279
+ children: /* @__PURE__ */ jsx("span", { className: "text", children: "Merge cells" })
34556
36280
  }
34557
36281
  );
34558
36282
  } else if (canUnmergeCell) {
@@ -34560,15 +36284,14 @@ function TableActionMenu({
34560
36284
  "button",
34561
36285
  {
34562
36286
  type: "button",
34563
- className: "item",
36287
+ className: menuItemClass,
34564
36288
  onClick: () => unmergeTableCellsAtSelection(),
34565
36289
  "data-test-id": "table-unmerge-cells",
34566
- children: /* @__PURE__ */ jsx("span", { className: "cteditor-text-[11px] cteditor-text-muted-foreground cteditor-font-medium cteditor-tracking-wider cteditor-block cteditor-pb-1", children: "Unmerge cells" })
36290
+ children: /* @__PURE__ */ jsx("span", { className: "text", children: "Unmerge cells" })
34567
36291
  }
34568
36292
  );
34569
36293
  }
34570
36294
  }
34571
- const menuItemClass = " cteditor-group cteditor-flex cteditor-items-center cteditor-gap-1.5 cteditor-px-2 cteditor-py-1 cteditor-rounded-sm cteditor-transition-all cteditor-duration-200 cteditor-cursor-pointer cteditor-text-xs hover:cteditor-bg-foreground/10";
34572
36295
  return createPortal(
34573
36296
  /* @__PURE__ */ jsxs(
34574
36297
  "div",
@@ -37240,9 +38963,57 @@ function processHtmlForExport(html, tableStyleMap, codeBlockStyles) {
37240
38963
  const wrapper = doc.createElement("div");
37241
38964
  wrapper.style.padding = "1em";
37242
38965
  wrapper.style.minHeight = "100%";
38966
+ wrapper.className = "editor-content-wrapper";
38967
+ const styleTag = doc.createElement("style");
38968
+ styleTag.textContent = `
38969
+ /* Responsive image styles - WYSIWYG for mobile */
38970
+ @media screen and (max-width: 768px) {
38971
+ /* Floated images stack on mobile - no text wrap */
38972
+ .image-float-left,
38973
+ .image-float-right,
38974
+ img[style*="float: left"],
38975
+ img[style*="float: right"] {
38976
+ float: none !important;
38977
+ clear: both !important;
38978
+ display: block !important;
38979
+ margin: 1em auto !important;
38980
+ max-width: 100% !important;
38981
+ /* On mobile, allow width to shrink but keep height proportional to width */
38982
+ width: auto !important;
38983
+ height: auto !important;
38984
+ }
38985
+
38986
+ /* Floated image containers (with captions) also stack */
38987
+ .image-float-container,
38988
+ .image-float-container-left,
38989
+ .image-float-container-right,
38990
+ p[style*="float: left"],
38991
+ p[style*="float: right"] {
38992
+ float: none !important;
38993
+ clear: both !important;
38994
+ max-width: 100% !important;
38995
+ margin: 1em 0 !important;
38996
+ }
38997
+
38998
+ /* Clear floats properly */
38999
+ .editor-content-wrapper::after {
39000
+ content: "";
39001
+ display: table;
39002
+ clear: both;
39003
+ }
39004
+ }
39005
+
39006
+ /* Clearfix for floated content */
39007
+ .editor-content-wrapper::after {
39008
+ content: "";
39009
+ display: table;
39010
+ clear: both;
39011
+ }
39012
+ `;
37243
39013
  while (doc.body.firstChild) {
37244
39014
  wrapper.appendChild(doc.body.firstChild);
37245
39015
  }
39016
+ wrapper.insertBefore(styleTag, wrapper.firstChild);
37246
39017
  return wrapper.outerHTML;
37247
39018
  }
37248
39019
  function cleanupHeaderCellStructure(container) {
@@ -37313,12 +39084,21 @@ function applyGenericSafeStyles(container, codeBlockStyles) {
37313
39084
  container.querySelectorAll("img").forEach((img) => {
37314
39085
  const position = img.getAttribute("data-position");
37315
39086
  const parent = img.parentElement;
37316
- img.style.cssText += "; max-width: 100%; height: auto;";
39087
+ const explicitWidth = img.getAttribute("width");
39088
+ const explicitHeight = img.getAttribute("height");
39089
+ const hasExplicitDimensions = explicitWidth && explicitHeight && explicitWidth !== "inherit" && explicitHeight !== "inherit";
39090
+ if (hasExplicitDimensions) {
39091
+ img.style.cssText += `; max-width: 100%; width: ${explicitWidth}px; height: ${explicitHeight}px;`;
39092
+ } else {
39093
+ img.style.cssText += "; max-width: 100%; height: auto;";
39094
+ }
37317
39095
  const hasCaption = parent && parent.tagName.toLowerCase() === "p" && parent.querySelector("em, i");
37318
39096
  if (position === "left" || position === "right") {
37319
39097
  const floatDir = position === "left" ? "left" : "right";
37320
39098
  const marginDir = position === "left" ? "right" : "left";
39099
+ img.classList.add("image-float-" + floatDir);
37321
39100
  if (hasCaption && parent) {
39101
+ parent.classList.add("image-float-container", "image-float-container-" + floatDir);
37322
39102
  parent.style.cssText += `; float: ${floatDir}; clear: ${floatDir}; max-width: 50%; margin-${marginDir}: 1em; margin-bottom: 0.5em; text-align: center; background-color: #f5f5f5; padding: 0.5em; border-radius: 4px;`;
37323
39103
  img.style.cssText += "; display: block; margin: 0 auto;";
37324
39104
  const caption = parent.querySelector("em, i");
@@ -37330,10 +39110,20 @@ function applyGenericSafeStyles(container, codeBlockStyles) {
37330
39110
  }
37331
39111
  } else if (position === "full") {
37332
39112
  img.style.cssText += "; display: block; width: 100%; margin: 1em 0;";
39113
+ } else if (position === "inline-left") {
39114
+ img.classList.add("image-inline-left");
39115
+ img.style.cssText += "; display: block; margin: 1em 0; text-align: left;";
39116
+ } else if (position === "inline-center") {
39117
+ img.classList.add("image-inline-center");
39118
+ img.style.cssText += "; display: block; margin: 1em auto;";
39119
+ } else if (position === "inline-right") {
39120
+ img.classList.add("image-inline-right");
39121
+ img.style.cssText += "; display: block; margin: 1em 0 1em auto;";
37333
39122
  } else {
37334
- img.style.cssText += "; display: block;";
39123
+ img.style.cssText += "; display: inline-block; vertical-align: middle;";
37335
39124
  if (parent && parent.style.textAlign === "center") {
37336
39125
  img.style.margin = "0 auto";
39126
+ img.style.display = "block";
37337
39127
  }
37338
39128
  }
37339
39129
  img.removeAttribute("data-position");
@@ -37685,24 +39475,52 @@ function preprocessInitialContent(html) {
37685
39475
  });
37686
39476
  const images = doc.querySelectorAll("img");
37687
39477
  images.forEach((img) => {
39478
+ const htmlImg = img;
37688
39479
  const parent = img.parentElement;
37689
39480
  if (!parent)
37690
39481
  return;
37691
- const imgFloat = img.style.float;
37692
- const parentFloat = parent.style.float;
37693
- const floatDir = imgFloat || parentFloat;
37694
- if (floatDir === "left" || floatDir === "right") {
37695
- img.setAttribute("data-position", floatDir);
37696
- if (parentFloat && parent.tagName.toLowerCase() === "p") {
37697
- parent.style.textAlign = floatDir;
37698
- parent.style.removeProperty("float");
37699
- parent.style.removeProperty("clear");
37700
- parent.style.removeProperty("max-width");
37701
- parent.style.removeProperty("background-color");
37702
- parent.style.removeProperty("padding");
37703
- parent.style.removeProperty("border-radius");
39482
+ if (htmlImg.classList.contains("image-inline-left")) {
39483
+ img.setAttribute("data-position", "inline-left");
39484
+ htmlImg.classList.remove("image-inline-left");
39485
+ } else if (htmlImg.classList.contains("image-inline-center")) {
39486
+ img.setAttribute("data-position", "inline-center");
39487
+ htmlImg.classList.remove("image-inline-center");
39488
+ } else if (htmlImg.classList.contains("image-inline-right")) {
39489
+ img.setAttribute("data-position", "inline-right");
39490
+ htmlImg.classList.remove("image-inline-right");
39491
+ } else if (htmlImg.classList.contains("image-float-left")) {
39492
+ img.setAttribute("data-position", "left");
39493
+ htmlImg.classList.remove("image-float-left");
39494
+ } else if (htmlImg.classList.contains("image-float-right")) {
39495
+ img.setAttribute("data-position", "right");
39496
+ htmlImg.classList.remove("image-float-right");
39497
+ } else {
39498
+ const imgFloat = htmlImg.style.float;
39499
+ const parentFloat = parent.style.float;
39500
+ const floatDir = imgFloat || parentFloat;
39501
+ if (floatDir === "left" || floatDir === "right") {
39502
+ img.setAttribute("data-position", floatDir);
39503
+ if (parentFloat && parent.tagName.toLowerCase() === "p") {
39504
+ parent.style.textAlign = floatDir;
39505
+ parent.style.removeProperty("float");
39506
+ parent.style.removeProperty("clear");
39507
+ parent.style.removeProperty("max-width");
39508
+ parent.style.removeProperty("background-color");
39509
+ parent.style.removeProperty("padding");
39510
+ parent.style.removeProperty("border-radius");
39511
+ }
39512
+ } else {
39513
+ const margin = htmlImg.style.margin;
39514
+ if (margin === "1em auto" || htmlImg.style.marginLeft === "auto" && htmlImg.style.marginRight === "auto") {
39515
+ img.setAttribute("data-position", "inline-center");
39516
+ } else if (htmlImg.style.marginLeft === "auto" && htmlImg.style.marginRight !== "auto") {
39517
+ img.setAttribute("data-position", "inline-right");
39518
+ }
37704
39519
  }
37705
39520
  }
39521
+ if (parent.classList.contains("image-float-container")) {
39522
+ parent.classList.remove("image-float-container", "image-float-container-left", "image-float-container-right");
39523
+ }
37706
39524
  });
37707
39525
  const styledElements = doc.querySelectorAll("span[style], b[style], strong[style], i[style], em[style]");
37708
39526
  styledElements.forEach((el) => {
@@ -38382,6 +40200,7 @@ const ConfigurableEditor = ({
38382
40200
  /* @__PURE__ */ jsx(CodeBlockNormalizerPlugin, {}),
38383
40201
  /* @__PURE__ */ jsx(CodeBlockSelectAllPlugin, {}),
38384
40202
  /* @__PURE__ */ jsx(SlashCommandPlugin, {}),
40203
+ /* @__PURE__ */ jsx(MarkdownShortcutsPlugin, {}),
38385
40204
  /* @__PURE__ */ jsx(CombinedPluginWrapper, {}),
38386
40205
  /* @__PURE__ */ jsx(OnChangeWrapper, { onChange }),
38387
40206
  /* @__PURE__ */ jsx(InitialContentPlugin, { initialContent }),
@@ -38392,6 +40211,7 @@ const ConfigurableEditor = ({
38392
40211
  /* @__PURE__ */ jsx(LinkPreviewPlugin, {}),
38393
40212
  /* @__PURE__ */ jsx(DragDropPaste, {}),
38394
40213
  /* @__PURE__ */ jsx(RichTextPastePlugin, {}),
40214
+ /* @__PURE__ */ jsx(PasteOptionsPlugin, {}),
38395
40215
  /* @__PURE__ */ jsx(FilePlugin, {}),
38396
40216
  /* @__PURE__ */ jsx(HorizontalRulePlugin, {}),
38397
40217
  /* @__PURE__ */ jsx(CustomHorizontalRulePlugin, {}),
@@ -38580,11 +40400,12 @@ const ConfigurableEditorWithAuth = ({
38580
40400
  };
38581
40401
  export {
38582
40402
  $isFileNode as $,
38583
- AiJsonResponse as A,
40403
+ AlignLeft as A,
38584
40404
  Button as B,
38585
40405
  ConfigurableEditorWithAuth as C,
38586
40406
  Download as D,
38587
40407
  ExternalLink as E,
40408
+ FileText as F,
38588
40409
  HtmlViewProvider as H,
38589
40410
  LocalStoragePlugin$1 as L,
38590
40411
  Sparkles as S,
@@ -38600,12 +40421,16 @@ export {
38600
40421
  DialogFooter as i,
38601
40422
  initialConfig as j,
38602
40423
  $isImageNode as k,
38603
- EditorProvider as l,
38604
- useEditor as m,
38605
- ConfigurableEditor as n,
38606
- editorConfig as o,
40424
+ AlignCenter as l,
40425
+ AlignRight as m,
40426
+ Type as n,
40427
+ AiJsonResponse as o,
40428
+ EditorProvider as p,
40429
+ useEditor as q,
40430
+ ConfigurableEditor as r,
40431
+ editorConfig as s,
38607
40432
  toast as t,
38608
40433
  useHtmlView as u,
38609
40434
  verifyApiKey as v
38610
40435
  };
38611
- //# sourceMappingURL=index-a2107b7c.js.map
40436
+ //# sourceMappingURL=index-0533674e.js.map