1- import { type Node , type NodeProps } from "@xyflow/react" ;
1+ import {
2+ type Node ,
3+ type NodeProps ,
4+ NodeResizer ,
5+ type ResizeDragEvent ,
6+ type ResizeParams ,
7+ } from "@xyflow/react" ;
28import { useEffect } from "react" ;
39
410import { BlockStack } from "@/components/ui/layout" ;
511import { Paragraph } from "@/components/ui/typography" ;
612import { cn } from "@/lib/utils" ;
13+ import { useComponentSpec } from "@/providers/ComponentSpecProvider" ;
714import { useContextPanel } from "@/providers/ContextPanelProvider" ;
15+ import { updateSubgraphSpec } from "@/utils/subgraphUtils" ;
816
917import { FlexNodeEditor } from "./FlexNodeEditor" ;
18+ import { updateFlexNodeInComponentSpec } from "./interface" ;
1019import type { FlexNodeData } from "./types" ;
1120
1221type FlexNodeProps = NodeProps < Node < FlexNodeData > > ;
1322
23+ const MIN_SIZE = { width : 50 , height : 50 } ;
24+
1425const FlexNode = ( { data, id, selected } : FlexNodeProps ) => {
1526 const { properties, readOnly } = data ;
1627 const { title, content, color } = properties ;
@@ -21,6 +32,34 @@ const FlexNode = ({ data, id, selected }: FlexNodeProps) => {
2132 setOpen : setContextPanelOpen ,
2233 } = useContextPanel ( ) ;
2334
35+ const {
36+ currentSubgraphSpec,
37+ currentSubgraphPath,
38+ componentSpec,
39+ setComponentSpec,
40+ } = useComponentSpec ( ) ;
41+
42+ const handleResizeEnd = ( _ : ResizeDragEvent , params : ResizeParams ) => {
43+ const width = Math . max ( params . width , MIN_SIZE . width ) ;
44+ const height = Math . max ( params . height , MIN_SIZE . height ) ;
45+
46+ const updatedSubgraphSpec = updateFlexNodeInComponentSpec (
47+ currentSubgraphSpec ,
48+ {
49+ ...data ,
50+ size : { width, height } ,
51+ } ,
52+ ) ;
53+
54+ const newRootSpec = updateSubgraphSpec (
55+ componentSpec ,
56+ currentSubgraphPath ,
57+ updatedSubgraphSpec ,
58+ ) ;
59+
60+ setComponentSpec ( newRootSpec ) ;
61+ } ;
62+
2463 useEffect ( ( ) => {
2564 if ( selected ) {
2665 setContent ( < FlexNodeEditor flexNode = { data } readOnly = { readOnly } /> ) ;
@@ -37,29 +76,40 @@ const FlexNode = ({ data, id, selected }: FlexNodeProps) => {
3776 const isTransparent = color === "transparent" ;
3877
3978 return (
40- < div
41- key = { id }
42- className = { cn (
43- "p-1 rounded-lg border-2 border-transparent h-full w-full" ,
44- isTransparent && ! title && ! content && "border-dashed border-warning" ,
45- selected && "border-gray-500 border-solid" ,
46- ) }
47- style = { { backgroundColor : color } }
48- >
79+ < >
80+ < NodeResizer
81+ color = "var(--edge-selected)"
82+ isVisible = { selected }
83+ minWidth = { 50 }
84+ minHeight = { 50 }
85+ onResizeEnd = { handleResizeEnd }
86+ />
4987 < div
88+ key = { id }
5089 className = { cn (
51- "rounded-sm p-1 h-full w-full overflow-hidden" ,
52- isTransparent ? "bg-transparent" : "bg-white/40" ,
90+ "p-1 rounded-lg h-full w-full" ,
91+ isTransparent &&
92+ ! title &&
93+ ! content &&
94+ "border-2 border-dashed border-warning" ,
5395 ) }
96+ style = { { backgroundColor : color } }
5497 >
55- < BlockStack gap = "1" >
56- < Paragraph size = "sm" weight = "semibold" >
57- { title }
58- </ Paragraph >
59- < Paragraph size = "xs" > { content } </ Paragraph >
60- </ BlockStack >
98+ < div
99+ className = { cn (
100+ "rounded-sm p-1 h-full w-full overflow-hidden" ,
101+ isTransparent ? "bg-transparent" : "bg-white/40" ,
102+ ) }
103+ >
104+ < BlockStack gap = "1" >
105+ < Paragraph size = "sm" weight = "semibold" >
106+ { title }
107+ </ Paragraph >
108+ < Paragraph size = "xs" > { content } </ Paragraph >
109+ </ BlockStack >
110+ </ div >
61111 </ div >
62- </ div >
112+ </ >
63113 ) ;
64114} ;
65115
0 commit comments