@tarviks/lexical-rich-editor 1.1.0 → 1.2.0

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.
package/dist/index.js CHANGED
@@ -1249,6 +1249,46 @@ var ContentEditorLevel = /* @__PURE__ */ ((ContentEditorLevel2) => {
1249
1249
  ContentEditorLevel2["Pro"] = "pro";
1250
1250
  return ContentEditorLevel2;
1251
1251
  })(ContentEditorLevel || {});
1252
+
1253
+ // src/Types/PageSetup.ts
1254
+ var DEFAULT_PAGE_SETUP = {
1255
+ size: "pageless",
1256
+ orientation: "portrait",
1257
+ margin: "normal"
1258
+ };
1259
+ var PAGE_SIZE_OPTIONS = [
1260
+ { key: "a4", label: 'A4 (8.27" x 11.69")', widthIn: 8.27, heightIn: 11.69 },
1261
+ { key: "letter", label: 'Letter (8.5" x 11")', widthIn: 8.5, heightIn: 11 },
1262
+ { key: "legal", label: 'Legal (8.5" x 14")', widthIn: 8.5, heightIn: 14 },
1263
+ { key: "tabloid", label: 'Tabloid (11" x 17")', widthIn: 11, heightIn: 17 },
1264
+ { key: "a3", label: 'A3 (11.69" x 16.54")', widthIn: 11.69, heightIn: 16.54 },
1265
+ { key: "a5", label: 'A5 (5.83" x 8.27")', widthIn: 5.83, heightIn: 8.27 },
1266
+ { key: "b4", label: 'B4 (9.84" x 13.90")', widthIn: 9.84, heightIn: 13.9 },
1267
+ { key: "b5", label: 'B5 (6.93" x 9.84")', widthIn: 6.93, heightIn: 9.84 },
1268
+ { key: "statement", label: 'Statement (5.5" x 8.5")', widthIn: 5.5, heightIn: 8.5 },
1269
+ { key: "executive", label: 'Executive (7.25" x 10.5")', widthIn: 7.25, heightIn: 10.5 },
1270
+ { key: "folio", label: 'Folio (8.5" x 13")', widthIn: 8.5, heightIn: 13 }
1271
+ ];
1272
+ var MARGIN_OPTIONS = [
1273
+ { key: "narrow", label: 'Narrow (0.25")', valueIn: 0.25 },
1274
+ { key: "normal", label: 'Normal (0.4")', valueIn: 0.4 },
1275
+ { key: "moderate", label: 'Moderate (0.75")', valueIn: 0.75 },
1276
+ { key: "wide", label: 'Wide (1")', valueIn: 1 }
1277
+ ];
1278
+ var CSS_PX_PER_INCH = 96;
1279
+ function resolvePageCanvasMetrics(value) {
1280
+ const margin = MARGIN_OPTIONS.find((o) => o.key === value.margin) ?? MARGIN_OPTIONS[1];
1281
+ if (value.size === "pageless") {
1282
+ return { widthPx: void 0, paddingPx: 20 };
1283
+ }
1284
+ const size = PAGE_SIZE_OPTIONS.find((o) => o.key === value.size);
1285
+ if (!size) return { widthPx: void 0, paddingPx: 20 };
1286
+ const widthIn = value.orientation === "landscape" ? size.heightIn : size.widthIn;
1287
+ return {
1288
+ widthPx: Math.round(widthIn * CSS_PX_PER_INCH),
1289
+ paddingPx: Math.round(margin.valueIn * CSS_PX_PER_INCH)
1290
+ };
1291
+ }
1252
1292
  var AutocompleteNode = class _AutocompleteNode extends lexical.TextNode {
1253
1293
  static getType() {
1254
1294
  return "autocomplete";
@@ -2487,6 +2527,236 @@ function CharacterStylesPopupPlugin(props) {
2487
2527
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
2488
2528
  return useCharacterStylesPopup(editor, props);
2489
2529
  }
2530
+
2531
+ // src/Utils/Sanitize.ts
2532
+ var DROP_ENTIRELY = /* @__PURE__ */ new Set([
2533
+ "script",
2534
+ "noscript",
2535
+ "style",
2536
+ "object",
2537
+ "embed",
2538
+ "form",
2539
+ "input",
2540
+ "button",
2541
+ "select",
2542
+ "textarea",
2543
+ "meta",
2544
+ "link",
2545
+ "base"
2546
+ ]);
2547
+ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
2548
+ // Block
2549
+ "p",
2550
+ "h1",
2551
+ "h2",
2552
+ "h3",
2553
+ "h4",
2554
+ "h5",
2555
+ "h6",
2556
+ "ul",
2557
+ "ol",
2558
+ "li",
2559
+ "blockquote",
2560
+ "pre",
2561
+ "div",
2562
+ "table",
2563
+ "thead",
2564
+ "tbody",
2565
+ "tfoot",
2566
+ "tr",
2567
+ "td",
2568
+ "th",
2569
+ // Inline
2570
+ "span",
2571
+ "a",
2572
+ "strong",
2573
+ "b",
2574
+ "em",
2575
+ "i",
2576
+ "u",
2577
+ "s",
2578
+ "del",
2579
+ "strike",
2580
+ "sub",
2581
+ "sup",
2582
+ "mark",
2583
+ "code",
2584
+ "br",
2585
+ "hr",
2586
+ // Media / embeds
2587
+ "img",
2588
+ "iframe"
2589
+ ]);
2590
+ var ALLOWED_ATTRS = /* @__PURE__ */ new Set([
2591
+ // Presentation
2592
+ "class",
2593
+ "style",
2594
+ "dir",
2595
+ "lang",
2596
+ // Anchors
2597
+ "href",
2598
+ "target",
2599
+ "rel",
2600
+ // Images
2601
+ "src",
2602
+ "alt",
2603
+ "width",
2604
+ "height",
2605
+ // Tables
2606
+ "colspan",
2607
+ "rowspan",
2608
+ // Lists — <ol type="a"> and <ol start="2">
2609
+ "start",
2610
+ "type",
2611
+ // Lexical-internal data markers
2612
+ "data-lex-block",
2613
+ "data-kind",
2614
+ "data-lexical-decorator",
2615
+ // Misc
2616
+ "title",
2617
+ "allowfullscreen"
2618
+ ]);
2619
+ var DANGEROUS_URL = /^\s*(javascript|data\s*:|vbscript)/i;
2620
+ function sanitizeElement(el) {
2621
+ for (const child of Array.from(el.children)) {
2622
+ sanitizeElement(child);
2623
+ }
2624
+ const tag = el.tagName.toLowerCase();
2625
+ if (DROP_ENTIRELY.has(tag)) {
2626
+ el.parentNode?.removeChild(el);
2627
+ return;
2628
+ }
2629
+ if (tag === "iframe") {
2630
+ const src = el.getAttribute("src") ?? "";
2631
+ const isYouTube = /^\s*https:\/\/(www\.)?(youtube\.com|youtube-nocookie\.com)\/embed\/[^?&/]+/i.test(src);
2632
+ if (!isYouTube) {
2633
+ el.parentNode?.removeChild(el);
2634
+ return;
2635
+ }
2636
+ }
2637
+ if (!ALLOWED_TAGS.has(tag)) {
2638
+ while (el.firstChild) {
2639
+ el.parentNode?.insertBefore(el.firstChild, el);
2640
+ }
2641
+ el.parentNode?.removeChild(el);
2642
+ return;
2643
+ }
2644
+ for (const { name, value } of Array.from(el.attributes)) {
2645
+ const lname = name.toLowerCase();
2646
+ if (!ALLOWED_ATTRS.has(lname)) {
2647
+ el.removeAttribute(name);
2648
+ continue;
2649
+ }
2650
+ if (lname === "href" || lname === "src") {
2651
+ if (DANGEROUS_URL.test(value)) {
2652
+ el.removeAttribute(name);
2653
+ }
2654
+ }
2655
+ if (lname === "style") {
2656
+ const safe = value.replace(/expression\s*\(/gi, "(").replace(/url\s*\(\s*['"]?\s*javascript:/gi, "url(");
2657
+ el.setAttribute("style", safe);
2658
+ }
2659
+ }
2660
+ if (tag === "a" && (el.getAttribute("target") || "").toLowerCase() === "_blank") {
2661
+ const rel = (el.getAttribute("rel") || "").trim();
2662
+ const tokens = new Set(
2663
+ rel.split(/\s+/).filter(Boolean).map((t) => t.toLowerCase())
2664
+ );
2665
+ tokens.add("noopener");
2666
+ tokens.add("noreferrer");
2667
+ el.setAttribute("rel", Array.from(tokens).join(" "));
2668
+ }
2669
+ }
2670
+ function sanitizeHtml(html) {
2671
+ if (!html || typeof html !== "string") return "";
2672
+ const doc = new DOMParser().parseFromString(html, "text/html");
2673
+ for (const child of Array.from(doc.body.children)) {
2674
+ sanitizeElement(child);
2675
+ }
2676
+ return doc.body.innerHTML;
2677
+ }
2678
+ function postProcessOutput(html) {
2679
+ if (!html) return html;
2680
+ const doc = new DOMParser().parseFromString(html, "text/html");
2681
+ for (const inner of Array.from(doc.querySelectorAll("b > strong"))) {
2682
+ const outer = inner.parentElement;
2683
+ _mergeAttributes(inner, outer);
2684
+ while (inner.firstChild) outer.insertBefore(inner.firstChild, inner);
2685
+ outer.removeChild(inner);
2686
+ }
2687
+ for (const inner of Array.from(doc.querySelectorAll("i > em"))) {
2688
+ const outer = inner.parentElement;
2689
+ _mergeAttributes(inner, outer);
2690
+ while (inner.firstChild) outer.insertBefore(inner.firstChild, inner);
2691
+ outer.removeChild(inner);
2692
+ }
2693
+ for (const p of Array.from(doc.querySelectorAll("p"))) {
2694
+ const style = p.style;
2695
+ const hasMargin = !!(style.margin || style.marginTop || style.marginRight || style.marginBottom || style.marginLeft);
2696
+ if (!hasMargin) style.margin = "0";
2697
+ if (!style.lineHeight) style.lineHeight = "1.25";
2698
+ }
2699
+ return doc.body.innerHTML;
2700
+ }
2701
+ function _mergeAttributes(src, dst) {
2702
+ for (const { name, value } of Array.from(src.attributes)) {
2703
+ if (name === "style") {
2704
+ const prev = dst.getAttribute("style") || "";
2705
+ dst.setAttribute("style", prev ? `${prev}; ${value}` : value);
2706
+ } else if (name === "class") {
2707
+ const prev = dst.getAttribute("class") || "";
2708
+ dst.setAttribute("class", prev ? `${prev} ${value}` : value);
2709
+ }
2710
+ }
2711
+ }
2712
+ var BLOCK_TAGS = /* @__PURE__ */ new Set([
2713
+ "p",
2714
+ "h1",
2715
+ "h2",
2716
+ "h3",
2717
+ "h4",
2718
+ "h5",
2719
+ "h6",
2720
+ "div",
2721
+ "ul",
2722
+ "ol",
2723
+ "li",
2724
+ "table",
2725
+ "blockquote",
2726
+ "pre",
2727
+ "hr"
2728
+ ]);
2729
+ function normalizeToBlockHtml(html) {
2730
+ if (!html) return "";
2731
+ const doc = new DOMParser().parseFromString(html, "text/html");
2732
+ const body = doc.body;
2733
+ const childNodes = Array.from(body.childNodes);
2734
+ const needsWrap = childNodes.some((node) => {
2735
+ if (node.nodeType === Node.TEXT_NODE) return !!node.nodeValue?.trim();
2736
+ if (node.nodeType === Node.ELEMENT_NODE)
2737
+ return !BLOCK_TAGS.has(node.tagName.toLowerCase());
2738
+ return false;
2739
+ });
2740
+ if (!needsWrap) return html;
2741
+ while (body.firstChild) body.removeChild(body.firstChild);
2742
+ let pendingP = null;
2743
+ for (const node of childNodes) {
2744
+ const isBlock = node.nodeType === Node.ELEMENT_NODE && BLOCK_TAGS.has(node.tagName.toLowerCase());
2745
+ const isWhitespace = node.nodeType === Node.TEXT_NODE && !node.nodeValue?.trim();
2746
+ if (isBlock) {
2747
+ if (pendingP) {
2748
+ body.appendChild(pendingP);
2749
+ pendingP = null;
2750
+ }
2751
+ body.appendChild(node);
2752
+ } else if (!isWhitespace) {
2753
+ if (!pendingP) pendingP = doc.createElement("p");
2754
+ pendingP.appendChild(node);
2755
+ }
2756
+ }
2757
+ if (pendingP) body.appendChild(pendingP);
2758
+ return body.innerHTML;
2759
+ }
2490
2760
  var CustomOnChangePlugin = ({ value, onChange }) => {
2491
2761
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
2492
2762
  const initializedRef = React9.useRef(false);
@@ -2507,7 +2777,7 @@ var CustomOnChangePlugin = ({ value, onChange }) => {
2507
2777
  }, [editor, value]);
2508
2778
  const handleChange = React9.useCallback((editorState) => {
2509
2779
  editorState.read(() => {
2510
- onChangeRef.current(html.$generateHtmlFromNodes(editor));
2780
+ onChangeRef.current(postProcessOutput(html.$generateHtmlFromNodes(editor)));
2511
2781
  });
2512
2782
  }, [editor]);
2513
2783
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -3519,279 +3789,81 @@ var $onDrop2 = (event, editor) => {
3519
3789
  const node = $getImageNodeInSelection2();
3520
3790
  if (!node) return false;
3521
3791
  const data = getDragImageData2(event);
3522
- if (!data) return false;
3523
- event.preventDefault();
3524
- if (canDropImage2(event)) {
3525
- const range = getDragSelection2(event);
3526
- node.remove();
3527
- const rangeSelection = lexical.$createRangeSelection();
3528
- if (range !== null && range !== void 0) {
3529
- rangeSelection.applyDOMRange(range);
3530
- }
3531
- lexical.$setSelection(rangeSelection);
3532
- editor.dispatchCommand(INSERT_INLINE_IMAGE_COMMAND, data);
3533
- }
3534
- return true;
3535
- };
3536
- var $getImageNodeInSelection2 = () => {
3537
- const selection = lexical.$getSelection();
3538
- if (!lexical.$isNodeSelection(selection)) return null;
3539
- const nodes = selection.getNodes();
3540
- const node = nodes[0];
3541
- return $isInlineImageNode(node) ? node : null;
3542
- };
3543
- var getDragImageData2 = (event) => {
3544
- const dragData = event.dataTransfer?.getData("application/x-lexical-drag");
3545
- if (!dragData) return null;
3546
- const { type, data } = JSON.parse(dragData);
3547
- if (type !== "image") return null;
3548
- return data;
3549
- };
3550
- var canDropImage2 = (event) => {
3551
- const target = event.target;
3552
- return !!(lexical.isHTMLElement(target) && !target.closest("code, span.editor-image") && lexical.isHTMLElement(target.parentElement) && target.parentElement.closest("div.ContentEditable__root"));
3553
- };
3554
- var getDragSelection2 = (event) => {
3555
- let range;
3556
- const domSelection = lexical.getDOMSelectionFromTarget(event.target);
3557
- if (document.caretRangeFromPoint) {
3558
- range = document.caretRangeFromPoint(event.clientX, event.clientY);
3559
- } else if (event.rangeParent && domSelection !== null) {
3560
- domSelection.collapse(event.rangeParent, event.rangeOffset || 0);
3561
- range = domSelection.getRangeAt(0);
3562
- } else {
3563
- throw Error("Cannot get the selection when dragging");
3564
- }
3565
- return range;
3566
- };
3567
- var INSERT_PAGE_BREAK = lexical.createCommand();
3568
- function PageBreakPlugin() {
3569
- const [editor] = LexicalComposerContext.useLexicalComposerContext();
3570
- React9.useEffect(() => {
3571
- if (!editor.hasNodes([PageBreakNode])) {
3572
- throw new Error(
3573
- "PageBreakPlugin: PageBreakNode is not registered on editor"
3574
- );
3575
- }
3576
- return utils.mergeRegister(
3577
- editor.registerCommand(
3578
- INSERT_PAGE_BREAK,
3579
- () => {
3580
- const selection = lexical.$getSelection();
3581
- if (!lexical.$isRangeSelection(selection)) {
3582
- return false;
3583
- }
3584
- const focusNode = selection.focus.getNode();
3585
- if (focusNode !== null) {
3586
- const pgBreak = $createPageBreakNode();
3587
- utils.$insertNodeToNearestRoot(pgBreak);
3588
- }
3589
- return true;
3590
- },
3591
- lexical.COMMAND_PRIORITY_EDITOR
3592
- )
3593
- );
3594
- }, [editor]);
3595
- return null;
3596
- }
3597
-
3598
- // src/Utils/Sanitize.ts
3599
- var DROP_ENTIRELY = /* @__PURE__ */ new Set([
3600
- "script",
3601
- "noscript",
3602
- "style",
3603
- "object",
3604
- "embed",
3605
- "form",
3606
- "input",
3607
- "button",
3608
- "select",
3609
- "textarea",
3610
- "meta",
3611
- "link",
3612
- "base"
3613
- ]);
3614
- var ALLOWED_TAGS = /* @__PURE__ */ new Set([
3615
- // Block
3616
- "p",
3617
- "h1",
3618
- "h2",
3619
- "h3",
3620
- "h4",
3621
- "h5",
3622
- "h6",
3623
- "ul",
3624
- "ol",
3625
- "li",
3626
- "blockquote",
3627
- "pre",
3628
- "div",
3629
- "table",
3630
- "thead",
3631
- "tbody",
3632
- "tfoot",
3633
- "tr",
3634
- "td",
3635
- "th",
3636
- // Inline
3637
- "span",
3638
- "a",
3639
- "strong",
3640
- "b",
3641
- "em",
3642
- "i",
3643
- "u",
3644
- "s",
3645
- "del",
3646
- "strike",
3647
- "sub",
3648
- "sup",
3649
- "mark",
3650
- "code",
3651
- "br",
3652
- "hr",
3653
- // Media / embeds
3654
- "img",
3655
- "iframe"
3656
- ]);
3657
- var ALLOWED_ATTRS = /* @__PURE__ */ new Set([
3658
- // Presentation
3659
- "class",
3660
- "style",
3661
- "dir",
3662
- "lang",
3663
- // Anchors
3664
- "href",
3665
- "target",
3666
- "rel",
3667
- // Images
3668
- "src",
3669
- "alt",
3670
- "width",
3671
- "height",
3672
- // Tables
3673
- "colspan",
3674
- "rowspan",
3675
- // Lists — <ol type="a"> and <ol start="2">
3676
- "start",
3677
- "type",
3678
- // Lexical-internal data markers
3679
- "data-lex-block",
3680
- "data-kind",
3681
- "data-lexical-decorator",
3682
- // Misc
3683
- "title",
3684
- "allowfullscreen"
3685
- ]);
3686
- var DANGEROUS_URL = /^\s*(javascript|data\s*:|vbscript)/i;
3687
- function sanitizeElement(el) {
3688
- for (const child of Array.from(el.children)) {
3689
- sanitizeElement(child);
3690
- }
3691
- const tag = el.tagName.toLowerCase();
3692
- if (DROP_ENTIRELY.has(tag)) {
3693
- el.parentNode?.removeChild(el);
3694
- return;
3695
- }
3696
- if (tag === "iframe") {
3697
- const src = el.getAttribute("src") ?? "";
3698
- const isYouTube = /^\s*https:\/\/(www\.)?(youtube\.com|youtube-nocookie\.com)\/embed\/[^?&/]+/i.test(src);
3699
- if (!isYouTube) {
3700
- el.parentNode?.removeChild(el);
3701
- return;
3702
- }
3703
- }
3704
- if (!ALLOWED_TAGS.has(tag)) {
3705
- while (el.firstChild) {
3706
- el.parentNode?.insertBefore(el.firstChild, el);
3707
- }
3708
- el.parentNode?.removeChild(el);
3709
- return;
3710
- }
3711
- for (const { name, value } of Array.from(el.attributes)) {
3712
- const lname = name.toLowerCase();
3713
- if (!ALLOWED_ATTRS.has(lname)) {
3714
- el.removeAttribute(name);
3715
- continue;
3716
- }
3717
- if (lname === "href" || lname === "src") {
3718
- if (DANGEROUS_URL.test(value)) {
3719
- el.removeAttribute(name);
3720
- }
3721
- }
3722
- if (lname === "style") {
3723
- const safe = value.replace(/expression\s*\(/gi, "(").replace(/url\s*\(\s*['"]?\s*javascript:/gi, "url(");
3724
- el.setAttribute("style", safe);
3792
+ if (!data) return false;
3793
+ event.preventDefault();
3794
+ if (canDropImage2(event)) {
3795
+ const range = getDragSelection2(event);
3796
+ node.remove();
3797
+ const rangeSelection = lexical.$createRangeSelection();
3798
+ if (range !== null && range !== void 0) {
3799
+ rangeSelection.applyDOMRange(range);
3725
3800
  }
3801
+ lexical.$setSelection(rangeSelection);
3802
+ editor.dispatchCommand(INSERT_INLINE_IMAGE_COMMAND, data);
3726
3803
  }
3727
- if (tag === "a" && (el.getAttribute("target") || "").toLowerCase() === "_blank") {
3728
- const rel = (el.getAttribute("rel") || "").trim();
3729
- const tokens = new Set(
3730
- rel.split(/\s+/).filter(Boolean).map((t) => t.toLowerCase())
3731
- );
3732
- tokens.add("noopener");
3733
- tokens.add("noreferrer");
3734
- el.setAttribute("rel", Array.from(tokens).join(" "));
3735
- }
3736
- }
3737
- function sanitizeHtml(html) {
3738
- if (!html || typeof html !== "string") return "";
3739
- const doc = new DOMParser().parseFromString(html, "text/html");
3740
- for (const child of Array.from(doc.body.children)) {
3741
- sanitizeElement(child);
3804
+ return true;
3805
+ };
3806
+ var $getImageNodeInSelection2 = () => {
3807
+ const selection = lexical.$getSelection();
3808
+ if (!lexical.$isNodeSelection(selection)) return null;
3809
+ const nodes = selection.getNodes();
3810
+ const node = nodes[0];
3811
+ return $isInlineImageNode(node) ? node : null;
3812
+ };
3813
+ var getDragImageData2 = (event) => {
3814
+ const dragData = event.dataTransfer?.getData("application/x-lexical-drag");
3815
+ if (!dragData) return null;
3816
+ const { type, data } = JSON.parse(dragData);
3817
+ if (type !== "image") return null;
3818
+ return data;
3819
+ };
3820
+ var canDropImage2 = (event) => {
3821
+ const target = event.target;
3822
+ return !!(lexical.isHTMLElement(target) && !target.closest("code, span.editor-image") && lexical.isHTMLElement(target.parentElement) && target.parentElement.closest("div.ContentEditable__root"));
3823
+ };
3824
+ var getDragSelection2 = (event) => {
3825
+ let range;
3826
+ const domSelection = lexical.getDOMSelectionFromTarget(event.target);
3827
+ if (document.caretRangeFromPoint) {
3828
+ range = document.caretRangeFromPoint(event.clientX, event.clientY);
3829
+ } else if (event.rangeParent && domSelection !== null) {
3830
+ domSelection.collapse(event.rangeParent, event.rangeOffset || 0);
3831
+ range = domSelection.getRangeAt(0);
3832
+ } else {
3833
+ throw Error("Cannot get the selection when dragging");
3742
3834
  }
3743
- return doc.body.innerHTML;
3744
- }
3745
- var BLOCK_TAGS = /* @__PURE__ */ new Set([
3746
- "p",
3747
- "h1",
3748
- "h2",
3749
- "h3",
3750
- "h4",
3751
- "h5",
3752
- "h6",
3753
- "div",
3754
- "ul",
3755
- "ol",
3756
- "li",
3757
- "table",
3758
- "blockquote",
3759
- "pre",
3760
- "hr"
3761
- ]);
3762
- function normalizeToBlockHtml(html) {
3763
- if (!html) return "";
3764
- const doc = new DOMParser().parseFromString(html, "text/html");
3765
- const body = doc.body;
3766
- const childNodes = Array.from(body.childNodes);
3767
- const needsWrap = childNodes.some((node) => {
3768
- if (node.nodeType === Node.TEXT_NODE) return !!node.nodeValue?.trim();
3769
- if (node.nodeType === Node.ELEMENT_NODE)
3770
- return !BLOCK_TAGS.has(node.tagName.toLowerCase());
3771
- return false;
3772
- });
3773
- if (!needsWrap) return html;
3774
- while (body.firstChild) body.removeChild(body.firstChild);
3775
- let pendingP = null;
3776
- for (const node of childNodes) {
3777
- const isBlock = node.nodeType === Node.ELEMENT_NODE && BLOCK_TAGS.has(node.tagName.toLowerCase());
3778
- const isWhitespace = node.nodeType === Node.TEXT_NODE && !node.nodeValue?.trim();
3779
- if (isBlock) {
3780
- if (pendingP) {
3781
- body.appendChild(pendingP);
3782
- pendingP = null;
3783
- }
3784
- body.appendChild(node);
3785
- } else if (!isWhitespace) {
3786
- if (!pendingP) pendingP = doc.createElement("p");
3787
- pendingP.appendChild(node);
3835
+ return range;
3836
+ };
3837
+ var INSERT_PAGE_BREAK = lexical.createCommand();
3838
+ function PageBreakPlugin() {
3839
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
3840
+ React9.useEffect(() => {
3841
+ if (!editor.hasNodes([PageBreakNode])) {
3842
+ throw new Error(
3843
+ "PageBreakPlugin: PageBreakNode is not registered on editor"
3844
+ );
3788
3845
  }
3789
- }
3790
- if (pendingP) body.appendChild(pendingP);
3791
- return body.innerHTML;
3846
+ return utils.mergeRegister(
3847
+ editor.registerCommand(
3848
+ INSERT_PAGE_BREAK,
3849
+ () => {
3850
+ const selection = lexical.$getSelection();
3851
+ if (!lexical.$isRangeSelection(selection)) {
3852
+ return false;
3853
+ }
3854
+ const focusNode = selection.focus.getNode();
3855
+ if (focusNode !== null) {
3856
+ const pgBreak = $createPageBreakNode();
3857
+ utils.$insertNodeToNearestRoot(pgBreak);
3858
+ }
3859
+ return true;
3860
+ },
3861
+ lexical.COMMAND_PRIORITY_EDITOR
3862
+ )
3863
+ );
3864
+ }, [editor]);
3865
+ return null;
3792
3866
  }
3793
-
3794
- // src/Utils/Helper.ts
3795
3867
  function findBlockByKind(kind) {
3796
3868
  const root = lexical.$getRoot();
3797
3869
  for (const child of root.getChildren()) {
@@ -3863,7 +3935,7 @@ function RefApiPlugin({
3863
3935
  editor.getEditorState().read(() => {
3864
3936
  html$1 = html.$generateHtmlFromNodes(editor, null);
3865
3937
  });
3866
- return html$1;
3938
+ return postProcessOutput(html$1);
3867
3939
  },
3868
3940
  clear: () => {
3869
3941
  editor.update(() => {
@@ -5012,7 +5084,8 @@ function getToolbarGroupsByLevel(level) {
5012
5084
  ["FontFamily", "|"],
5013
5085
  ["FontSize", "|"],
5014
5086
  ["Decorators", "|"],
5015
- ["Align"]
5087
+ ["Align", "|"],
5088
+ ["PageSetup"]
5016
5089
  ];
5017
5090
  case "pro" /* Pro */:
5018
5091
  default:
@@ -5027,7 +5100,8 @@ function getToolbarGroupsByLevel(level) {
5027
5100
  ["FontFamily", "|"],
5028
5101
  ["FontSize", "|"],
5029
5102
  ["Decorators", "|"],
5030
- ["Align"]
5103
+ ["Align", "|"],
5104
+ ["PageSetup"]
5031
5105
  ];
5032
5106
  }
5033
5107
  }
@@ -5065,6 +5139,7 @@ var normalizeHex = (v) => {
5065
5139
  if (hex.length === 4 || hex.length === 7) return hex.toLowerCase();
5066
5140
  return "#000000";
5067
5141
  };
5142
+ var isCompleteHex = (v) => /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test((v ?? "").trim());
5068
5143
  var hexToRgb = (hex) => {
5069
5144
  const h = normalizeHex(hex).replace("#", "");
5070
5145
  if (h.length === 3) {
@@ -5147,62 +5222,118 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon, onOpenChange
5147
5222
  };
5148
5223
  }, [open]);
5149
5224
  const appliedHex = React9__namespace.useMemo(() => normalizeHex(value || "#000000"), [value]);
5150
- const [hex, setHex] = React9__namespace.useState(appliedHex);
5225
+ const [hex, setHexState] = React9__namespace.useState(appliedHex);
5226
+ const [hexText, setHexText] = React9__namespace.useState(appliedHex);
5151
5227
  const { r, g, b } = React9__namespace.useMemo(() => hexToRgb(hex), [hex]);
5152
5228
  const hsv = React9__namespace.useMemo(() => rgbToHsv(r, g, b), [r, g, b]);
5153
5229
  const [h, setH] = React9__namespace.useState(hsv.h);
5154
5230
  const [s, setS] = React9__namespace.useState(hsv.s);
5155
5231
  const [v, setV] = React9__namespace.useState(hsv.v);
5156
- const setDraft = React9__namespace.useCallback((nextHex) => {
5157
- setHex(nextHex);
5158
- const rgb = hexToRgb(nextHex);
5159
- const next = rgbToHsv(rgb.r, rgb.g, rgb.b);
5160
- setH(next.h);
5161
- setS(next.s);
5162
- setV(next.v);
5163
- }, []);
5164
- const setDraftFromHsv = React9__namespace.useCallback((hh, ss, vv) => {
5165
- const rgb = hsvToRgb(hh, ss, vv);
5166
- setHex(rgbToHex(rgb.r, rgb.g, rgb.b));
5167
- setH(hh);
5168
- setS(ss);
5169
- setV(vv);
5170
- }, []);
5232
+ const commit = React9__namespace.useCallback(
5233
+ (nextHex) => {
5234
+ const rgb = hexToRgb(nextHex);
5235
+ const next = rgbToHsv(rgb.r, rgb.g, rgb.b);
5236
+ setHexState(nextHex);
5237
+ setHexText(nextHex);
5238
+ setH(next.h);
5239
+ setS(next.s);
5240
+ setV(next.v);
5241
+ onChange(nextHex);
5242
+ },
5243
+ [onChange]
5244
+ );
5245
+ const commitFromHsv = React9__namespace.useCallback(
5246
+ (hh, ss, vv) => {
5247
+ const rgb = hsvToRgb(hh, ss, vv);
5248
+ const nextHex = rgbToHex(rgb.r, rgb.g, rgb.b);
5249
+ setHexState(nextHex);
5250
+ setHexText(nextHex);
5251
+ setH(hh);
5252
+ setS(ss);
5253
+ setV(vv);
5254
+ onChange(nextHex);
5255
+ },
5256
+ [onChange]
5257
+ );
5171
5258
  const wasOpenRef = React9__namespace.useRef(open);
5172
5259
  React9__namespace.useEffect(() => {
5173
5260
  const justOpened = open && !wasOpenRef.current;
5174
5261
  wasOpenRef.current = open;
5175
5262
  if (!justOpened) return;
5176
- setDraft(appliedHex);
5177
- }, [appliedHex, open, setDraft]);
5263
+ setHexState(appliedHex);
5264
+ setHexText(appliedHex);
5265
+ const rgb = hexToRgb(appliedHex);
5266
+ const next = rgbToHsv(rgb.r, rgb.g, rgb.b);
5267
+ setH(next.h);
5268
+ setS(next.s);
5269
+ setV(next.v);
5270
+ }, [appliedHex, open]);
5178
5271
  const svRef = React9__namespace.useRef(null);
5179
- const handleSVClick = React9__namespace.useCallback(
5272
+ const svPointFromEvent = React9__namespace.useCallback((clientX, clientY) => {
5273
+ if (!svRef.current) return null;
5274
+ const rect = svRef.current.getBoundingClientRect();
5275
+ const x = clamp3(clientX - rect.left, 0, rect.width);
5276
+ const y = clamp3(clientY - rect.top, 0, rect.height);
5277
+ const ss = rect.width === 0 ? 0 : x / rect.width;
5278
+ const vv = rect.height === 0 ? 0 : 1 - y / rect.height;
5279
+ return { ss, vv };
5280
+ }, []);
5281
+ const hRef = React9__namespace.useRef(h);
5282
+ hRef.current = h;
5283
+ const handleSVPointerDown = React9__namespace.useCallback(
5284
+ (e) => {
5285
+ e.currentTarget.setPointerCapture(e.pointerId);
5286
+ const pt = svPointFromEvent(e.clientX, e.clientY);
5287
+ if (pt) commitFromHsv(hRef.current, pt.ss, pt.vv);
5288
+ },
5289
+ [svPointFromEvent, commitFromHsv]
5290
+ );
5291
+ const handleSVPointerMove = React9__namespace.useCallback(
5180
5292
  (e) => {
5181
- if (!svRef.current) return;
5182
- const rect = svRef.current.getBoundingClientRect();
5183
- const x = clamp3(e.clientX - rect.left, 0, rect.width);
5184
- const y = clamp3(e.clientY - rect.top, 0, rect.height);
5185
- const ss = rect.width === 0 ? 0 : x / rect.width;
5186
- const vv = rect.height === 0 ? 0 : 1 - y / rect.height;
5187
- setDraftFromHsv(h, ss, vv);
5293
+ if (e.buttons !== 1) return;
5294
+ const pt = svPointFromEvent(e.clientX, e.clientY);
5295
+ if (pt) commitFromHsv(hRef.current, pt.ss, pt.vv);
5188
5296
  },
5189
- [h, setDraftFromHsv]
5297
+ [svPointFromEvent, commitFromHsv]
5190
5298
  );
5191
5299
  const hueRef = React9__namespace.useRef(null);
5192
- const handleHueClick = React9__namespace.useCallback(
5300
+ const sRef = React9__namespace.useRef(s);
5301
+ sRef.current = s;
5302
+ const vRef = React9__namespace.useRef(v);
5303
+ vRef.current = v;
5304
+ const huePointFromEvent = React9__namespace.useCallback((clientX) => {
5305
+ if (!hueRef.current) return null;
5306
+ const rect = hueRef.current.getBoundingClientRect();
5307
+ const x = clamp3(clientX - rect.left, 0, rect.width);
5308
+ return rect.width === 0 ? 0 : x / rect.width * 360;
5309
+ }, []);
5310
+ const handleHuePointerDown = React9__namespace.useCallback(
5311
+ (e) => {
5312
+ e.currentTarget.setPointerCapture(e.pointerId);
5313
+ const hh = huePointFromEvent(e.clientX);
5314
+ if (hh != null) commitFromHsv(hh, sRef.current, vRef.current);
5315
+ },
5316
+ [huePointFromEvent, commitFromHsv]
5317
+ );
5318
+ const handleHuePointerMove = React9__namespace.useCallback(
5193
5319
  (e) => {
5194
- if (!hueRef.current) return;
5195
- const rect = hueRef.current.getBoundingClientRect();
5196
- const x = clamp3(e.clientX - rect.left, 0, rect.width);
5197
- const hh = rect.width === 0 ? 0 : x / rect.width * 360;
5198
- setDraftFromHsv(hh, s, v);
5320
+ if (e.buttons !== 1) return;
5321
+ const hh = huePointFromEvent(e.clientX);
5322
+ if (hh != null) commitFromHsv(hh, sRef.current, vRef.current);
5323
+ },
5324
+ [huePointFromEvent, commitFromHsv]
5325
+ );
5326
+ const handleHexChange = React9__namespace.useCallback(
5327
+ (_, val) => {
5328
+ const next = val ?? "";
5329
+ setHexText(next);
5330
+ if (isCompleteHex(next.trim())) commit(normalizeHex(next));
5199
5331
  },
5200
- [s, v, setDraftFromHsv]
5332
+ [commit]
5201
5333
  );
5202
- const handleApply = React9__namespace.useCallback(() => {
5203
- onChange(hex);
5204
- setOpenAndNotify(false);
5205
- }, [onChange, hex, setOpenAndNotify]);
5334
+ const handleHexBlur = React9__namespace.useCallback(() => {
5335
+ commit(normalizeHex(hexText));
5336
+ }, [hexText, commit]);
5206
5337
  const svThumb = React9__namespace.useMemo(() => ({ left: `${s * 100}%`, top: `${(1 - v) * 100}%` }), [s, v]);
5207
5338
  const hueThumb = React9__namespace.useMemo(() => ({ left: `${h / 360 * 100}%` }), [h]);
5208
5339
  const hueColor = React9__namespace.useMemo(() => {
@@ -5257,44 +5388,192 @@ var ColorPickerControl = ({ value, title, disabled, onChange, icon, onOpenChange
5257
5388
  directionalHint: 4,
5258
5389
  className: "aoColorCallout",
5259
5390
  preventDismissOnEvent,
5260
- children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 10 }, styles: { root: { padding: 12, width: 320 } }, children: [
5261
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aoLexRow", children: [
5262
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexSwatch", style: { background: hex } }),
5263
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexTitle", children: title })
5264
- ] }),
5265
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aoLexRow", children: [
5266
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexLabel", children: "Hex" }),
5391
+ children: /* @__PURE__ */ jsxRuntime.jsxs(react.Stack, { tokens: { childrenGap: 14 }, styles: { root: { padding: "14px 16px 16px", width: 288 } }, children: [
5392
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
5393
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, fontWeight: 600, color: "#242424", letterSpacing: 0.1 }, children: title }),
5267
5394
  /* @__PURE__ */ jsxRuntime.jsx(
5268
- react.TextField,
5395
+ "button",
5269
5396
  {
5270
- value: hex,
5271
- onChange: (_, val) => setHex(normalizeHex(val || "")),
5272
- onBlur: () => setDraft(normalizeHex(hex))
5397
+ type: "button",
5398
+ "aria-label": "Close",
5399
+ onClick: () => setOpenAndNotify(false),
5400
+ style: {
5401
+ display: "flex",
5402
+ alignItems: "center",
5403
+ justifyContent: "center",
5404
+ width: 24,
5405
+ height: 24,
5406
+ padding: 0,
5407
+ border: "none",
5408
+ borderRadius: 4,
5409
+ background: "transparent",
5410
+ color: "#616161",
5411
+ cursor: "pointer"
5412
+ },
5413
+ onMouseEnter: (e) => e.currentTarget.style.background = "#f0f0f0",
5414
+ onMouseLeave: (e) => e.currentTarget.style.background = "transparent",
5415
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.Dismiss16Regular, {})
5273
5416
  }
5274
5417
  )
5275
5418
  ] }),
5276
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexSwatches", children: PRESET.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
5277
- "button",
5419
+ /* @__PURE__ */ jsxRuntime.jsxs(
5420
+ "div",
5278
5421
  {
5279
- type: "button",
5280
- className: "aoLexSwatchBtn",
5281
- style: { background: c },
5282
- onClick: () => setDraft(c),
5283
- title: c
5284
- },
5285
- c
5286
- )) }),
5287
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aoLexSV", ref: svRef, onClick: handleSVClick, children: [
5288
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexSVHue", style: { background: hueColor } }),
5289
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexSVWhite" }),
5290
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexSVBlack" }),
5291
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexSVThumb", style: svThumb })
5422
+ ref: svRef,
5423
+ onPointerDown: handleSVPointerDown,
5424
+ onPointerMove: handleSVPointerMove,
5425
+ style: {
5426
+ position: "relative",
5427
+ width: "100%",
5428
+ height: 150,
5429
+ borderRadius: 8,
5430
+ overflow: "hidden",
5431
+ cursor: "crosshair",
5432
+ touchAction: "none",
5433
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.08)"
5434
+ },
5435
+ children: [
5436
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, background: hueColor } }),
5437
+ /* @__PURE__ */ jsxRuntime.jsx(
5438
+ "div",
5439
+ {
5440
+ style: {
5441
+ position: "absolute",
5442
+ inset: 0,
5443
+ background: "linear-gradient(to right, #fff, rgba(255,255,255,0))"
5444
+ }
5445
+ }
5446
+ ),
5447
+ /* @__PURE__ */ jsxRuntime.jsx(
5448
+ "div",
5449
+ {
5450
+ style: {
5451
+ position: "absolute",
5452
+ inset: 0,
5453
+ background: "linear-gradient(to top, #000, rgba(0,0,0,0))"
5454
+ }
5455
+ }
5456
+ ),
5457
+ /* @__PURE__ */ jsxRuntime.jsx(
5458
+ "div",
5459
+ {
5460
+ style: {
5461
+ position: "absolute",
5462
+ width: 16,
5463
+ height: 16,
5464
+ borderRadius: "50%",
5465
+ border: "2px solid #fff",
5466
+ boxShadow: "0 0 0 1px rgba(0,0,0,0.35), 0 1px 3px rgba(0,0,0,0.4)",
5467
+ transform: "translate(-50%, -50%)",
5468
+ pointerEvents: "none",
5469
+ ...svThumb
5470
+ }
5471
+ }
5472
+ )
5473
+ ]
5474
+ }
5475
+ ),
5476
+ /* @__PURE__ */ jsxRuntime.jsx(
5477
+ "div",
5478
+ {
5479
+ ref: hueRef,
5480
+ onPointerDown: handleHuePointerDown,
5481
+ onPointerMove: handleHuePointerMove,
5482
+ style: {
5483
+ position: "relative",
5484
+ width: "100%",
5485
+ height: 12,
5486
+ borderRadius: 999,
5487
+ cursor: "pointer",
5488
+ touchAction: "none",
5489
+ background: "linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)",
5490
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.08)"
5491
+ },
5492
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5493
+ "div",
5494
+ {
5495
+ style: {
5496
+ position: "absolute",
5497
+ top: "50%",
5498
+ width: 16,
5499
+ height: 16,
5500
+ borderRadius: "50%",
5501
+ background: hueColor,
5502
+ border: "2px solid #fff",
5503
+ boxShadow: "0 0 0 1px rgba(0,0,0,0.35), 0 1px 3px rgba(0,0,0,0.4)",
5504
+ transform: "translate(-50%, -50%)",
5505
+ pointerEvents: "none",
5506
+ ...hueThumb
5507
+ }
5508
+ }
5509
+ )
5510
+ }
5511
+ ),
5512
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
5513
+ /* @__PURE__ */ jsxRuntime.jsx(
5514
+ "div",
5515
+ {
5516
+ style: {
5517
+ width: 32,
5518
+ height: 32,
5519
+ borderRadius: 6,
5520
+ flexShrink: 0,
5521
+ background: hex,
5522
+ boxShadow: "inset 0 0 0 1px rgba(0,0,0,0.12)"
5523
+ }
5524
+ }
5525
+ ),
5526
+ /* @__PURE__ */ jsxRuntime.jsx(
5527
+ react.TextField,
5528
+ {
5529
+ value: hexText,
5530
+ onChange: handleHexChange,
5531
+ onBlur: handleHexBlur,
5532
+ onKeyDown: (e) => {
5533
+ if (e.key === "Enter") commit(normalizeHex(hexText));
5534
+ },
5535
+ styles: { root: { flex: 1 }, fieldGroup: { borderRadius: 6 } }
5536
+ }
5537
+ )
5292
5538
  ] }),
5293
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexHue", ref: hueRef, onClick: handleHueClick, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexHueThumb", style: hueThumb }) }),
5294
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aoLexPreview", style: { background: hex } }),
5295
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aoLexActions", children: [
5296
- /* @__PURE__ */ jsxRuntime.jsx(react.DefaultButton, { type: "button", text: "Apply", onClick: handleApply }),
5297
- /* @__PURE__ */ jsxRuntime.jsx(react.DefaultButton, { type: "button", text: "Close", onClick: () => setOpenAndNotify(false) })
5539
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5540
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, fontWeight: 600, color: "#8a8a8a", marginBottom: 6, letterSpacing: 0.3 }, children: "STANDARD COLORS" }),
5541
+ /* @__PURE__ */ jsxRuntime.jsx(
5542
+ "div",
5543
+ {
5544
+ style: {
5545
+ display: "grid",
5546
+ gridTemplateColumns: "repeat(9, 1fr)",
5547
+ gap: 6
5548
+ },
5549
+ children: PRESET.map((c) => {
5550
+ const isSelected = c.toLowerCase() === hex.toLowerCase();
5551
+ return /* @__PURE__ */ jsxRuntime.jsx(
5552
+ "button",
5553
+ {
5554
+ type: "button",
5555
+ onClick: () => commit(c),
5556
+ title: c,
5557
+ "aria-label": c,
5558
+ style: {
5559
+ width: 22,
5560
+ height: 22,
5561
+ padding: 0,
5562
+ borderRadius: 5,
5563
+ background: c,
5564
+ cursor: "pointer",
5565
+ boxShadow: isSelected ? "0 0 0 2px #fff, 0 0 0 3px #4a86e8" : "inset 0 0 0 1px rgba(0,0,0,0.15)",
5566
+ border: "none",
5567
+ transition: "transform 80ms ease"
5568
+ },
5569
+ onMouseEnter: (e) => e.currentTarget.style.transform = "scale(1.12)",
5570
+ onMouseLeave: (e) => e.currentTarget.style.transform = "scale(1)"
5571
+ },
5572
+ c
5573
+ );
5574
+ })
5575
+ }
5576
+ )
5298
5577
  ] })
5299
5578
  ] })
5300
5579
  }
@@ -5726,6 +6005,60 @@ var InsertLinkPlugin = ({ disabled }) => {
5726
6005
  }
5727
6006
  );
5728
6007
  };
6008
+ function PageSetupPlugin({ disabled, value, onChange }) {
6009
+ const sizeLabel = value.size === "pageless" ? "Pageless" : PAGE_SIZE_OPTIONS.find((o) => o.key === value.size)?.label ?? "Pageless";
6010
+ const isPaged = value.size !== "pageless";
6011
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6012
+ reactComponents.Menu,
6013
+ {
6014
+ checkedValues: {
6015
+ size: [value.size],
6016
+ orientation: [value.orientation],
6017
+ margin: [value.margin]
6018
+ },
6019
+ onCheckedValueChange: (_, data) => {
6020
+ const selected = data.checkedItems[0];
6021
+ if (!selected) return;
6022
+ if (data.name === "size") onChange({ ...value, size: selected });
6023
+ else if (data.name === "orientation")
6024
+ onChange({ ...value, orientation: selected });
6025
+ else if (data.name === "margin") onChange({ ...value, margin: selected });
6026
+ },
6027
+ children: [
6028
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuTrigger, { disableButtonEnhancement: true, children: /* @__PURE__ */ jsxRuntime.jsx(
6029
+ reactComponents.Button,
6030
+ {
6031
+ appearance: "subtle",
6032
+ size: "small",
6033
+ disabled,
6034
+ icon: /* @__PURE__ */ jsxRuntime.jsx(reactIcons.DocumentRegular, {}),
6035
+ title: "Page setup",
6036
+ style: { minWidth: "auto" },
6037
+ children: sizeLabel
6038
+ }
6039
+ ) }),
6040
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuPopover, { style: { minWidth: 220 }, children: /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.MenuList, { children: [
6041
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.MenuGroup, { children: [
6042
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuGroupHeader, { children: "Page size" }),
6043
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "size", value: "pageless", children: "Pageless" }),
6044
+ PAGE_SIZE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "size", value: opt.key, children: opt.label }, opt.key))
6045
+ ] }),
6046
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuDivider, {}),
6047
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.MenuGroup, { children: [
6048
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuGroupHeader, { children: "Orientation" }),
6049
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "orientation", value: "portrait", disabled: !isPaged, children: "Portrait" }),
6050
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "orientation", value: "landscape", disabled: !isPaged, children: "Landscape" })
6051
+ ] }),
6052
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuDivider, {}),
6053
+ /* @__PURE__ */ jsxRuntime.jsxs(reactComponents.MenuGroup, { children: [
6054
+ /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuGroupHeader, { children: "Margins" }),
6055
+ MARGIN_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(reactComponents.MenuItemRadio, { name: "margin", value: opt.key, disabled: !isPaged, children: opt.label }, opt.key))
6056
+ ] })
6057
+ ] }) })
6058
+ ]
6059
+ }
6060
+ );
6061
+ }
5729
6062
  var TableItemPlugin = ({ disabled }) => {
5730
6063
  const [editor] = LexicalComposerContext.useLexicalComposerContext();
5731
6064
  const [columns, setColumns] = React9.useState("");
@@ -5943,7 +6276,8 @@ var ALLOWED_TOKENS = {
5943
6276
  FontSize: true,
5944
6277
  Decorators: true,
5945
6278
  CodeBlock: true,
5946
- Align: true
6279
+ Align: true,
6280
+ PageSetup: true
5947
6281
  };
5948
6282
  function sanitizePluginGroups(groups) {
5949
6283
  if (!groups || groups.length === 0) return [];
@@ -6482,6 +6816,16 @@ var ToolBarPlugins = (props) => {
6482
6816
  key
6483
6817
  );
6484
6818
  }
6819
+ case "PageSetup":
6820
+ return /* @__PURE__ */ jsxRuntime.jsx(
6821
+ PageSetupPlugin,
6822
+ {
6823
+ disabled: !isEditable || props.readOnly,
6824
+ value: props.pageSetup,
6825
+ onChange: props.onPageSetupChange
6826
+ },
6827
+ key
6828
+ );
6485
6829
  default:
6486
6830
  return null;
6487
6831
  }
@@ -6833,6 +7177,8 @@ var ContentEditorComponent = React9.forwardRef(
6833
7177
  const [charCount, setCharCount] = React9.useState(0);
6834
7178
  const handleCharCount = React9.useCallback((count) => setCharCount(count), []);
6835
7179
  const [refErrors, setRefErrors] = React9.useState([]);
7180
+ const [pageSetup, setPageSetup] = React9.useState(DEFAULT_PAGE_SETUP);
7181
+ const pageCanvas = resolvePageCanvasMetrics(pageSetup);
6836
7182
  const contentEditableDomRef = React9.useRef(null);
6837
7183
  const previousOverLimitRef = React9.useRef(false);
6838
7184
  const focusedRef = React9.useRef(false);
@@ -6874,8 +7220,8 @@ var ContentEditorComponent = React9.forwardRef(
6874
7220
  color: "var(--colorNeutralForeground3, grey)",
6875
7221
  position: "absolute",
6876
7222
  top: props.level !== "none" /* None */ ? "17px" : "27px",
6877
- left: 20,
6878
- right: 20,
7223
+ left: pageCanvas.paddingPx,
7224
+ right: pageCanvas.paddingPx,
6879
7225
  fontSize: "14px",
6880
7226
  pointerEvents: "none",
6881
7227
  userSelect: "none"
@@ -6886,8 +7232,6 @@ var ContentEditorComponent = React9.forwardRef(
6886
7232
  outline: "none",
6887
7233
  overflow: "auto",
6888
7234
  marginTop: "0px",
6889
- paddingLeft: "20px",
6890
- paddingRight: "20px",
6891
7235
  position: "relative",
6892
7236
  background: "var(--colorNeutralBackground1, #ffffff)",
6893
7237
  justifyContent: "center",
@@ -6987,7 +7331,9 @@ var ContentEditorComponent = React9.forwardRef(
6987
7331
  ToolBarPlugins,
6988
7332
  {
6989
7333
  level: props.level ?? "basic" /* Basic */,
6990
- readOnly: props.readOnly
7334
+ readOnly: props.readOnly,
7335
+ pageSetup,
7336
+ onPageSetupChange: setPageSetup
6991
7337
  }
6992
7338
  )
6993
7339
  }
@@ -7001,7 +7347,8 @@ var ContentEditorComponent = React9.forwardRef(
7001
7347
  padding: "15px 0px",
7002
7348
  overflowY: "scroll",
7003
7349
  overflowX: "auto",
7004
- minWidth: 0
7350
+ minWidth: 0,
7351
+ background: pageCanvas.widthPx !== void 0 ? "#eef0f2" : void 0
7005
7352
  },
7006
7353
  onClickCapture: handleReadOnlyClickCapture,
7007
7354
  children: [
@@ -7020,7 +7367,15 @@ var ContentEditorComponent = React9.forwardRef(
7020
7367
  {
7021
7368
  ref: contentEditableDomRef,
7022
7369
  className: react.css(EditorStyles.contentEditor),
7023
- style: { paddingTop: props.level !== "none" /* None */ ? 0 : 10 },
7370
+ style: {
7371
+ paddingTop: props.level !== "none" /* None */ ? 0 : 10,
7372
+ paddingLeft: pageCanvas.paddingPx,
7373
+ paddingRight: pageCanvas.paddingPx,
7374
+ maxWidth: pageCanvas.widthPx,
7375
+ marginLeft: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7376
+ marginRight: pageCanvas.widthPx !== void 0 ? "auto" : void 0,
7377
+ boxShadow: pageCanvas.widthPx !== void 0 ? "0 0 0 1px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.08)" : void 0
7378
+ },
7024
7379
  spellCheck: !resolvedSpellCheck,
7025
7380
  autoCorrect: resolvedSpellCheck ? "off" : void 0,
7026
7381
  autoCapitalize: resolvedSpellCheck ? "off" : void 0