@refactico/pages 0.2.0 → 0.2.2

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
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { useRef, useState, useEffect, useCallback, memo, createContext } from 'react';
2
+ import { useRef, useState, useEffect, useCallback, memo, createContext, useMemo } from 'react';
3
3
 
4
4
  const generateId = () => {
5
5
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
@@ -880,7 +880,7 @@ const AlignRightIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsxs(
880
880
  ]
881
881
  }
882
882
  );
883
- const CheckIcon = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
883
+ const CheckIcon$1 = ({ className = "", size = 20 }) => /* @__PURE__ */ jsx(
884
884
  "svg",
885
885
  {
886
886
  className,
@@ -1725,13 +1725,20 @@ const CodeBlock = ({
1725
1725
  const [copied, setCopied] = useState(false);
1726
1726
  const textareaRef = useRef(null);
1727
1727
  const isDark = theme === "dark";
1728
- const handleCodeChange = (e) => {
1729
- onUpdate({ ...block, code: e.target.value });
1728
+ const resizeTextarea = () => {
1730
1729
  if (textareaRef.current) {
1731
1730
  textareaRef.current.style.height = "auto";
1732
1731
  textareaRef.current.style.height = textareaRef.current.scrollHeight + "px";
1733
1732
  }
1734
1733
  };
1734
+ useEffect(() => {
1735
+ if (!readOnly) {
1736
+ resizeTextarea();
1737
+ }
1738
+ }, [block.code, readOnly]);
1739
+ const handleCodeChange = (e) => {
1740
+ onUpdate({ ...block, code: e.target.value });
1741
+ };
1735
1742
  const handleLanguageChange = (e) => {
1736
1743
  onUpdate({ ...block, language: e.target.value });
1737
1744
  };
@@ -1812,7 +1819,7 @@ const CodeBlock = ({
1812
1819
  onClick: copyToClipboard,
1813
1820
  className: "p-1.5 rounded-lg hover:bg-slate-700 text-slate-400 hover:text-white transition-colors",
1814
1821
  title: "Copy code",
1815
- children: copied ? /* @__PURE__ */ jsx(CheckIcon, { size: 16 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 16 })
1822
+ children: copied ? /* @__PURE__ */ jsx(CheckIcon$1, { size: 16 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 16 })
1816
1823
  }
1817
1824
  )
1818
1825
  ] })
@@ -2481,7 +2488,7 @@ const ListBlock = ({
2481
2488
  onClick: () => toggleChecked(index),
2482
2489
  disabled: readOnly,
2483
2490
  className: `flex-shrink-0 w-5 h-5 rounded border-2 flex items-center justify-center transition-colors ${block.checkedItems?.[index] ? "bg-indigo-500 border-indigo-500 text-white" : isDark ? "border-slate-500 hover:border-indigo-400" : "border-slate-300 hover:border-indigo-400"}`,
2484
- children: block.checkedItems?.[index] && /* @__PURE__ */ jsx(CheckIcon, { size: 12 })
2491
+ children: block.checkedItems?.[index] && /* @__PURE__ */ jsx(CheckIcon$1, { size: 12 })
2485
2492
  }
2486
2493
  ),
2487
2494
  readOnly ? /* @__PURE__ */ jsx(
@@ -3467,4 +3474,928 @@ const DIVIDER_STYLE_CLASSES = {
3467
3474
  dotted: "border-dotted"
3468
3475
  };
3469
3476
 
3470
- export { ALIGNMENT_CLASSES, CALLOUT_ICONS, CALLOUT_LABELS, CALLOUT_VARIANT_STYLES, DIVIDER_STYLE_CLASSES, FONT_SIZE_CLASSES, PagesEditor, QUOTE_STYLE_CLASSES, SUPPORTED_LANGUAGES, cloneBlock, createCalloutBlock, createCodeBlock, createDividerBlock, createEmptyEditorData, createHeadingBlock, createImageBlock, createListBlock, createQuoteBlock, createTableBlock, createTextBlock, fileToBase64, generateId, getMutedTextClass, getPlaceholderClass, getPrimaryTextClass, getSecondaryTextClass, getSmallToolbarButtonClass, getToolbarButtonClass, getToolbarContainerClass, getToolbarDividerClass, isDarkTheme, moveArrayItem, useAutoResize, useBlockToolbar, useClickOutside, validateEditorData };
3477
+ function deepEqual(a, b) {
3478
+ if (a === b) return true;
3479
+ if (typeof a !== typeof b) return false;
3480
+ if (a === null || b === null) return a === b;
3481
+ if (typeof a !== "object") return false;
3482
+ if (Array.isArray(a) && Array.isArray(b)) {
3483
+ if (a.length !== b.length) return false;
3484
+ return a.every((item, index) => deepEqual(item, b[index]));
3485
+ }
3486
+ if (Array.isArray(a) || Array.isArray(b)) return false;
3487
+ const aObj = a;
3488
+ const bObj = b;
3489
+ const aKeys = Object.keys(aObj);
3490
+ const bKeys = Object.keys(bObj);
3491
+ if (aKeys.length !== bKeys.length) return false;
3492
+ return aKeys.every((key) => deepEqual(aObj[key], bObj[key]));
3493
+ }
3494
+ function getPropertyChanges(oldBlock, newBlock) {
3495
+ const changes = [];
3496
+ const oldObj = oldBlock;
3497
+ const newObj = newBlock;
3498
+ const allKeys = /* @__PURE__ */ new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);
3499
+ for (const key of allKeys) {
3500
+ if (key === "id") continue;
3501
+ const oldValue = oldObj[key];
3502
+ const newValue = newObj[key];
3503
+ if (!deepEqual(oldValue, newValue)) {
3504
+ changes.push({ path: key, oldValue, newValue });
3505
+ }
3506
+ }
3507
+ return changes;
3508
+ }
3509
+ function compareEditorData(oldData, newData) {
3510
+ const oldBlocks = oldData.blocks;
3511
+ const newBlocks = newData.blocks;
3512
+ const blockDiffs = [];
3513
+ const oldBlockMap = new Map(oldBlocks.map((b) => [b.id, b]));
3514
+ const processedIds = /* @__PURE__ */ new Set();
3515
+ for (const newBlock of newBlocks) {
3516
+ const oldBlock = oldBlockMap.get(newBlock.id);
3517
+ processedIds.add(newBlock.id);
3518
+ if (!oldBlock) {
3519
+ blockDiffs.push({ type: "added", newBlock });
3520
+ } else {
3521
+ const changes = getPropertyChanges(oldBlock, newBlock);
3522
+ if (changes.length > 0) {
3523
+ blockDiffs.push({ type: "modified", oldBlock, newBlock, changes });
3524
+ } else {
3525
+ blockDiffs.push({ type: "unchanged", oldBlock, newBlock });
3526
+ }
3527
+ }
3528
+ }
3529
+ for (const oldBlock of oldBlocks) {
3530
+ if (!processedIds.has(oldBlock.id)) {
3531
+ blockDiffs.push({ type: "removed", oldBlock });
3532
+ }
3533
+ }
3534
+ const summary = {
3535
+ added: blockDiffs.filter((d) => d.type === "added").length,
3536
+ removed: blockDiffs.filter((d) => d.type === "removed").length,
3537
+ modified: blockDiffs.filter((d) => d.type === "modified").length,
3538
+ unchanged: blockDiffs.filter((d) => d.type === "unchanged").length
3539
+ };
3540
+ return { blocks: blockDiffs, summary };
3541
+ }
3542
+ function formatValue(value) {
3543
+ if (value === void 0) return "undefined";
3544
+ if (value === null) return "null";
3545
+ if (typeof value === "string") return `"${value}"`;
3546
+ if (typeof value === "object") {
3547
+ return JSON.stringify(value, null, 2);
3548
+ }
3549
+ return String(value);
3550
+ }
3551
+ function getBlockTypeLabel(block) {
3552
+ const labels = {
3553
+ text: "Text",
3554
+ heading: "Heading",
3555
+ image: "Image",
3556
+ code: "Code",
3557
+ table: "Table",
3558
+ divider: "Divider",
3559
+ quote: "Quote",
3560
+ list: "List",
3561
+ callout: "Callout"
3562
+ };
3563
+ return labels[block.type] || block.type;
3564
+ }
3565
+ function getBlockPreview(block, maxLength = 50) {
3566
+ switch (block.type) {
3567
+ case "text":
3568
+ case "heading":
3569
+ case "quote":
3570
+ case "callout": {
3571
+ const content = block.content || "";
3572
+ return content.length > maxLength ? content.substring(0, maxLength) + "..." : content;
3573
+ }
3574
+ case "code":
3575
+ return block.language || "code";
3576
+ case "image":
3577
+ return block.alt || "Image";
3578
+ case "list":
3579
+ return `${block.items.length} items`;
3580
+ case "table":
3581
+ return `${block.rows.length} rows`;
3582
+ case "divider":
3583
+ return block.style || "solid";
3584
+ default:
3585
+ return "";
3586
+ }
3587
+ }
3588
+
3589
+ function BlockRenderer({ block, theme }) {
3590
+ const noop = () => {
3591
+ };
3592
+ switch (block.type) {
3593
+ case "text":
3594
+ return /* @__PURE__ */ jsx(
3595
+ TextBlock,
3596
+ {
3597
+ block,
3598
+ onUpdate: noop,
3599
+ readOnly: true,
3600
+ theme
3601
+ }
3602
+ );
3603
+ case "heading":
3604
+ return /* @__PURE__ */ jsx(
3605
+ HeadingBlock,
3606
+ {
3607
+ block,
3608
+ onUpdate: noop,
3609
+ readOnly: true,
3610
+ theme
3611
+ }
3612
+ );
3613
+ case "image":
3614
+ return /* @__PURE__ */ jsx(
3615
+ ImageBlock,
3616
+ {
3617
+ block,
3618
+ onUpdate: noop,
3619
+ readOnly: true,
3620
+ theme
3621
+ }
3622
+ );
3623
+ case "code":
3624
+ return /* @__PURE__ */ jsx(
3625
+ CodeBlock,
3626
+ {
3627
+ block,
3628
+ onUpdate: noop,
3629
+ readOnly: true,
3630
+ theme
3631
+ }
3632
+ );
3633
+ case "table":
3634
+ return /* @__PURE__ */ jsx(
3635
+ TableBlock,
3636
+ {
3637
+ block,
3638
+ onUpdate: noop,
3639
+ readOnly: true,
3640
+ theme
3641
+ }
3642
+ );
3643
+ case "divider":
3644
+ return /* @__PURE__ */ jsx(
3645
+ DividerBlock,
3646
+ {
3647
+ block,
3648
+ onUpdate: noop,
3649
+ readOnly: true,
3650
+ theme
3651
+ }
3652
+ );
3653
+ case "quote":
3654
+ return /* @__PURE__ */ jsx(
3655
+ QuoteBlock,
3656
+ {
3657
+ block,
3658
+ onUpdate: noop,
3659
+ readOnly: true,
3660
+ theme
3661
+ }
3662
+ );
3663
+ case "list":
3664
+ return /* @__PURE__ */ jsx(
3665
+ ListBlock,
3666
+ {
3667
+ block,
3668
+ onUpdate: noop,
3669
+ readOnly: true,
3670
+ theme
3671
+ }
3672
+ );
3673
+ case "callout":
3674
+ return /* @__PURE__ */ jsx(
3675
+ CalloutBlock,
3676
+ {
3677
+ block,
3678
+ onUpdate: noop,
3679
+ readOnly: true,
3680
+ theme
3681
+ }
3682
+ );
3683
+ default:
3684
+ return null;
3685
+ }
3686
+ }
3687
+
3688
+ const PlusCircleIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3689
+ "svg",
3690
+ {
3691
+ width: size,
3692
+ height: size,
3693
+ viewBox: "0 0 24 24",
3694
+ fill: "none",
3695
+ stroke: "currentColor",
3696
+ strokeWidth: "2",
3697
+ strokeLinecap: "round",
3698
+ strokeLinejoin: "round",
3699
+ className,
3700
+ children: [
3701
+ /* @__PURE__ */ jsx(
3702
+ "circle",
3703
+ {
3704
+ cx: "12",
3705
+ cy: "12",
3706
+ r: "10"
3707
+ }
3708
+ ),
3709
+ /* @__PURE__ */ jsx(
3710
+ "line",
3711
+ {
3712
+ x1: "12",
3713
+ y1: "8",
3714
+ x2: "12",
3715
+ y2: "16"
3716
+ }
3717
+ ),
3718
+ /* @__PURE__ */ jsx(
3719
+ "line",
3720
+ {
3721
+ x1: "8",
3722
+ y1: "12",
3723
+ x2: "16",
3724
+ y2: "12"
3725
+ }
3726
+ )
3727
+ ]
3728
+ }
3729
+ );
3730
+ const MinusCircleIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3731
+ "svg",
3732
+ {
3733
+ width: size,
3734
+ height: size,
3735
+ viewBox: "0 0 24 24",
3736
+ fill: "none",
3737
+ stroke: "currentColor",
3738
+ strokeWidth: "2",
3739
+ strokeLinecap: "round",
3740
+ strokeLinejoin: "round",
3741
+ className,
3742
+ children: [
3743
+ /* @__PURE__ */ jsx(
3744
+ "circle",
3745
+ {
3746
+ cx: "12",
3747
+ cy: "12",
3748
+ r: "10"
3749
+ }
3750
+ ),
3751
+ /* @__PURE__ */ jsx(
3752
+ "line",
3753
+ {
3754
+ x1: "8",
3755
+ y1: "12",
3756
+ x2: "16",
3757
+ y2: "12"
3758
+ }
3759
+ )
3760
+ ]
3761
+ }
3762
+ );
3763
+ const EditIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3764
+ "svg",
3765
+ {
3766
+ width: size,
3767
+ height: size,
3768
+ viewBox: "0 0 24 24",
3769
+ fill: "none",
3770
+ stroke: "currentColor",
3771
+ strokeWidth: "2",
3772
+ strokeLinecap: "round",
3773
+ strokeLinejoin: "round",
3774
+ className,
3775
+ children: [
3776
+ /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
3777
+ /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
3778
+ ]
3779
+ }
3780
+ );
3781
+ const CheckIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsx(
3782
+ "svg",
3783
+ {
3784
+ width: size,
3785
+ height: size,
3786
+ viewBox: "0 0 24 24",
3787
+ fill: "none",
3788
+ stroke: "currentColor",
3789
+ strokeWidth: "2",
3790
+ strokeLinecap: "round",
3791
+ strokeLinejoin: "round",
3792
+ className,
3793
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
3794
+ }
3795
+ );
3796
+ const SplitIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3797
+ "svg",
3798
+ {
3799
+ width: size,
3800
+ height: size,
3801
+ viewBox: "0 0 24 24",
3802
+ fill: "none",
3803
+ stroke: "currentColor",
3804
+ strokeWidth: "2",
3805
+ strokeLinecap: "round",
3806
+ strokeLinejoin: "round",
3807
+ className,
3808
+ children: [
3809
+ /* @__PURE__ */ jsx(
3810
+ "rect",
3811
+ {
3812
+ x: "3",
3813
+ y: "3",
3814
+ width: "18",
3815
+ height: "18",
3816
+ rx: "2"
3817
+ }
3818
+ ),
3819
+ /* @__PURE__ */ jsx(
3820
+ "line",
3821
+ {
3822
+ x1: "12",
3823
+ y1: "3",
3824
+ x2: "12",
3825
+ y2: "21"
3826
+ }
3827
+ )
3828
+ ]
3829
+ }
3830
+ );
3831
+ const UnifiedIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3832
+ "svg",
3833
+ {
3834
+ width: size,
3835
+ height: size,
3836
+ viewBox: "0 0 24 24",
3837
+ fill: "none",
3838
+ stroke: "currentColor",
3839
+ strokeWidth: "2",
3840
+ strokeLinecap: "round",
3841
+ strokeLinejoin: "round",
3842
+ className,
3843
+ children: [
3844
+ /* @__PURE__ */ jsx(
3845
+ "rect",
3846
+ {
3847
+ x: "3",
3848
+ y: "3",
3849
+ width: "18",
3850
+ height: "18",
3851
+ rx: "2"
3852
+ }
3853
+ ),
3854
+ /* @__PURE__ */ jsx(
3855
+ "line",
3856
+ {
3857
+ x1: "3",
3858
+ y1: "9",
3859
+ x2: "21",
3860
+ y2: "9"
3861
+ }
3862
+ ),
3863
+ /* @__PURE__ */ jsx(
3864
+ "line",
3865
+ {
3866
+ x1: "3",
3867
+ y1: "15",
3868
+ x2: "21",
3869
+ y2: "15"
3870
+ }
3871
+ )
3872
+ ]
3873
+ }
3874
+ );
3875
+ const GripVerticalIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3876
+ "svg",
3877
+ {
3878
+ width: size,
3879
+ height: size,
3880
+ viewBox: "0 0 24 24",
3881
+ fill: "currentColor",
3882
+ className,
3883
+ children: [
3884
+ /* @__PURE__ */ jsx(
3885
+ "circle",
3886
+ {
3887
+ cx: "9",
3888
+ cy: "5",
3889
+ r: "1.5"
3890
+ }
3891
+ ),
3892
+ /* @__PURE__ */ jsx(
3893
+ "circle",
3894
+ {
3895
+ cx: "15",
3896
+ cy: "5",
3897
+ r: "1.5"
3898
+ }
3899
+ ),
3900
+ /* @__PURE__ */ jsx(
3901
+ "circle",
3902
+ {
3903
+ cx: "9",
3904
+ cy: "12",
3905
+ r: "1.5"
3906
+ }
3907
+ ),
3908
+ /* @__PURE__ */ jsx(
3909
+ "circle",
3910
+ {
3911
+ cx: "15",
3912
+ cy: "12",
3913
+ r: "1.5"
3914
+ }
3915
+ ),
3916
+ /* @__PURE__ */ jsx(
3917
+ "circle",
3918
+ {
3919
+ cx: "9",
3920
+ cy: "19",
3921
+ r: "1.5"
3922
+ }
3923
+ ),
3924
+ /* @__PURE__ */ jsx(
3925
+ "circle",
3926
+ {
3927
+ cx: "15",
3928
+ cy: "19",
3929
+ r: "1.5"
3930
+ }
3931
+ )
3932
+ ]
3933
+ }
3934
+ );
3935
+ const UndoIcon = ({ size = 16, className = "" }) => /* @__PURE__ */ jsxs(
3936
+ "svg",
3937
+ {
3938
+ width: size,
3939
+ height: size,
3940
+ viewBox: "0 0 24 24",
3941
+ fill: "none",
3942
+ stroke: "currentColor",
3943
+ strokeWidth: "2",
3944
+ strokeLinecap: "round",
3945
+ strokeLinejoin: "round",
3946
+ className,
3947
+ children: [
3948
+ /* @__PURE__ */ jsx("path", { d: "M3 7v6h6" }),
3949
+ /* @__PURE__ */ jsx("path", { d: "M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13" })
3950
+ ]
3951
+ }
3952
+ );
3953
+
3954
+ const useIsMobile = () => {
3955
+ const [isMobile, setIsMobile] = useState(false);
3956
+ useEffect(() => {
3957
+ const checkMobile = () => setIsMobile(window.innerWidth < 768);
3958
+ checkMobile();
3959
+ window.addEventListener("resize", checkMobile);
3960
+ return () => window.removeEventListener("resize", checkMobile);
3961
+ }, []);
3962
+ return isMobile;
3963
+ };
3964
+ function JsonDiff({
3965
+ oldData,
3966
+ newData,
3967
+ onChange,
3968
+ theme = "light",
3969
+ className = "",
3970
+ initialSplitPosition = 50,
3971
+ minPanelWidth = 20,
3972
+ allowRevert = true
3973
+ }) {
3974
+ const isDark = theme === "dark";
3975
+ const isMobile = useIsMobile();
3976
+ const [viewMode, setViewMode] = useState(isMobile ? "unified" : "split");
3977
+ const [splitPosition, setSplitPosition] = useState(initialSplitPosition);
3978
+ const [isDragging, setIsDragging] = useState(false);
3979
+ const [currentData, setCurrentData] = useState(newData);
3980
+ const containerRef = useRef(null);
3981
+ useEffect(() => {
3982
+ setCurrentData(newData);
3983
+ }, [newData]);
3984
+ useEffect(() => {
3985
+ if (isMobile && viewMode === "split") {
3986
+ setViewMode("unified");
3987
+ }
3988
+ }, [isMobile, viewMode]);
3989
+ const diffResult = useMemo(() => compareEditorData(oldData, currentData), [oldData, currentData]);
3990
+ const handleMouseDown = useCallback((e) => {
3991
+ e.preventDefault();
3992
+ setIsDragging(true);
3993
+ }, []);
3994
+ const handleMouseMove = useCallback(
3995
+ (e) => {
3996
+ if (!isDragging || !containerRef.current) return;
3997
+ const rect = containerRef.current.getBoundingClientRect();
3998
+ const newPosition = (e.clientX - rect.left) / rect.width * 100;
3999
+ const clampedPosition = Math.max(minPanelWidth, Math.min(100 - minPanelWidth, newPosition));
4000
+ setSplitPosition(clampedPosition);
4001
+ },
4002
+ [isDragging, minPanelWidth]
4003
+ );
4004
+ const handleMouseUp = useCallback(() => {
4005
+ setIsDragging(false);
4006
+ }, []);
4007
+ useEffect(() => {
4008
+ if (isDragging) {
4009
+ document.addEventListener("mousemove", handleMouseMove);
4010
+ document.addEventListener("mouseup", handleMouseUp);
4011
+ document.body.style.cursor = "col-resize";
4012
+ document.body.style.userSelect = "none";
4013
+ }
4014
+ return () => {
4015
+ document.removeEventListener("mousemove", handleMouseMove);
4016
+ document.removeEventListener("mouseup", handleMouseUp);
4017
+ document.body.style.cursor = "";
4018
+ document.body.style.userSelect = "";
4019
+ };
4020
+ }, [isDragging, handleMouseMove, handleMouseUp]);
4021
+ const handleRevert = useCallback(
4022
+ (diff) => {
4023
+ let newBlocks;
4024
+ if (diff.type === "added" && diff.newBlock) {
4025
+ newBlocks = currentData.blocks.filter((b) => b.id !== diff.newBlock.id);
4026
+ } else if (diff.type === "removed" && diff.oldBlock) {
4027
+ const oldIndex = oldData.blocks.findIndex((b) => b.id === diff.oldBlock.id);
4028
+ newBlocks = [...currentData.blocks];
4029
+ let insertIndex = newBlocks.length;
4030
+ for (let i = oldIndex - 1; i >= 0; i--) {
4031
+ const prevBlock = oldData.blocks[i];
4032
+ const prevIndexInCurrent = newBlocks.findIndex((b) => b.id === prevBlock?.id);
4033
+ if (prevIndexInCurrent !== -1) {
4034
+ insertIndex = prevIndexInCurrent + 1;
4035
+ break;
4036
+ }
4037
+ }
4038
+ newBlocks.splice(insertIndex, 0, diff.oldBlock);
4039
+ } else if (diff.type === "modified" && diff.oldBlock && diff.newBlock) {
4040
+ newBlocks = currentData.blocks.map(
4041
+ (b) => b.id === diff.newBlock.id ? diff.oldBlock : b
4042
+ );
4043
+ } else {
4044
+ return;
4045
+ }
4046
+ const updatedData = {
4047
+ ...currentData,
4048
+ blocks: newBlocks,
4049
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4050
+ };
4051
+ setCurrentData(updatedData);
4052
+ onChange?.(updatedData);
4053
+ },
4054
+ [currentData, oldData, onChange]
4055
+ );
4056
+ const getDiffStyles = (type) => {
4057
+ const styles = {
4058
+ added: {
4059
+ bg: isDark ? "bg-emerald-950/30" : "bg-emerald-50",
4060
+ border: isDark ? "border-emerald-600" : "border-emerald-400",
4061
+ badge: isDark ? "bg-emerald-900 text-emerald-300" : "bg-emerald-100 text-emerald-700",
4062
+ icon: /* @__PURE__ */ jsx(PlusCircleIcon, { size: 14 }),
4063
+ label: "Added",
4064
+ revertLabel: "Remove"
4065
+ },
4066
+ removed: {
4067
+ bg: isDark ? "bg-red-950/30" : "bg-red-50",
4068
+ border: isDark ? "border-red-600" : "border-red-400",
4069
+ badge: isDark ? "bg-red-900 text-red-300" : "bg-red-100 text-red-700",
4070
+ icon: /* @__PURE__ */ jsx(MinusCircleIcon, { size: 14 }),
4071
+ label: "Removed",
4072
+ revertLabel: "Restore"
4073
+ },
4074
+ modified: {
4075
+ bg: isDark ? "bg-amber-950/30" : "bg-amber-50",
4076
+ border: isDark ? "border-amber-600" : "border-amber-400",
4077
+ badge: isDark ? "bg-amber-900 text-amber-300" : "bg-amber-100 text-amber-700",
4078
+ icon: /* @__PURE__ */ jsx(EditIcon, { size: 14 }),
4079
+ label: "Modified",
4080
+ revertLabel: "Revert"
4081
+ },
4082
+ unchanged: {
4083
+ bg: "bg-transparent",
4084
+ border: isDark ? "border-slate-700" : "border-slate-200",
4085
+ badge: isDark ? "bg-slate-800 text-slate-400" : "bg-slate-100 text-slate-500",
4086
+ icon: /* @__PURE__ */ jsx(CheckIcon, { size: 14 }),
4087
+ label: "Unchanged",
4088
+ revertLabel: ""
4089
+ }
4090
+ };
4091
+ return styles[type];
4092
+ };
4093
+ const renderBlockContent = (block, diffType, showBadge, badgeLabel, diff) => {
4094
+ const style = getDiffStyles(diffType);
4095
+ const showRevert = allowRevert && diff && diffType !== "unchanged";
4096
+ return /* @__PURE__ */ jsxs(
4097
+ "div",
4098
+ {
4099
+ className: `relative rounded-xl border-2 ${style.border} ${style.bg} overflow-hidden h-full`,
4100
+ children: [
4101
+ /* @__PURE__ */ jsxs(
4102
+ "div",
4103
+ {
4104
+ className: `flex items-center justify-between px-4 py-2 border-b ${isDark ? "border-slate-700" : "border-slate-200"}`,
4105
+ children: [
4106
+ /* @__PURE__ */ jsx(
4107
+ "span",
4108
+ {
4109
+ className: `text-xs font-medium uppercase tracking-wide ${isDark ? "text-slate-400" : "text-slate-500"}`,
4110
+ children: getBlockTypeLabel(block)
4111
+ }
4112
+ ),
4113
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
4114
+ showBadge && /* @__PURE__ */ jsxs(
4115
+ "span",
4116
+ {
4117
+ className: `flex items-center gap-1.5 px-2 py-1 rounded-full text-xs font-medium ${style.badge}`,
4118
+ children: [
4119
+ style.icon,
4120
+ badgeLabel || style.label
4121
+ ]
4122
+ }
4123
+ ),
4124
+ showRevert && diff && /* @__PURE__ */ jsxs(
4125
+ "button",
4126
+ {
4127
+ onClick: () => handleRevert(diff),
4128
+ className: `flex items-center gap-1 px-2 py-1 rounded-lg text-xs font-medium transition-colors ${isDark ? "bg-slate-700 text-slate-300 hover:bg-slate-600 hover:text-white" : "bg-slate-200 text-slate-600 hover:bg-slate-300 hover:text-slate-900"}`,
4129
+ title: style.revertLabel,
4130
+ children: [
4131
+ /* @__PURE__ */ jsx(UndoIcon, { size: 12 }),
4132
+ style.revertLabel
4133
+ ]
4134
+ }
4135
+ )
4136
+ ] })
4137
+ ]
4138
+ }
4139
+ ),
4140
+ /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(
4141
+ BlockRenderer,
4142
+ {
4143
+ block,
4144
+ theme
4145
+ }
4146
+ ) })
4147
+ ]
4148
+ }
4149
+ );
4150
+ };
4151
+ const renderPlaceholder = (message, diff, showRevert) => /* @__PURE__ */ jsxs(
4152
+ "div",
4153
+ {
4154
+ className: `h-full min-h-[100px] rounded-xl border-2 border-dashed flex flex-col items-center justify-center gap-3 ${isDark ? "border-slate-700 bg-slate-800/30" : "border-slate-200 bg-slate-50"}`,
4155
+ children: [
4156
+ /* @__PURE__ */ jsx("span", { className: `text-sm ${isDark ? "text-slate-500" : "text-slate-400"}`, children: message }),
4157
+ allowRevert && diff && /* @__PURE__ */ jsxs(
4158
+ "button",
4159
+ {
4160
+ onClick: () => handleRevert(diff),
4161
+ className: `flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium transition-colors ${isDark ? "bg-slate-700 text-slate-300 hover:bg-slate-600 hover:text-white" : "bg-slate-200 text-slate-600 hover:bg-slate-300 hover:text-slate-900"}`,
4162
+ children: [
4163
+ /* @__PURE__ */ jsx(UndoIcon, { size: 12 }),
4164
+ diff.type === "added" ? "Remove this block" : "Restore this block"
4165
+ ]
4166
+ }
4167
+ )
4168
+ ]
4169
+ }
4170
+ );
4171
+ const renderUnifiedDiffItem = (diff, index) => {
4172
+ if (diff.type === "unchanged") {
4173
+ return /* @__PURE__ */ jsx(
4174
+ "div",
4175
+ {
4176
+ className: "opacity-60",
4177
+ children: renderBlockContent(diff.oldBlock, "unchanged", false)
4178
+ },
4179
+ diff.oldBlock?.id || index
4180
+ );
4181
+ }
4182
+ if (diff.type === "added") {
4183
+ return /* @__PURE__ */ jsx("div", { children: renderBlockContent(diff.newBlock, "added", true, void 0, diff) }, diff.newBlock?.id || index);
4184
+ }
4185
+ if (diff.type === "removed") {
4186
+ return /* @__PURE__ */ jsx("div", { children: renderBlockContent(diff.oldBlock, "removed", true, void 0, diff) }, diff.oldBlock?.id || index);
4187
+ }
4188
+ return /* @__PURE__ */ jsxs(
4189
+ "div",
4190
+ {
4191
+ className: "space-y-2",
4192
+ children: [
4193
+ /* @__PURE__ */ jsxs("div", { className: "relative pl-4", children: [
4194
+ /* @__PURE__ */ jsx(
4195
+ "div",
4196
+ {
4197
+ className: `absolute left-0 top-0 bottom-0 w-1 rounded-full ${isDark ? "bg-red-500" : "bg-red-400"}`
4198
+ }
4199
+ ),
4200
+ /* @__PURE__ */ jsx("div", { className: "opacity-80", children: renderBlockContent(diff.oldBlock, "removed", true, "Before") })
4201
+ ] }),
4202
+ /* @__PURE__ */ jsxs("div", { className: "relative pl-4", children: [
4203
+ /* @__PURE__ */ jsx(
4204
+ "div",
4205
+ {
4206
+ className: `absolute left-0 top-0 bottom-0 w-1 rounded-full ${isDark ? "bg-emerald-500" : "bg-emerald-400"}`
4207
+ }
4208
+ ),
4209
+ renderBlockContent(diff.newBlock, "added", true, "After", diff)
4210
+ ] })
4211
+ ]
4212
+ },
4213
+ diff.oldBlock?.id || index
4214
+ );
4215
+ };
4216
+ return /* @__PURE__ */ jsxs(
4217
+ "div",
4218
+ {
4219
+ ref: containerRef,
4220
+ className: `json-diff w-full h-full flex flex-col ${isDark ? "bg-slate-900" : "bg-white"} ${className}`,
4221
+ children: [
4222
+ /* @__PURE__ */ jsxs(
4223
+ "div",
4224
+ {
4225
+ className: `flex-shrink-0 flex flex-wrap items-center justify-between gap-4 p-4 border-b ${isDark ? "border-slate-700" : "border-slate-200"}`,
4226
+ children: [
4227
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
4228
+ /* @__PURE__ */ jsx("span", { className: `text-sm font-medium ${isDark ? "text-slate-300" : "text-slate-700"}`, children: "Changes:" }),
4229
+ diffResult.summary.added > 0 && /* @__PURE__ */ jsxs(
4230
+ "span",
4231
+ {
4232
+ className: `inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-full ${isDark ? "bg-emerald-900/50 text-emerald-400" : "bg-emerald-100 text-emerald-700"}`,
4233
+ children: [
4234
+ /* @__PURE__ */ jsx(PlusCircleIcon, { size: 12 }),
4235
+ diffResult.summary.added,
4236
+ " added"
4237
+ ]
4238
+ }
4239
+ ),
4240
+ diffResult.summary.removed > 0 && /* @__PURE__ */ jsxs(
4241
+ "span",
4242
+ {
4243
+ className: `inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-full ${isDark ? "bg-red-900/50 text-red-400" : "bg-red-100 text-red-700"}`,
4244
+ children: [
4245
+ /* @__PURE__ */ jsx(MinusCircleIcon, { size: 12 }),
4246
+ diffResult.summary.removed,
4247
+ " removed"
4248
+ ]
4249
+ }
4250
+ ),
4251
+ diffResult.summary.modified > 0 && /* @__PURE__ */ jsxs(
4252
+ "span",
4253
+ {
4254
+ className: `inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium rounded-full ${isDark ? "bg-amber-900/50 text-amber-400" : "bg-amber-100 text-amber-700"}`,
4255
+ children: [
4256
+ /* @__PURE__ */ jsx(EditIcon, { size: 12 }),
4257
+ diffResult.summary.modified,
4258
+ " modified"
4259
+ ]
4260
+ }
4261
+ ),
4262
+ diffResult.summary.added === 0 && diffResult.summary.removed === 0 && diffResult.summary.modified === 0 && /* @__PURE__ */ jsx("span", { className: `text-sm ${isDark ? "text-slate-400" : "text-slate-500"}`, children: "No changes detected" })
4263
+ ] }),
4264
+ !isMobile && /* @__PURE__ */ jsxs(
4265
+ "div",
4266
+ {
4267
+ className: `flex items-center rounded-lg p-1 ${isDark ? "bg-slate-800" : "bg-slate-100"}`,
4268
+ children: [
4269
+ /* @__PURE__ */ jsxs(
4270
+ "button",
4271
+ {
4272
+ onClick: () => setViewMode("split"),
4273
+ className: `flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${viewMode === "split" ? isDark ? "bg-slate-700 text-white" : "bg-white text-slate-900 shadow-sm" : isDark ? "text-slate-400 hover:text-slate-200" : "text-slate-600 hover:text-slate-900"}`,
4274
+ children: [
4275
+ /* @__PURE__ */ jsx(SplitIcon, { size: 14 }),
4276
+ "Split"
4277
+ ]
4278
+ }
4279
+ ),
4280
+ /* @__PURE__ */ jsxs(
4281
+ "button",
4282
+ {
4283
+ onClick: () => setViewMode("unified"),
4284
+ className: `flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${viewMode === "unified" ? isDark ? "bg-slate-700 text-white" : "bg-white text-slate-900 shadow-sm" : isDark ? "text-slate-400 hover:text-slate-200" : "text-slate-600 hover:text-slate-900"}`,
4285
+ children: [
4286
+ /* @__PURE__ */ jsx(UnifiedIcon, { size: 14 }),
4287
+ "Unified"
4288
+ ]
4289
+ }
4290
+ )
4291
+ ]
4292
+ }
4293
+ )
4294
+ ]
4295
+ }
4296
+ ),
4297
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto relative", children: viewMode === "split" ? /* @__PURE__ */ jsxs("div", { className: "relative min-h-full", children: [
4298
+ /* @__PURE__ */ jsx(
4299
+ "div",
4300
+ {
4301
+ className: "sticky top-1/2 -translate-y-1/2 z-30 pointer-events-none",
4302
+ style: { marginLeft: `calc(${splitPosition}% - 20px)`, height: 0 },
4303
+ children: /* @__PURE__ */ jsx(
4304
+ "div",
4305
+ {
4306
+ className: `pointer-events-auto w-10 h-10 rounded-xl cursor-col-resize flex items-center justify-center transition-all ${isDragging ? "bg-indigo-500 scale-110 shadow-lg" : isDark ? "bg-slate-700 hover:bg-indigo-500 shadow-md" : "bg-slate-200 hover:bg-indigo-500 shadow-md"}`,
4307
+ onMouseDown: handleMouseDown,
4308
+ children: /* @__PURE__ */ jsx(
4309
+ GripVerticalIcon,
4310
+ {
4311
+ size: 18,
4312
+ className: `transition-colors ${isDragging ? "text-white" : isDark ? "text-slate-400" : "text-slate-500"}`
4313
+ }
4314
+ )
4315
+ }
4316
+ )
4317
+ }
4318
+ ),
4319
+ /* @__PURE__ */ jsx(
4320
+ "div",
4321
+ {
4322
+ className: `absolute top-0 bottom-0 w-px transition-colors ${isDragging ? "bg-indigo-500" : isDark ? "bg-slate-700" : "bg-slate-300"}`,
4323
+ style: { left: `${splitPosition}%` }
4324
+ }
4325
+ ),
4326
+ /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
4327
+ /* @__PURE__ */ jsxs(
4328
+ "div",
4329
+ {
4330
+ className: "flex mb-4 sticky top-0 z-20 py-2 -mx-4 px-4",
4331
+ style: {
4332
+ background: isDark ? "rgb(15 23 42)" : "white"
4333
+ },
4334
+ children: [
4335
+ /* @__PURE__ */ jsx(
4336
+ "div",
4337
+ {
4338
+ style: { width: `${splitPosition}%` },
4339
+ className: `flex-shrink-0 pr-6 pb-2 border-b ${isDark ? "border-slate-700" : "border-slate-200"}`,
4340
+ children: /* @__PURE__ */ jsx(
4341
+ "h3",
4342
+ {
4343
+ className: `text-sm font-semibold uppercase tracking-wide ${isDark ? "text-slate-400" : "text-slate-500"}`,
4344
+ children: "📄 Original"
4345
+ }
4346
+ )
4347
+ }
4348
+ ),
4349
+ /* @__PURE__ */ jsx(
4350
+ "div",
4351
+ {
4352
+ style: { width: `${100 - splitPosition}%` },
4353
+ className: `flex-shrink-0 pl-6 pb-2 border-b ${isDark ? "border-slate-700" : "border-slate-200"}`,
4354
+ children: /* @__PURE__ */ jsx(
4355
+ "h3",
4356
+ {
4357
+ className: `text-sm font-semibold uppercase tracking-wide ${isDark ? "text-slate-400" : "text-slate-500"}`,
4358
+ children: "✨ Modified"
4359
+ }
4360
+ )
4361
+ }
4362
+ )
4363
+ ]
4364
+ }
4365
+ ),
4366
+ /* @__PURE__ */ jsx("div", { className: "space-y-4", children: diffResult.blocks.map((diff, idx) => /* @__PURE__ */ jsxs(
4367
+ "div",
4368
+ {
4369
+ className: "flex",
4370
+ children: [
4371
+ /* @__PURE__ */ jsx(
4372
+ "div",
4373
+ {
4374
+ style: { width: `${splitPosition}%` },
4375
+ className: "flex-shrink-0 pr-6",
4376
+ children: diff.type === "added" ? renderPlaceholder("New block added →", diff) : diff.type === "removed" ? renderBlockContent(diff.oldBlock, "removed", true, void 0, diff) : diff.type === "modified" ? renderBlockContent(diff.oldBlock, "modified", true, "Before") : /* @__PURE__ */ jsx("div", { className: "opacity-60 h-full", children: renderBlockContent(diff.oldBlock, "unchanged", false) })
4377
+ }
4378
+ ),
4379
+ /* @__PURE__ */ jsx(
4380
+ "div",
4381
+ {
4382
+ style: { width: `${100 - splitPosition}%` },
4383
+ className: "flex-shrink-0 pl-6",
4384
+ children: diff.type === "removed" ? renderPlaceholder("← Block removed", diff) : diff.type === "added" ? renderBlockContent(diff.newBlock, "added", true, void 0, diff) : diff.type === "modified" ? renderBlockContent(diff.newBlock, "modified", true, "After", diff) : /* @__PURE__ */ jsx("div", { className: "opacity-60 h-full", children: renderBlockContent(diff.newBlock, "unchanged", false) })
4385
+ }
4386
+ )
4387
+ ]
4388
+ },
4389
+ diff.oldBlock?.id || diff.newBlock?.id || idx
4390
+ )) })
4391
+ ] })
4392
+ ] }) : (
4393
+ /* Unified View */
4394
+ /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("div", { className: "space-y-4 max-w-4xl mx-auto", children: diffResult.blocks.map((diff, idx) => renderUnifiedDiffItem(diff, idx)) }) })
4395
+ ) })
4396
+ ]
4397
+ }
4398
+ );
4399
+ }
4400
+
4401
+ export { ALIGNMENT_CLASSES, BlockRenderer, CALLOUT_ICONS, CALLOUT_LABELS, CALLOUT_VARIANT_STYLES, DIVIDER_STYLE_CLASSES, FONT_SIZE_CLASSES, JsonDiff, PagesEditor, QUOTE_STYLE_CLASSES, SUPPORTED_LANGUAGES, cloneBlock, compareEditorData, createCalloutBlock, createCodeBlock, createDividerBlock, createEmptyEditorData, createHeadingBlock, createImageBlock, createListBlock, createQuoteBlock, createTableBlock, createTextBlock, deepEqual, fileToBase64, formatValue, generateId, getBlockPreview, getBlockTypeLabel, getMutedTextClass, getPlaceholderClass, getPrimaryTextClass, getPropertyChanges, getSecondaryTextClass, getSmallToolbarButtonClass, getToolbarButtonClass, getToolbarContainerClass, getToolbarDividerClass, isDarkTheme, moveArrayItem, useAutoResize, useBlockToolbar, useClickOutside, validateEditorData };