ct-rich-text-editor 1.3.18 → 1.3.19

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, 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, 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";
@@ -1479,7 +1479,7 @@ const AiTextTransform = async ({ content, apiKey }) => {
1479
1479
  const AI_ACTION_COMMAND = createCommand(
1480
1480
  "AI_ACTION_COMMAND"
1481
1481
  );
1482
- const ImageView = React__default.lazy(() => import("./index-2bc5ccbc.js"));
1482
+ const ImageView = React__default.lazy(() => import("./index-913b3634.js"));
1483
1483
  function isGoogleDocCheckboxImg(img) {
1484
1484
  return img.parentElement != null && img.parentElement.tagName === "LI" && img.previousSibling === null && img.getAttribute("aria-roledescription") === "checkbox";
1485
1485
  }
@@ -1489,11 +1489,16 @@ function $convertImageElement(domNode) {
1489
1489
  return null;
1490
1490
  }
1491
1491
  const { alt: altText, src, width, height } = img;
1492
- const node = $createImageNode({ altText, height, src, width });
1492
+ const positionAttr = img.getAttribute("data-position");
1493
+ let position = "none";
1494
+ if (positionAttr === "left" || positionAttr === "right" || positionAttr === "full") {
1495
+ position = positionAttr;
1496
+ }
1497
+ const node = $createImageNode({ altText, height, src, width, position });
1493
1498
  return { node };
1494
1499
  }
1495
1500
  class ImageNode extends DecoratorNode {
1496
- constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, key) {
1501
+ constructor(src, altText, maxWidth, width, height, showCaption, caption, captionsEnabled, originalPrompt, position, key) {
1497
1502
  super(key);
1498
1503
  __publicField(this, "__src");
1499
1504
  __publicField(this, "__altText");
@@ -1505,6 +1510,7 @@ class ImageNode extends DecoratorNode {
1505
1510
  // Captions cannot yet be used within editor cells
1506
1511
  __publicField(this, "__captionsEnabled");
1507
1512
  __publicField(this, "__originalPrompt");
1513
+ __publicField(this, "__position");
1508
1514
  this.__src = src;
1509
1515
  this.__altText = altText;
1510
1516
  this.__maxWidth = maxWidth;
@@ -1516,6 +1522,7 @@ class ImageNode extends DecoratorNode {
1516
1522
  });
1517
1523
  this.__captionsEnabled = captionsEnabled || captionsEnabled === void 0;
1518
1524
  this.__originalPrompt = originalPrompt || "";
1525
+ this.__position = position || "none";
1519
1526
  }
1520
1527
  // to identify the image node and must unique too
1521
1528
  static getType() {
@@ -1533,12 +1540,13 @@ class ImageNode extends DecoratorNode {
1533
1540
  node.__caption,
1534
1541
  node.__captionsEnabled,
1535
1542
  node.__originalPrompt,
1543
+ node.__position,
1536
1544
  node.__key
1537
1545
  );
1538
1546
  }
1539
1547
  // importing to json format
1540
1548
  static importJSON(serializedNode) {
1541
- const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt } = serializedNode;
1549
+ const { altText, height, width, maxWidth, caption, src, showCaption, originalPrompt, position } = serializedNode;
1542
1550
  const node = $createImageNode({
1543
1551
  altText,
1544
1552
  height,
@@ -1546,8 +1554,9 @@ class ImageNode extends DecoratorNode {
1546
1554
  showCaption,
1547
1555
  src,
1548
1556
  width,
1549
- originalPrompt: originalPrompt || ""
1557
+ originalPrompt: originalPrompt || "",
1550
1558
  // Default to empty string if undefined
1559
+ position: position || "none"
1551
1560
  });
1552
1561
  const nestedEditor = node.__caption;
1553
1562
  const editorState = nestedEditor.parseEditorState(caption.editorState);
@@ -1558,12 +1567,15 @@ class ImageNode extends DecoratorNode {
1558
1567
  }
1559
1568
  // Exports this node as an actual <img> tag in the DOM when needed
1560
1569
  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 };
1570
+ const img = document.createElement("img");
1571
+ img.setAttribute("src", this.__src);
1572
+ img.setAttribute("alt", this.__altText);
1573
+ img.setAttribute("width", this.__width.toString());
1574
+ img.setAttribute("height", this.__height.toString());
1575
+ if (this.__position && this.__position !== "none") {
1576
+ img.setAttribute("data-position", this.__position);
1577
+ }
1578
+ return { element: img };
1567
1579
  }
1568
1580
  // convert img tag into image node in the editor using convertImageElement func
1569
1581
  static importDOM() {
@@ -1585,7 +1597,8 @@ class ImageNode extends DecoratorNode {
1585
1597
  type: "image",
1586
1598
  version: 1,
1587
1599
  width: this.__width === "inherit" ? 0 : this.__width,
1588
- originalPrompt: this.__originalPrompt
1600
+ originalPrompt: this.__originalPrompt,
1601
+ position: this.__position
1589
1602
  };
1590
1603
  }
1591
1604
  // setting width and height when resizing
@@ -1607,9 +1620,26 @@ class ImageNode extends DecoratorNode {
1607
1620
  if (className !== void 0) {
1608
1621
  span.className = className;
1609
1622
  }
1623
+ if (this.__position === "left") {
1624
+ span.style.cssText = "float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1625
+ } else if (this.__position === "right") {
1626
+ span.style.cssText = "float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1627
+ } else if (this.__position === "full") {
1628
+ span.style.cssText = "display: block; width: 100%; margin: 1em 0;";
1629
+ }
1610
1630
  return span;
1611
1631
  }
1612
- updateDOM() {
1632
+ updateDOM(prevNode, dom) {
1633
+ if (prevNode.__position !== this.__position) {
1634
+ dom.style.cssText = "";
1635
+ if (this.__position === "left") {
1636
+ dom.style.cssText = "float: left; margin-right: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1637
+ } else if (this.__position === "right") {
1638
+ dom.style.cssText = "float: right; margin-left: 1em; margin-bottom: 0.5em; max-width: 50%; display: block;";
1639
+ } else if (this.__position === "full") {
1640
+ dom.style.cssText = "display: block; width: 100%; margin: 1em 0;";
1641
+ }
1642
+ }
1613
1643
  return false;
1614
1644
  }
1615
1645
  // to get the image src
@@ -1633,6 +1663,15 @@ class ImageNode extends DecoratorNode {
1633
1663
  const writable = this.getWritable();
1634
1664
  writable.__originalPrompt = prompt;
1635
1665
  }
1666
+ // to get the image position (float)
1667
+ getPosition() {
1668
+ return this.__position;
1669
+ }
1670
+ // to set the image position (float)
1671
+ setPosition(position) {
1672
+ const writable = this.getWritable();
1673
+ writable.__position = position;
1674
+ }
1636
1675
  // to render the image tag
1637
1676
  decorate() {
1638
1677
  return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(
@@ -1648,7 +1687,8 @@ class ImageNode extends DecoratorNode {
1648
1687
  caption: this.__caption,
1649
1688
  captionsEnabled: this.__captionsEnabled,
1650
1689
  resizable: true,
1651
- originalPrompt: this.__originalPrompt
1690
+ originalPrompt: this.__originalPrompt,
1691
+ position: this.__position
1652
1692
  }
1653
1693
  ) });
1654
1694
  }
@@ -1663,7 +1703,8 @@ function $createImageNode({
1663
1703
  showCaption,
1664
1704
  caption,
1665
1705
  key,
1666
- originalPrompt
1706
+ originalPrompt,
1707
+ position
1667
1708
  }) {
1668
1709
  return $applyNodeReplacement(
1669
1710
  new ImageNode(
@@ -1676,6 +1717,7 @@ function $createImageNode({
1676
1717
  caption,
1677
1718
  captionsEnabled,
1678
1719
  originalPrompt,
1720
+ position,
1679
1721
  key
1680
1722
  )
1681
1723
  );
@@ -7551,6 +7593,17 @@ const Minimize2 = createLucideIcon("Minimize2", [
7551
7593
  * See the LICENSE file in the root directory of this source tree.
7552
7594
  */
7553
7595
  const Minus = createLucideIcon("Minus", [["path", { d: "M5 12h14", key: "1ays0h" }]]);
7596
+ /**
7597
+ * @license lucide-react v0.344.0 - ISC
7598
+ *
7599
+ * This source code is licensed under the ISC license.
7600
+ * See the LICENSE file in the root directory of this source tree.
7601
+ */
7602
+ const PanelBottomOpen = createLucideIcon("PanelBottomOpen", [
7603
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }],
7604
+ ["path", { d: "M3 15h18", key: "5xshup" }],
7605
+ ["path", { d: "m9 10 3-3 3 3", key: "11gsxs" }]
7606
+ ]);
7554
7607
  /**
7555
7608
  * @license lucide-react v0.344.0 - ISC
7556
7609
  *
@@ -7660,6 +7713,16 @@ const Search = createLucideIcon("Search", [
7660
7713
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }],
7661
7714
  ["path", { d: "m21 21-4.3-4.3", key: "1qie3q" }]
7662
7715
  ]);
7716
+ /**
7717
+ * @license lucide-react v0.344.0 - ISC
7718
+ *
7719
+ * This source code is licensed under the ISC license.
7720
+ * See the LICENSE file in the root directory of this source tree.
7721
+ */
7722
+ const Send = createLucideIcon("Send", [
7723
+ ["path", { d: "m22 2-7 20-4-9-9-4Z", key: "1q3vgg" }],
7724
+ ["path", { d: "M22 2 11 13", key: "nzbqef" }]
7725
+ ]);
7663
7726
  /**
7664
7727
  * @license lucide-react v0.344.0 - ISC
7665
7728
  *
@@ -15282,7 +15345,7 @@ const EmbedComponent = ({ url, displayType, alignment, nodeKey }) => {
15282
15345
  }
15283
15346
  );
15284
15347
  };
15285
- const FileComponent = React$1.lazy(() => import("./index-7ddd4fcc.js"));
15348
+ const FileComponent = React$1.lazy(() => import("./index-afa4eda8.js"));
15286
15349
  function convertFileElement(domNode) {
15287
15350
  if (domNode instanceof HTMLDivElement) {
15288
15351
  const dataUrl = domNode.getAttribute("data-lexical-file-src");
@@ -18577,7 +18640,7 @@ const formatMenuItems = [
18577
18640
  }
18578
18641
  ];
18579
18642
  const LOWEST_PRIORITY = 1;
18580
- const DEFAULT_FONT_SIZE = 15;
18643
+ const DEFAULT_FONT_SIZE$1 = 15;
18581
18644
  const INITIAL_TOOLBAR_STATE = {
18582
18645
  bgColor: "#fff",
18583
18646
  blockType: "paragraph",
@@ -18588,9 +18651,9 @@ const INITIAL_TOOLBAR_STATE = {
18588
18651
  fontColor: "#000",
18589
18652
  fontFamily: "Arial",
18590
18653
  // Current font size in px
18591
- fontSize: `${DEFAULT_FONT_SIZE}px`,
18654
+ fontSize: `${DEFAULT_FONT_SIZE$1}px`,
18592
18655
  // Font size input value - for controlled input
18593
- fontSizeInputValue: `${DEFAULT_FONT_SIZE}`,
18656
+ fontSizeInputValue: `${DEFAULT_FONT_SIZE$1}`,
18594
18657
  isBold: false,
18595
18658
  isCode: false,
18596
18659
  isHighlight: false,
@@ -19061,12 +19124,15 @@ const useVoiceToText = ({ onTranscriptUpdate }) => {
19061
19124
  };
19062
19125
  };
19063
19126
  const TOGGLE_AI_CHAT_COMMAND = createCommand();
19127
+ const SHOW_INLINE_AI_PROMPT_COMMAND = createCommand();
19064
19128
  function AIChatDialog({
19065
19129
  open,
19066
19130
  onOpenChange,
19067
19131
  editor,
19068
19132
  apiKey,
19069
- initialText
19133
+ initialText,
19134
+ onShowInEditor,
19135
+ selectedTextForInline
19070
19136
  }) {
19071
19137
  const [inputValue, setInputValue] = useState$1("");
19072
19138
  const [isLoading, setIsLoading] = useState$1(false);
@@ -19330,6 +19396,24 @@ function AIChatDialog({
19330
19396
  children: "Cancel"
19331
19397
  }
19332
19398
  ),
19399
+ /* @__PURE__ */ jsxs(
19400
+ Button,
19401
+ {
19402
+ variant: "outline",
19403
+ onClick: () => {
19404
+ if (onShowInEditor) {
19405
+ onShowInEditor(provider, selectedTextForInline);
19406
+ handleClose();
19407
+ }
19408
+ },
19409
+ disabled: isLoading,
19410
+ title: "Show AI prompt in the editor text area",
19411
+ children: [
19412
+ /* @__PURE__ */ jsx(PanelBottomOpen, { size: 16 }),
19413
+ "Show in Editor"
19414
+ ]
19415
+ }
19416
+ ),
19333
19417
  /* @__PURE__ */ jsx(
19334
19418
  Button,
19335
19419
  {
@@ -19347,10 +19431,257 @@ function AIChatDialog({
19347
19431
  ] })
19348
19432
  ] }) }) });
19349
19433
  }
19350
- function useAIChatToolbar(editor, apiKey) {
19434
+ function InlineAIPrompt({
19435
+ editor,
19436
+ apiKey,
19437
+ initialProvider,
19438
+ selectedText: initialSelectedText,
19439
+ onClose,
19440
+ anchorElem
19441
+ }) {
19442
+ const [provider, setProvider] = useState$1(initialProvider);
19443
+ const [inputValue, setInputValue] = useState$1("");
19444
+ const [isLoading, setIsLoading] = useState$1(false);
19445
+ const inputRef = useRef(null);
19446
+ const [selectedText, setSelectedText] = useState$1(initialSelectedText);
19447
+ useEffect$1(() => {
19448
+ const unregister = editor.registerUpdateListener(({ editorState }) => {
19449
+ editorState.read(() => {
19450
+ const selection = $getSelection();
19451
+ if (selection && selection.getTextContent().trim()) {
19452
+ const newSelectedText = selection.getTextContent();
19453
+ if (newSelectedText.trim() !== "") {
19454
+ setSelectedText(newSelectedText);
19455
+ }
19456
+ }
19457
+ });
19458
+ });
19459
+ return () => {
19460
+ unregister();
19461
+ };
19462
+ }, [editor]);
19463
+ useEffect$1(() => {
19464
+ if (inputRef.current) {
19465
+ inputRef.current.focus();
19466
+ }
19467
+ }, []);
19468
+ const handleSubmit = async () => {
19469
+ var _a, _b;
19470
+ if (!inputValue.trim() || isLoading)
19471
+ return;
19472
+ if (!selectedText || selectedText.trim() === "") {
19473
+ toast.error("Please select some text first");
19474
+ return;
19475
+ }
19476
+ setIsLoading(true);
19477
+ const fullPrompt = `${inputValue}
19478
+
19479
+ 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.
19480
+
19481
+ Text to transform:
19482
+ "${selectedText}"`;
19483
+ try {
19484
+ const response = await AiEditorAction({ content: fullPrompt, provider, apiKey });
19485
+ let htmlString = response.data;
19486
+ if (typeof htmlString === "string") {
19487
+ htmlString = htmlString.trim();
19488
+ if (htmlString.startsWith('"') && htmlString.endsWith('"') || htmlString.startsWith("'") && htmlString.endsWith("'")) {
19489
+ htmlString = htmlString.slice(1, -1);
19490
+ }
19491
+ }
19492
+ editor.update(() => {
19493
+ const parser = new DOMParser();
19494
+ const dom = parser.parseFromString(htmlString.trim(), "text/html");
19495
+ const nodes = $generateNodesFromDOM(editor, dom);
19496
+ const currentSelection = $getSelection();
19497
+ if (currentSelection) {
19498
+ $insertNodes(nodes);
19499
+ }
19500
+ });
19501
+ setInputValue("");
19502
+ setSelectedText("");
19503
+ } catch (error) {
19504
+ console.error("Error processing AI action:", error);
19505
+ 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);
19506
+ const safeMessage = apiMessage && !/^Request failed with status code \d+/.test(apiMessage) ? apiMessage : "Error processing your request. Please try again.";
19507
+ toast.error(safeMessage);
19508
+ } finally {
19509
+ setIsLoading(false);
19510
+ }
19511
+ };
19512
+ const handleKeyDown = (e) => {
19513
+ if (e.key === "Enter" && !e.shiftKey && !isLoading && inputValue.trim()) {
19514
+ e.preventDefault();
19515
+ handleSubmit();
19516
+ }
19517
+ if (e.key === "Escape") {
19518
+ onClose();
19519
+ }
19520
+ };
19521
+ const hasSelectedText = selectedText && selectedText.trim() !== "";
19522
+ const displayText = hasSelectedText ? selectedText.length > 50 ? selectedText.substring(0, 50) + "..." : selectedText : "";
19523
+ return /* @__PURE__ */ jsxs(
19524
+ "div",
19525
+ {
19526
+ style: {
19527
+ position: "absolute",
19528
+ bottom: "12px",
19529
+ left: "50%",
19530
+ transform: "translateX(-50%)",
19531
+ display: "flex",
19532
+ flexDirection: "column",
19533
+ gap: "8px",
19534
+ backgroundColor: "#1a1a1a",
19535
+ padding: "12px 16px",
19536
+ borderRadius: "12px",
19537
+ border: "1px solid #333",
19538
+ boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
19539
+ zIndex: 10,
19540
+ maxWidth: "500px"
19541
+ },
19542
+ children: [
19543
+ /* @__PURE__ */ jsx(
19544
+ "div",
19545
+ {
19546
+ style: {
19547
+ display: "flex",
19548
+ alignItems: "center",
19549
+ gap: "8px",
19550
+ padding: "6px 10px",
19551
+ backgroundColor: hasSelectedText ? "#2a2a2a" : "#3a2a2a",
19552
+ borderRadius: "6px",
19553
+ fontSize: "12px",
19554
+ color: "#999",
19555
+ border: hasSelectedText ? "none" : "1px solid #5a3a3a"
19556
+ },
19557
+ children: hasSelectedText ? /* @__PURE__ */ jsxs(Fragment, { children: [
19558
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: "Selected:" }),
19559
+ /* @__PURE__ */ jsxs("span", { style: { color: "#ccc", fontStyle: "italic" }, children: [
19560
+ '"',
19561
+ displayText,
19562
+ '"'
19563
+ ] })
19564
+ ] }) : /* @__PURE__ */ jsx("span", { style: { color: "#f87171" }, children: "⚠ Please select some text in the editor first" })
19565
+ }
19566
+ ),
19567
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "10px" }, children: [
19568
+ /* @__PURE__ */ jsx(Sparkles, { size: 16, style: { color: "#fff", flexShrink: 0 } }),
19569
+ /* @__PURE__ */ jsxs(
19570
+ "select",
19571
+ {
19572
+ value: provider,
19573
+ onChange: (e) => setProvider(e.target.value),
19574
+ style: {
19575
+ width: "100px",
19576
+ height: "32px",
19577
+ padding: "0 8px",
19578
+ fontSize: "13px",
19579
+ fontWeight: 500,
19580
+ border: "1px solid #444",
19581
+ borderRadius: "6px",
19582
+ outline: "none",
19583
+ backgroundColor: "#2a2a2a",
19584
+ color: "#fff",
19585
+ cursor: "pointer"
19586
+ },
19587
+ children: [
19588
+ /* @__PURE__ */ jsx("option", { value: "chatgpt", children: "ChatGPT" }),
19589
+ /* @__PURE__ */ jsx("option", { value: "claude", children: "Claude" }),
19590
+ /* @__PURE__ */ jsx("option", { value: "grok", children: "Grok" })
19591
+ ]
19592
+ }
19593
+ ),
19594
+ /* @__PURE__ */ jsx(
19595
+ "input",
19596
+ {
19597
+ ref: inputRef,
19598
+ type: "text",
19599
+ value: inputValue,
19600
+ onChange: (e) => setInputValue(e.target.value),
19601
+ onKeyDown: handleKeyDown,
19602
+ placeholder: hasSelectedText ? "What do you want to do with this text?" : "Select text first...",
19603
+ disabled: isLoading,
19604
+ style: {
19605
+ width: "280px",
19606
+ height: "32px",
19607
+ padding: "0 12px",
19608
+ fontSize: "13px",
19609
+ border: "1px solid #444",
19610
+ borderRadius: "6px",
19611
+ outline: "none",
19612
+ backgroundColor: "#2a2a2a",
19613
+ color: "#fff"
19614
+ }
19615
+ }
19616
+ ),
19617
+ /* @__PURE__ */ jsx(
19618
+ "button",
19619
+ {
19620
+ type: "button",
19621
+ onClick: handleSubmit,
19622
+ disabled: isLoading || !inputValue.trim(),
19623
+ style: {
19624
+ height: "32px",
19625
+ width: "32px",
19626
+ backgroundColor: "#fff",
19627
+ color: "#1a1a1a",
19628
+ borderRadius: "6px",
19629
+ border: "none",
19630
+ display: "flex",
19631
+ alignItems: "center",
19632
+ justifyContent: "center",
19633
+ cursor: isLoading || !inputValue.trim() ? "not-allowed" : "pointer",
19634
+ opacity: isLoading || !inputValue.trim() ? 0.5 : 1,
19635
+ flexShrink: 0,
19636
+ transition: "background-color 0.2s"
19637
+ },
19638
+ children: isLoading ? /* @__PURE__ */ jsx("div", { style: {
19639
+ height: "14px",
19640
+ width: "14px",
19641
+ border: "2px solid #1a1a1a",
19642
+ borderTopColor: "transparent",
19643
+ borderRadius: "50%",
19644
+ animation: "spin 1s linear infinite"
19645
+ } }) : /* @__PURE__ */ jsx(Send, { size: 14 })
19646
+ }
19647
+ ),
19648
+ /* @__PURE__ */ jsx(
19649
+ "button",
19650
+ {
19651
+ type: "button",
19652
+ onClick: onClose,
19653
+ style: {
19654
+ height: "32px",
19655
+ width: "32px",
19656
+ backgroundColor: "transparent",
19657
+ color: "#888",
19658
+ borderRadius: "6px",
19659
+ border: "none",
19660
+ display: "flex",
19661
+ alignItems: "center",
19662
+ justifyContent: "center",
19663
+ cursor: "pointer",
19664
+ flexShrink: 0,
19665
+ transition: "color 0.2s"
19666
+ },
19667
+ title: "Close (Esc)",
19668
+ onMouseEnter: (e) => e.currentTarget.style.color = "#fff",
19669
+ onMouseLeave: (e) => e.currentTarget.style.color = "#888",
19670
+ children: /* @__PURE__ */ jsx(X$1, { size: 16 })
19671
+ }
19672
+ )
19673
+ ] })
19674
+ ]
19675
+ }
19676
+ );
19677
+ }
19678
+ function useAIChatToolbar(editor, apiKey, anchorElem) {
19351
19679
  const [isVisible, setIsVisible] = useState$1(false);
19352
19680
  const [selectedText, setSelectedText] = useState$1(void 0);
19353
19681
  const savedSelectionRef = useRef(null);
19682
+ const [showInlinePrompt, setShowInlinePrompt] = useState$1(false);
19683
+ const [inlineProvider, setInlineProvider] = useState$1("chatgpt");
19684
+ const [inlineSelectedText, setInlineSelectedText] = useState$1("");
19354
19685
  const toggleAIChat = useCallback((text) => {
19355
19686
  editor.getEditorState().read(() => {
19356
19687
  const selection = $getSelection();
@@ -19361,8 +19692,17 @@ function useAIChatToolbar(editor, apiKey) {
19361
19692
  setSelectedText(text);
19362
19693
  setIsVisible((prevState) => !prevState);
19363
19694
  }, [editor]);
19695
+ const handleShowInEditor = useCallback((provider, textFromDialog) => {
19696
+ setInlineProvider(provider);
19697
+ setInlineSelectedText(textFromDialog || selectedText || "");
19698
+ setShowInlinePrompt(true);
19699
+ }, [selectedText]);
19700
+ const handleCloseInlinePrompt = useCallback(() => {
19701
+ setShowInlinePrompt(false);
19702
+ setInlineSelectedText("");
19703
+ }, []);
19364
19704
  useEffect$1(() => {
19365
- return editor.registerCommand(
19705
+ const unregisterToggle = editor.registerCommand(
19366
19706
  TOGGLE_AI_CHAT_COMMAND,
19367
19707
  (text) => {
19368
19708
  toggleAIChat(text);
@@ -19370,18 +19710,55 @@ function useAIChatToolbar(editor, apiKey) {
19370
19710
  },
19371
19711
  COMMAND_PRIORITY_LOW
19372
19712
  );
19713
+ const unregisterInline = editor.registerCommand(
19714
+ SHOW_INLINE_AI_PROMPT_COMMAND,
19715
+ (payload) => {
19716
+ let currentSelectedText = "";
19717
+ editor.getEditorState().read(() => {
19718
+ const selection = $getSelection();
19719
+ if (selection) {
19720
+ currentSelectedText = selection.getTextContent();
19721
+ }
19722
+ });
19723
+ setInlineProvider((payload == null ? void 0 : payload.provider) || "chatgpt");
19724
+ setInlineSelectedText((payload == null ? void 0 : payload.initialText) || currentSelectedText);
19725
+ setShowInlinePrompt(true);
19726
+ return true;
19727
+ },
19728
+ COMMAND_PRIORITY_LOW
19729
+ );
19730
+ return () => {
19731
+ unregisterToggle();
19732
+ unregisterInline();
19733
+ };
19373
19734
  }, [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
- ) });
19735
+ const editorRootElement = editor.getRootElement();
19736
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
19737
+ isVisible && /* @__PURE__ */ jsx(
19738
+ AIChatDialog,
19739
+ {
19740
+ open: isVisible,
19741
+ onOpenChange: setIsVisible,
19742
+ editor,
19743
+ apiKey,
19744
+ initialText: selectedText,
19745
+ savedSelection: savedSelectionRef.current,
19746
+ onShowInEditor: handleShowInEditor,
19747
+ selectedTextForInline: selectedText
19748
+ }
19749
+ ),
19750
+ showInlinePrompt && /* @__PURE__ */ jsx(
19751
+ InlineAIPrompt,
19752
+ {
19753
+ editor,
19754
+ apiKey,
19755
+ initialProvider: inlineProvider,
19756
+ selectedText: inlineSelectedText,
19757
+ onClose: handleCloseInlinePrompt,
19758
+ anchorElem: editorRootElement
19759
+ }
19760
+ )
19761
+ ] });
19385
19762
  }
19386
19763
  function AIChatPlugin({
19387
19764
  apiKey
@@ -19991,10 +20368,10 @@ const PDF_CONFIG = {
19991
20368
  };
19992
20369
  const loadHtml2Pdf = async () => {
19993
20370
  try {
19994
- const mod = await import("./html2pdf.bundle.min-db02af80.js").then((n) => n.h);
20371
+ const mod = await import("./html2pdf.bundle.min-f1b4a78e.js").then((n) => n.h);
19995
20372
  return (mod == null ? void 0 : mod.default) || mod;
19996
20373
  } catch {
19997
- const mod2 = await import("./html2pdf.bundle-0a42a49f.js").then((n) => n.h);
20374
+ const mod2 = await import("./html2pdf.bundle-a30dde70.js").then((n) => n.h);
19998
20375
  return (mod2 == null ? void 0 : mod2.default) || mod2;
19999
20376
  }
20000
20377
  };
@@ -23236,92 +23613,123 @@ const FontFamilyMenu = ({
23236
23613
  activeEditor
23237
23614
  }) => {
23238
23615
  const [selectedFont, setSelectedFont] = useState$1("Arial");
23616
+ const [detectedFonts, setDetectedFonts] = useState$1(/* @__PURE__ */ new Set());
23617
+ const allFonts = useMemo(() => {
23618
+ const fontSet = new Set(fonts);
23619
+ detectedFonts.forEach((font) => fontSet.add(font));
23620
+ return Array.from(fontSet);
23621
+ }, [fonts, detectedFonts]);
23239
23622
  useEffect$1(() => {
23240
23623
  return activeEditor.registerUpdateListener(({ editorState }) => {
23241
23624
  editorState.read(() => {
23242
- var _a;
23243
23625
  const selection = $getSelection();
23244
23626
  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);
23250
- }
23627
+ const fontFamily = $getSelectionStyleValueForProperty(
23628
+ selection,
23629
+ "font-family",
23630
+ "Arial"
23631
+ );
23632
+ const cleanedFont = fontFamily.replace(/^["']|["']$/g, "").trim();
23633
+ setSelectedFont(cleanedFont);
23634
+ if (cleanedFont && cleanedFont !== "Arial" && !fonts.includes(cleanedFont)) {
23635
+ setDetectedFonts((prev) => {
23636
+ if (prev.has(cleanedFont))
23637
+ return prev;
23638
+ const newSet = new Set(prev);
23639
+ newSet.add(cleanedFont);
23640
+ return newSet;
23641
+ });
23251
23642
  }
23252
23643
  }
23253
23644
  });
23254
23645
  });
23255
- }, [activeEditor]);
23256
- const applyFontFamily = (fontFamily) => {
23257
- activeEditor.update(() => {
23258
- const selection = $getSelection();
23259
- if ($isRangeSelection(selection)) {
23260
- $patchStyleText(selection, { "font-family": fontFamily });
23261
- }
23262
- });
23263
- };
23646
+ }, [activeEditor, fonts]);
23647
+ const applyFontFamily = useCallback(
23648
+ (fontFamily) => {
23649
+ activeEditor.update(() => {
23650
+ const selection = $getSelection();
23651
+ if ($isRangeSelection(selection)) {
23652
+ $patchStyleText(selection, { "font-family": fontFamily });
23653
+ }
23654
+ });
23655
+ },
23656
+ [activeEditor]
23657
+ );
23264
23658
  const handleFontChange = (value) => {
23265
23659
  setSelectedFont(value);
23266
23660
  applyFontFamily(value);
23267
23661
  };
23268
23662
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Select, { value: selectedFont, onValueChange: handleFontChange, children: [
23269
23663
  /* @__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)) })
23664
+ /* @__PURE__ */ jsx(SelectContent, { children: allFonts.map((font) => /* @__PURE__ */ jsx(SelectItem, { value: font, style: { fontFamily: font }, children: font }, font)) })
23271
23665
  ] }) });
23272
23666
  };
23273
23667
  const MIN_FONT_SIZE = 8;
23274
23668
  const MAX_FONT_SIZE = 72;
23669
+ const DEFAULT_FONT_SIZE = 16;
23275
23670
  const STEP_SIZE = 2;
23276
23671
  const FontSizeControl = () => {
23277
23672
  const [editor] = useLexicalComposerContext();
23278
- const [fontSize, setFontSize] = useState$1(16);
23279
- const [inputValue, setInputValue] = useState$1("16");
23673
+ const [fontSize, setFontSize] = useState$1(DEFAULT_FONT_SIZE);
23674
+ const [inputValue, setInputValue] = useState$1(DEFAULT_FONT_SIZE.toString());
23675
+ const pendingFontSizeRef = React__default.useRef(null);
23280
23676
  useEffect$1(() => {
23281
23677
  return editor.registerUpdateListener(({ editorState }) => {
23282
23678
  editorState.read(() => {
23283
- var _a;
23284
23679
  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
- }
23680
+ if ($isRangeSelection(selection)) {
23681
+ const fontSizeStr = $getSelectionStyleValueForProperty(
23682
+ selection,
23683
+ "font-size",
23684
+ `${DEFAULT_FONT_SIZE}px`
23685
+ );
23686
+ const size2 = parseInt(fontSizeStr, 10) || DEFAULT_FONT_SIZE;
23687
+ if (pendingFontSizeRef.current !== null && size2 === pendingFontSizeRef.current) {
23688
+ pendingFontSizeRef.current = null;
23689
+ }
23690
+ if (pendingFontSizeRef.current === null) {
23691
+ setFontSize(size2);
23692
+ setInputValue(size2.toString());
23294
23693
  }
23295
23694
  }
23296
23695
  });
23297
23696
  });
23298
23697
  }, [editor]);
23698
+ useEffect$1(() => {
23699
+ const rootElement = editor.getRootElement();
23700
+ if (!rootElement)
23701
+ return;
23702
+ const handleFocus = () => {
23703
+ if (pendingFontSizeRef.current !== null) {
23704
+ const pendingSize = pendingFontSizeRef.current;
23705
+ editor.update(() => {
23706
+ const selection = $getSelection();
23707
+ if ($isRangeSelection(selection)) {
23708
+ $patchStyleText(selection, { "font-size": `${pendingSize}px` });
23709
+ }
23710
+ });
23711
+ }
23712
+ };
23713
+ rootElement.addEventListener("focus", handleFocus);
23714
+ return () => {
23715
+ rootElement.removeEventListener("focus", handleFocus);
23716
+ };
23717
+ }, [editor]);
23299
23718
  const applyFontSize = useCallback(
23300
23719
  (size2) => {
23720
+ pendingFontSizeRef.current = size2;
23301
23721
  editor.update(() => {
23302
23722
  const selection = $getSelection();
23303
23723
  if ($isRangeSelection(selection)) {
23304
23724
  $patchStyleText(selection, { "font-size": `${size2}px` });
23305
23725
  }
23306
23726
  });
23307
- setFontSize(size2);
23308
- setInputValue(size2.toString());
23309
23727
  },
23310
23728
  [editor]
23311
23729
  );
23312
- useEffect$1(() => {
23313
- applyFontSize(fontSize);
23314
- }, [fontSize, applyFontSize]);
23315
23730
  const handleFontSizeChange = (event) => {
23316
23731
  const value = event.target.value.replace(/\D/g, "");
23317
23732
  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
23733
  };
23326
23734
  const handleFontSizeBlur = () => {
23327
23735
  if (inputValue === "" || isNaN(Number(inputValue))) {
@@ -23332,15 +23740,28 @@ const FontSizeControl = () => {
23332
23740
  Math.min(Number(inputValue), MAX_FONT_SIZE)
23333
23741
  );
23334
23742
  setFontSize(newSize);
23743
+ setInputValue(newSize.toString());
23744
+ applyFontSize(newSize);
23745
+ }
23746
+ };
23747
+ const handleKeyDown = (event) => {
23748
+ if (event.key === "Enter") {
23749
+ event.preventDefault();
23750
+ handleFontSizeBlur();
23751
+ editor.focus();
23335
23752
  }
23336
23753
  };
23337
23754
  const increaseFontSize = () => {
23338
23755
  const newSize = Math.min(fontSize + STEP_SIZE, MAX_FONT_SIZE);
23339
23756
  setFontSize(newSize);
23757
+ setInputValue(newSize.toString());
23758
+ applyFontSize(newSize);
23340
23759
  };
23341
23760
  const decreaseFontSize = () => {
23342
23761
  const newSize = Math.max(fontSize - STEP_SIZE, MIN_FONT_SIZE);
23343
23762
  setFontSize(newSize);
23763
+ setInputValue(newSize.toString());
23764
+ applyFontSize(newSize);
23344
23765
  };
23345
23766
  return /* @__PURE__ */ jsxs("div", { className: "cteditor-flex cteditor-items-center cteditor-gap-1", children: [
23346
23767
  /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
@@ -23362,7 +23783,8 @@ const FontSizeControl = () => {
23362
23783
  className: "!cteditor-w-9 !cteditor-h-6 !cteditor-p-0 !cteditor-text-center !cteditor-bg-secondary",
23363
23784
  value: inputValue,
23364
23785
  onChange: handleFontSizeChange,
23365
- onBlur: handleFontSizeBlur
23786
+ onBlur: handleFontSizeBlur,
23787
+ onKeyDown: handleKeyDown
23366
23788
  }
23367
23789
  ),
23368
23790
  /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(Tooltip, { children: [
@@ -25735,7 +26157,15 @@ const Toolbar = ({
25735
26157
  });
25736
26158
  }, [editor]);
25737
26159
  const toggleAIChat = useCallback(() => {
25738
- editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, void 0);
26160
+ editor.getEditorState().read(() => {
26161
+ const selection = $getSelection();
26162
+ if ($isRangeSelection(selection)) {
26163
+ const selectedText = selection.getTextContent();
26164
+ editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, selectedText || void 0);
26165
+ } else {
26166
+ editor.dispatchCommand(TOGGLE_AI_CHAT_COMMAND, void 0);
26167
+ }
26168
+ });
25739
26169
  }, [editor]);
25740
26170
  const createTodo = useCallback(() => {
25741
26171
  editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND, void 0);
@@ -28381,26 +28811,6 @@ function DragDropPaste() {
28381
28811
  return;
28382
28812
  }
28383
28813
  }
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
28814
  };
28405
28815
  const editorElement = editor.getRootElement();
28406
28816
  if (editorElement) {
@@ -31074,6 +31484,827 @@ function NewMentionsPlugin({
31074
31484
  }
31075
31485
  );
31076
31486
  }
31487
+ function detectCSSAlignment(element) {
31488
+ let current = element;
31489
+ while (current && current !== document.body) {
31490
+ const style = current.style;
31491
+ const computedStyle = window.getComputedStyle(current);
31492
+ const textAlign = style.textAlign || computedStyle.textAlign;
31493
+ if (textAlign === "center")
31494
+ return "center";
31495
+ if (textAlign === "right")
31496
+ return "right";
31497
+ if (textAlign === "justify")
31498
+ return "justify";
31499
+ const display = computedStyle.display;
31500
+ const justifyContent = computedStyle.justifyContent;
31501
+ if (display === "flex" && (justifyContent === "center" || justifyContent === "space-around")) {
31502
+ return "center";
31503
+ }
31504
+ const marginLeft = computedStyle.marginLeft;
31505
+ const marginRight = computedStyle.marginRight;
31506
+ if (marginLeft === "auto" && marginRight === "auto") {
31507
+ return "center";
31508
+ }
31509
+ current = current.parentElement;
31510
+ }
31511
+ return null;
31512
+ }
31513
+ function getImageDimensions(imgElement) {
31514
+ let width = parseInt(imgElement.getAttribute("width") || "0");
31515
+ let height = parseInt(imgElement.getAttribute("height") || "0");
31516
+ if (width === 0) {
31517
+ const styleWidth = imgElement.style.width;
31518
+ if (styleWidth && styleWidth.endsWith("px")) {
31519
+ width = parseInt(styleWidth);
31520
+ }
31521
+ }
31522
+ if (height === 0) {
31523
+ const styleHeight = imgElement.style.height;
31524
+ if (styleHeight && styleHeight.endsWith("px")) {
31525
+ height = parseInt(styleHeight);
31526
+ }
31527
+ }
31528
+ if (width === 0 || height === 0) {
31529
+ try {
31530
+ const computed = window.getComputedStyle(imgElement);
31531
+ if (width === 0 && computed.width && computed.width !== "auto") {
31532
+ width = parseInt(computed.width);
31533
+ }
31534
+ if (height === 0 && computed.height && computed.height !== "auto") {
31535
+ height = parseInt(computed.height);
31536
+ }
31537
+ } catch {
31538
+ }
31539
+ }
31540
+ if (imgElement instanceof HTMLImageElement) {
31541
+ if (width === 0 && imgElement.naturalWidth) {
31542
+ width = imgElement.naturalWidth;
31543
+ }
31544
+ if (height === 0 && imgElement.naturalHeight) {
31545
+ height = imgElement.naturalHeight;
31546
+ }
31547
+ }
31548
+ return { width, height };
31549
+ }
31550
+ function shouldCenterImage(imgElement) {
31551
+ var _a;
31552
+ const { width, height } = getImageDimensions(imgElement);
31553
+ if (width >= 500) {
31554
+ return true;
31555
+ }
31556
+ const parent = imgElement.parentElement;
31557
+ if (parent) {
31558
+ const siblings = Array.from(parent.childNodes);
31559
+ const meaningfulSiblings = siblings.filter((node) => {
31560
+ var _a2, _b;
31561
+ if (node === imgElement)
31562
+ return false;
31563
+ if (node.nodeType === Node.TEXT_NODE) {
31564
+ return ((_a2 = node.textContent) == null ? void 0 : _a2.trim().length) !== 0;
31565
+ }
31566
+ if (node.nodeType === Node.ELEMENT_NODE) {
31567
+ const el = node;
31568
+ if (el.tagName.toLowerCase() === "br")
31569
+ return false;
31570
+ return ((_b = el.textContent) == null ? void 0 : _b.trim().length) !== 0;
31571
+ }
31572
+ return false;
31573
+ });
31574
+ if (meaningfulSiblings.length === 0) {
31575
+ return true;
31576
+ }
31577
+ }
31578
+ if (width > 0 && height > 0 && width > height * 1.5 && width >= 300) {
31579
+ return true;
31580
+ }
31581
+ let current = imgElement.parentElement;
31582
+ while (current && current !== document.body) {
31583
+ const tagName = current.tagName.toLowerCase();
31584
+ if (tagName === "figure" || tagName === "article" || tagName === "section") {
31585
+ if (width >= 200 || width === 0) {
31586
+ return true;
31587
+ }
31588
+ }
31589
+ current = current.parentElement;
31590
+ }
31591
+ try {
31592
+ const computed = window.getComputedStyle(imgElement);
31593
+ if (computed.display === "block") {
31594
+ if (width >= 200 || width === 0) {
31595
+ return true;
31596
+ }
31597
+ }
31598
+ } catch {
31599
+ }
31600
+ if (width === 0) {
31601
+ const parentTag = parent == null ? void 0 : parent.tagName.toLowerCase();
31602
+ if (parentTag === "p" || parentTag === "div") {
31603
+ const textContent = ((_a = parent == null ? void 0 : parent.textContent) == null ? void 0 : _a.trim()) || "";
31604
+ if (textContent === "") {
31605
+ return true;
31606
+ }
31607
+ }
31608
+ }
31609
+ return false;
31610
+ }
31611
+ function detectClassBasedAlignment(element) {
31612
+ let current = element;
31613
+ while (current && current !== document.body) {
31614
+ const className = current.className || "";
31615
+ if (className.includes("image-style-align-right") || className.includes("image-style-side")) {
31616
+ return "right";
31617
+ }
31618
+ if (className.includes("image-style-align-left")) {
31619
+ return "left";
31620
+ }
31621
+ if (className.includes("image-style-align-center") || className.includes("image_resized") && !className.includes("align"))
31622
+ ;
31623
+ if (className.includes("align-right")) {
31624
+ return "right";
31625
+ }
31626
+ if (className.includes("align-left")) {
31627
+ return "left";
31628
+ }
31629
+ if (className.includes("align-center")) {
31630
+ return "center";
31631
+ }
31632
+ if (className.includes("float-right") || className.includes("pull-right")) {
31633
+ return "right";
31634
+ }
31635
+ if (className.includes("float-left") || className.includes("pull-left")) {
31636
+ return "left";
31637
+ }
31638
+ try {
31639
+ const computed = window.getComputedStyle(current);
31640
+ if (computed.float === "right") {
31641
+ return "right";
31642
+ }
31643
+ if (computed.float === "left") {
31644
+ return "left";
31645
+ }
31646
+ } catch {
31647
+ }
31648
+ current = current.parentElement;
31649
+ }
31650
+ return null;
31651
+ }
31652
+ function detectImageAlignment(imgElement) {
31653
+ const classAlignment = detectClassBasedAlignment(imgElement);
31654
+ if (classAlignment) {
31655
+ return classAlignment;
31656
+ }
31657
+ const cssAlignment = detectCSSAlignment(imgElement);
31658
+ if (cssAlignment) {
31659
+ return cssAlignment;
31660
+ }
31661
+ if (shouldCenterImage(imgElement)) {
31662
+ return "center";
31663
+ }
31664
+ return "left";
31665
+ }
31666
+ function alignmentToPosition(alignment) {
31667
+ switch (alignment) {
31668
+ case "left":
31669
+ return "left";
31670
+ case "right":
31671
+ return "right";
31672
+ default:
31673
+ return "none";
31674
+ }
31675
+ }
31676
+ function isFloatAlignment(alignment) {
31677
+ return alignment === "left" || alignment === "right";
31678
+ }
31679
+ const IS_BOLD = 1;
31680
+ const IS_ITALIC = 2;
31681
+ const IS_STRIKETHROUGH = 4;
31682
+ const IS_UNDERLINE = 8;
31683
+ const IS_CODE = 16;
31684
+ const IS_SUBSCRIPT = 32;
31685
+ const IS_SUPERSCRIPT = 64;
31686
+ const IS_HIGHLIGHT = 128;
31687
+ function detectCKEditorSource(html) {
31688
+ return html.includes('class="image"') || // CKEditor's figure class for images
31689
+ html.includes('class="image ') || html.includes("image-style-") || // CKEditor's image alignment classes
31690
+ html.includes("ck-") || // CKEditor's internal classes
31691
+ html.includes("data-cke-");
31692
+ }
31693
+ const DEFAULT_HEADING_STYLES = {
31694
+ h1: { fontSize: "36px", lineHeight: "1.2" },
31695
+ h2: { fontSize: "29px", lineHeight: "1.25" },
31696
+ h3: { fontSize: "24px", lineHeight: "1.3" },
31697
+ h4: { fontSize: "20px", lineHeight: "1.35" },
31698
+ h5: { fontSize: "17px", lineHeight: "1.4" },
31699
+ h6: { fontSize: "15px", lineHeight: "1.45" }
31700
+ };
31701
+ const DEFAULT_PARAGRAPH_FONT_SIZE = "16px";
31702
+ const DEFAULT_PARAGRAPH_LINE_HEIGHT = "1.6";
31703
+ const MIN_HEADING_FONT_SIZES = {
31704
+ h1: 24,
31705
+ h2: 20,
31706
+ h3: 18,
31707
+ h4: 16,
31708
+ h5: 14,
31709
+ h6: 12
31710
+ };
31711
+ function parseStyleString(styleStr) {
31712
+ const result = {};
31713
+ if (!styleStr)
31714
+ return result;
31715
+ const parts = styleStr.split(";");
31716
+ for (const part of parts) {
31717
+ const colonIndex = part.indexOf(":");
31718
+ if (colonIndex > 0) {
31719
+ const key = part.substring(0, colonIndex).trim().toLowerCase();
31720
+ const value = part.substring(colonIndex + 1).trim();
31721
+ if (key && value) {
31722
+ result[key] = value;
31723
+ }
31724
+ }
31725
+ }
31726
+ return result;
31727
+ }
31728
+ function getStyleInfoFromElement(element) {
31729
+ const result = {
31730
+ format: 0,
31731
+ fontFamily: "",
31732
+ fontSize: "",
31733
+ lineHeight: "",
31734
+ letterSpacing: "",
31735
+ wordSpacing: "",
31736
+ color: "",
31737
+ backgroundColor: ""
31738
+ };
31739
+ let current = element;
31740
+ const elementsStack = [];
31741
+ while (current && current !== document.body) {
31742
+ elementsStack.push(current);
31743
+ current = current.parentElement;
31744
+ }
31745
+ for (let i2 = elementsStack.length - 1; i2 >= 0; i2--) {
31746
+ const el = elementsStack[i2];
31747
+ const tag = el.tagName.toLowerCase();
31748
+ if (tag === "strong" || tag === "b")
31749
+ result.format |= IS_BOLD;
31750
+ if (tag === "em" || tag === "i")
31751
+ result.format |= IS_ITALIC;
31752
+ if (tag === "u")
31753
+ result.format |= IS_UNDERLINE;
31754
+ if (tag === "s" || tag === "strike" || tag === "del")
31755
+ result.format |= IS_STRIKETHROUGH;
31756
+ if (tag === "code")
31757
+ result.format |= IS_CODE;
31758
+ if (tag === "sub")
31759
+ result.format |= IS_SUBSCRIPT;
31760
+ if (tag === "sup")
31761
+ result.format |= IS_SUPERSCRIPT;
31762
+ if (tag === "mark")
31763
+ result.format |= IS_HIGHLIGHT;
31764
+ const styleAttr = el.getAttribute("style") || "";
31765
+ const parsedStyle = parseStyleString(styleAttr);
31766
+ const style = el.style;
31767
+ const fontWeight = parsedStyle["font-weight"] || style.fontWeight;
31768
+ if (fontWeight === "bold" || fontWeight === "700" || parseInt(fontWeight || "0") >= 700) {
31769
+ result.format |= IS_BOLD;
31770
+ }
31771
+ const fontStyle = parsedStyle["font-style"] || style.fontStyle;
31772
+ if (fontStyle === "italic") {
31773
+ result.format |= IS_ITALIC;
31774
+ }
31775
+ const textDecoration = parsedStyle["text-decoration"] || style.textDecoration || "";
31776
+ if (textDecoration.includes("underline")) {
31777
+ result.format |= IS_UNDERLINE;
31778
+ }
31779
+ if (textDecoration.includes("line-through")) {
31780
+ result.format |= IS_STRIKETHROUGH;
31781
+ }
31782
+ const fontFamily = parsedStyle["font-family"] || style.fontFamily;
31783
+ if (fontFamily) {
31784
+ const family = fontFamily.split(",")[0].trim().replace(/["']/g, "");
31785
+ if (family && family !== "inherit" && family !== "initial") {
31786
+ result.fontFamily = family;
31787
+ }
31788
+ }
31789
+ const fontSize = parsedStyle["font-size"] || style.fontSize;
31790
+ if (fontSize && fontSize !== "inherit" && fontSize !== "initial") {
31791
+ result.fontSize = fontSize;
31792
+ }
31793
+ const lineHeight = parsedStyle["line-height"] || style.lineHeight;
31794
+ if (lineHeight && lineHeight !== "inherit" && lineHeight !== "initial" && lineHeight !== "normal") {
31795
+ result.lineHeight = lineHeight;
31796
+ }
31797
+ const letterSpacing = parsedStyle["letter-spacing"] || style.letterSpacing;
31798
+ if (letterSpacing && letterSpacing !== "inherit" && letterSpacing !== "initial" && letterSpacing !== "normal") {
31799
+ result.letterSpacing = letterSpacing;
31800
+ }
31801
+ const wordSpacing = parsedStyle["word-spacing"] || style.wordSpacing;
31802
+ if (wordSpacing && wordSpacing !== "inherit" && wordSpacing !== "initial" && wordSpacing !== "normal") {
31803
+ result.wordSpacing = wordSpacing;
31804
+ }
31805
+ const color = parsedStyle["color"] || style.color;
31806
+ if (color && color !== "inherit" && color !== "initial") {
31807
+ result.color = color;
31808
+ }
31809
+ const bgColor = parsedStyle["background-color"] || parsedStyle["background"] || style.backgroundColor;
31810
+ if (bgColor && bgColor !== "inherit" && bgColor !== "initial" && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)") {
31811
+ result.backgroundColor = bgColor;
31812
+ }
31813
+ }
31814
+ try {
31815
+ const computedStyle = window.getComputedStyle(element);
31816
+ if (!result.fontFamily && computedStyle.fontFamily) {
31817
+ const fontFamily = computedStyle.fontFamily.split(",")[0].trim().replace(/["']/g, "");
31818
+ const genericFonts = ["serif", "sans-serif", "monospace", "cursive", "fantasy", "system-ui", "-apple-system", "BlinkMacSystemFont"];
31819
+ if (fontFamily && !genericFonts.includes(fontFamily)) {
31820
+ result.fontFamily = fontFamily;
31821
+ }
31822
+ }
31823
+ if (!result.fontSize && computedStyle.fontSize && computedStyle.fontSize !== "16px") {
31824
+ result.fontSize = computedStyle.fontSize;
31825
+ }
31826
+ if (!result.lineHeight && computedStyle.lineHeight && computedStyle.lineHeight !== "normal") {
31827
+ const lineHeightValue = computedStyle.lineHeight;
31828
+ if (lineHeightValue && !lineHeightValue.endsWith("px")) {
31829
+ result.lineHeight = lineHeightValue;
31830
+ } else if (lineHeightValue && result.fontSize) {
31831
+ result.lineHeight = lineHeightValue;
31832
+ } else if (lineHeightValue) {
31833
+ result.lineHeight = lineHeightValue;
31834
+ }
31835
+ }
31836
+ if (!result.letterSpacing && computedStyle.letterSpacing && computedStyle.letterSpacing !== "normal" && computedStyle.letterSpacing !== "0px") {
31837
+ result.letterSpacing = computedStyle.letterSpacing;
31838
+ }
31839
+ if (!result.wordSpacing && computedStyle.wordSpacing && computedStyle.wordSpacing !== "normal" && computedStyle.wordSpacing !== "0px") {
31840
+ result.wordSpacing = computedStyle.wordSpacing;
31841
+ }
31842
+ if (!result.color && computedStyle.color) {
31843
+ const color = computedStyle.color;
31844
+ if (color !== "rgb(0, 0, 0)" && color !== "#000000" && color !== "black") {
31845
+ result.color = color;
31846
+ }
31847
+ }
31848
+ if (!result.backgroundColor && computedStyle.backgroundColor) {
31849
+ const bgColor = computedStyle.backgroundColor;
31850
+ if (bgColor !== "rgba(0, 0, 0, 0)" && bgColor !== "transparent") {
31851
+ result.backgroundColor = bgColor;
31852
+ }
31853
+ }
31854
+ } catch {
31855
+ }
31856
+ return result;
31857
+ }
31858
+ function buildStyleString(info) {
31859
+ const styles = [];
31860
+ if (info.fontFamily)
31861
+ styles.push(`font-family: ${info.fontFamily}`);
31862
+ if (info.fontSize)
31863
+ styles.push(`font-size: ${info.fontSize}`);
31864
+ if (info.lineHeight)
31865
+ styles.push(`line-height: ${info.lineHeight}`);
31866
+ if (info.letterSpacing)
31867
+ styles.push(`letter-spacing: ${info.letterSpacing}`);
31868
+ if (info.wordSpacing)
31869
+ styles.push(`word-spacing: ${info.wordSpacing}`);
31870
+ if (info.color)
31871
+ styles.push(`color: ${info.color}`);
31872
+ if (info.backgroundColor)
31873
+ styles.push(`background-color: ${info.backgroundColor}`);
31874
+ return styles.join("; ");
31875
+ }
31876
+ function createStyledTextNode(text, parentElement) {
31877
+ const textNode = $createTextNode(text);
31878
+ const styleInfo = getStyleInfoFromElement(parentElement);
31879
+ if (styleInfo.format) {
31880
+ textNode.setFormat(styleInfo.format);
31881
+ }
31882
+ const styleString = buildStyleString(styleInfo);
31883
+ if (styleString) {
31884
+ textNode.setStyle(styleString);
31885
+ }
31886
+ return textNode;
31887
+ }
31888
+ const defaultPasteContext = {
31889
+ isCKEditor: false
31890
+ };
31891
+ let currentPasteContext = defaultPasteContext;
31892
+ function processNode(domNode, parentElement = null) {
31893
+ var _a;
31894
+ const results = [];
31895
+ if (domNode.nodeType === Node.TEXT_NODE) {
31896
+ const text = domNode.textContent || "";
31897
+ if (text && parentElement) {
31898
+ const hasNonWhitespace = text.trim().length > 0;
31899
+ const isSignificantWhitespace = /\s/.test(text) && !hasNonWhitespace;
31900
+ if (hasNonWhitespace || isSignificantWhitespace) {
31901
+ const normalizedText = text.replace(/\s+/g, " ");
31902
+ const textNode = createStyledTextNode(normalizedText, parentElement);
31903
+ results.push(textNode);
31904
+ }
31905
+ }
31906
+ return results;
31907
+ }
31908
+ if (domNode.nodeType !== Node.ELEMENT_NODE) {
31909
+ return results;
31910
+ }
31911
+ const element = domNode;
31912
+ const tagName = element.tagName.toLowerCase();
31913
+ switch (tagName) {
31914
+ case "p":
31915
+ case "div": {
31916
+ const paragraph = $createParagraphNode();
31917
+ const styleInfo = getStyleInfoFromElement(element);
31918
+ const hasExplicitFontSize = styleInfo.fontSize && styleInfo.fontSize !== "16px";
31919
+ if (!hasExplicitFontSize && currentPasteContext.isCKEditor) {
31920
+ processChildrenWithStyle(element, paragraph, {
31921
+ fontSize: DEFAULT_PARAGRAPH_FONT_SIZE,
31922
+ lineHeight: DEFAULT_PARAGRAPH_LINE_HEIGHT
31923
+ });
31924
+ } else {
31925
+ processChildren(element, paragraph);
31926
+ }
31927
+ if (paragraph.getChildrenSize() > 0 || tagName === "p") {
31928
+ results.push(paragraph);
31929
+ }
31930
+ break;
31931
+ }
31932
+ case "h1":
31933
+ case "h2":
31934
+ case "h3":
31935
+ case "h4":
31936
+ case "h5":
31937
+ case "h6": {
31938
+ const heading = $createHeadingNode(tagName);
31939
+ const styleInfo = getStyleInfoFromElement(element);
31940
+ let hasAppropriateFontSize = false;
31941
+ if (styleInfo.fontSize) {
31942
+ const fontSizeValue = parseFloat(styleInfo.fontSize);
31943
+ const minExpectedSize = MIN_HEADING_FONT_SIZES[tagName] || 14;
31944
+ if (fontSizeValue >= minExpectedSize) {
31945
+ hasAppropriateFontSize = true;
31946
+ }
31947
+ }
31948
+ if (!hasAppropriateFontSize) {
31949
+ const defaultStyles = DEFAULT_HEADING_STYLES[tagName];
31950
+ if (defaultStyles) {
31951
+ processChildrenWithStyle(element, heading, defaultStyles);
31952
+ } else {
31953
+ processChildren(element, heading);
31954
+ }
31955
+ } else {
31956
+ processChildren(element, heading);
31957
+ }
31958
+ results.push(heading);
31959
+ break;
31960
+ }
31961
+ case "ul":
31962
+ case "ol": {
31963
+ const listType = tagName === "ul" ? "bullet" : "number";
31964
+ const list = $createListNode(listType);
31965
+ const listItems = element.querySelectorAll(":scope > li");
31966
+ listItems.forEach((li) => {
31967
+ const listItem = $createListItemNode();
31968
+ processChildren(li, listItem);
31969
+ list.append(listItem);
31970
+ });
31971
+ if (list.getChildrenSize() > 0) {
31972
+ results.push(list);
31973
+ }
31974
+ break;
31975
+ }
31976
+ case "li": {
31977
+ const list = $createListNode("bullet");
31978
+ const listItem = $createListItemNode();
31979
+ processChildren(element, listItem);
31980
+ list.append(listItem);
31981
+ results.push(list);
31982
+ break;
31983
+ }
31984
+ case "blockquote": {
31985
+ const quote = $createQuoteNode();
31986
+ processChildren(element, quote);
31987
+ results.push(quote);
31988
+ break;
31989
+ }
31990
+ case "a": {
31991
+ const href = element.getAttribute("href") || "";
31992
+ if (href) {
31993
+ const linkNode = $createLinkNode(href, { target: "_blank", rel: "noopener" });
31994
+ processChildren(element, linkNode);
31995
+ results.push(linkNode);
31996
+ } else {
31997
+ const children = processChildren(element);
31998
+ results.push(...children);
31999
+ }
32000
+ break;
32001
+ }
32002
+ case "img": {
32003
+ const src = element.getAttribute("src") || "";
32004
+ if (src && !src.startsWith("file:///")) {
32005
+ const alt = element.getAttribute("alt") || "";
32006
+ const width = parseInt(element.getAttribute("width") || "0") || void 0;
32007
+ const height = parseInt(element.getAttribute("height") || "0") || void 0;
32008
+ const alignment = detectImageAlignment(element);
32009
+ const position = alignmentToPosition(alignment);
32010
+ const imageNode = $createImageNode({
32011
+ src,
32012
+ altText: alt,
32013
+ width,
32014
+ height,
32015
+ position: isFloatAlignment(alignment) ? position : "none"
32016
+ });
32017
+ if (alignment === "center") {
32018
+ const paragraph = $createParagraphNode();
32019
+ paragraph.setFormat("center");
32020
+ paragraph.append(imageNode);
32021
+ results.push(paragraph);
32022
+ } else {
32023
+ results.push(imageNode);
32024
+ }
32025
+ }
32026
+ break;
32027
+ }
32028
+ case "br": {
32029
+ results.push($createLineBreakNode());
32030
+ break;
32031
+ }
32032
+ case "figure": {
32033
+ const img = element.querySelector("img");
32034
+ const figureAlignment = detectClassBasedAlignment(element);
32035
+ const alignment = figureAlignment || (img ? detectImageAlignment(img) : "left");
32036
+ const position = alignmentToPosition(alignment);
32037
+ const isFloat = isFloatAlignment(alignment);
32038
+ const figcaption = element.querySelector("figcaption");
32039
+ const captionText = ((_a = figcaption == null ? void 0 : figcaption.textContent) == null ? void 0 : _a.trim()) || "";
32040
+ if (img) {
32041
+ const src = img.getAttribute("src") || "";
32042
+ if (src && !src.startsWith("file:///")) {
32043
+ const alt = img.getAttribute("alt") || "";
32044
+ const width = parseInt(img.getAttribute("width") || "0") || void 0;
32045
+ const height = parseInt(img.getAttribute("height") || "0") || void 0;
32046
+ const imageNode = $createImageNode({
32047
+ src,
32048
+ altText: alt,
32049
+ width,
32050
+ height,
32051
+ position: isFloat ? position : "none"
32052
+ });
32053
+ if (alignment === "center") {
32054
+ const paragraph = $createParagraphNode();
32055
+ paragraph.setFormat("center");
32056
+ paragraph.append(imageNode);
32057
+ results.push(paragraph);
32058
+ if (captionText) {
32059
+ const captionPara = $createParagraphNode();
32060
+ captionPara.setFormat("center");
32061
+ const textNode = $createTextNode(captionText);
32062
+ textNode.setFormat(IS_ITALIC);
32063
+ captionPara.append(textNode);
32064
+ results.push(captionPara);
32065
+ }
32066
+ } else {
32067
+ if (captionText) {
32068
+ const paragraph = $createParagraphNode();
32069
+ paragraph.setFormat(alignment === "right" ? "right" : "left");
32070
+ paragraph.append(imageNode);
32071
+ paragraph.append($createLineBreakNode());
32072
+ const captionNode = $createTextNode(captionText);
32073
+ captionNode.setFormat(IS_ITALIC);
32074
+ paragraph.append(captionNode);
32075
+ results.push(paragraph);
32076
+ } else {
32077
+ results.push(imageNode);
32078
+ }
32079
+ }
32080
+ }
32081
+ }
32082
+ break;
32083
+ }
32084
+ case "strong":
32085
+ case "b":
32086
+ case "em":
32087
+ case "i":
32088
+ case "u":
32089
+ case "s":
32090
+ case "strike":
32091
+ case "del":
32092
+ case "code":
32093
+ case "sub":
32094
+ case "sup":
32095
+ case "mark":
32096
+ case "span":
32097
+ case "font": {
32098
+ const children = processChildren(element);
32099
+ results.push(...children);
32100
+ break;
32101
+ }
32102
+ case "script":
32103
+ case "style":
32104
+ case "meta":
32105
+ case "link":
32106
+ case "head":
32107
+ case "title":
32108
+ case "noscript":
32109
+ break;
32110
+ case "table":
32111
+ case "tbody":
32112
+ case "thead":
32113
+ case "tfoot":
32114
+ case "tr":
32115
+ case "td":
32116
+ case "th": {
32117
+ break;
32118
+ }
32119
+ default: {
32120
+ const children = processChildren(element);
32121
+ results.push(...children);
32122
+ }
32123
+ }
32124
+ return results;
32125
+ }
32126
+ function processChildren(element, parentNode) {
32127
+ const results = [];
32128
+ const childNodes = element.childNodes;
32129
+ for (let i2 = 0; i2 < childNodes.length; i2++) {
32130
+ const child = childNodes[i2];
32131
+ const nodes = processNode(child, element);
32132
+ if (parentNode) {
32133
+ nodes.forEach((node) => parentNode.append(node));
32134
+ } else {
32135
+ results.push(...nodes);
32136
+ }
32137
+ }
32138
+ return results;
32139
+ }
32140
+ function processChildrenWithStyle(element, parentNode, defaultStyles) {
32141
+ const childNodes = element.childNodes;
32142
+ for (let i2 = 0; i2 < childNodes.length; i2++) {
32143
+ const child = childNodes[i2];
32144
+ if (child.nodeType === Node.TEXT_NODE) {
32145
+ const text = child.textContent || "";
32146
+ if (text) {
32147
+ const hasNonWhitespace = text.trim().length > 0;
32148
+ const isSignificantWhitespace = /\s/.test(text) && !hasNonWhitespace;
32149
+ if (hasNonWhitespace || isSignificantWhitespace) {
32150
+ const normalizedText = text.replace(/\s+/g, " ");
32151
+ const textNode = $createTextNode(normalizedText);
32152
+ const styleInfo = getStyleInfoFromElement(element);
32153
+ if (styleInfo.format) {
32154
+ textNode.setFormat(styleInfo.format);
32155
+ }
32156
+ const styles = [];
32157
+ if (styleInfo.fontFamily) {
32158
+ styles.push(`font-family: ${styleInfo.fontFamily}`);
32159
+ }
32160
+ const usingDefaultFontSize = !styleInfo.fontSize && defaultStyles.fontSize;
32161
+ if (styleInfo.fontSize) {
32162
+ styles.push(`font-size: ${styleInfo.fontSize}`);
32163
+ } else if (defaultStyles.fontSize) {
32164
+ styles.push(`font-size: ${defaultStyles.fontSize}`);
32165
+ }
32166
+ if (styleInfo.lineHeight) {
32167
+ const isAbsoluteLineHeight = styleInfo.lineHeight.endsWith("px");
32168
+ if (usingDefaultFontSize && isAbsoluteLineHeight) {
32169
+ styles.push(`line-height: ${defaultStyles.lineHeight}`);
32170
+ } else {
32171
+ styles.push(`line-height: ${styleInfo.lineHeight}`);
32172
+ }
32173
+ } else if (defaultStyles.lineHeight) {
32174
+ styles.push(`line-height: ${defaultStyles.lineHeight}`);
32175
+ }
32176
+ if (styleInfo.letterSpacing) {
32177
+ styles.push(`letter-spacing: ${styleInfo.letterSpacing}`);
32178
+ }
32179
+ if (styleInfo.wordSpacing) {
32180
+ styles.push(`word-spacing: ${styleInfo.wordSpacing}`);
32181
+ }
32182
+ if (styleInfo.color) {
32183
+ styles.push(`color: ${styleInfo.color}`);
32184
+ }
32185
+ if (styleInfo.backgroundColor) {
32186
+ styles.push(`background-color: ${styleInfo.backgroundColor}`);
32187
+ }
32188
+ if (styles.length > 0) {
32189
+ textNode.setStyle(styles.join("; "));
32190
+ }
32191
+ parentNode.append(textNode);
32192
+ }
32193
+ }
32194
+ } else {
32195
+ const nodes = processNode(child, element);
32196
+ nodes.forEach((node) => {
32197
+ if ($isTextNode(node)) {
32198
+ const currentStyle = node.getStyle();
32199
+ const hasFontSize = currentStyle.includes("font-size");
32200
+ const hasLineHeight = currentStyle.includes("line-height");
32201
+ if (!hasFontSize || !hasLineHeight) {
32202
+ const newStyles = currentStyle ? [currentStyle] : [];
32203
+ if (!hasFontSize && defaultStyles.fontSize) {
32204
+ newStyles.push(`font-size: ${defaultStyles.fontSize}`);
32205
+ }
32206
+ if (!hasFontSize && hasLineHeight) {
32207
+ const lineHeightMatch = currentStyle.match(/line-height:\s*([^;]+)/);
32208
+ if (lineHeightMatch && lineHeightMatch[1].trim().endsWith("px")) {
32209
+ const filteredStyles = newStyles.filter((s2) => !s2.includes("line-height"));
32210
+ filteredStyles.push(`line-height: ${defaultStyles.lineHeight}`);
32211
+ node.setStyle(filteredStyles.join("; "));
32212
+ parentNode.append(node);
32213
+ return;
32214
+ }
32215
+ }
32216
+ if (!hasLineHeight && defaultStyles.lineHeight) {
32217
+ newStyles.push(`line-height: ${defaultStyles.lineHeight}`);
32218
+ }
32219
+ node.setStyle(newStyles.join("; "));
32220
+ }
32221
+ }
32222
+ parentNode.append(node);
32223
+ });
32224
+ }
32225
+ }
32226
+ }
32227
+ function wrapFloatedImagesInParagraphs(nodes) {
32228
+ return nodes.map((node) => {
32229
+ if ($isImageNode(node)) {
32230
+ const position = node.getPosition();
32231
+ if (position === "left" || position === "right") {
32232
+ const wrapper = $createParagraphNode();
32233
+ wrapper.append(node);
32234
+ return wrapper;
32235
+ }
32236
+ }
32237
+ return node;
32238
+ });
32239
+ }
32240
+ function createStyledDocument(html) {
32241
+ const container = document.createElement("div");
32242
+ container.style.cssText = "position: absolute; left: -9999px; top: -9999px; visibility: hidden;";
32243
+ const parser = new DOMParser();
32244
+ const doc = parser.parseFromString(html, "text/html");
32245
+ const styleTags = doc.querySelectorAll("style");
32246
+ const injectedStyles = [];
32247
+ styleTags.forEach((styleTag) => {
32248
+ const newStyle = document.createElement("style");
32249
+ newStyle.textContent = styleTag.textContent;
32250
+ document.head.appendChild(newStyle);
32251
+ injectedStyles.push(newStyle);
32252
+ });
32253
+ container.innerHTML = doc.body.innerHTML;
32254
+ document.body.appendChild(container);
32255
+ const cleanup = () => {
32256
+ injectedStyles.forEach((style) => style.remove());
32257
+ container.remove();
32258
+ };
32259
+ return { container, cleanup };
32260
+ }
32261
+ function convertHTMLToNodesWithStyles(html, editor) {
32262
+ const isCKEditor = detectCKEditorSource(html);
32263
+ currentPasteContext = {
32264
+ isCKEditor
32265
+ };
32266
+ const { container, cleanup } = createStyledDocument(html);
32267
+ try {
32268
+ const customNodes = processNode(container, null);
32269
+ const filteredCustomNodes = customNodes.filter((node) => {
32270
+ if (node instanceof ParagraphNode) {
32271
+ return node.getTextContent().trim().length > 0 || node.getChildrenSize() > 0;
32272
+ }
32273
+ return true;
32274
+ });
32275
+ if (filteredCustomNodes.length > 0) {
32276
+ const hasTables = html.includes("<table");
32277
+ if (hasTables) {
32278
+ const parser2 = new DOMParser();
32279
+ const doc2 = parser2.parseFromString(html, "text/html");
32280
+ const lexicalNodes = $generateNodesFromDOM(editor, doc2);
32281
+ const mergedNodes = [];
32282
+ let customIndex = 0;
32283
+ lexicalNodes.forEach((lexicalNode) => {
32284
+ const nodeType = lexicalNode.getType();
32285
+ if (nodeType === "table") {
32286
+ mergedNodes.push(lexicalNode);
32287
+ } else if (customIndex < filteredCustomNodes.length) {
32288
+ mergedNodes.push(filteredCustomNodes[customIndex]);
32289
+ customIndex++;
32290
+ }
32291
+ });
32292
+ while (customIndex < filteredCustomNodes.length) {
32293
+ mergedNodes.push(filteredCustomNodes[customIndex]);
32294
+ customIndex++;
32295
+ }
32296
+ return wrapFloatedImagesInParagraphs(mergedNodes.length > 0 ? mergedNodes : filteredCustomNodes);
32297
+ }
32298
+ return wrapFloatedImagesInParagraphs(filteredCustomNodes);
32299
+ }
32300
+ const parser = new DOMParser();
32301
+ const doc = parser.parseFromString(html, "text/html");
32302
+ return $generateNodesFromDOM(editor, doc);
32303
+ } finally {
32304
+ cleanup();
32305
+ currentPasteContext = defaultPasteContext;
32306
+ }
32307
+ }
31077
32308
  function RichTextPastePlugin() {
31078
32309
  const [editor] = useLexicalComposerContext();
31079
32310
  useEffect$1(() => {
@@ -31083,192 +32314,55 @@ function RichTextPastePlugin() {
31083
32314
  const clipboardData = event.clipboardData;
31084
32315
  if (!clipboardData)
31085
32316
  return false;
32317
+ const files = clipboardData.files;
32318
+ if (files && files.length > 0) {
32319
+ const hasImages = Array.from(files).some(
32320
+ (file) => file.type.startsWith("image/")
32321
+ );
32322
+ if (hasImages) {
32323
+ return false;
32324
+ }
32325
+ }
31086
32326
  const htmlContent = clipboardData.getData("text/html");
31087
32327
  const plainText = clipboardData.getData("text/plain");
31088
32328
  if (htmlContent) {
31089
32329
  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
- }
32330
+ editor.update(
32331
+ () => {
32332
+ const selection = $getSelection();
32333
+ if (!$isRangeSelection(selection))
32334
+ return;
32335
+ try {
32336
+ const nodes = convertHTMLToNodesWithStyles(htmlContent, editor);
32337
+ if (nodes.length > 0) {
32338
+ const filteredNodes = nodes.filter((node) => {
32339
+ if (node instanceof ParagraphNode) {
32340
+ const textContent = node.getTextContent();
32341
+ const hasChildren = node.getChildrenSize() > 0;
32342
+ return textContent.trim().length > 0 || hasChildren;
31156
32343
  }
32344
+ return true;
31157
32345
  });
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);
32346
+ if (filteredNodes.length > 0) {
32347
+ selection.insertNodes(filteredNodes);
31174
32348
  }
31175
32349
  }
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);
32350
+ } catch (error) {
32351
+ console.error("Error during HTML paste:", error);
32352
+ if (plainText) {
32353
+ selection.insertRawText(plainText);
31201
32354
  }
31202
32355
  }
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
- }
32356
+ },
32357
+ { tag: "paste" }
32358
+ );
32359
+ return true;
31215
32360
  }
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
- };
32361
+ return false;
32362
+ },
32363
+ COMMAND_PRIORITY_HIGH
32364
+ );
32365
+ }, [editor]);
31272
32366
  return null;
31273
32367
  }
31274
32368
  function getOptionMeta(label) {
@@ -35248,6 +36342,95 @@ function TableImageAutoResizePlugin() {
35248
36342
  }, [editor]);
35249
36343
  return null;
35250
36344
  }
36345
+ const DEFAULT_SYNC_INTERVAL = 2 * 60 * 1e3;
36346
+ const UsageTrackingPlugin = ({
36347
+ licenseKey,
36348
+ syncIntervalMs = DEFAULT_SYNC_INTERVAL
36349
+ }) => {
36350
+ const [editor] = useLexicalComposerContext();
36351
+ const lastCountRef = useRef({ characters: 0, words: 0 });
36352
+ const pendingDeltaRef = useRef({ characters: 0, words: 0 });
36353
+ const isSyncingRef = useRef(false);
36354
+ const syncToBackend = useCallback(async () => {
36355
+ if (!licenseKey || isSyncingRef.current)
36356
+ return;
36357
+ const { characters, words } = pendingDeltaRef.current;
36358
+ if (characters === 0 && words === 0)
36359
+ return;
36360
+ isSyncingRef.current = true;
36361
+ try {
36362
+ await backendAPI.post("/api/analytics/track-usage", {
36363
+ licenseKey,
36364
+ characters,
36365
+ words
36366
+ });
36367
+ pendingDeltaRef.current = { characters: 0, words: 0 };
36368
+ } catch (error) {
36369
+ console.error("Failed to sync usage stats:", error);
36370
+ } finally {
36371
+ isSyncingRef.current = false;
36372
+ }
36373
+ }, [licenseKey]);
36374
+ useEffect$1(() => {
36375
+ if (!licenseKey)
36376
+ return;
36377
+ const unregister = editor.registerUpdateListener(({ editorState }) => {
36378
+ editorState.read(() => {
36379
+ const root2 = $getRoot();
36380
+ const text = root2.getTextContent();
36381
+ const currentWords = text.trim().split(/\s+/).filter((word) => word.length > 0).length;
36382
+ const currentCharacters = text.replace(/\s/g, "").length;
36383
+ const deltaCharacters = Math.max(
36384
+ 0,
36385
+ currentCharacters - lastCountRef.current.characters
36386
+ );
36387
+ const deltaWords = Math.max(
36388
+ 0,
36389
+ currentWords - lastCountRef.current.words
36390
+ );
36391
+ lastCountRef.current = {
36392
+ characters: currentCharacters,
36393
+ words: currentWords
36394
+ };
36395
+ if (deltaCharacters > 0 || deltaWords > 0) {
36396
+ pendingDeltaRef.current.characters += deltaCharacters;
36397
+ pendingDeltaRef.current.words += deltaWords;
36398
+ }
36399
+ });
36400
+ });
36401
+ const syncInterval = setInterval(syncToBackend, syncIntervalMs);
36402
+ const handleBeforeUnload = () => {
36403
+ const { characters, words } = pendingDeltaRef.current;
36404
+ if (characters > 0 || words > 0) {
36405
+ const data = JSON.stringify({
36406
+ licenseKey,
36407
+ characters,
36408
+ words
36409
+ });
36410
+ const baseURL = backendAPI.defaults.baseURL || "";
36411
+ navigator.sendBeacon(
36412
+ `${baseURL}/api/analytics/track-usage`,
36413
+ new Blob([data], { type: "application/json" })
36414
+ );
36415
+ }
36416
+ };
36417
+ const handleVisibilityChange = () => {
36418
+ if (document.visibilityState === "hidden") {
36419
+ syncToBackend();
36420
+ }
36421
+ };
36422
+ window.addEventListener("beforeunload", handleBeforeUnload);
36423
+ document.addEventListener("visibilitychange", handleVisibilityChange);
36424
+ return () => {
36425
+ unregister();
36426
+ clearInterval(syncInterval);
36427
+ syncToBackend();
36428
+ window.removeEventListener("beforeunload", handleBeforeUnload);
36429
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
36430
+ };
36431
+ }, [editor, licenseKey, syncToBackend, syncIntervalMs]);
36432
+ return null;
36433
+ };
35251
36434
  const WordCountPlugin = () => {
35252
36435
  const [editor] = useLexicalComposerContext();
35253
36436
  const [stats, setStats] = useState$1({
@@ -35485,11 +36668,12 @@ function applyGenericSafeStyles(container) {
35485
36668
  }
35486
36669
  });
35487
36670
  };
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
- );
36671
+ const defaultFontFamily = "Arial, sans-serif";
36672
+ const selectors = "table, p, span, li, td, th, div, h1, h2, h3, h4, h5, h6";
36673
+ addStyle(selectors, "line-height: 1.5;");
36674
+ addStyleIfNotSet(selectors, "font-family", defaultFontFamily);
36675
+ addStyleIfNotSet("table, p, span, li, td, th, div", "font-size", "16px");
36676
+ addStyle("p", "margin: 0 0 1em 0;");
35493
36677
  addStyle("th p, td p", "margin: 0; padding: 0;");
35494
36678
  addStyle(
35495
36679
  "table",
@@ -35501,7 +36685,34 @@ function applyGenericSafeStyles(container) {
35501
36685
  );
35502
36686
  addStyleIfNotSet("th", "background-color", "#f8f9fa");
35503
36687
  addStyle("th", "font-weight: 600;");
35504
- addStyle("img", "max-width: 100%; height: auto; display: block;");
36688
+ container.querySelectorAll("img").forEach((img) => {
36689
+ const position = img.getAttribute("data-position");
36690
+ const parent = img.parentElement;
36691
+ img.style.cssText += "; max-width: 100%; height: auto;";
36692
+ const hasCaption = parent && parent.tagName.toLowerCase() === "p" && parent.querySelector("em, i");
36693
+ if (position === "left" || position === "right") {
36694
+ const floatDir = position === "left" ? "left" : "right";
36695
+ const marginDir = position === "left" ? "right" : "left";
36696
+ if (hasCaption && parent) {
36697
+ 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;`;
36698
+ img.style.cssText += "; display: block; margin: 0 auto;";
36699
+ const caption = parent.querySelector("em, i");
36700
+ if (caption) {
36701
+ caption.style.cssText += "; display: block; font-size: 0.85em; line-height: 1.4; color: #666; padding-top: 0.5em;";
36702
+ }
36703
+ } else {
36704
+ img.style.cssText += `; float: ${floatDir}; clear: ${floatDir}; margin-${marginDir}: 1em; margin-bottom: 0.5em; max-width: 50%;`;
36705
+ }
36706
+ } else if (position === "full") {
36707
+ img.style.cssText += "; display: block; width: 100%; margin: 1em 0;";
36708
+ } else {
36709
+ img.style.cssText += "; display: block;";
36710
+ if (parent && parent.style.textAlign === "center") {
36711
+ img.style.margin = "0 auto";
36712
+ }
36713
+ }
36714
+ img.removeAttribute("data-position");
36715
+ });
35505
36716
  addStyle("h1", "font-size: 2em; font-weight: bold; margin: 0.67em 0;");
35506
36717
  addStyle("h2", "font-size: 1.5em; font-weight: bold; margin: 0.75em 0;");
35507
36718
  addStyle("h3", "font-size: 1.17em; font-weight: bold; margin: 0.83em 0;");
@@ -35696,7 +36907,7 @@ function detectTableStylesFromInline(table) {
35696
36907
  return result;
35697
36908
  }
35698
36909
  function preprocessInitialContent(html) {
35699
- if (!html || !html.includes("<table")) {
36910
+ if (!html) {
35700
36911
  return html;
35701
36912
  }
35702
36913
  const parser = new DOMParser();
@@ -35729,6 +36940,72 @@ function preprocessInitialContent(html) {
35729
36940
  table.classList.add("PlaygroundEditorTheme__table");
35730
36941
  }
35731
36942
  });
36943
+ const images = doc.querySelectorAll("img");
36944
+ images.forEach((img) => {
36945
+ const parent = img.parentElement;
36946
+ if (!parent)
36947
+ return;
36948
+ const imgFloat = img.style.float;
36949
+ const parentFloat = parent.style.float;
36950
+ const floatDir = imgFloat || parentFloat;
36951
+ if (floatDir === "left" || floatDir === "right") {
36952
+ img.setAttribute("data-position", floatDir);
36953
+ if (parentFloat && parent.tagName.toLowerCase() === "p") {
36954
+ parent.style.textAlign = floatDir;
36955
+ parent.style.removeProperty("float");
36956
+ parent.style.removeProperty("clear");
36957
+ parent.style.removeProperty("max-width");
36958
+ parent.style.removeProperty("background-color");
36959
+ parent.style.removeProperty("padding");
36960
+ parent.style.removeProperty("border-radius");
36961
+ }
36962
+ }
36963
+ });
36964
+ const styledElements = doc.querySelectorAll("span[style], b[style], strong[style], i[style], em[style]");
36965
+ styledElements.forEach((el) => {
36966
+ const htmlEl = el;
36967
+ const style = htmlEl.style;
36968
+ const relevantStyles = [];
36969
+ if (style.fontFamily) {
36970
+ const fontFamily = style.fontFamily.replace(/["']/g, "");
36971
+ relevantStyles.push(`font-family: ${fontFamily}`);
36972
+ }
36973
+ if (style.fontSize) {
36974
+ relevantStyles.push(`font-size: ${style.fontSize}`);
36975
+ }
36976
+ if (style.lineHeight) {
36977
+ relevantStyles.push(`line-height: ${style.lineHeight}`);
36978
+ }
36979
+ if (style.color && style.color !== "rgb(0, 0, 0)") {
36980
+ relevantStyles.push(`color: ${style.color}`);
36981
+ }
36982
+ if (style.backgroundColor && style.backgroundColor !== "rgba(0, 0, 0, 0)" && style.backgroundColor !== "transparent") {
36983
+ relevantStyles.push(`background-color: ${style.backgroundColor}`);
36984
+ }
36985
+ if (style.letterSpacing && style.letterSpacing !== "normal") {
36986
+ relevantStyles.push(`letter-spacing: ${style.letterSpacing}`);
36987
+ }
36988
+ if (style.wordSpacing && style.wordSpacing !== "normal") {
36989
+ relevantStyles.push(`word-spacing: ${style.wordSpacing}`);
36990
+ }
36991
+ if (relevantStyles.length > 0) {
36992
+ htmlEl.setAttribute("style", relevantStyles.join("; "));
36993
+ }
36994
+ });
36995
+ const headings = doc.querySelectorAll("h1, h2, h3, h4, h5, h6");
36996
+ headings.forEach((heading) => {
36997
+ const tagName = heading.tagName.toLowerCase();
36998
+ const className = `PlaygroundEditorTheme__${tagName}`;
36999
+ if (!heading.classList.contains(className)) {
37000
+ heading.classList.add(className);
37001
+ }
37002
+ });
37003
+ const paragraphs = doc.querySelectorAll("p");
37004
+ paragraphs.forEach((p2) => {
37005
+ if (!p2.classList.contains("PlaygroundEditorTheme__paragraph")) {
37006
+ p2.classList.add("PlaygroundEditorTheme__paragraph");
37007
+ }
37008
+ });
35732
37009
  return doc.body.innerHTML;
35733
37010
  }
35734
37011
  const useAutoExpandingHeight = ({
@@ -35799,6 +37076,8 @@ const useStyles = () => ({
35799
37076
  "cteditor-relative cteditor-min-h-[300px] cteditor-rounded-lg cteditor-p-3 !cteditor-h-auto cteditor-resize-none cteditor-outline-0 cteditor-content",
35800
37077
  // Ensure strong contrast in both themes
35801
37078
  "cteditor-text-foreground cteditor-bg-background",
37079
+ // Default font: Arial 16px to match toolbar defaults and ensure WYSIWYG output
37080
+ "cteditor-font-arial cteditor-text-base",
35802
37081
  // Caret and spacing
35803
37082
  "cteditor-caret-[#3b82f6] cteditor-p-0 cteditor-transition-all cteditor-duration-200",
35804
37083
  "cteditor-w-full ",
@@ -36137,7 +37416,8 @@ const ConfigurableEditor = ({
36137
37416
  ErrorBoundary: LexicalErrorBoundary
36138
37417
  }
36139
37418
  ),
36140
- /* @__PURE__ */ jsx(WordCountPlugin, {})
37419
+ /* @__PURE__ */ jsx(WordCountPlugin, {}),
37420
+ /* @__PURE__ */ jsx(UsageTrackingPlugin, { licenseKey: apiKey })
36141
37421
  ] }),
36142
37422
  /* @__PURE__ */ jsx(HtmlViewDisplay, {}),
36143
37423
  /* @__PURE__ */ jsx(AIRephrasePlugin, {}),
@@ -36227,9 +37507,9 @@ const ScopedEditorWrapper = ({
36227
37507
  }) => {
36228
37508
  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
37509
  };
36230
- const trackEditorLoad = async () => {
37510
+ const trackEditorLoad = async (licenseKey) => {
36231
37511
  try {
36232
- await backendAPI.post("/api/analytics/editor-load", {});
37512
+ await backendAPI.post("/api/analytics/editor-load", { licenseKey });
36233
37513
  } catch {
36234
37514
  }
36235
37515
  };
@@ -36312,11 +37592,11 @@ const ConfigurableEditorWithAuth = ({
36312
37592
  }, [isAuthenticated, error]);
36313
37593
  useEffect$1(() => {
36314
37594
  console.log("isAuthenticated:", isAuthenticated);
36315
- if (isAuthenticated && !hasTrackedLoadRef.current) {
37595
+ if (isAuthenticated && !hasTrackedLoadRef.current && apiKey) {
36316
37596
  hasTrackedLoadRef.current = true;
36317
- trackEditorLoad();
37597
+ trackEditorLoad(apiKey);
36318
37598
  }
36319
- }, [isAuthenticated]);
37599
+ }, [isAuthenticated, apiKey]);
36320
37600
  if (isLoading) {
36321
37601
  return /* @__PURE__ */ jsx(ScopedEditorWrapper, { children: /* @__PURE__ */ jsx(LoadingMessage, { children: /* @__PURE__ */ jsx("span", { children: "Loading editor..." }) }) });
36322
37602
  }
@@ -36375,4 +37655,4 @@ export {
36375
37655
  useHtmlView as u,
36376
37656
  verifyApiKey as v
36377
37657
  };
36378
- //# sourceMappingURL=index-dbb526cd.js.map
37658
+ //# sourceMappingURL=index-23abcbd9.js.map