ct-rich-text-editor 1.3.18 → 1.3.20

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,14 +24,14 @@ 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, $setSelection, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, UNDO_COMMAND, REDO_COMMAND, $createRangeSelection, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, getDOMSelection, CLICK_COMMAND, COMMAND_PRIORITY_HIGH, $isLineBreakNode, PASTE_COMMAND, isDOMNode } from "lexical";
27
+ import { createCommand, DecoratorNode, createEditor, $applyNodeReplacement, $insertNodes, $isRootOrShadowRoot, $createParagraphNode, COMMAND_PRIORITY_EDITOR, COMMAND_PRIORITY_LOW, $getSelection, $isRangeSelection, $getNearestNodeFromDOMNode, $setSelection, isHTMLElement as isHTMLElement$1, TextNode, $getRoot, $createTextNode, $getNodeByKey, $isParagraphNode, $isTextNode, FORMAT_TEXT_COMMAND, FORMAT_ELEMENT_COMMAND, KEY_DOWN_COMMAND, COMMAND_PRIORITY_CRITICAL, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $isElementNode, SELECTION_CHANGE_COMMAND, UNDO_COMMAND, REDO_COMMAND, $createRangeSelection, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE_COMMAND, KEY_TAB_COMMAND, KEY_ENTER_COMMAND, $createNodeSelection, $isNodeSelection, getDOMSelection, CLICK_COMMAND, COMMAND_PRIORITY_HIGH, $isLineBreakNode, PASTE_COMMAND, 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
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";
33
33
  import { HeadingNode, QuoteNode, $isHeadingNode, $createHeadingNode, $createQuoteNode, DRAG_DROP_PASTE } from "@lexical/rich-text";
34
- import { $isAtNodeEnd, $selectAll, $patchStyleText, $setBlocksType, $isParentElementRTL, $getSelectionStyleValueForProperty } from "@lexical/selection";
34
+ import { $isAtNodeEnd, $selectAll, $patchStyleText, $setBlocksType, $getSelectionStyleValueForProperty, $isParentElementRTL } from "@lexical/selection";
35
35
  import { HorizontalRuleNode } from "@lexical/react/LexicalHorizontalRuleNode";
36
36
  import DescriptionIcon from "@mui/icons-material/Description";
37
37
  import FolderZipIcon from "@mui/icons-material/FolderZip";
@@ -40,15 +40,7 @@ import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
40
40
  import PictureAsPdfIcon from "@mui/icons-material/PictureAsPdf";
41
41
  import { $isDecoratorBlockNode } from "@lexical/react/LexicalDecoratorBlockNode";
42
42
  import EmojiPicker from "emoji-picker-react";
43
- import CodeIcon$1 from "@mui/icons-material/Code";
44
- import ContentCopyIcon from "@mui/icons-material/ContentCopy";
45
- import CropOriginalIcon from "@mui/icons-material/CropOriginal";
46
- import DeleteIcon from "@mui/icons-material/Delete";
47
- import FormatAlignCenterIcon from "@mui/icons-material/FormatAlignCenter";
48
- import FormatAlignLeftIcon from "@mui/icons-material/FormatAlignLeft";
49
- import FormatAlignRightIcon from "@mui/icons-material/FormatAlignRight";
50
- import LinkIcon$1 from "@mui/icons-material/Link";
51
- import OpenInNewIcon from "@mui/icons-material/OpenInNew";
43
+ import { Link as Link$1, CropOriginal, Code as Code$1, FormatAlignLeft, FormatAlignCenter, FormatAlignRight, OpenInNew, Delete, ContentCopy } from "@mui/icons-material";
52
44
  import { LinkPlugin as LinkPlugin$1 } from "@lexical/react/LexicalLinkPlugin";
53
45
  import { useBasicTypeaheadTriggerMatch, LexicalTypeaheadMenuPlugin, MenuOption } from "@lexical/react/LexicalTypeaheadMenuPlugin";
54
46
  import { useLexicalEditable } from "@lexical/react/useLexicalEditable";
@@ -1479,7 +1471,7 @@ const AiTextTransform = async ({ content, apiKey }) => {
1479
1471
  const AI_ACTION_COMMAND = createCommand(
1480
1472
  "AI_ACTION_COMMAND"
1481
1473
  );
1482
- const ImageView = React__default.lazy(() => import("./index-2bc5ccbc.js"));
1474
+ const ImageView = React__default.lazy(() => import("./index-d1931d92.js"));
1483
1475
  function isGoogleDocCheckboxImg(img) {
1484
1476
  return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
1485
1477
  }
@@ -1489,11 +1481,16 @@ function $convertImageElement(domNode) {
1489
1481
  return null;
1490
1482
  }
1491
1483
  const { alt: altText, src, width, height } = img;
1492
- const node = $createImageNode({ altText, height, src, width });
1484
+ const positionAttr = img.getAttribute("data-position");
1485
+ let position = "none";
1486
+ if (positionAttr === "left" || positionAttr === "right" || positionAttr === "full") {
1487
+ position = positionAttr;
1488
+ }
1489
+ const node = $createImageNode({ altText, height, src, width, position });
1493
1490
  return { node };
1494
1491
  }
1495
1492
  class ImageNode extends DecoratorNode {
1496
- constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, key) {
1493
+ constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, position, key) {
1497
1494
  super(key);
1498
1495
  __publicField(this, "__src");
1499
1496
  __publicField(this, "__altText");
@@ -1505,6 +1502,7 @@ class ImageNode extends DecoratorNode {
1505
1502
  // Captions cannot yet be used within editor cells
1506
1503
  __publicField(this, "__captionsEnabled");
1507
1504
  __publicField(this, "__originalPrompt");
1505
+ __publicField(this, "__position");
1508
1506
  this.__src = src;
1509
1507
  this.__altText = altText;
1510
1508
  this.__maxWidth = maxWidth;
@@ -1516,6 +1514,7 @@ class ImageNode extends DecoratorNode {
1516
1514
  });
1517
1515
  this.__captionsEnabled = captionsEnabled || captionsEnabled === void 0;
1518
1516
  this.__originalPrompt = originalPrompt || "";
1517
+ this.__position = position || "none";
1519
1518
  }
1520
1519
  // to identify the image node and must unique too
1521
1520
  static getType() {
@@ -1533,12 +1532,13 @@ class ImageNode extends DecoratorNode {
1533
1532
  node.__caption,
1534
1533
  node.__captionsEnabled,
1535
1534
  node.__originalPrompt,
1535
+ node.__position,
1536
1536
  node.__key
1537
1537
  );
1538
1538
  }
1539
1539
  // importing to json format
1540
1540
  static importJSON(serializedNode) {
1541
- const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt } = serializedNode;
1541
+ const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt, position } = serializedNode;
1542
1542
  const node = $createImageNode({
1543
1543
  altText,
1544
1544
  height,
@@ -1546,8 +1546,9 @@ class ImageNode extends DecoratorNode {
1546
1546
  showCaption,
1547
1547
  src,
1548
1548
  width,
1549
- originalPrompt: originalPrompt || ""
1549
+ originalPrompt: originalPrompt || "",
1550
1550
  // Default to empty string if undefined
1551
+ position: position || "none"
1551
1552
  });
1552
1553
  const nestedEditor = node.__caption;
1553
1554
  const editorState = nestedEditor.parseEditorState(caption.editorState);
@@ -1558,12 +1559,15 @@ class ImageNode extends DecoratorNode {
1558
1559
  }
1559
1560
  // Exports this node as an actual <img> tag in the DOM when needed
1560
1561
  exportDOM() {
1561
- const element = document.createElement("img");
1562
- element.setAttribute("src", this.__src);
1563
- element.setAttribute("alt", this.__altText);
1564
- element.setAttribute("width", this.__width.toString());
1565
- element.setAttribute("height", this.__height.toString());
1566
- return { element };
1562
+ const img = document.createElement("img");
1563
+ img.setAttribute("src", this.__src);
1564
+ img.setAttribute("alt", this.__altText);
1565
+ img.setAttribute("width", this.__width.toString());
1566
+ img.setAttribute("height", this.__height.toString());
1567
+ if (this.__position && this.__position !== "none") {
1568
+ img.setAttribute("data-position", this.__position);
1569
+ }
1570
+ return { element: img };
1567
1571
  }
1568
1572
  // convert img tag into image node in the editor using convertImageElement func
1569
1573
  static importDOM() {
@@ -1585,7 +1589,8 @@ class ImageNode extends DecoratorNode {
1585
1589
  type: "image",
1586
1590
  version: 1,
1587
1591
  width: this.__width === "inherit" ? 0 : this.__width,
1588
- originalPrompt: this.__originalPrompt
1592
+ originalPrompt: this.__originalPrompt,
1593
+ position: this.__position
1589
1594
  };
1590
1595
  }
1591
1596
  // setting width and height when resizing
@@ -1607,9 +1612,26 @@ class ImageNode extends DecoratorNode {
1607
1612
  if (className !== void 0) {
1608
1613
  span.className = className;
1609
1614
  }
1615
+ if (this.__position === "left") {
1616
+ span.style.cssText = "float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1617
+ } else if (this.__position === "right") {
1618
+ span.style.cssText = "float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1619
+ } else if (this.__position === "full") {
1620
+ span.style.cssText = "display: block; width: 100%; margin: 1em 0;";
1621
+ }
1610
1622
  return span;
1611
1623
  }
1612
- updateDOM() {
1624
+ updateDOM(prevNode, dom) {
1625
+ if (prevNode.__position !== this.__position) {
1626
+ dom.style.cssText = "";
1627
+ if (this.__position === "left") {
1628
+ dom.style.cssText = "float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1629
+ } else if (this.__position === "right") {
1630
+ dom.style.cssText = "float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1631
+ } else if (this.__position === "full") {
1632
+ dom.style.cssText = "display: block; width: 100%; margin: 1em 0;";
1633
+ }
1634
+ }
1613
1635
  return false;
1614
1636
  }
1615
1637
  // to get the image src
@@ -1633,6 +1655,15 @@ class ImageNode extends DecoratorNode {
1633
1655
  const writable = this.getWritable();
1634
1656
  writable.__originalPrompt = prompt;
1635
1657
  }
1658
+ // to get the image position (float)
1659
+ getPosition() {
1660
+ return this.__position;
1661
+ }
1662
+ // to set the image position (float)
1663
+ setPosition(position) {
1664
+ const writable = this.getWritable();
1665
+ writable.__position = position;
1666
+ }
1636
1667
  // to render the image tag
1637
1668
  decorate() {
1638
1669
  return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
@@ -1648,7 +1679,8 @@ class ImageNode extends DecoratorNode {
1648
1679
  caption: this.__caption,
1649
1680
  captionsEnabled: this.__captionsEnabled,
1650
1681
  resizable: true,
1651
- originalPrompt: this.__originalPrompt
1682
+ originalPrompt: this.__originalPrompt,
1683
+ position: this.__position
1652
1684
  }
1653
1685
  ) });
1654
1686
  }
@@ -1663,7 +1695,8 @@ function $createImageNode({
1663
1695
  showCaption,
1664
1696
  caption,
1665
1697
  key,
1666
- originalPrompt
1698
+ originalPrompt,
1699
+ position
1667
1700
  }) {
1668
1701
  return $applyNodeReplacement(
1669
1702
  new ImageNode(
@@ -1676,6 +1709,7 @@ function $createImageNode({
1676
1709
  caption,
1677
1710
  captionsEnabled,
1678
1711
  originalPrompt,
1712
+ position,
1679
1713
  key
1680
1714
  )
1681
1715
  );
@@ -7551,6 +7585,17 @@ const Minimize2 = createLucideIcon("Minimize2", [
7551
7585
  * See the LICENSE file in the root directory of this source tree.
7552
7586
  */
7553
7587
  const Minus = createLucideIcon("Minus", [["path", { d: "M5 12h14", key: "1ays0h" }]]);
7588
+ /**
7589
+ * @license lucide-react v0.344.0 - ISC
7590
+ *
7591
+ * This source code is licensed under the ISC license.
7592
+ * See the LICENSE file in the root directory of this source tree.
7593
+ */
7594
+ const PanelBottomOpen = createLucideIcon("PanelBottomOpen", [
7595
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
7596
+ ["path", { d: "M3 15h18", key: "5xshup" }],
7597
+ ["path", { d: "m9 10 3-3 3 3", key: "11gsxs" }]
7598
+ ]);
7554
7599
  /**
7555
7600
  * @license lucide-react v0.344.0 - ISC
7556
7601
  *
@@ -7660,6 +7705,16 @@ const Search = createLucideIcon("Search", [
7660
7705
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
7661
7706
  ["path", { d: "m21 21-4.3-4.3", key: "1qie3q" }]
7662
7707
  ]);
7708
+ /**
7709
+ * @license lucide-react v0.344.0 - ISC
7710
+ *
7711
+ * This source code is licensed under the ISC license.
7712
+ * See the LICENSE file in the root directory of this source tree.
7713
+ */
7714
+ const Send = createLucideIcon("Send", [
7715
+ ["path", { d: "m22 2-7 20-4-9-9-4Z", key: "1q3vgg" }],
7716
+ ["path", { d: "M22 2 11 13", key: "nzbqef" }]
7717
+ ]);
7663
7718
  /**
7664
7719
  * @license lucide-react v0.344.0 - ISC
7665
7720
  *
@@ -15282,7 +15337,7 @@ const EmbedComponent = ({ url, displayType, alignment, nodeKey }) => {
15282
15337
  }
15283
15338
  );
15284
15339
  };
15285
- const FileComponent = React$1.lazy(() => import("./index-7ddd4fcc.js"));
15340
+ const FileComponent = React$1.lazy(() => import("./index-9505418d.js"));
15286
15341
  function convertFileElement(domNode) {
15287
15342
  if (domNode instanceof HTMLDivElement) {
15288
15343
  const dataUrl = domNode.getAttribute("data-lexical-file-src");
@@ -18577,7 +18632,7 @@ const formatMenuItems = [
18577
18632
  }
18578
18633
  ];
18579
18634
  const LOWEST_PRIORITY = 1;
18580
- const DEFAULT_FONT_SIZE = 15;
18635
+ const DEFAULT_FONT_SIZE$1 = 15;
18581
18636
  const INITIAL_TOOLBAR_STATE = {
18582
18637
  bgColor: "#fff",
18583
18638
  blockType: "paragraph",
@@ -18588,9 +18643,9 @@ const INITIAL_TOOLBAR_STATE = {
18588
18643
  fontColor: "#000",
18589
18644
  fontFamily: "Arial",
18590
18645
  // Current font size in px
18591
- fontSize: `${DEFAULT_FONT_SIZE}px`,
18646
+ fontSize: `${DEFAULT_FONT_SIZE$1}px`,
18592
18647
  // Font size input value - for controlled input
18593
- fontSizeInputValue: `${DEFAULT_FONT_SIZE}`,
18648
+ fontSizeInputValue: `${DEFAULT_FONT_SIZE$1}`,
18594
18649
  isBold: false,
18595
18650
  isCode: false,
18596
18651
  isHighlight: false,
@@ -19061,12 +19116,15 @@ const useVoiceToText = ({ onTranscriptUpdate }) => {
19061
19116
  };
19062
19117
  };
19063
19118
  const TOGGLE_AI_CHAT_COMMAND = createCommand();
19119
+ const SHOW_INLINE_AI_PROMPT_COMMAND = createCommand();
19064
19120
  function AIChatDialog({
19065
19121
  open,
19066
19122
  onOpenChange,
19067
19123
  editor,
19068
19124
  apiKey,
19069
- initialText
19125
+ initialText,
19126
+ onShowInEditor,
19127
+ selectedTextForInline
19070
19128
  }) {
19071
19129
  const [inputValue, setInputValue] = useState$1("");
19072
19130
  const [isLoading, setIsLoading] = useState$1(false);
@@ -19330,6 +19388,24 @@ function AIChatDialog({
19330
19388
  children: "Cancel"
19331
19389
  }
19332
19390
  ),
19391
+ /* @__PURE__ */ jsxs(
19392
+ Button,
19393
+ {
19394
+ variant: "outline",
19395
+ onClick: () => {
19396
+ if (onShowInEditor) {
19397
+ onShowInEditor(provider, selectedTextForInline);
19398
+ handleClose();
19399
+ }
19400
+ },
19401
+ disabled: isLoading,
19402
+ title: "Show AI prompt in the editor text area",
19403
+ children: [
19404
+ /* @__PURE__ */ jsx(PanelBottomOpen, { size: 16 }),
19405
+ "Show in Editor"
19406
+ ]
19407
+ }
19408
+ ),
19333
19409
  /* @__PURE__ */ jsx(
19334
19410
  Button,
19335
19411
  {
@@ -19347,10 +19423,257 @@ function AIChatDialog({
19347
19423
  ] })
19348
19424
  ] }) }) });
19349
19425
  }
19350
- function useAIChatToolbar(editor, apiKey) {
19426
+ function InlineAIPrompt({
19427
+ editor,
19428
+ apiKey,
19429
+ initialProvider,
19430
+ selectedText: initialSelectedText,
19431
+ onClose,
19432
+ anchorElem
19433
+ }) {
19434
+ const [provider, setProvider] = useState$1(initialProvider);
19435
+ const [inputValue, setInputValue] = useState$1("");
19436
+ const [isLoading, setIsLoading] = useState$1(false);
19437
+ const inputRef = useRef(null);
19438
+ const [selectedText, setSelectedText] = useState$1(initialSelectedText);
19439
+ useEffect$1(() => {
19440
+ const unregister = editor.registerUpdateListener(({ editorState }) => {
19441
+ editorState.read(() => {
19442
+ const selection = $getSelection();
19443
+ if (selection && selection.getTextContent().trim()) {
19444
+ const newSelectedText = selection.getTextContent();
19445
+ if (newSelectedText.trim() !== "") {
19446
+ setSelectedText(newSelectedText);
19447
+ }
19448
+ }
19449
+ });
19450
+ });
19451
+ return () => {
19452
+ unregister();
19453
+ };
19454
+ }, [editor]);
19455
+ useEffect$1(() => {
19456
+ if (inputRef.current) {
19457
+ inputRef.current.focus();
19458
+ }
19459
+ }, []);
19460
+ const handleSubmit = async () => {
19461
+ var _a, _b;
19462
+ if (!inputValue.trim() || isLoading)
19463
+ return;
19464
+ if (!selectedText || selectedText.trim() === "") {
19465
+ toast.error("Please select some text first");
19466
+ return;
19467
+ }
19468
+ setIsLoading(true);
19469
+ const fullPrompt = `${inputValue}
19470
+
19471
+ 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.
19472
+
19473
+ Text to transform:
19474
+ "${selectedText}"`;
19475
+ try {
19476
+ const response = await AiEditorAction({ content: fullPrompt, provider, apiKey });
19477
+ let htmlString = response.data;
19478
+ if (typeof htmlString === "string") {
19479
+ htmlString = htmlString.trim();
19480
+ if (htmlString.startsWith('"') && htmlString.endsWith('"') || htmlString.startsWith("'") && htmlString.endsWith("'")) {
19481
+ htmlString = htmlString.slice(1, -1);
19482
+ }
19483
+ }
19484
+ editor.update(() => {
19485
+ const parser = new DOMParser();
19486
+ const dom = parser.parseFromString(htmlString.trim(), "text/html");
19487
+ const nodes = $generateNodesFromDOM(editor, dom);
19488
+ const currentSelection = $getSelection();
19489
+ if (currentSelection) {
19490
+ $insertNodes(nodes);
19491
+ }
19492
+ });
19493
+ setInputValue("");
19494
+ setSelectedText("");
19495
+ } catch (error) {
19496
+ console.error("Error processing AI action:", error);
19497
+ const apiMessage = ((_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message) ?? (error instanceof Error ? error.message : null);
19498
+ const safeMessage = apiMessage && !/^Request failed with status code \d+/.test(apiMessage) ? apiMessage : "Error processing your request. Please try again.";
19499
+ toast.error(safeMessage);
19500
+ } finally {
19501
+ setIsLoading(false);
19502
+ }
19503
+ };
19504
+ const handleKeyDown = (e) => {
19505
+ if (e.key === "Enter" && !e.shiftKey && !isLoading && inputValue.trim()) {
19506
+ e.preventDefault();
19507
+ handleSubmit();
19508
+ }
19509
+ if (e.key === "Escape") {
19510
+ onClose();
19511
+ }
19512
+ };
19513
+ const hasSelectedText = selectedText && selectedText.trim() !== "";
19514
+ const displayText = hasSelectedText ? selectedText.length > 50 ? selectedText.substring(0, 50) + "..." : selectedText : "";
19515
+ return /* @__PURE__ */ jsxs(
19516
+ "div",
19517
+ {
19518
+ style: {
19519
+ position: "absolute",
19520
+ bottom: "12px",
19521
+ left: "50%",
19522
+ transform: "translateX(-50%)",
19523
+ display: "flex",
19524
+ flexDirection: "column",
19525
+ gap: "8px",
19526
+ backgroundColor: "#1a1a1a",
19527
+ padding: "12px 16px",
19528
+ borderRadius: "12px",
19529
+ border: "1px solid #333",
19530
+ boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
19531
+ zIndex: 10,
19532
+ maxWidth: "500px"
19533
+ },
19534
+ children: [
19535
+ /* @__PURE__ */ jsx(
19536
+ "div",
19537
+ {
19538
+ style: {
19539
+ display: "flex",
19540
+ alignItems: "center",
19541
+ gap: "8px",
19542
+ padding: "6px 10px",
19543
+ backgroundColor: hasSelectedText ? "#2a2a2a" : "#3a2a2a",
19544
+ borderRadius: "6px",
19545
+ fontSize: "12px",
19546
+ color: "#999",
19547
+ border: hasSelectedText ? "none" : "1px solid #5a3a3a"
19548
+ },
19549
+ children: hasSelectedText ? /* @__PURE__ */ jsxs(Fragment, { children: [
19550
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: "Selected:" }),
19551
+ /* @__PURE__ */ jsxs("span", { style: { color: "#ccc", fontStyle: "italic" }, children: [
19552
+ '"',
19553
+ displayText,
19554
+ '"'
19555
+ ] })
19556
+ ] }) : /* @__PURE__ */ jsx("span", { style: { color: "#f87171" }, children: "⚠ Please select some text in the editor first" })
19557
+ }
19558
+ ),
19559
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [
19560
+ /* @__PURE__ */ jsx(Sparkles, { size: 16, style: { color: "#fff", flexShrink: 0 } }),
19561
+ /* @__PURE__ */ jsxs(
19562
+ "select",
19563
+ {
19564
+ value: provider,
19565
+ onChange: (e) => setProvider(e.target.value),
19566
+ style: {
19567
+ width: "100px",
19568
+ height: "32px",
19569
+ padding: "0 8px",
19570
+ fontSize: "13px",
19571
+ fontWeight: 500,
19572
+ border: "1px solid #444",
19573
+ borderRadius: "6px",
19574
+ outline: "none",
19575
+ backgroundColor: "#2a2a2a",
19576
+ color: "#fff",
19577
+ cursor: "pointer"
19578
+ },
19579
+ children: [
19580
+ /* @__PURE__ */ jsx("option", { value: "chatgpt", children: "ChatGPT" }),
19581
+ /* @__PURE__ */ jsx("option", { value: "claude", children: "Claude" }),
19582
+ /* @__PURE__ */ jsx("option", { value: "grok", children: "Grok" })
19583
+ ]
19584
+ }
19585
+ ),
19586
+ /* @__PURE__ */ jsx(
19587
+ "input",
19588
+ {
19589
+ ref: inputRef,
19590
+ type: "text",
19591
+ value: inputValue,
19592
+ onChange: (e) => setInputValue(e.target.value),
19593
+ onKeyDown: handleKeyDown,
19594
+ placeholder: hasSelectedText ? "What do you want to do with this text?" : "Select text first...",
19595
+ disabled: isLoading,
19596
+ style: {
19597
+ width: "280px",
19598
+ height: "32px",
19599
+ padding: "0 12px",
19600
+ fontSize: "13px",
19601
+ border: "1px solid #444",
19602
+ borderRadius: "6px",
19603
+ outline: "none",
19604
+ backgroundColor: "#2a2a2a",
19605
+ color: "#fff"
19606
+ }
19607
+ }
19608
+ ),
19609
+ /* @__PURE__ */ jsx(
19610
+ "button",
19611
+ {
19612
+ type: "button",
19613
+ onClick: handleSubmit,
19614
+ disabled: isLoading || !inputValue.trim(),
19615
+ style: {
19616
+ height: "32px",
19617
+ width: "32px",
19618
+ backgroundColor: "#fff",
19619
+ color: "#1a1a1a",
19620
+ borderRadius: "6px",
19621
+ border: "none",
19622
+ display: "flex",
19623
+ alignItems: "center",
19624
+ justifyContent: "center",
19625
+ cursor: isLoading || !inputValue.trim() ? "not-allowed" : "pointer",
19626
+ opacity: isLoading || !inputValue.trim() ? 0.5 : 1,
19627
+ flexShrink: 0,
19628
+ transition: "background-color 0.2s"
19629
+ },
19630
+ children: isLoading ? /* @__PURE__ */ jsx("div", { style: {
19631
+ height: "14px",
19632
+ width: "14px",
19633
+ border: "2px solid #1a1a1a",
19634
+ borderTopColor: "transparent",
19635
+ borderRadius: "50%",
19636
+ animation: "spin 1s linear infinite"
19637
+ } }) : /* @__PURE__ */ jsx(Send, { size: 14 })
19638
+ }
19639
+ ),
19640
+ /* @__PURE__ */ jsx(
19641
+ "button",
19642
+ {
19643
+ type: "button",
19644
+ onClick: onClose,
19645
+ style: {
19646
+ height: "32px",
19647
+ width: "32px",
19648
+ backgroundColor: "transparent",
19649
+ color: "#888",
19650
+ borderRadius: "6px",
19651
+ border: "none",
19652
+ display: "flex",
19653
+ alignItems: "center",
19654
+ justifyContent: "center",
19655
+ cursor: "pointer",
19656
+ flexShrink: 0,
19657
+ transition: "color 0.2s"
19658
+ },
19659
+ title: "Close (Esc)",
19660
+ onMouseEnter: (e) => e.currentTarget.style.color = "#fff",
19661
+ onMouseLeave: (e) => e.currentTarget.style.color = "#888",
19662
+ children: /* @__PURE__ */ jsx(X$1, { size: 16 })
19663
+ }
19664
+ )
19665
+ ] })
19666
+ ]
19667
+ }
19668
+ );
19669
+ }
19670
+ function useAIChatToolbar(editor, apiKey, anchorElem) {
19351
19671
  const [isVisible, setIsVisible] = useState$1(false);
19352
19672
  const [selectedText, setSelectedText] = useState$1(void 0);
19353
19673
  const savedSelectionRef = useRef(null);
19674
+ const [showInlinePrompt, setShowInlinePrompt] = useState$1(false);
19675
+ const [inlineProvider, setInlineProvider] = useState$1("chatgpt");
19676
+ const [inlineSelectedText, setInlineSelectedText] = useState$1("");
19354
19677
  const toggleAIChat = useCallback((text) => {
19355
19678
  editor.getEditorState().read(() => {
19356
19679
  const selection = $getSelection();
@@ -19361,8 +19684,17 @@ function useAIChatToolbar(editor, apiKey) {
19361
19684
  setSelectedText(text);
19362
19685
  setIsVisible((prevState) => !prevState);
19363
19686
  }, [editor]);
19687
+ const handleShowInEditor = useCallback((provider, textFromDialog) => {
19688
+ setInlineProvider(provider);
19689
+ setInlineSelectedText(textFromDialog || selectedText || "");
19690
+ setShowInlinePrompt(true);
19691
+ }, [selectedText]);
19692
+ const handleCloseInlinePrompt = useCallback(() => {
19693
+ setShowInlinePrompt(false);
19694
+ setInlineSelectedText("");
19695
+ }, []);
19364
19696
  useEffect$1(() => {
19365
- return editor.registerCommand(
19697
+ const unregisterToggle = editor.registerCommand(
19366
19698
  TOGGLE_AI_CHAT_COMMAND,
19367
19699
  (text) => {
19368
19700
  toggleAIChat(text);
@@ -19370,18 +19702,55 @@ function useAIChatToolbar(editor, apiKey) {
19370
19702
  },
19371
19703
  COMMAND_PRIORITY_LOW
19372
19704
  );
19705
+ const unregisterInline = editor.registerCommand(
19706
+ SHOW_INLINE_AI_PROMPT_COMMAND,
19707
+ (payload) => {
19708
+ let currentSelectedText = "";
19709
+ editor.getEditorState().read(() => {
19710
+ const selection = $getSelection();
19711
+ if (selection) {
19712
+ currentSelectedText = selection.getTextContent();
19713
+ }
19714
+ });
19715
+ setInlineProvider((payload == null ? void 0 : payload.provider) || "chatgpt");
19716
+ setInlineSelectedText((payload == null ? void 0 : payload.initialText) || currentSelectedText);
19717
+ setShowInlinePrompt(true);
19718
+ return true;
19719
+ },
19720
+ COMMAND_PRIORITY_LOW
19721
+ );
19722
+ return () => {
19723
+ unregisterToggle();
19724
+ unregisterInline();
19725
+ };
19373
19726
  }, [editor, toggleAIChat]);
19374
- return /* @__PURE__ */ jsx(Fragment, { children: isVisible && /* @__PURE__ */ jsx(
19375
- AIChatDialog,
19376
- {
19377
- open: isVisible,
19378
- onOpenChange: setIsVisible,
19379
- editor,
19380
- apiKey,
19381
- initialText: selectedText,
19382
- savedSelection: savedSelectionRef.current
19383
- }
19384
- ) });
19727
+ const editorRootElement = editor.getRootElement();
19728
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
19729
+ isVisible && /* @__PURE__ */ jsx(
19730
+ AIChatDialog,
19731
+ {
19732
+ open: isVisible,
19733
+ onOpenChange: setIsVisible,
19734
+ editor,
19735
+ apiKey,
19736
+ initialText: selectedText,
19737
+ savedSelection: savedSelectionRef.current,
19738
+ onShowInEditor: handleShowInEditor,
19739
+ selectedTextForInline: selectedText
19740
+ }
19741
+ ),
19742
+ showInlinePrompt && /* @__PURE__ */ jsx(
19743
+ InlineAIPrompt,
19744
+ {
19745
+ editor,
19746
+ apiKey,
19747
+ initialProvider: inlineProvider,
19748
+ selectedText: inlineSelectedText,
19749
+ onClose: handleCloseInlinePrompt,
19750
+ anchorElem: editorRootElement
19751
+ }
19752
+ )
19753
+ ] });
19385
19754
  }
19386
19755
  function AIChatPlugin({
19387
19756
  apiKey
@@ -19991,10 +20360,10 @@ const PDF_CONFIG = {
19991
20360
  };
19992
20361
  const loadHtml2Pdf = async () => {
19993
20362
  try {
19994
- const mod = await import("./html2pdf.bundle.min-db02af80.js").then((n) => n.h);
20363
+ const mod = await import("./html2pdf.bundle.min-d830ece3.js").then((n) => n.h);
19995
20364
  return (mod == null ? void 0 : mod.default) || mod;
19996
20365
  } catch {
19997
- const mod2 = await import("./html2pdf.bundle-0a42a49f.js").then((n) => n.h);
20366
+ const mod2 = await import("./html2pdf.bundle-dea9d834.js").then((n) => n.h);
19998
20367
  return (mod2 == null ? void 0 : mod2.default) || mod2;
19999
20368
  }
20000
20369
  };
@@ -23236,92 +23605,212 @@ const FontFamilyMenu = ({
23236
23605
  activeEditor
23237
23606
  }) => {
23238
23607
  const [selectedFont, setSelectedFont] = useState$1("Arial");
23608
+ const [detectedFonts, setDetectedFonts] = useState$1(/* @__PURE__ */ new Set());
23609
+ const pendingFontRef = React__default.useRef(null);
23610
+ const userJustSetFontRef = React__default.useRef(false);
23611
+ const allFonts = useMemo(() => {
23612
+ const fontSet = new Set(fonts);
23613
+ detectedFonts.forEach((font) => fontSet.add(font));
23614
+ return Array.from(fontSet);
23615
+ }, [fonts, detectedFonts]);
23239
23616
  useEffect$1(() => {
23240
23617
  return activeEditor.registerUpdateListener(({ editorState }) => {
23241
23618
  editorState.read(() => {
23242
- var _a;
23243
23619
  const selection = $getSelection();
23244
23620
  if ($isRangeSelection(selection)) {
23245
- const anchorNode = selection.anchor.getNode();
23246
- if ($isTextNode(anchorNode)) {
23247
- const fontFamily = (_a = anchorNode.getStyle().match(/font-family:\s*([^;]+)/)) == null ? void 0 : _a[1];
23248
- if (fontFamily) {
23249
- setSelectedFont(fontFamily);
23621
+ const fontFamily = $getSelectionStyleValueForProperty(
23622
+ selection,
23623
+ "font-family",
23624
+ "Arial"
23625
+ );
23626
+ const cleanedFont = fontFamily.replace(/^["']|["']$/g, "").trim();
23627
+ if (userJustSetFontRef.current) {
23628
+ userJustSetFontRef.current = false;
23629
+ return;
23630
+ }
23631
+ if (!selection.isCollapsed() && pendingFontRef.current !== null) {
23632
+ pendingFontRef.current = null;
23633
+ }
23634
+ if (pendingFontRef.current !== null && cleanedFont !== pendingFontRef.current && cleanedFont !== "Arial") {
23635
+ pendingFontRef.current = null;
23636
+ }
23637
+ if (pendingFontRef.current === null) {
23638
+ setSelectedFont(cleanedFont);
23639
+ if (cleanedFont && cleanedFont !== "Arial" && !fonts.includes(cleanedFont)) {
23640
+ setDetectedFonts((prev) => {
23641
+ if (prev.has(cleanedFont))
23642
+ return prev;
23643
+ const newSet = new Set(prev);
23644
+ newSet.add(cleanedFont);
23645
+ return newSet;
23646
+ });
23250
23647
  }
23251
23648
  }
23252
23649
  }
23253
23650
  });
23254
23651
  });
23652
+ }, [activeEditor, fonts]);
23653
+ useEffect$1(() => {
23654
+ return activeEditor.registerCommand(
23655
+ KEY_DOWN_COMMAND,
23656
+ (event) => {
23657
+ if (pendingFontRef.current !== null && event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
23658
+ const pendingFont = pendingFontRef.current;
23659
+ const selection = $getSelection();
23660
+ if ($isRangeSelection(selection) && selection.isCollapsed()) {
23661
+ $patchStyleText(selection, { "font-family": pendingFont });
23662
+ }
23663
+ }
23664
+ return false;
23665
+ },
23666
+ COMMAND_PRIORITY_CRITICAL
23667
+ );
23255
23668
  }, [activeEditor]);
23256
- const applyFontFamily = (fontFamily) => {
23257
- activeEditor.update(() => {
23258
- const selection = $getSelection();
23259
- if ($isRangeSelection(selection)) {
23260
- $patchStyleText(selection, { "font-family": fontFamily });
23669
+ useEffect$1(() => {
23670
+ const rootElement = activeEditor.getRootElement();
23671
+ if (!rootElement)
23672
+ return;
23673
+ const handleFocus = () => {
23674
+ if (pendingFontRef.current !== null) {
23675
+ const pendingFont = pendingFontRef.current;
23676
+ activeEditor.update(() => {
23677
+ const selection = $getSelection();
23678
+ if ($isRangeSelection(selection) && selection.isCollapsed()) {
23679
+ userJustSetFontRef.current = true;
23680
+ $patchStyleText(selection, { "font-family": pendingFont });
23681
+ }
23682
+ });
23261
23683
  }
23262
- });
23263
- };
23684
+ };
23685
+ rootElement.addEventListener("focus", handleFocus);
23686
+ return () => {
23687
+ rootElement.removeEventListener("focus", handleFocus);
23688
+ };
23689
+ }, [activeEditor]);
23690
+ const applyFontFamily = useCallback(
23691
+ (fontFamily) => {
23692
+ pendingFontRef.current = fontFamily;
23693
+ userJustSetFontRef.current = true;
23694
+ activeEditor.update(() => {
23695
+ const selection = $getSelection();
23696
+ if ($isRangeSelection(selection)) {
23697
+ $patchStyleText(selection, { "font-family": fontFamily });
23698
+ }
23699
+ });
23700
+ },
23701
+ [activeEditor]
23702
+ );
23264
23703
  const handleFontChange = (value) => {
23265
23704
  setSelectedFont(value);
23266
23705
  applyFontFamily(value);
23267
23706
  };
23268
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Select, { value: selectedFont, onValueChange: handleFontChange, children: [
23269
- /* @__PURE__ */ jsx(SelectTrigger, { className: "!cteditor-h-7 md:!cteditor-bg-secondary !cteditor-bg-foreground/5 cteditor-text-foreground md:!cteditor-w-[120px] cteditor-text-xs max-md:cteditor-w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select font" }) }),
23270
- /* @__PURE__ */ jsx(SelectContent, { children: fonts.map((font) => /* @__PURE__ */ jsx(SelectItem, { value: font, style: { fontFamily: font }, children: font }, font)) })
23271
- ] }) });
23707
+ const handleMouseDown = (e) => {
23708
+ e.preventDefault();
23709
+ };
23710
+ return /* @__PURE__ */ jsxs(Select, { value: selectedFont, onValueChange: handleFontChange, children: [
23711
+ /* @__PURE__ */ jsx(
23712
+ SelectTrigger,
23713
+ {
23714
+ className: "!cteditor-h-7 md:!cteditor-bg-secondary !cteditor-bg-foreground/5 cteditor-text-foreground md:!cteditor-w-[120px] cteditor-text-xs max-md:cteditor-w-full",
23715
+ onMouseDown: handleMouseDown,
23716
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select font" })
23717
+ }
23718
+ ),
23719
+ /* @__PURE__ */ jsx(SelectContent, { onMouseDown: handleMouseDown, children: allFonts.map((font) => /* @__PURE__ */ jsx(SelectItem, { value: font, style: { fontFamily: font }, onMouseDown: handleMouseDown, children: font }, font)) })
23720
+ ] });
23272
23721
  };
23273
23722
  const MIN_FONT_SIZE = 8;
23274
23723
  const MAX_FONT_SIZE = 72;
23724
+ const DEFAULT_FONT_SIZE = 16;
23275
23725
  const STEP_SIZE = 2;
23276
23726
  const FontSizeControl = () => {
23277
23727
  const [editor] = useLexicalComposerContext();
23278
- const [fontSize, setFontSize] = useState$1(16);
23279
- const [inputValue, setInputValue] = useState$1("16");
23728
+ const [fontSize, setFontSize] = useState$1(DEFAULT_FONT_SIZE);
23729
+ const [inputValue, setInputValue] = useState$1(DEFAULT_FONT_SIZE.toString());
23730
+ const pendingFontSizeRef = React__default.useRef(null);
23731
+ const userJustSetSizeRef = React__default.useRef(false);
23280
23732
  useEffect$1(() => {
23281
23733
  return editor.registerUpdateListener(({ editorState }) => {
23282
23734
  editorState.read(() => {
23283
- var _a;
23284
23735
  const selection = $getSelection();
23285
- if ($isRangeSelection(selection) && !selection.isCollapsed()) {
23286
- const anchorNode = selection.anchor.getNode();
23287
- if ($isTextNode(anchorNode)) {
23288
- const detectedSize = (_a = anchorNode.getStyle().match(/font-size:\s*(\d+)/)) == null ? void 0 : _a[1];
23289
- if (detectedSize) {
23290
- const size2 = parseInt(detectedSize, 10);
23291
- setFontSize(size2);
23292
- setInputValue(size2.toString());
23293
- }
23736
+ if ($isRangeSelection(selection)) {
23737
+ const fontSizeStr = $getSelectionStyleValueForProperty(
23738
+ selection,
23739
+ "font-size",
23740
+ `${DEFAULT_FONT_SIZE}px`
23741
+ );
23742
+ const size2 = parseInt(fontSizeStr, 10) || DEFAULT_FONT_SIZE;
23743
+ if (userJustSetSizeRef.current) {
23744
+ userJustSetSizeRef.current = false;
23745
+ return;
23746
+ }
23747
+ if (!selection.isCollapsed() && pendingFontSizeRef.current !== null) {
23748
+ pendingFontSizeRef.current = null;
23749
+ }
23750
+ if (pendingFontSizeRef.current !== null && size2 !== pendingFontSizeRef.current && size2 !== DEFAULT_FONT_SIZE) {
23751
+ pendingFontSizeRef.current = null;
23752
+ }
23753
+ if (pendingFontSizeRef.current === null) {
23754
+ setFontSize(size2);
23755
+ setInputValue(size2.toString());
23294
23756
  }
23295
23757
  }
23296
23758
  });
23297
23759
  });
23298
23760
  }, [editor]);
23761
+ useEffect$1(() => {
23762
+ return editor.registerCommand(
23763
+ KEY_DOWN_COMMAND,
23764
+ (event) => {
23765
+ if (pendingFontSizeRef.current !== null && event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
23766
+ const pendingSize = pendingFontSizeRef.current;
23767
+ const selection = $getSelection();
23768
+ if ($isRangeSelection(selection) && selection.isCollapsed()) {
23769
+ $patchStyleText(selection, { "font-size": `${pendingSize}px` });
23770
+ }
23771
+ }
23772
+ return false;
23773
+ },
23774
+ COMMAND_PRIORITY_CRITICAL
23775
+ );
23776
+ }, [editor]);
23777
+ useEffect$1(() => {
23778
+ const rootElement = editor.getRootElement();
23779
+ if (!rootElement)
23780
+ return;
23781
+ const handleFocus = () => {
23782
+ if (pendingFontSizeRef.current !== null) {
23783
+ const pendingSize = pendingFontSizeRef.current;
23784
+ editor.update(() => {
23785
+ const selection = $getSelection();
23786
+ if ($isRangeSelection(selection) && selection.isCollapsed()) {
23787
+ userJustSetSizeRef.current = true;
23788
+ $patchStyleText(selection, { "font-size": `${pendingSize}px` });
23789
+ }
23790
+ });
23791
+ }
23792
+ };
23793
+ rootElement.addEventListener("focus", handleFocus);
23794
+ return () => {
23795
+ rootElement.removeEventListener("focus", handleFocus);
23796
+ };
23797
+ }, [editor]);
23299
23798
  const applyFontSize = useCallback(
23300
23799
  (size2) => {
23800
+ pendingFontSizeRef.current = size2;
23801
+ userJustSetSizeRef.current = true;
23301
23802
  editor.update(() => {
23302
23803
  const selection = $getSelection();
23303
23804
  if ($isRangeSelection(selection)) {
23304
23805
  $patchStyleText(selection, { "font-size": `${size2}px` });
23305
23806
  }
23306
23807
  });
23307
- setFontSize(size2);
23308
- setInputValue(size2.toString());
23309
23808
  },
23310
23809
  [editor]
23311
23810
  );
23312
- useEffect$1(() => {
23313
- applyFontSize(fontSize);
23314
- }, [fontSize, applyFontSize]);
23315
23811
  const handleFontSizeChange = (event) => {
23316
23812
  const value = event.target.value.replace(/\D/g, "");
23317
23813
  setInputValue(value);
23318
- if (value !== "") {
23319
- const newSize = Math.max(
23320
- MIN_FONT_SIZE,
23321
- Math.min(Number(value), MAX_FONT_SIZE)
23322
- );
23323
- setFontSize(newSize);
23324
- }
23325
23814
  };
23326
23815
  const handleFontSizeBlur = () => {
23327
23816
  if (inputValue === "" || isNaN(Number(inputValue))) {
@@ -23332,15 +23821,31 @@ const FontSizeControl = () => {
23332
23821
  Math.min(Number(inputValue), MAX_FONT_SIZE)
23333
23822
  );
23334
23823
  setFontSize(newSize);
23824
+ setInputValue(newSize.toString());
23825
+ applyFontSize(newSize);
23826
+ }
23827
+ };
23828
+ const handleKeyDown = (event) => {
23829
+ if (event.key === "Enter") {
23830
+ event.preventDefault();
23831
+ handleFontSizeBlur();
23832
+ editor.focus();
23335
23833
  }
23336
23834
  };
23337
23835
  const increaseFontSize = () => {
23338
23836
  const newSize = Math.min(fontSize + STEP_SIZE, MAX_FONT_SIZE);
23339
23837
  setFontSize(newSize);
23838
+ setInputValue(newSize.toString());
23839
+ applyFontSize(newSize);
23340
23840
  };
23341
23841
  const decreaseFontSize = () => {
23342
23842
  const newSize = Math.max(fontSize - STEP_SIZE, MIN_FONT_SIZE);
23343
23843
  setFontSize(newSize);
23844
+ setInputValue(newSize.toString());
23845
+ applyFontSize(newSize);
23846
+ };
23847
+ const handleMouseDown = (e) => {
23848
+ e.preventDefault();
23344
23849
  };
23345
23850
  return /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-1", children: [
23346
23851
  /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
@@ -23350,6 +23855,7 @@ const FontSizeControl = () => {
23350
23855
  variant: "ghost",
23351
23856
  size: "icon-sm",
23352
23857
  onClick: decreaseFontSize,
23858
+ onMouseDown: handleMouseDown,
23353
23859
  className: "cteditor-text-foreground/50",
23354
23860
  children: /* @__PURE__ */ jsx(Minus, { className: "!cteditor-size-[18px]" })
23355
23861
  }
@@ -23362,7 +23868,8 @@ const FontSizeControl = () => {
23362
23868
  className: "!cteditor-w-9 !cteditor-h-6 !cteditor-p-0 !cteditor-text-center !cteditor-bg-secondary",
23363
23869
  value: inputValue,
23364
23870
  onChange: handleFontSizeChange,
23365
- onBlur: handleFontSizeBlur
23871
+ onBlur: handleFontSizeBlur,
23872
+ onKeyDown: handleKeyDown
23366
23873
  }
23367
23874
  ),
23368
23875
  /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
@@ -23372,6 +23879,7 @@ const FontSizeControl = () => {
23372
23879
  variant: "ghost",
23373
23880
  size: "icon-sm",
23374
23881
  onClick: increaseFontSize,
23882
+ onMouseDown: handleMouseDown,
23375
23883
  className: "cteditor-text-foreground/50",
23376
23884
  children: /* @__PURE__ */ jsx(Plus, { className: "!cteditor-size-[18px]" })
23377
23885
  }
@@ -25735,7 +26243,15 @@ const Toolbar = ({
25735
26243
  });
25736
26244
  }, [editor]);
25737
26245
  const toggleAIChat = useCallback(() => {
25738
- editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, void 0);
26246
+ editor.getEditorState().read(() => {
26247
+ const selection = $getSelection();
26248
+ if ($isRangeSelection(selection)) {
26249
+ const selectedText = selection.getTextContent();
26250
+ editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, selectedText || void 0);
26251
+ } else {
26252
+ editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, void 0);
26253
+ }
26254
+ });
25739
26255
  }, [editor]);
25740
26256
  const createTodo = useCallback(() => {
25741
26257
  editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND, void 0);
@@ -28381,26 +28897,6 @@ function DragDropPaste() {
28381
28897
  return;
28382
28898
  }
28383
28899
  }
28384
- const html = clipboardData.getData("text/html");
28385
- if (html) {
28386
- const tempDiv = document.createElement("div");
28387
- tempDiv.innerHTML = html;
28388
- const images = tempDiv.querySelectorAll("img");
28389
- if (images.length > 0) {
28390
- e.preventDefault();
28391
- images.forEach((img) => {
28392
- if (img.src) {
28393
- editor.dispatchCommand(INSERT_IMAGE_COMMAND, {
28394
- altText: img.alt || "Pasted image",
28395
- src: img.src,
28396
- width: img.width || void 0,
28397
- height: img.height || void 0
28398
- });
28399
- }
28400
- });
28401
- return;
28402
- }
28403
- }
28404
28900
  };
28405
28901
  const editorElement = editor.getRootElement();
28406
28902
  if (editorElement) {
@@ -28762,7 +29258,7 @@ function FloatingEmbedMenu({
28762
29258
  handleDisplayTypeChange("url");
28763
29259
  },
28764
29260
  title: "URL",
28765
- children: /* @__PURE__ */ jsx(LinkIcon$1, { fontSize: "small" })
29261
+ children: /* @__PURE__ */ jsx(Link$1, { fontSize: "small" })
28766
29262
  }
28767
29263
  ),
28768
29264
  /* @__PURE__ */ jsx(
@@ -28774,7 +29270,7 @@ function FloatingEmbedMenu({
28774
29270
  handleDisplayTypeChange("card");
28775
29271
  },
28776
29272
  title: "Card",
28777
- children: /* @__PURE__ */ jsx(CropOriginalIcon, { fontSize: "small" })
29273
+ children: /* @__PURE__ */ jsx(CropOriginal, { fontSize: "small" })
28778
29274
  }
28779
29275
  ),
28780
29276
  /* @__PURE__ */ jsx(
@@ -28786,7 +29282,7 @@ function FloatingEmbedMenu({
28786
29282
  handleDisplayTypeChange("embed");
28787
29283
  },
28788
29284
  title: "Embedded",
28789
- children: /* @__PURE__ */ jsx(CodeIcon$1, { fontSize: "small" })
29285
+ children: /* @__PURE__ */ jsx(Code$1, { fontSize: "small" })
28790
29286
  }
28791
29287
  )
28792
29288
  ] }) }),
@@ -28801,7 +29297,7 @@ function FloatingEmbedMenu({
28801
29297
  handleAlignmentChange("left");
28802
29298
  },
28803
29299
  title: "Left",
28804
- children: /* @__PURE__ */ jsx(FormatAlignLeftIcon, { fontSize: "small" })
29300
+ children: /* @__PURE__ */ jsx(FormatAlignLeft, { fontSize: "small" })
28805
29301
  }
28806
29302
  ),
28807
29303
  /* @__PURE__ */ jsx(
@@ -28813,7 +29309,7 @@ function FloatingEmbedMenu({
28813
29309
  handleAlignmentChange("center");
28814
29310
  },
28815
29311
  title: "Center",
28816
- children: /* @__PURE__ */ jsx(FormatAlignCenterIcon, { fontSize: "small" })
29312
+ children: /* @__PURE__ */ jsx(FormatAlignCenter, { fontSize: "small" })
28817
29313
  }
28818
29314
  ),
28819
29315
  /* @__PURE__ */ jsx(
@@ -28825,7 +29321,7 @@ function FloatingEmbedMenu({
28825
29321
  handleAlignmentChange("right");
28826
29322
  },
28827
29323
  title: "Right",
28828
- children: /* @__PURE__ */ jsx(FormatAlignRightIcon, { fontSize: "small" })
29324
+ children: /* @__PURE__ */ jsx(FormatAlignRight, { fontSize: "small" })
28829
29325
  }
28830
29326
  )
28831
29327
  ] }) }),
@@ -28837,7 +29333,7 @@ function FloatingEmbedMenu({
28837
29333
  className: "embed-menu-button",
28838
29334
  onClick: handleOpenInNewTab,
28839
29335
  title: "Open in new tab",
28840
- children: /* @__PURE__ */ jsx(OpenInNewIcon, { fontSize: "small" })
29336
+ children: /* @__PURE__ */ jsx(OpenInNew, { fontSize: "small" })
28841
29337
  }
28842
29338
  ),
28843
29339
  /* @__PURE__ */ jsx(
@@ -28846,7 +29342,7 @@ function FloatingEmbedMenu({
28846
29342
  className: "embed-menu-button",
28847
29343
  onClick: handleRemoveEmbed,
28848
29344
  title: "Remove",
28849
- children: /* @__PURE__ */ jsx(DeleteIcon, { fontSize: "small" })
29345
+ children: /* @__PURE__ */ jsx(Delete, { fontSize: "small" })
28850
29346
  }
28851
29347
  ),
28852
29348
  /* @__PURE__ */ jsx(
@@ -28855,7 +29351,7 @@ function FloatingEmbedMenu({
28855
29351
  className: "embed-menu-button",
28856
29352
  onClick: handleCopyUrl,
28857
29353
  title: "Copy",
28858
- children: /* @__PURE__ */ jsx(ContentCopyIcon, { fontSize: "small" })
29354
+ children: /* @__PURE__ */ jsx(ContentCopy, { fontSize: "small" })
28859
29355
  }
28860
29356
  )
28861
29357
  ] }) })
@@ -31074,6 +31570,922 @@ function NewMentionsPlugin({
31074
31570
  }
31075
31571
  );
31076
31572
  }
31573
+ function detectCSSAlignment(element) {
31574
+ let current = element;
31575
+ while (current && current !== document.body) {
31576
+ const style = current.style;
31577
+ const computedStyle = window.getComputedStyle(current);
31578
+ const textAlign = style.textAlign || computedStyle.textAlign;
31579
+ if (textAlign === "center")
31580
+ return "center";
31581
+ if (textAlign === "right")
31582
+ return "right";
31583
+ if (textAlign === "justify")
31584
+ return "justify";
31585
+ const display = computedStyle.display;
31586
+ const justifyContent = computedStyle.justifyContent;
31587
+ if (display === "flex" && (justifyContent === "center" || justifyContent === "space-around")) {
31588
+ return "center";
31589
+ }
31590
+ const marginLeft = computedStyle.marginLeft;
31591
+ const marginRight = computedStyle.marginRight;
31592
+ if (marginLeft === "auto" && marginRight === "auto") {
31593
+ return "center";
31594
+ }
31595
+ current = current.parentElement;
31596
+ }
31597
+ return null;
31598
+ }
31599
+ function getImageDimensions(imgElement) {
31600
+ let width = parseInt(imgElement.getAttribute("width") || "0");
31601
+ let height = parseInt(imgElement.getAttribute("height") || "0");
31602
+ if (width === 0) {
31603
+ const styleWidth = imgElement.style.width;
31604
+ if (styleWidth && styleWidth.endsWith("px")) {
31605
+ width = parseInt(styleWidth);
31606
+ }
31607
+ }
31608
+ if (height === 0) {
31609
+ const styleHeight = imgElement.style.height;
31610
+ if (styleHeight && styleHeight.endsWith("px")) {
31611
+ height = parseInt(styleHeight);
31612
+ }
31613
+ }
31614
+ if (width === 0 || height === 0) {
31615
+ try {
31616
+ const computed = window.getComputedStyle(imgElement);
31617
+ if (width === 0 && computed.width && computed.width !== "auto") {
31618
+ width = parseInt(computed.width);
31619
+ }
31620
+ if (height === 0 && computed.height && computed.height !== "auto") {
31621
+ height = parseInt(computed.height);
31622
+ }
31623
+ } catch {
31624
+ }
31625
+ }
31626
+ if (imgElement instanceof HTMLImageElement) {
31627
+ if (width === 0 && imgElement.naturalWidth) {
31628
+ width = imgElement.naturalWidth;
31629
+ }
31630
+ if (height === 0 && imgElement.naturalHeight) {
31631
+ height = imgElement.naturalHeight;
31632
+ }
31633
+ }
31634
+ return { width, height };
31635
+ }
31636
+ function shouldCenterImage(imgElement) {
31637
+ var _a;
31638
+ const { width, height } = getImageDimensions(imgElement);
31639
+ if (width >= 500) {
31640
+ return true;
31641
+ }
31642
+ const parent = imgElement.parentElement;
31643
+ if (parent) {
31644
+ const siblings = Array.from(parent.childNodes);
31645
+ const meaningfulSiblings = siblings.filter((node) => {
31646
+ var _a2, _b;
31647
+ if (node === imgElement)
31648
+ return false;
31649
+ if (node.nodeType === Node.TEXT_NODE) {
31650
+ return ((_a2 = node.textContent) == null ? void 0 : _a2.trim().length) !== 0;
31651
+ }
31652
+ if (node.nodeType === Node.ELEMENT_NODE) {
31653
+ const el = node;
31654
+ if (el.tagName.toLowerCase() === "br")
31655
+ return false;
31656
+ return ((_b = el.textContent) == null ? void 0 : _b.trim().length) !== 0;
31657
+ }
31658
+ return false;
31659
+ });
31660
+ if (meaningfulSiblings.length === 0) {
31661
+ return true;
31662
+ }
31663
+ }
31664
+ if (width > 0 && height > 0 && width > height * 1.5 && width >= 300) {
31665
+ return true;
31666
+ }
31667
+ let current = imgElement.parentElement;
31668
+ while (current && current !== document.body) {
31669
+ const tagName = current.tagName.toLowerCase();
31670
+ if (tagName === "figure" || tagName === "article" || tagName === "section") {
31671
+ if (width >= 200 || width === 0) {
31672
+ return true;
31673
+ }
31674
+ }
31675
+ current = current.parentElement;
31676
+ }
31677
+ try {
31678
+ const computed = window.getComputedStyle(imgElement);
31679
+ if (computed.display === "block") {
31680
+ if (width >= 200 || width === 0) {
31681
+ return true;
31682
+ }
31683
+ }
31684
+ } catch {
31685
+ }
31686
+ if (width === 0) {
31687
+ const parentTag = parent == null ? void 0 : parent.tagName.toLowerCase();
31688
+ if (parentTag === "p" || parentTag === "div") {
31689
+ const textContent = ((_a = parent == null ? void 0 : parent.textContent) == null ? void 0 : _a.trim()) || "";
31690
+ if (textContent === "") {
31691
+ return true;
31692
+ }
31693
+ }
31694
+ }
31695
+ return false;
31696
+ }
31697
+ function detectClassBasedAlignment(element) {
31698
+ let current = element;
31699
+ while (current && current !== document.body) {
31700
+ const className = current.className || "";
31701
+ if (className.includes("image-style-align-right") || className.includes("image-style-side")) {
31702
+ return "right";
31703
+ }
31704
+ if (className.includes("image-style-align-left")) {
31705
+ return "left";
31706
+ }
31707
+ if (className.includes("image-style-align-center") || className.includes("image_resized") && !className.includes("align"))
31708
+ ;
31709
+ if (className.includes("align-right")) {
31710
+ return "right";
31711
+ }
31712
+ if (className.includes("align-left")) {
31713
+ return "left";
31714
+ }
31715
+ if (className.includes("align-center")) {
31716
+ return "center";
31717
+ }
31718
+ if (className.includes("float-right") || className.includes("pull-right")) {
31719
+ return "right";
31720
+ }
31721
+ if (className.includes("float-left") || className.includes("pull-left")) {
31722
+ return "left";
31723
+ }
31724
+ try {
31725
+ const computed = window.getComputedStyle(current);
31726
+ if (computed.float === "right") {
31727
+ return "right";
31728
+ }
31729
+ if (computed.float === "left") {
31730
+ return "left";
31731
+ }
31732
+ } catch {
31733
+ }
31734
+ current = current.parentElement;
31735
+ }
31736
+ return null;
31737
+ }
31738
+ function detectImageAlignment(imgElement) {
31739
+ const classAlignment = detectClassBasedAlignment(imgElement);
31740
+ if (classAlignment) {
31741
+ return classAlignment;
31742
+ }
31743
+ const cssAlignment = detectCSSAlignment(imgElement);
31744
+ if (cssAlignment) {
31745
+ return cssAlignment;
31746
+ }
31747
+ if (shouldCenterImage(imgElement)) {
31748
+ return "center";
31749
+ }
31750
+ return "left";
31751
+ }
31752
+ function alignmentToPosition(alignment) {
31753
+ switch (alignment) {
31754
+ case "left":
31755
+ return "left";
31756
+ case "right":
31757
+ return "right";
31758
+ default:
31759
+ return "none";
31760
+ }
31761
+ }
31762
+ function isFloatAlignment(alignment) {
31763
+ return alignment === "left" || alignment === "right";
31764
+ }
31765
+ const IS_BOLD = 1;
31766
+ const IS_ITALIC = 2;
31767
+ const IS_STRIKETHROUGH = 4;
31768
+ const IS_UNDERLINE = 8;
31769
+ const IS_CODE = 16;
31770
+ const IS_SUBSCRIPT = 32;
31771
+ const IS_SUPERSCRIPT = 64;
31772
+ const IS_HIGHLIGHT = 128;
31773
+ function parseColor(color) {
31774
+ if (!color)
31775
+ return null;
31776
+ color = color.trim().toLowerCase();
31777
+ if (color.startsWith("#")) {
31778
+ let hex = color.slice(1);
31779
+ if (hex.length === 3) {
31780
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
31781
+ }
31782
+ if (hex.length === 6) {
31783
+ return {
31784
+ r: parseInt(hex.slice(0, 2), 16),
31785
+ g: parseInt(hex.slice(2, 4), 16),
31786
+ b: parseInt(hex.slice(4, 6), 16)
31787
+ };
31788
+ }
31789
+ }
31790
+ const rgbMatch = color.match(/rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
31791
+ if (rgbMatch) {
31792
+ return {
31793
+ r: parseInt(rgbMatch[1]),
31794
+ g: parseInt(rgbMatch[2]),
31795
+ b: parseInt(rgbMatch[3])
31796
+ };
31797
+ }
31798
+ const namedColors = {
31799
+ white: { r: 255, g: 255, b: 255 },
31800
+ black: { r: 0, g: 0, b: 0 },
31801
+ red: { r: 255, g: 0, b: 0 },
31802
+ green: { r: 0, g: 128, b: 0 },
31803
+ blue: { r: 0, g: 0, b: 255 },
31804
+ yellow: { r: 255, g: 255, b: 0 },
31805
+ transparent: { r: 0, g: 0, b: 0 }
31806
+ // Will be handled separately
31807
+ };
31808
+ return namedColors[color] || null;
31809
+ }
31810
+ function getLuminance(r2, g2, b2) {
31811
+ const sR = r2 / 255;
31812
+ const sG = g2 / 255;
31813
+ const sB = b2 / 255;
31814
+ const R = sR <= 0.03928 ? sR / 12.92 : Math.pow((sR + 0.055) / 1.055, 2.4);
31815
+ const G = sG <= 0.03928 ? sG / 12.92 : Math.pow((sG + 0.055) / 1.055, 2.4);
31816
+ const B = sB <= 0.03928 ? sB / 12.92 : Math.pow((sB + 0.055) / 1.055, 2.4);
31817
+ return 0.2126 * R + 0.7152 * G + 0.0722 * B;
31818
+ }
31819
+ function isLightColor(color) {
31820
+ const parsed = parseColor(color);
31821
+ if (!parsed)
31822
+ return null;
31823
+ return getLuminance(parsed.r, parsed.g, parsed.b) > 0.5;
31824
+ }
31825
+ function getEditorBackgroundColor(editor) {
31826
+ const rootElement = editor.getRootElement();
31827
+ if (!rootElement)
31828
+ return null;
31829
+ try {
31830
+ const computedStyle = window.getComputedStyle(rootElement);
31831
+ const bgColor = computedStyle.backgroundColor;
31832
+ if (bgColor === "transparent" || bgColor === "rgba(0, 0, 0, 0)") {
31833
+ let parent = rootElement.parentElement;
31834
+ while (parent) {
31835
+ const parentBg = window.getComputedStyle(parent).backgroundColor;
31836
+ if (parentBg && parentBg !== "transparent" && parentBg !== "rgba(0, 0, 0, 0)") {
31837
+ return parentBg;
31838
+ }
31839
+ parent = parent.parentElement;
31840
+ }
31841
+ return "rgb(255, 255, 255)";
31842
+ }
31843
+ return bgColor;
31844
+ } catch {
31845
+ return null;
31846
+ }
31847
+ }
31848
+ function isEditorDarkMode(editor) {
31849
+ const bgColor = getEditorBackgroundColor(editor);
31850
+ if (!bgColor)
31851
+ return false;
31852
+ const isLight = isLightColor(bgColor);
31853
+ return isLight === false;
31854
+ }
31855
+ function adjustColorsForTheme(styleInfo) {
31856
+ const adjusted = { ...styleInfo };
31857
+ adjusted.backgroundColor = "";
31858
+ adjusted.color = "";
31859
+ return adjusted;
31860
+ }
31861
+ function detectCKEditorSource(html) {
31862
+ return html.includes('class="image"') || // CKEditor's figure class for images
31863
+ html.includes('class="image ') || html.includes("image-style-") || // CKEditor's image alignment classes
31864
+ html.includes("ck-") || // CKEditor's internal classes
31865
+ html.includes("data-cke-");
31866
+ }
31867
+ const DEFAULT_HEADING_STYLES = {
31868
+ h1: { fontSize: "36px", lineHeight: "1.2" },
31869
+ h2: { fontSize: "29px", lineHeight: "1.25" },
31870
+ h3: { fontSize: "24px", lineHeight: "1.3" },
31871
+ h4: { fontSize: "20px", lineHeight: "1.35" },
31872
+ h5: { fontSize: "17px", lineHeight: "1.4" },
31873
+ h6: { fontSize: "15px", lineHeight: "1.45" }
31874
+ };
31875
+ const DEFAULT_PARAGRAPH_FONT_SIZE = "16px";
31876
+ const DEFAULT_PARAGRAPH_LINE_HEIGHT = "1.6";
31877
+ const MIN_HEADING_FONT_SIZES = {
31878
+ h1: 24,
31879
+ h2: 20,
31880
+ h3: 18,
31881
+ h4: 16,
31882
+ h5: 14,
31883
+ h6: 12
31884
+ };
31885
+ function parseStyleString(styleStr) {
31886
+ const result = {};
31887
+ if (!styleStr)
31888
+ return result;
31889
+ const parts = styleStr.split(";");
31890
+ for (const part of parts) {
31891
+ const colonIndex = part.indexOf(":");
31892
+ if (colonIndex > 0) {
31893
+ const key = part.substring(0, colonIndex).trim().toLowerCase();
31894
+ const value = part.substring(colonIndex + 1).trim();
31895
+ if (key && value) {
31896
+ result[key] = value;
31897
+ }
31898
+ }
31899
+ }
31900
+ return result;
31901
+ }
31902
+ function getStyleInfoFromElement(element) {
31903
+ const result = {
31904
+ format: 0,
31905
+ fontFamily: "",
31906
+ fontSize: "",
31907
+ lineHeight: "",
31908
+ letterSpacing: "",
31909
+ wordSpacing: "",
31910
+ color: "",
31911
+ backgroundColor: ""
31912
+ };
31913
+ let current = element;
31914
+ const elementsStack = [];
31915
+ while (current && current !== document.body) {
31916
+ elementsStack.push(current);
31917
+ current = current.parentElement;
31918
+ }
31919
+ for (let i2 = elementsStack.length - 1; i2 >= 0; i2--) {
31920
+ const el = elementsStack[i2];
31921
+ const tag = el.tagName.toLowerCase();
31922
+ if (tag === "strong" || tag === "b")
31923
+ result.format |= IS_BOLD;
31924
+ if (tag === "em" || tag === "i")
31925
+ result.format |= IS_ITALIC;
31926
+ if (tag === "u")
31927
+ result.format |= IS_UNDERLINE;
31928
+ if (tag === "s" || tag === "strike" || tag === "del")
31929
+ result.format |= IS_STRIKETHROUGH;
31930
+ if (tag === "code")
31931
+ result.format |= IS_CODE;
31932
+ if (tag === "sub")
31933
+ result.format |= IS_SUBSCRIPT;
31934
+ if (tag === "sup")
31935
+ result.format |= IS_SUPERSCRIPT;
31936
+ if (tag === "mark")
31937
+ result.format |= IS_HIGHLIGHT;
31938
+ const styleAttr = el.getAttribute("style") || "";
31939
+ const parsedStyle = parseStyleString(styleAttr);
31940
+ const style = el.style;
31941
+ const fontWeight = parsedStyle["font-weight"] || style.fontWeight;
31942
+ if (fontWeight === "bold" || fontWeight === "700" || parseInt(fontWeight || "0") >= 700) {
31943
+ result.format |= IS_BOLD;
31944
+ }
31945
+ const fontStyle = parsedStyle["font-style"] || style.fontStyle;
31946
+ if (fontStyle === "italic") {
31947
+ result.format |= IS_ITALIC;
31948
+ }
31949
+ const textDecoration = parsedStyle["text-decoration"] || style.textDecoration || "";
31950
+ if (textDecoration.includes("underline")) {
31951
+ result.format |= IS_UNDERLINE;
31952
+ }
31953
+ if (textDecoration.includes("line-through")) {
31954
+ result.format |= IS_STRIKETHROUGH;
31955
+ }
31956
+ const fontFamily = parsedStyle["font-family"] || style.fontFamily;
31957
+ if (fontFamily) {
31958
+ const family = fontFamily.split(",")[0].trim().replace(/["']/g, "");
31959
+ if (family && family !== "inherit" && family !== "initial") {
31960
+ result.fontFamily = family;
31961
+ }
31962
+ }
31963
+ const fontSize = parsedStyle["font-size"] || style.fontSize;
31964
+ if (fontSize && fontSize !== "inherit" && fontSize !== "initial") {
31965
+ result.fontSize = fontSize;
31966
+ }
31967
+ const lineHeight = parsedStyle["line-height"] || style.lineHeight;
31968
+ if (lineHeight && lineHeight !== "inherit" && lineHeight !== "initial" && lineHeight !== "normal") {
31969
+ result.lineHeight = lineHeight;
31970
+ }
31971
+ const letterSpacing = parsedStyle["letter-spacing"] || style.letterSpacing;
31972
+ if (letterSpacing && letterSpacing !== "inherit" && letterSpacing !== "initial" && letterSpacing !== "normal") {
31973
+ result.letterSpacing = letterSpacing;
31974
+ }
31975
+ const wordSpacing = parsedStyle["word-spacing"] || style.wordSpacing;
31976
+ if (wordSpacing && wordSpacing !== "inherit" && wordSpacing !== "initial" && wordSpacing !== "normal") {
31977
+ result.wordSpacing = wordSpacing;
31978
+ }
31979
+ const color = parsedStyle["color"] || style.color;
31980
+ if (color && color !== "inherit" && color !== "initial") {
31981
+ result.color = color;
31982
+ }
31983
+ const bgColor = parsedStyle["background-color"] || parsedStyle["background"] || style.backgroundColor;
31984
+ if (bgColor && bgColor !== "inherit" && bgColor !== "initial" && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") {
31985
+ result.backgroundColor = bgColor;
31986
+ }
31987
+ }
31988
+ try {
31989
+ const computedStyle = window.getComputedStyle(element);
31990
+ if (!result.fontFamily && computedStyle.fontFamily) {
31991
+ const fontFamily = computedStyle.fontFamily.split(",")[0].trim().replace(/["']/g, "");
31992
+ const genericFonts = ["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui", "-apple-system", "BlinkMacSystemFont"];
31993
+ if (fontFamily && !genericFonts.includes(fontFamily)) {
31994
+ result.fontFamily = fontFamily;
31995
+ }
31996
+ }
31997
+ if (!result.fontSize && computedStyle.fontSize && computedStyle.fontSize !== "16px") {
31998
+ result.fontSize = computedStyle.fontSize;
31999
+ }
32000
+ if (!result.lineHeight && computedStyle.lineHeight && computedStyle.lineHeight !== "normal") {
32001
+ const lineHeightValue = computedStyle.lineHeight;
32002
+ if (lineHeightValue && !lineHeightValue.endsWith("px")) {
32003
+ result.lineHeight = lineHeightValue;
32004
+ } else if (lineHeightValue && result.fontSize) {
32005
+ result.lineHeight = lineHeightValue;
32006
+ } else if (lineHeightValue) {
32007
+ result.lineHeight = lineHeightValue;
32008
+ }
32009
+ }
32010
+ if (!result.letterSpacing && computedStyle.letterSpacing && computedStyle.letterSpacing !== "normal" && computedStyle.letterSpacing !== "0px") {
32011
+ result.letterSpacing = computedStyle.letterSpacing;
32012
+ }
32013
+ if (!result.wordSpacing && computedStyle.wordSpacing && computedStyle.wordSpacing !== "normal" && computedStyle.wordSpacing !== "0px") {
32014
+ result.wordSpacing = computedStyle.wordSpacing;
32015
+ }
32016
+ if (!result.color && computedStyle.color) {
32017
+ const color = computedStyle.color;
32018
+ if (color !== "rgb(0, 0, 0)" && color !== "#000000" && color !== "black") {
32019
+ result.color = color;
32020
+ }
32021
+ }
32022
+ if (!result.backgroundColor && computedStyle.backgroundColor) {
32023
+ const bgColor = computedStyle.backgroundColor;
32024
+ if (bgColor !== "rgba(0, 0, 0, 0)" && bgColor !== "transparent") {
32025
+ result.backgroundColor = bgColor;
32026
+ }
32027
+ }
32028
+ } catch {
32029
+ }
32030
+ return result;
32031
+ }
32032
+ function buildStyleString(info) {
32033
+ const styles = [];
32034
+ if (info.fontFamily)
32035
+ styles.push(`font-family: ${info.fontFamily}`);
32036
+ if (info.fontSize)
32037
+ styles.push(`font-size: ${info.fontSize}`);
32038
+ if (info.lineHeight)
32039
+ styles.push(`line-height: ${info.lineHeight}`);
32040
+ if (info.letterSpacing)
32041
+ styles.push(`letter-spacing: ${info.letterSpacing}`);
32042
+ if (info.wordSpacing)
32043
+ styles.push(`word-spacing: ${info.wordSpacing}`);
32044
+ if (info.color)
32045
+ styles.push(`color: ${info.color}`);
32046
+ if (info.backgroundColor)
32047
+ styles.push(`background-color: ${info.backgroundColor}`);
32048
+ return styles.join("; ");
32049
+ }
32050
+ function createStyledTextNode(text, parentElement) {
32051
+ const textNode = $createTextNode(text);
32052
+ let styleInfo = getStyleInfoFromElement(parentElement);
32053
+ styleInfo = adjustColorsForTheme(styleInfo);
32054
+ if (styleInfo.format) {
32055
+ textNode.setFormat(styleInfo.format);
32056
+ }
32057
+ const styleString = buildStyleString(styleInfo);
32058
+ if (styleString) {
32059
+ textNode.setStyle(styleString);
32060
+ }
32061
+ return textNode;
32062
+ }
32063
+ const defaultPasteContext = {
32064
+ isCKEditor: false
32065
+ };
32066
+ let currentPasteContext = defaultPasteContext;
32067
+ function processNode(domNode, parentElement = null) {
32068
+ var _a;
32069
+ const results = [];
32070
+ if (domNode.nodeType === Node.TEXT_NODE) {
32071
+ const text = domNode.textContent || "";
32072
+ if (text && parentElement) {
32073
+ const hasNonWhitespace = text.trim().length > 0;
32074
+ const isSignificantWhitespace = /\s/.test(text) && !hasNonWhitespace;
32075
+ if (hasNonWhitespace || isSignificantWhitespace) {
32076
+ const normalizedText = text.replace(/\s+/g, " ");
32077
+ const textNode = createStyledTextNode(normalizedText, parentElement);
32078
+ results.push(textNode);
32079
+ }
32080
+ }
32081
+ return results;
32082
+ }
32083
+ if (domNode.nodeType !== Node.ELEMENT_NODE) {
32084
+ return results;
32085
+ }
32086
+ const element = domNode;
32087
+ const tagName = element.tagName.toLowerCase();
32088
+ switch (tagName) {
32089
+ case "p":
32090
+ case "div": {
32091
+ const paragraph = $createParagraphNode();
32092
+ const styleInfo = getStyleInfoFromElement(element);
32093
+ const hasExplicitFontSize = styleInfo.fontSize && styleInfo.fontSize !== "16px";
32094
+ if (!hasExplicitFontSize && currentPasteContext.isCKEditor) {
32095
+ processChildrenWithStyle(element, paragraph, {
32096
+ fontSize: DEFAULT_PARAGRAPH_FONT_SIZE,
32097
+ lineHeight: DEFAULT_PARAGRAPH_LINE_HEIGHT
32098
+ });
32099
+ } else {
32100
+ processChildren(element, paragraph);
32101
+ }
32102
+ if (paragraph.getChildrenSize() > 0 || tagName === "p") {
32103
+ results.push(paragraph);
32104
+ }
32105
+ break;
32106
+ }
32107
+ case "h1":
32108
+ case "h2":
32109
+ case "h3":
32110
+ case "h4":
32111
+ case "h5":
32112
+ case "h6": {
32113
+ const heading = $createHeadingNode(tagName);
32114
+ const styleInfo = getStyleInfoFromElement(element);
32115
+ let hasAppropriateFontSize = false;
32116
+ if (styleInfo.fontSize) {
32117
+ const fontSizeValue = parseFloat(styleInfo.fontSize);
32118
+ const minExpectedSize = MIN_HEADING_FONT_SIZES[tagName] || 14;
32119
+ if (fontSizeValue >= minExpectedSize) {
32120
+ hasAppropriateFontSize = true;
32121
+ }
32122
+ }
32123
+ if (!hasAppropriateFontSize) {
32124
+ const defaultStyles = DEFAULT_HEADING_STYLES[tagName];
32125
+ if (defaultStyles) {
32126
+ processChildrenWithStyle(element, heading, defaultStyles);
32127
+ } else {
32128
+ processChildren(element, heading);
32129
+ }
32130
+ } else {
32131
+ processChildren(element, heading);
32132
+ }
32133
+ results.push(heading);
32134
+ break;
32135
+ }
32136
+ case "ul":
32137
+ case "ol": {
32138
+ const listType = tagName === "ul" ? "bullet" : "number";
32139
+ const list = $createListNode(listType);
32140
+ const listItems = element.querySelectorAll(":scope > li");
32141
+ listItems.forEach((li) => {
32142
+ const listItem = $createListItemNode();
32143
+ processChildren(li, listItem);
32144
+ list.append(listItem);
32145
+ });
32146
+ if (list.getChildrenSize() > 0) {
32147
+ results.push(list);
32148
+ }
32149
+ break;
32150
+ }
32151
+ case "li": {
32152
+ const list = $createListNode("bullet");
32153
+ const listItem = $createListItemNode();
32154
+ processChildren(element, listItem);
32155
+ list.append(listItem);
32156
+ results.push(list);
32157
+ break;
32158
+ }
32159
+ case "blockquote": {
32160
+ const quote = $createQuoteNode();
32161
+ processChildren(element, quote);
32162
+ results.push(quote);
32163
+ break;
32164
+ }
32165
+ case "a": {
32166
+ const href = element.getAttribute("href") || "";
32167
+ if (href) {
32168
+ const linkNode = $createLinkNode(href, { target: "_blank", rel: "noopener" });
32169
+ processChildren(element, linkNode);
32170
+ results.push(linkNode);
32171
+ } else {
32172
+ const children = processChildren(element);
32173
+ results.push(...children);
32174
+ }
32175
+ break;
32176
+ }
32177
+ case "img": {
32178
+ const src = element.getAttribute("src") || "";
32179
+ if (src && !src.startsWith("file:///")) {
32180
+ const alt = element.getAttribute("alt") || "";
32181
+ const width = parseInt(element.getAttribute("width") || "0") || void 0;
32182
+ const height = parseInt(element.getAttribute("height") || "0") || void 0;
32183
+ const alignment = detectImageAlignment(element);
32184
+ const position = alignmentToPosition(alignment);
32185
+ const imageNode = $createImageNode({
32186
+ src,
32187
+ altText: alt,
32188
+ width,
32189
+ height,
32190
+ position: isFloatAlignment(alignment) ? position : "none"
32191
+ });
32192
+ if (alignment === "center") {
32193
+ const paragraph = $createParagraphNode();
32194
+ paragraph.setFormat("center");
32195
+ paragraph.append(imageNode);
32196
+ results.push(paragraph);
32197
+ } else {
32198
+ results.push(imageNode);
32199
+ }
32200
+ }
32201
+ break;
32202
+ }
32203
+ case "br": {
32204
+ results.push($createLineBreakNode());
32205
+ break;
32206
+ }
32207
+ case "figure": {
32208
+ const img = element.querySelector("img");
32209
+ const figureAlignment = detectClassBasedAlignment(element);
32210
+ const alignment = figureAlignment || (img ? detectImageAlignment(img) : "left");
32211
+ const position = alignmentToPosition(alignment);
32212
+ const isFloat = isFloatAlignment(alignment);
32213
+ const figcaption = element.querySelector("figcaption");
32214
+ const captionText = ((_a = figcaption == null ? void 0 : figcaption.textContent) == null ? void 0 : _a.trim()) || "";
32215
+ if (img) {
32216
+ const src = img.getAttribute("src") || "";
32217
+ if (src && !src.startsWith("file:///")) {
32218
+ const alt = img.getAttribute("alt") || "";
32219
+ const width = parseInt(img.getAttribute("width") || "0") || void 0;
32220
+ const height = parseInt(img.getAttribute("height") || "0") || void 0;
32221
+ const imageNode = $createImageNode({
32222
+ src,
32223
+ altText: alt,
32224
+ width,
32225
+ height,
32226
+ position: isFloat ? position : "none"
32227
+ });
32228
+ if (alignment === "center") {
32229
+ const paragraph = $createParagraphNode();
32230
+ paragraph.setFormat("center");
32231
+ paragraph.append(imageNode);
32232
+ results.push(paragraph);
32233
+ if (captionText) {
32234
+ const captionPara = $createParagraphNode();
32235
+ captionPara.setFormat("center");
32236
+ const textNode = $createTextNode(captionText);
32237
+ textNode.setFormat(IS_ITALIC);
32238
+ captionPara.append(textNode);
32239
+ results.push(captionPara);
32240
+ }
32241
+ } else {
32242
+ if (captionText) {
32243
+ const paragraph = $createParagraphNode();
32244
+ paragraph.setFormat(alignment === "right" ? "right" : "left");
32245
+ paragraph.append(imageNode);
32246
+ paragraph.append($createLineBreakNode());
32247
+ const captionNode = $createTextNode(captionText);
32248
+ captionNode.setFormat(IS_ITALIC);
32249
+ paragraph.append(captionNode);
32250
+ results.push(paragraph);
32251
+ } else {
32252
+ results.push(imageNode);
32253
+ }
32254
+ }
32255
+ }
32256
+ }
32257
+ break;
32258
+ }
32259
+ case "strong":
32260
+ case "b":
32261
+ case "em":
32262
+ case "i":
32263
+ case "u":
32264
+ case "s":
32265
+ case "strike":
32266
+ case "del":
32267
+ case "code":
32268
+ case "sub":
32269
+ case "sup":
32270
+ case "mark":
32271
+ case "span":
32272
+ case "font": {
32273
+ const children = processChildren(element);
32274
+ results.push(...children);
32275
+ break;
32276
+ }
32277
+ case "script":
32278
+ case "style":
32279
+ case "meta":
32280
+ case "link":
32281
+ case "head":
32282
+ case "title":
32283
+ case "noscript":
32284
+ break;
32285
+ case "table":
32286
+ case "tbody":
32287
+ case "thead":
32288
+ case "tfoot":
32289
+ case "tr":
32290
+ case "td":
32291
+ case "th": {
32292
+ break;
32293
+ }
32294
+ default: {
32295
+ const children = processChildren(element);
32296
+ results.push(...children);
32297
+ }
32298
+ }
32299
+ return results;
32300
+ }
32301
+ function processChildren(element, parentNode) {
32302
+ const results = [];
32303
+ const childNodes = element.childNodes;
32304
+ for (let i2 = 0; i2 < childNodes.length; i2++) {
32305
+ const child = childNodes[i2];
32306
+ const nodes = processNode(child, element);
32307
+ if (parentNode) {
32308
+ nodes.forEach((node) => parentNode.append(node));
32309
+ } else {
32310
+ results.push(...nodes);
32311
+ }
32312
+ }
32313
+ return results;
32314
+ }
32315
+ function processChildrenWithStyle(element, parentNode, defaultStyles) {
32316
+ const childNodes = element.childNodes;
32317
+ for (let i2 = 0; i2 < childNodes.length; i2++) {
32318
+ const child = childNodes[i2];
32319
+ if (child.nodeType === Node.TEXT_NODE) {
32320
+ const text = child.textContent || "";
32321
+ if (text) {
32322
+ const hasNonWhitespace = text.trim().length > 0;
32323
+ const isSignificantWhitespace = /\s/.test(text) && !hasNonWhitespace;
32324
+ if (hasNonWhitespace || isSignificantWhitespace) {
32325
+ const normalizedText = text.replace(/\s+/g, " ");
32326
+ const textNode = $createTextNode(normalizedText);
32327
+ let styleInfo = getStyleInfoFromElement(element);
32328
+ styleInfo = adjustColorsForTheme(styleInfo);
32329
+ if (styleInfo.format) {
32330
+ textNode.setFormat(styleInfo.format);
32331
+ }
32332
+ const styles = [];
32333
+ if (styleInfo.fontFamily) {
32334
+ styles.push(`font-family: ${styleInfo.fontFamily}`);
32335
+ }
32336
+ const usingDefaultFontSize = !styleInfo.fontSize && defaultStyles.fontSize;
32337
+ if (styleInfo.fontSize) {
32338
+ styles.push(`font-size: ${styleInfo.fontSize}`);
32339
+ } else if (defaultStyles.fontSize) {
32340
+ styles.push(`font-size: ${defaultStyles.fontSize}`);
32341
+ }
32342
+ if (styleInfo.lineHeight) {
32343
+ const isAbsoluteLineHeight = styleInfo.lineHeight.endsWith("px");
32344
+ if (usingDefaultFontSize && isAbsoluteLineHeight) {
32345
+ styles.push(`line-height: ${defaultStyles.lineHeight}`);
32346
+ } else {
32347
+ styles.push(`line-height: ${styleInfo.lineHeight}`);
32348
+ }
32349
+ } else if (defaultStyles.lineHeight) {
32350
+ styles.push(`line-height: ${defaultStyles.lineHeight}`);
32351
+ }
32352
+ if (styleInfo.letterSpacing) {
32353
+ styles.push(`letter-spacing: ${styleInfo.letterSpacing}`);
32354
+ }
32355
+ if (styleInfo.wordSpacing) {
32356
+ styles.push(`word-spacing: ${styleInfo.wordSpacing}`);
32357
+ }
32358
+ if (styleInfo.color) {
32359
+ styles.push(`color: ${styleInfo.color}`);
32360
+ }
32361
+ if (styleInfo.backgroundColor) {
32362
+ styles.push(`background-color: ${styleInfo.backgroundColor}`);
32363
+ }
32364
+ if (styles.length > 0) {
32365
+ textNode.setStyle(styles.join("; "));
32366
+ }
32367
+ parentNode.append(textNode);
32368
+ }
32369
+ }
32370
+ } else {
32371
+ const nodes = processNode(child, element);
32372
+ nodes.forEach((node) => {
32373
+ if ($isTextNode(node)) {
32374
+ const currentStyle = node.getStyle();
32375
+ const hasFontSize = currentStyle.includes("font-size");
32376
+ const hasLineHeight = currentStyle.includes("line-height");
32377
+ if (!hasFontSize || !hasLineHeight) {
32378
+ const newStyles = currentStyle ? [currentStyle] : [];
32379
+ if (!hasFontSize && defaultStyles.fontSize) {
32380
+ newStyles.push(`font-size: ${defaultStyles.fontSize}`);
32381
+ }
32382
+ if (!hasFontSize && hasLineHeight) {
32383
+ const lineHeightMatch = currentStyle.match(/line-height:\s*([^;]+)/);
32384
+ if (lineHeightMatch && lineHeightMatch[1].trim().endsWith("px")) {
32385
+ const filteredStyles = newStyles.filter((s2) => !s2.includes("line-height"));
32386
+ filteredStyles.push(`line-height: ${defaultStyles.lineHeight}`);
32387
+ node.setStyle(filteredStyles.join("; "));
32388
+ parentNode.append(node);
32389
+ return;
32390
+ }
32391
+ }
32392
+ if (!hasLineHeight && defaultStyles.lineHeight) {
32393
+ newStyles.push(`line-height: ${defaultStyles.lineHeight}`);
32394
+ }
32395
+ node.setStyle(newStyles.join("; "));
32396
+ }
32397
+ }
32398
+ parentNode.append(node);
32399
+ });
32400
+ }
32401
+ }
32402
+ }
32403
+ function wrapFloatedImagesInParagraphs(nodes) {
32404
+ return nodes.map((node) => {
32405
+ if ($isImageNode(node)) {
32406
+ const position = node.getPosition();
32407
+ if (position === "left" || position === "right") {
32408
+ const wrapper = $createParagraphNode();
32409
+ wrapper.append(node);
32410
+ return wrapper;
32411
+ }
32412
+ }
32413
+ return node;
32414
+ });
32415
+ }
32416
+ function createStyledDocument(html) {
32417
+ const container = document.createElement("div");
32418
+ container.style.cssText = "position: absolute; left: -9999px; top: -9999px; visibility: hidden;";
32419
+ const parser = new DOMParser();
32420
+ const doc = parser.parseFromString(html, "text/html");
32421
+ const styleTags = doc.querySelectorAll("style");
32422
+ const injectedStyles = [];
32423
+ styleTags.forEach((styleTag) => {
32424
+ const newStyle = document.createElement("style");
32425
+ newStyle.textContent = styleTag.textContent;
32426
+ document.head.appendChild(newStyle);
32427
+ injectedStyles.push(newStyle);
32428
+ });
32429
+ container.innerHTML = doc.body.innerHTML;
32430
+ document.body.appendChild(container);
32431
+ const cleanup = () => {
32432
+ injectedStyles.forEach((style) => style.remove());
32433
+ container.remove();
32434
+ };
32435
+ return { container, cleanup };
32436
+ }
32437
+ function convertHTMLToNodesWithStyles(html, editor) {
32438
+ const isCKEditor = detectCKEditorSource(html);
32439
+ currentPasteContext = {
32440
+ isCKEditor
32441
+ };
32442
+ const editorBgColor = getEditorBackgroundColor(editor);
32443
+ ({
32444
+ editorIsDark: isEditorDarkMode(editor),
32445
+ editorBgColor
32446
+ });
32447
+ const { container, cleanup } = createStyledDocument(html);
32448
+ try {
32449
+ const customNodes = processNode(container, null);
32450
+ const filteredCustomNodes = customNodes.filter((node) => {
32451
+ if (node instanceof ParagraphNode) {
32452
+ return node.getTextContent().trim().length > 0 || node.getChildrenSize() > 0;
32453
+ }
32454
+ return true;
32455
+ });
32456
+ if (filteredCustomNodes.length > 0) {
32457
+ const hasTables = html.includes("<table");
32458
+ if (hasTables) {
32459
+ const parser2 = new DOMParser();
32460
+ const doc2 = parser2.parseFromString(html, "text/html");
32461
+ const lexicalNodes = $generateNodesFromDOM(editor, doc2);
32462
+ const mergedNodes = [];
32463
+ let customIndex = 0;
32464
+ lexicalNodes.forEach((lexicalNode) => {
32465
+ const nodeType = lexicalNode.getType();
32466
+ if (nodeType === "table") {
32467
+ mergedNodes.push(lexicalNode);
32468
+ } else if (customIndex < filteredCustomNodes.length) {
32469
+ mergedNodes.push(filteredCustomNodes[customIndex]);
32470
+ customIndex++;
32471
+ }
32472
+ });
32473
+ while (customIndex < filteredCustomNodes.length) {
32474
+ mergedNodes.push(filteredCustomNodes[customIndex]);
32475
+ customIndex++;
32476
+ }
32477
+ return wrapFloatedImagesInParagraphs(mergedNodes.length > 0 ? mergedNodes : filteredCustomNodes);
32478
+ }
32479
+ return wrapFloatedImagesInParagraphs(filteredCustomNodes);
32480
+ }
32481
+ const parser = new DOMParser();
32482
+ const doc = parser.parseFromString(html, "text/html");
32483
+ return $generateNodesFromDOM(editor, doc);
32484
+ } finally {
32485
+ cleanup();
32486
+ currentPasteContext = defaultPasteContext;
32487
+ }
32488
+ }
31077
32489
  function RichTextPastePlugin() {
31078
32490
  const [editor] = useLexicalComposerContext();
31079
32491
  useEffect$1(() => {
@@ -31083,192 +32495,55 @@ function RichTextPastePlugin() {
31083
32495
  const clipboardData = event.clipboardData;
31084
32496
  if (!clipboardData)
31085
32497
  return false;
32498
+ const files = clipboardData.files;
32499
+ if (files && files.length > 0) {
32500
+ const hasImages = Array.from(files).some(
32501
+ (file) => file.type.startsWith("image/")
32502
+ );
32503
+ if (hasImages) {
32504
+ return false;
32505
+ }
32506
+ }
31086
32507
  const htmlContent = clipboardData.getData("text/html");
31087
32508
  const plainText = clipboardData.getData("text/plain");
31088
32509
  if (htmlContent) {
31089
32510
  event.preventDefault();
31090
- handleHtmlPaste(htmlContent);
31091
- return true;
31092
- } else if (plainText) {
31093
- event.preventDefault();
31094
- handleMarkdownPaste(plainText);
31095
- return true;
31096
- }
31097
- return false;
31098
- },
31099
- COMMAND_PRIORITY_LOW
31100
- );
31101
- }, [editor]);
31102
- const handleHtmlPaste = (htmlContent) => {
31103
- editor.update(() => {
31104
- const selection = $getSelection();
31105
- if ($isRangeSelection(selection)) {
31106
- const tempDiv = document.createElement("div");
31107
- tempDiv.innerHTML = htmlContent;
31108
- const processNode = (node) => {
31109
- if (node.nodeType === Node.TEXT_NODE) {
31110
- const text = node.textContent || "";
31111
- const textNode = $createTextNode(text);
31112
- if (node.parentElement) {
31113
- if (node.parentElement.tagName === "STRONG" || node.parentElement.tagName === "B") {
31114
- textNode.setFormat("bold");
31115
- }
31116
- if (node.parentElement.tagName === "EM" || node.parentElement.tagName === "I") {
31117
- textNode.setFormat("italic");
31118
- }
31119
- if (node.parentElement.tagName === "U") {
31120
- textNode.setFormat("underline");
31121
- }
31122
- if (node.parentElement.tagName === "CODE") {
31123
- textNode.setFormat("code");
31124
- }
31125
- if (node.parentElement.tagName === "STRIKE" || node.parentElement.tagName === "S") {
31126
- textNode.setFormat("strikethrough");
31127
- }
31128
- if (node.parentElement.tagName === "SUB") {
31129
- textNode.setFormat("subscript");
31130
- }
31131
- if (node.parentElement.tagName === "SUP") {
31132
- textNode.setFormat("superscript");
31133
- }
31134
- }
31135
- return textNode;
31136
- }
31137
- if (node.nodeType === Node.ELEMENT_NODE) {
31138
- const element = node;
31139
- if (element.tagName === "UL" || element.tagName === "OL") {
31140
- const listNode = $createListNode(
31141
- element.tagName === "UL" ? "bullet" : "number"
31142
- );
31143
- Array.from(element.childNodes).forEach((child) => {
31144
- if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "LI") {
31145
- const listItemNode = $createListItemNode();
31146
- Array.from(child.childNodes).forEach((grandChild) => {
31147
- const processedNode = processNode(grandChild);
31148
- if (processedNode) {
31149
- if (Array.isArray(processedNode)) {
31150
- processedNode.forEach(
31151
- (node2) => listItemNode.append(node2)
31152
- );
31153
- } else {
31154
- listItemNode.append(processedNode);
31155
- }
32511
+ editor.update(
32512
+ () => {
32513
+ const selection = $getSelection();
32514
+ if (!$isRangeSelection(selection))
32515
+ return;
32516
+ try {
32517
+ const nodes = convertHTMLToNodesWithStyles(htmlContent, editor);
32518
+ if (nodes.length > 0) {
32519
+ const filteredNodes = nodes.filter((node) => {
32520
+ if (node instanceof ParagraphNode) {
32521
+ const textContent = node.getTextContent();
32522
+ const hasChildren = node.getChildrenSize() > 0;
32523
+ return textContent.trim().length > 0 || hasChildren;
31156
32524
  }
32525
+ return true;
31157
32526
  });
31158
- listNode.append(listItemNode);
31159
- }
31160
- });
31161
- return listNode;
31162
- }
31163
- if (element.tagName.match(/^H[1-6]$/)) {
31164
- const headingNode = $createHeadingNode(
31165
- element.tagName.toLowerCase()
31166
- );
31167
- Array.from(element.childNodes).forEach((child) => {
31168
- const processedNode = processNode(child);
31169
- if (processedNode) {
31170
- if (Array.isArray(processedNode)) {
31171
- processedNode.forEach((node2) => headingNode.append(node2));
31172
- } else {
31173
- headingNode.append(processedNode);
32527
+ if (filteredNodes.length > 0) {
32528
+ selection.insertNodes(filteredNodes);
31174
32529
  }
31175
32530
  }
31176
- });
31177
- return headingNode;
31178
- }
31179
- if (element.tagName === "P") {
31180
- const paragraphNode = $createParagraphNode();
31181
- Array.from(element.childNodes).forEach((child) => {
31182
- const processedNode = processNode(child);
31183
- if (processedNode) {
31184
- if (Array.isArray(processedNode)) {
31185
- processedNode.forEach((node2) => paragraphNode.append(node2));
31186
- } else {
31187
- paragraphNode.append(processedNode);
31188
- }
31189
- }
31190
- });
31191
- return paragraphNode;
31192
- }
31193
- const nodes = [];
31194
- Array.from(element.childNodes).forEach((child) => {
31195
- const processedNode = processNode(child);
31196
- if (processedNode) {
31197
- if (Array.isArray(processedNode)) {
31198
- nodes.push(...processedNode);
31199
- } else {
31200
- nodes.push(processedNode);
32531
+ } catch (error) {
32532
+ console.error("Error during HTML paste:", error);
32533
+ if (plainText) {
32534
+ selection.insertRawText(plainText);
31201
32535
  }
31202
32536
  }
31203
- });
31204
- return nodes;
31205
- }
31206
- return null;
31207
- };
31208
- const processedNodes = processNode(tempDiv);
31209
- if (processedNodes) {
31210
- if (Array.isArray(processedNodes)) {
31211
- selection.insertNodes(processedNodes);
31212
- } else {
31213
- selection.insertNodes([processedNodes]);
31214
- }
32537
+ },
32538
+ { tag: "paste" }
32539
+ );
32540
+ return true;
31215
32541
  }
31216
- }
31217
- });
31218
- };
31219
- const handleMarkdownPaste = (text) => {
31220
- editor.update(() => {
31221
- const selection = $getSelection();
31222
- if ($isRangeSelection(selection)) {
31223
- const lines = text.split("\n");
31224
- const nodes = [];
31225
- lines.forEach((line) => {
31226
- const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
31227
- if (headingMatch) {
31228
- const level = headingMatch[1].length;
31229
- const content = headingMatch[2];
31230
- const headingNode = $createHeadingNode(
31231
- `h${level}`
31232
- );
31233
- headingNode.append($createTextNode(content));
31234
- nodes.push(headingNode);
31235
- return;
31236
- }
31237
- const bulletMatch = line.match(/^-\s+(.+)$/);
31238
- if (bulletMatch) {
31239
- const listNode = $createListNode("bullet");
31240
- const listItemNode = $createListItemNode();
31241
- listItemNode.append($createTextNode(bulletMatch[1]));
31242
- listNode.append(listItemNode);
31243
- nodes.push(listNode);
31244
- return;
31245
- }
31246
- const numberedMatch = line.match(/^\d+\.\s+(.+)$/);
31247
- if (numberedMatch) {
31248
- const listNode = $createListNode("number");
31249
- const listItemNode = $createListItemNode();
31250
- listItemNode.append($createTextNode(numberedMatch[1]));
31251
- listNode.append(listItemNode);
31252
- nodes.push(listNode);
31253
- return;
31254
- }
31255
- const textNode = $createTextNode(line);
31256
- if (line.includes("**") || line.includes("__")) {
31257
- textNode.setFormat("bold");
31258
- }
31259
- if (line.includes("*") || line.includes("_")) {
31260
- textNode.setFormat("italic");
31261
- }
31262
- if (line.includes("***") || line.includes("___")) {
31263
- textNode.setFormat("bold");
31264
- textNode.setFormat("italic");
31265
- }
31266
- nodes.push(textNode);
31267
- });
31268
- selection.insertNodes(nodes);
31269
- }
31270
- });
31271
- };
32542
+ return false;
32543
+ },
32544
+ COMMAND_PRIORITY_HIGH
32545
+ );
32546
+ }, [editor]);
31272
32547
  return null;
31273
32548
  }
31274
32549
  function getOptionMeta(label) {
@@ -35248,6 +36523,95 @@ function TableImageAutoResizePlugin() {
35248
36523
  }, [editor]);
35249
36524
  return null;
35250
36525
  }
36526
+ const DEFAULT_SYNC_INTERVAL = 2 * 60 * 1e3;
36527
+ const UsageTrackingPlugin = ({
36528
+ licenseKey,
36529
+ syncIntervalMs = DEFAULT_SYNC_INTERVAL
36530
+ }) => {
36531
+ const [editor] = useLexicalComposerContext();
36532
+ const lastCountRef = useRef({ characters: 0, words: 0 });
36533
+ const pendingDeltaRef = useRef({ characters: 0, words: 0 });
36534
+ const isSyncingRef = useRef(false);
36535
+ const syncToBackend = useCallback(async () => {
36536
+ if (!licenseKey || isSyncingRef.current)
36537
+ return;
36538
+ const { characters, words } = pendingDeltaRef.current;
36539
+ if (characters === 0 && words === 0)
36540
+ return;
36541
+ isSyncingRef.current = true;
36542
+ try {
36543
+ await backendAPI.post("/api/analytics/track-usage", {
36544
+ licenseKey,
36545
+ characters,
36546
+ words
36547
+ });
36548
+ pendingDeltaRef.current = { characters: 0, words: 0 };
36549
+ } catch (error) {
36550
+ console.error("Failed to sync usage stats:", error);
36551
+ } finally {
36552
+ isSyncingRef.current = false;
36553
+ }
36554
+ }, [licenseKey]);
36555
+ useEffect$1(() => {
36556
+ if (!licenseKey)
36557
+ return;
36558
+ const unregister = editor.registerUpdateListener(({ editorState }) => {
36559
+ editorState.read(() => {
36560
+ const root2 = $getRoot();
36561
+ const text = root2.getTextContent();
36562
+ const currentWords = text.trim().split(/\s+/).filter((word) => word.length > 0).length;
36563
+ const currentCharacters = text.replace(/\s/g, "").length;
36564
+ const deltaCharacters = Math.max(
36565
+ 0,
36566
+ currentCharacters - lastCountRef.current.characters
36567
+ );
36568
+ const deltaWords = Math.max(
36569
+ 0,
36570
+ currentWords - lastCountRef.current.words
36571
+ );
36572
+ lastCountRef.current = {
36573
+ characters: currentCharacters,
36574
+ words: currentWords
36575
+ };
36576
+ if (deltaCharacters > 0 || deltaWords > 0) {
36577
+ pendingDeltaRef.current.characters += deltaCharacters;
36578
+ pendingDeltaRef.current.words += deltaWords;
36579
+ }
36580
+ });
36581
+ });
36582
+ const syncInterval = setInterval(syncToBackend, syncIntervalMs);
36583
+ const handleBeforeUnload = () => {
36584
+ const { characters, words } = pendingDeltaRef.current;
36585
+ if (characters > 0 || words > 0) {
36586
+ const data = JSON.stringify({
36587
+ licenseKey,
36588
+ characters,
36589
+ words
36590
+ });
36591
+ const baseURL = backendAPI.defaults.baseURL || "";
36592
+ navigator.sendBeacon(
36593
+ `${baseURL}/api/analytics/track-usage`,
36594
+ new Blob([data], { type: "application/json" })
36595
+ );
36596
+ }
36597
+ };
36598
+ const handleVisibilityChange = () => {
36599
+ if (document.visibilityState === "hidden") {
36600
+ syncToBackend();
36601
+ }
36602
+ };
36603
+ window.addEventListener("beforeunload", handleBeforeUnload);
36604
+ document.addEventListener("visibilitychange", handleVisibilityChange);
36605
+ return () => {
36606
+ unregister();
36607
+ clearInterval(syncInterval);
36608
+ syncToBackend();
36609
+ window.removeEventListener("beforeunload", handleBeforeUnload);
36610
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
36611
+ };
36612
+ }, [editor, licenseKey, syncToBackend, syncIntervalMs]);
36613
+ return null;
36614
+ };
35251
36615
  const WordCountPlugin = () => {
35252
36616
  const [editor] = useLexicalComposerContext();
35253
36617
  const [stats, setStats] = useState$1({
@@ -35296,10 +36660,38 @@ const WordCountPlugin = () => {
35296
36660
  }
35297
36661
  );
35298
36662
  };
36663
+ function getEditorColors(rootElement) {
36664
+ try {
36665
+ const computedStyle = window.getComputedStyle(rootElement);
36666
+ let bgColor = computedStyle.backgroundColor;
36667
+ let textColor = computedStyle.color;
36668
+ if (bgColor === "transparent" || bgColor === "rgba(0, 0, 0, 0)") {
36669
+ let parent = rootElement.parentElement;
36670
+ while (parent) {
36671
+ const parentBg = window.getComputedStyle(parent).backgroundColor;
36672
+ if (parentBg && parentBg !== "transparent" && parentBg !== "rgba(0, 0, 0, 0)") {
36673
+ bgColor = parentBg;
36674
+ break;
36675
+ }
36676
+ parent = parent.parentElement;
36677
+ }
36678
+ if (bgColor === "transparent" || bgColor === "rgba(0, 0, 0, 0)") {
36679
+ bgColor = "rgb(255, 255, 255)";
36680
+ }
36681
+ }
36682
+ if (!textColor || textColor === "rgba(0, 0, 0, 0)") {
36683
+ textColor = "rgb(0, 0, 0)";
36684
+ }
36685
+ return { bgColor, textColor };
36686
+ } catch {
36687
+ return { bgColor: "rgb(255, 255, 255)", textColor: "rgb(0, 0, 0)" };
36688
+ }
36689
+ }
35299
36690
  function exportEditorWithInlineStyle(editor) {
35300
36691
  const rootElement = editor.getRootElement();
35301
36692
  if (!rootElement)
35302
36693
  return "";
36694
+ const { bgColor, textColor } = getEditorColors(rootElement);
35303
36695
  const tableStyleMap = /* @__PURE__ */ new Map();
35304
36696
  const liveTables = rootElement.querySelectorAll("table");
35305
36697
  liveTables.forEach((table, index2) => {
@@ -35310,9 +36702,9 @@ function exportEditorWithInlineStyle(editor) {
35310
36702
  const headerBgColors = [];
35311
36703
  headerCells.forEach((th) => {
35312
36704
  const computed = window.getComputedStyle(th);
35313
- const bgColor = computed.backgroundColor;
35314
- if (bgColor && bgColor !== "rgba(0, 0, 0, 0)") {
35315
- headerBgColors.push(bgColor);
36705
+ const bgColor2 = computed.backgroundColor;
36706
+ if (bgColor2 && bgColor2 !== "rgba(0, 0, 0, 0)") {
36707
+ headerBgColors.push(bgColor2);
35316
36708
  } else {
35317
36709
  headerBgColors.push("");
35318
36710
  }
@@ -35347,7 +36739,7 @@ function exportEditorWithInlineStyle(editor) {
35347
36739
  editor.getEditorState().read(() => {
35348
36740
  htmlString = $generateHtmlFromNodes(editor, null);
35349
36741
  });
35350
- return processHtmlForExport(htmlString, tableStyleMap);
36742
+ return processHtmlForExport(htmlString, tableStyleMap, bgColor, textColor);
35351
36743
  }
35352
36744
  function normalizeColorForComparison(color) {
35353
36745
  if (!color)
@@ -35397,7 +36789,7 @@ function detectTableColorsFromVariables(table) {
35397
36789
  }
35398
36790
  return null;
35399
36791
  }
35400
- function processHtmlForExport(html, tableStyleMap) {
36792
+ function processHtmlForExport(html, tableStyleMap, bgColor, textColor) {
35401
36793
  const parser = new DOMParser();
35402
36794
  const doc = parser.parseFromString(html, "text/html");
35403
36795
  const tables = doc.querySelectorAll("table");
@@ -35407,14 +36799,14 @@ function processHtmlForExport(html, tableStyleMap) {
35407
36799
  return;
35408
36800
  const headerCells = table.querySelectorAll("th");
35409
36801
  headerCells.forEach((th, cellIndex) => {
35410
- const bgColor = styleInfo.headerBgColors[cellIndex];
35411
- if (bgColor) {
36802
+ const bgColor2 = styleInfo.headerBgColors[cellIndex];
36803
+ if (bgColor2) {
35412
36804
  const el = th;
35413
- el.style.setProperty("background-color", bgColor, "important");
35414
- const textColor = getContrastColor(bgColor);
35415
- el.style.color = textColor;
36805
+ el.style.setProperty("background-color", bgColor2, "important");
36806
+ const textColor2 = getContrastColor(bgColor2);
36807
+ el.style.color = textColor2;
35416
36808
  el.querySelectorAll("*").forEach((nested) => {
35417
- nested.style.color = textColor;
36809
+ nested.style.color = textColor2;
35418
36810
  });
35419
36811
  }
35420
36812
  });
@@ -35429,18 +36821,18 @@ function processHtmlForExport(html, tableStyleMap) {
35429
36821
  const el = cell;
35430
36822
  const explicitColor = styleInfo.explicitCellColors.get(`${rowIndex}-${cellIndex}`);
35431
36823
  if (explicitColor) {
35432
- const textColor = getContrastColor(explicitColor);
36824
+ const textColor2 = getContrastColor(explicitColor);
35433
36825
  el.style.setProperty("background-color", explicitColor, "important");
35434
- el.style.color = textColor;
36826
+ el.style.color = textColor2;
35435
36827
  el.querySelectorAll("*").forEach((nested) => {
35436
- nested.style.color = textColor;
36828
+ nested.style.color = textColor2;
35437
36829
  });
35438
36830
  } else if (stripingColor) {
35439
- const textColor = getContrastColor(stripingColor);
36831
+ const textColor2 = getContrastColor(stripingColor);
35440
36832
  el.style.setProperty("background-color", stripingColor, "important");
35441
- el.style.color = textColor;
36833
+ el.style.color = textColor2;
35442
36834
  el.querySelectorAll("*").forEach((nested) => {
35443
- nested.style.color = textColor;
36835
+ nested.style.color = textColor2;
35444
36836
  });
35445
36837
  }
35446
36838
  });
@@ -35449,7 +36841,15 @@ function processHtmlForExport(html, tableStyleMap) {
35449
36841
  cleanupHeaderCellStructure(doc.body);
35450
36842
  applyGenericSafeStyles(doc.body);
35451
36843
  cleanupClasses(doc.body);
35452
- return doc.body.innerHTML;
36844
+ const wrapper = doc.createElement("div");
36845
+ wrapper.style.backgroundColor = bgColor;
36846
+ wrapper.style.color = textColor;
36847
+ wrapper.style.padding = "1em";
36848
+ wrapper.style.minHeight = "100%";
36849
+ while (doc.body.firstChild) {
36850
+ wrapper.appendChild(doc.body.firstChild);
36851
+ }
36852
+ return wrapper.outerHTML;
35453
36853
  }
35454
36854
  function cleanupHeaderCellStructure(container) {
35455
36855
  const allHeaderCells = container.querySelectorAll("th");
@@ -35477,6 +36877,19 @@ function applyGenericSafeStyles(container) {
35477
36877
  el.style.cssText += "; " + styles;
35478
36878
  });
35479
36879
  };
36880
+ const addStyleIfNotSetOnElementOrChildren = (selector, property, value) => {
36881
+ container.querySelectorAll(selector).forEach((el) => {
36882
+ const currentValue = el.style.getPropertyValue(property);
36883
+ if (currentValue && currentValue !== "initial" && currentValue !== "inherit") {
36884
+ return;
36885
+ }
36886
+ const childrenWithProperty = el.querySelectorAll(`[style*="${property}"]`);
36887
+ if (childrenWithProperty.length > 0) {
36888
+ return;
36889
+ }
36890
+ el.style.setProperty(property, value);
36891
+ });
36892
+ };
35480
36893
  const addStyleIfNotSet = (selector, property, value) => {
35481
36894
  container.querySelectorAll(selector).forEach((el) => {
35482
36895
  const currentValue = el.style.getPropertyValue(property);
@@ -35485,11 +36898,13 @@ function applyGenericSafeStyles(container) {
35485
36898
  }
35486
36899
  });
35487
36900
  };
35488
- const fontReset = 'font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; font-size: 14px; line-height: 1.5;';
35489
- addStyle(
35490
- "table, p, span, li, td, th, div, h1, h2, h3, h4, h5, h6",
35491
- fontReset
35492
- );
36901
+ const defaultFontFamily = "Arial, sans-serif";
36902
+ const blockSelectors = "table, p, li, td, th, div, h1, h2, h3, h4, h5, h6";
36903
+ const allSelectors = "table, p, span, li, td, th, div, h1, h2, h3, h4, h5, h6";
36904
+ addStyle(allSelectors, "line-height: 1.5;");
36905
+ addStyleIfNotSetOnElementOrChildren(blockSelectors, "font-family", defaultFontFamily);
36906
+ addStyleIfNotSet("table, p, li, td, th, div", "font-size", "16px");
36907
+ addStyle("p", "margin: 0 0 1em 0;");
35493
36908
  addStyle("th p, td p", "margin: 0; padding: 0;");
35494
36909
  addStyle(
35495
36910
  "table",
@@ -35501,7 +36916,34 @@ function applyGenericSafeStyles(container) {
35501
36916
  );
35502
36917
  addStyleIfNotSet("th", "background-color", "#f8f9fa");
35503
36918
  addStyle("th", "font-weight: 600;");
35504
- addStyle("img", "max-width: 100%; height: auto; display: block;");
36919
+ container.querySelectorAll("img").forEach((img) => {
36920
+ const position = img.getAttribute("data-position");
36921
+ const parent = img.parentElement;
36922
+ img.style.cssText += "; max-width: 100%; height: auto;";
36923
+ const hasCaption = parent && parent.tagName.toLowerCase() === "p" && parent.querySelector("em, i");
36924
+ if (position === "left" || position === "right") {
36925
+ const floatDir = position === "left" ? "left" : "right";
36926
+ const marginDir = position === "left" ? "right" : "left";
36927
+ if (hasCaption && parent) {
36928
+ 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;`;
36929
+ img.style.cssText += "; display: block; margin: 0 auto;";
36930
+ const caption = parent.querySelector("em, i");
36931
+ if (caption) {
36932
+ caption.style.cssText += "; display: block; font-size: 0.85em; line-height: 1.4; color: #666; padding-top: 0.5em;";
36933
+ }
36934
+ } else {
36935
+ img.style.cssText += `; float: ${floatDir}; clear: ${floatDir}; margin-${marginDir}: 1em; margin-bottom: 0.5em; max-width: 50%;`;
36936
+ }
36937
+ } else if (position === "full") {
36938
+ img.style.cssText += "; display: block; width: 100%; margin: 1em 0;";
36939
+ } else {
36940
+ img.style.cssText += "; display: block;";
36941
+ if (parent && parent.style.textAlign === "center") {
36942
+ img.style.margin = "0 auto";
36943
+ }
36944
+ }
36945
+ img.removeAttribute("data-position");
36946
+ });
35505
36947
  addStyle("h1", "font-size: 2em; font-weight: bold; margin: 0.67em 0;");
35506
36948
  addStyle("h2", "font-size: 1.5em; font-weight: bold; margin: 0.75em 0;");
35507
36949
  addStyle("h3", "font-size: 1.17em; font-weight: bold; margin: 0.83em 0;");
@@ -35696,11 +37138,28 @@ function detectTableStylesFromInline(table) {
35696
37138
  return result;
35697
37139
  }
35698
37140
  function preprocessInitialContent(html) {
35699
- if (!html || !html.includes("<table")) {
37141
+ if (!html) {
35700
37142
  return html;
35701
37143
  }
35702
37144
  const parser = new DOMParser();
35703
- const doc = parser.parseFromString(html, "text/html");
37145
+ let doc = parser.parseFromString(html, "text/html");
37146
+ let body = doc.body;
37147
+ if (body.children.length === 1) {
37148
+ const firstChild = body.children[0];
37149
+ if (firstChild.tagName === "DIV" && firstChild.style.backgroundColor && firstChild.style.color && firstChild.style.padding) {
37150
+ const innerHtml = firstChild.innerHTML;
37151
+ doc = parser.parseFromString(innerHtml, "text/html");
37152
+ body = doc.body;
37153
+ }
37154
+ }
37155
+ const emptyParagraphs = body.querySelectorAll("p");
37156
+ emptyParagraphs.forEach((p2) => {
37157
+ var _a, _b;
37158
+ const hasOnlyBrOrWhitespace = !((_a = p2.textContent) == null ? void 0 : _a.trim()) && (p2.innerHTML.trim() === "" || p2.innerHTML.trim() === "<br>" || p2.querySelector("br") !== null && !((_b = p2.textContent) == null ? void 0 : _b.trim()));
37159
+ if (hasOnlyBrOrWhitespace) {
37160
+ p2.remove();
37161
+ }
37162
+ });
35704
37163
  const tables = doc.querySelectorAll("table");
35705
37164
  tables.forEach((table) => {
35706
37165
  const styles = detectTableStylesFromInline(table);
@@ -35729,6 +37188,72 @@ function preprocessInitialContent(html) {
35729
37188
  table.classList.add("PlaygroundEditorTheme__table");
35730
37189
  }
35731
37190
  });
37191
+ const images = doc.querySelectorAll("img");
37192
+ images.forEach((img) => {
37193
+ const parent = img.parentElement;
37194
+ if (!parent)
37195
+ return;
37196
+ const imgFloat = img.style.float;
37197
+ const parentFloat = parent.style.float;
37198
+ const floatDir = imgFloat || parentFloat;
37199
+ if (floatDir === "left" || floatDir === "right") {
37200
+ img.setAttribute("data-position", floatDir);
37201
+ if (parentFloat && parent.tagName.toLowerCase() === "p") {
37202
+ parent.style.textAlign = floatDir;
37203
+ parent.style.removeProperty("float");
37204
+ parent.style.removeProperty("clear");
37205
+ parent.style.removeProperty("max-width");
37206
+ parent.style.removeProperty("background-color");
37207
+ parent.style.removeProperty("padding");
37208
+ parent.style.removeProperty("border-radius");
37209
+ }
37210
+ }
37211
+ });
37212
+ const styledElements = doc.querySelectorAll("span[style], b[style], strong[style], i[style], em[style]");
37213
+ styledElements.forEach((el) => {
37214
+ const htmlEl = el;
37215
+ const style = htmlEl.style;
37216
+ const relevantStyles = [];
37217
+ if (style.fontFamily) {
37218
+ const fontFamily = style.fontFamily.replace(/["']/g, "");
37219
+ relevantStyles.push(`font-family: ${fontFamily}`);
37220
+ }
37221
+ if (style.fontSize) {
37222
+ relevantStyles.push(`font-size: ${style.fontSize}`);
37223
+ }
37224
+ if (style.lineHeight) {
37225
+ relevantStyles.push(`line-height: ${style.lineHeight}`);
37226
+ }
37227
+ if (style.color && style.color !== "rgb(0, 0, 0)") {
37228
+ relevantStyles.push(`color: ${style.color}`);
37229
+ }
37230
+ if (style.backgroundColor && style.backgroundColor !== "rgba(0, 0, 0, 0)" && style.backgroundColor !== "transparent") {
37231
+ relevantStyles.push(`background-color: ${style.backgroundColor}`);
37232
+ }
37233
+ if (style.letterSpacing && style.letterSpacing !== "normal") {
37234
+ relevantStyles.push(`letter-spacing: ${style.letterSpacing}`);
37235
+ }
37236
+ if (style.wordSpacing && style.wordSpacing !== "normal") {
37237
+ relevantStyles.push(`word-spacing: ${style.wordSpacing}`);
37238
+ }
37239
+ if (relevantStyles.length > 0) {
37240
+ htmlEl.setAttribute("style", relevantStyles.join("; "));
37241
+ }
37242
+ });
37243
+ const headings = doc.querySelectorAll("h1, h2, h3, h4, h5, h6");
37244
+ headings.forEach((heading) => {
37245
+ const tagName = heading.tagName.toLowerCase();
37246
+ const className = `PlaygroundEditorTheme__${tagName}`;
37247
+ if (!heading.classList.contains(className)) {
37248
+ heading.classList.add(className);
37249
+ }
37250
+ });
37251
+ const paragraphs = doc.querySelectorAll("p");
37252
+ paragraphs.forEach((p2) => {
37253
+ if (!p2.classList.contains("PlaygroundEditorTheme__paragraph")) {
37254
+ p2.classList.add("PlaygroundEditorTheme__paragraph");
37255
+ }
37256
+ });
35732
37257
  return doc.body.innerHTML;
35733
37258
  }
35734
37259
  const useAutoExpandingHeight = ({
@@ -35799,6 +37324,8 @@ const useStyles = () => ({
35799
37324
  "cteditor-relative cteditor-min-h-[300px] cteditor-rounded-lg cteditor-p-3 !cteditor-h-auto cteditor-resize-none cteditor-outline-0 cteditor-content",
35800
37325
  // Ensure strong contrast in both themes
35801
37326
  "cteditor-text-foreground cteditor-bg-background",
37327
+ // Default font: Arial 16px to match toolbar defaults and ensure WYSIWYG output
37328
+ "cteditor-font-arial cteditor-text-base",
35802
37329
  // Caret and spacing
35803
37330
  "cteditor-caret-[#3b82f6] cteditor-p-0 cteditor-transition-all cteditor-duration-200",
35804
37331
  "cteditor-w-full ",
@@ -35849,6 +37376,172 @@ const OnChangeWrapper = ({
35849
37376
  };
35850
37377
  return /* @__PURE__ */ jsx(OnChangePlugin, { onChange: handleChange });
35851
37378
  };
37379
+ function getStyleFromElement(element) {
37380
+ const styles = [];
37381
+ const style = element.style;
37382
+ if (style.fontFamily) {
37383
+ const fontFamily = style.fontFamily.replace(/["']/g, "").trim();
37384
+ if (fontFamily) {
37385
+ styles.push(`font-family: ${fontFamily}`);
37386
+ }
37387
+ }
37388
+ if (style.fontSize) {
37389
+ styles.push(`font-size: ${style.fontSize}`);
37390
+ }
37391
+ if (style.lineHeight) {
37392
+ styles.push(`line-height: ${style.lineHeight}`);
37393
+ }
37394
+ if (style.color && style.color !== "rgb(0, 0, 0)") {
37395
+ styles.push(`color: ${style.color}`);
37396
+ }
37397
+ if (style.backgroundColor && style.backgroundColor !== "rgba(0, 0, 0, 0)" && style.backgroundColor !== "transparent") {
37398
+ styles.push(`background-color: ${style.backgroundColor}`);
37399
+ }
37400
+ if (style.letterSpacing && style.letterSpacing !== "normal") {
37401
+ styles.push(`letter-spacing: ${style.letterSpacing}`);
37402
+ }
37403
+ if (style.wordSpacing && style.wordSpacing !== "normal") {
37404
+ styles.push(`word-spacing: ${style.wordSpacing}`);
37405
+ }
37406
+ return styles.join("; ");
37407
+ }
37408
+ function collectTextSegmentsFromElement(element) {
37409
+ const segments = [];
37410
+ function traverse(node, inheritedStyle) {
37411
+ if (node.nodeType === Node.TEXT_NODE) {
37412
+ const text = node.textContent || "";
37413
+ if (text) {
37414
+ segments.push({ text, style: inheritedStyle });
37415
+ }
37416
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
37417
+ const el = node;
37418
+ const tagName = el.tagName.toLowerCase();
37419
+ if (["br", "img", "hr"].includes(tagName)) {
37420
+ return;
37421
+ }
37422
+ const elementStyle = getStyleFromElement(el);
37423
+ const currentStyle = elementStyle || inheritedStyle;
37424
+ const children = el.childNodes;
37425
+ for (let i2 = 0; i2 < children.length; i2++) {
37426
+ traverse(children[i2], currentStyle);
37427
+ }
37428
+ }
37429
+ }
37430
+ traverse(element, "");
37431
+ return segments;
37432
+ }
37433
+ function splitAndStyleTextNode(textNode, segments) {
37434
+ if (!$isTextNode(textNode) || segments.length === 0) {
37435
+ return;
37436
+ }
37437
+ const nodeText = textNode.getTextContent();
37438
+ const format = textNode.getFormat();
37439
+ const styledSegments = segments.filter((s2) => s2.style);
37440
+ if (styledSegments.length <= 1) {
37441
+ const styledSegment = styledSegments[0];
37442
+ if (styledSegment) {
37443
+ textNode.setStyle(styledSegment.style);
37444
+ }
37445
+ return;
37446
+ }
37447
+ const splitPoints = [];
37448
+ let runningOffset = 0;
37449
+ for (const segment of segments) {
37450
+ const segmentLength = segment.text.length;
37451
+ if (segment.style) {
37452
+ splitPoints.push({
37453
+ offset: runningOffset,
37454
+ style: segment.style
37455
+ });
37456
+ }
37457
+ runningOffset += segmentLength;
37458
+ }
37459
+ if (splitPoints.length === 0) {
37460
+ return;
37461
+ }
37462
+ const offsetsToSplit = [];
37463
+ runningOffset = 0;
37464
+ for (let i2 = 0; i2 < segments.length - 1; i2++) {
37465
+ runningOffset += segments[i2].text.length;
37466
+ if (runningOffset > 0 && runningOffset < nodeText.length) {
37467
+ offsetsToSplit.push(runningOffset);
37468
+ }
37469
+ }
37470
+ if (offsetsToSplit.length === 0) {
37471
+ if (splitPoints[0]) {
37472
+ textNode.setStyle(splitPoints[0].style);
37473
+ }
37474
+ return;
37475
+ }
37476
+ try {
37477
+ const splitNodes = textNode.splitText(...offsetsToSplit);
37478
+ let segmentIndex = 0;
37479
+ for (const splitNode of splitNodes) {
37480
+ if ($isTextNode(splitNode) && segmentIndex < segments.length) {
37481
+ const segment = segments[segmentIndex];
37482
+ if (segment.style) {
37483
+ splitNode.setStyle(segment.style);
37484
+ }
37485
+ splitNode.setFormat(format);
37486
+ segmentIndex++;
37487
+ }
37488
+ }
37489
+ } catch {
37490
+ if (splitPoints[0]) {
37491
+ textNode.setStyle(splitPoints[0].style);
37492
+ }
37493
+ }
37494
+ }
37495
+ const BLOCK_SELECTORS = "p, h1, h2, h3, h4, h5, h6, li, blockquote";
37496
+ function collectBlockStyleMap(container) {
37497
+ const map = /* @__PURE__ */ new Map();
37498
+ const blocks = container.querySelectorAll(BLOCK_SELECTORS);
37499
+ blocks.forEach((block) => {
37500
+ const segments = collectTextSegmentsFromElement(block);
37501
+ const fullText = segments.map((s2) => s2.text).join("").trim();
37502
+ if (fullText && segments.some((s2) => s2.style)) {
37503
+ const normalizedText = fullText.replace(/\s+/g, " ").toLowerCase();
37504
+ map.set(normalizedText, segments);
37505
+ }
37506
+ });
37507
+ return map;
37508
+ }
37509
+ function applyStylesToBlockNodes(lexicalNodes, blockStyleMap) {
37510
+ for (const node of lexicalNodes) {
37511
+ if ($isElementNode(node)) {
37512
+ const nodeType = node.getType();
37513
+ const isBlockElement = [
37514
+ "paragraph",
37515
+ "heading",
37516
+ "listitem",
37517
+ "quote"
37518
+ ].includes(nodeType);
37519
+ if (isBlockElement) {
37520
+ const nodeText = node.getTextContent().trim();
37521
+ if (nodeText) {
37522
+ const normalizedNodeText = nodeText.replace(/\s+/g, " ").toLowerCase();
37523
+ const segments = blockStyleMap.get(normalizedNodeText);
37524
+ if (segments && segments.length > 0) {
37525
+ const textChildren = node.getChildren().filter($isTextNode);
37526
+ if (textChildren.length === 1) {
37527
+ splitAndStyleTextNode(textChildren[0], segments);
37528
+ } else if (textChildren.length > 0) {
37529
+ for (let i2 = 0; i2 < textChildren.length && i2 < segments.length; i2++) {
37530
+ const textNode = textChildren[i2];
37531
+ const segment = segments[i2];
37532
+ if (segment.style) {
37533
+ textNode.setStyle(segment.style);
37534
+ }
37535
+ }
37536
+ }
37537
+ }
37538
+ }
37539
+ } else {
37540
+ applyStylesToBlockNodes(node.getChildren(), blockStyleMap);
37541
+ }
37542
+ }
37543
+ }
37544
+ }
35852
37545
  const InitialContentPlugin = ({
35853
37546
  initialContent
35854
37547
  }) => {
@@ -35862,7 +37555,9 @@ const InitialContentPlugin = ({
35862
37555
  editor.update(() => {
35863
37556
  const parser = new DOMParser();
35864
37557
  const dom = parser.parseFromString(processedHtml, "text/html");
37558
+ const blockStyleMap = collectBlockStyleMap(dom.body);
35865
37559
  const nodes = $generateNodesFromDOM(editor, dom);
37560
+ applyStylesToBlockNodes(nodes, blockStyleMap);
35866
37561
  const root2 = $getRoot();
35867
37562
  root2.clear();
35868
37563
  root2.append(...nodes);
@@ -36137,7 +37832,8 @@ const ConfigurableEditor = ({
36137
37832
  ErrorBoundary: LexicalErrorBoundary
36138
37833
  }
36139
37834
  ),
36140
- /* @__PURE__ */ jsx(WordCountPlugin, {})
37835
+ /* @__PURE__ */ jsx(WordCountPlugin, {}),
37836
+ /* @__PURE__ */ jsx(UsageTrackingPlugin, { licenseKey: apiKey })
36141
37837
  ] }),
36142
37838
  /* @__PURE__ */ jsx(HtmlViewDisplay, {}),
36143
37839
  /* @__PURE__ */ jsx(AIRephrasePlugin, {}),
@@ -36227,9 +37923,9 @@ const ScopedEditorWrapper = ({
36227
37923
  }) => {
36228
37924
  return /* @__PURE__ */ jsx("div", { id: "ct-editor-f47ac10b", className: "cteditor-max-w-full", children: /* @__PURE__ */ jsx("div", { className: "cteditor-p-2 cteditor-w-full cteditor-relative", children }) });
36229
37925
  };
36230
- const trackEditorLoad = async () => {
37926
+ const trackEditorLoad = async (licenseKey) => {
36231
37927
  try {
36232
- await backendAPI.post("/api/analytics/editor-load", {});
37928
+ await backendAPI.post("/api/analytics/editor-load", { licenseKey });
36233
37929
  } catch {
36234
37930
  }
36235
37931
  };
@@ -36312,11 +38008,11 @@ const ConfigurableEditorWithAuth = ({
36312
38008
  }, [isAuthenticated, error]);
36313
38009
  useEffect$1(() => {
36314
38010
  console.log("isAuthenticated:", isAuthenticated);
36315
- if (isAuthenticated && !hasTrackedLoadRef.current) {
38011
+ if (isAuthenticated && !hasTrackedLoadRef.current && apiKey) {
36316
38012
  hasTrackedLoadRef.current = true;
36317
- trackEditorLoad();
38013
+ trackEditorLoad(apiKey);
36318
38014
  }
36319
- }, [isAuthenticated]);
38015
+ }, [isAuthenticated, apiKey]);
36320
38016
  if (isLoading) {
36321
38017
  return /* @__PURE__ */ jsx(ScopedEditorWrapper, { children: /* @__PURE__ */ jsx(LoadingMessage, { children: /* @__PURE__ */ jsx("span", { children: "Loading editor..." }) }) });
36322
38018
  }
@@ -36375,4 +38071,4 @@ export {
36375
38071
  useHtmlView as u,
36376
38072
  verifyApiKey as v
36377
38073
  };
36378
- //# sourceMappingURL=index-dbb526cd.js.map
38074
+ //# sourceMappingURL=index-c4b49ec3.js.map