@refactico/pages 0.2.1 → 0.2.3

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,
@@ -1823,7 +1823,7 @@ const CodeBlock = ({
1823
1823
  onClick: copyToClipboard,
1824
1824
  className: "p-1.5 rounded-lg hover:bg-slate-700 text-slate-400 hover:text-white transition-colors",
1825
1825
  title: "Copy code",
1826
- 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 })
1827
1827
  }
1828
1828
  )
1829
1829
  ] })
@@ -2492,7 +2492,7 @@ const ListBlock = ({
2492
2492
  onClick: () => toggleChecked(index),
2493
2493
  disabled: readOnly,
2494
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"}`,
2495
- children: block.checkedItems?.[index] && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { size: 12 })
2495
+ children: block.checkedItems?.[index] && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon$1, { size: 12 })
2496
2496
  }
2497
2497
  ),
2498
2498
  readOnly ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -3478,16 +3478,943 @@ const DIVIDER_STYLE_CLASSES = {
3478
3478
  dotted: "border-dotted"
3479
3479
  };
3480
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
+
3481
4405
  exports.ALIGNMENT_CLASSES = ALIGNMENT_CLASSES;
4406
+ exports.BlockRenderer = BlockRenderer;
3482
4407
  exports.CALLOUT_ICONS = CALLOUT_ICONS;
3483
4408
  exports.CALLOUT_LABELS = CALLOUT_LABELS;
3484
4409
  exports.CALLOUT_VARIANT_STYLES = CALLOUT_VARIANT_STYLES;
3485
4410
  exports.DIVIDER_STYLE_CLASSES = DIVIDER_STYLE_CLASSES;
3486
4411
  exports.FONT_SIZE_CLASSES = FONT_SIZE_CLASSES;
4412
+ exports.JsonDiff = JsonDiff;
3487
4413
  exports.PagesEditor = PagesEditor;
3488
4414
  exports.QUOTE_STYLE_CLASSES = QUOTE_STYLE_CLASSES;
3489
4415
  exports.SUPPORTED_LANGUAGES = SUPPORTED_LANGUAGES;
3490
4416
  exports.cloneBlock = cloneBlock;
4417
+ exports.compareEditorData = compareEditorData;
3491
4418
  exports.createCalloutBlock = createCalloutBlock;
3492
4419
  exports.createCodeBlock = createCodeBlock;
3493
4420
  exports.createDividerBlock = createDividerBlock;
@@ -3498,11 +4425,16 @@ exports.createListBlock = createListBlock;
3498
4425
  exports.createQuoteBlock = createQuoteBlock;
3499
4426
  exports.createTableBlock = createTableBlock;
3500
4427
  exports.createTextBlock = createTextBlock;
4428
+ exports.deepEqual = deepEqual;
3501
4429
  exports.fileToBase64 = fileToBase64;
4430
+ exports.formatValue = formatValue;
3502
4431
  exports.generateId = generateId;
4432
+ exports.getBlockPreview = getBlockPreview;
4433
+ exports.getBlockTypeLabel = getBlockTypeLabel;
3503
4434
  exports.getMutedTextClass = getMutedTextClass;
3504
4435
  exports.getPlaceholderClass = getPlaceholderClass;
3505
4436
  exports.getPrimaryTextClass = getPrimaryTextClass;
4437
+ exports.getPropertyChanges = getPropertyChanges;
3506
4438
  exports.getSecondaryTextClass = getSecondaryTextClass;
3507
4439
  exports.getSmallToolbarButtonClass = getSmallToolbarButtonClass;
3508
4440
  exports.getToolbarButtonClass = getToolbarButtonClass;