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