11'use client'
22
3- import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
3+ import { useCallback , useMemo , useRef } from 'react'
44import clsx from 'clsx'
55import { getBlocksForSidebar } from '@/lib/workflows/trigger-utils'
66import { LoopTool } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/loop/loop-config'
77import { ParallelTool } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/subflows/parallel/parallel-config'
88import type { BlockConfig } from '@/blocks/types'
9- import { useSidebarStore } from '@/stores/sidebar/store '
9+ import { usePanelResize } from '../../hooks/use-panel-resize '
1010
1111interface BlocksProps {
1212 disabled ?: boolean
@@ -22,19 +22,21 @@ interface BlockItem {
2222}
2323
2424/**
25- * Constants for blocks panel sizing
25+ * Blocks panel component displaying available block types.
26+ * Uses the panel resize hook for shared resize/toggle functionality.
27+ *
28+ * @param props - Component props
29+ * @returns Blocks panel with resizable functionality
2630 */
27- const DEFAULT_HEIGHT = 200
28- const MIN_HEIGHT = 28
29- const HEADER_HEIGHT = 28
30-
3131export function Blocks ( { disabled = false } : BlocksProps ) {
32- const [ isResizing , setIsResizing ] = useState ( false )
33- const { blocksHeight, setBlocksHeight, setTriggersHeight } = useSidebarStore ( )
34- const startYRef = useRef < number > ( 0 )
35- const startHeightRef = useRef < number > ( 0 )
3632 const containerRef = useRef < HTMLDivElement > ( null )
3733
34+ // Panel resize hook
35+ const { handleMouseDown, handleToggle } = usePanelResize ( {
36+ panelType : 'blocks' ,
37+ containerRef,
38+ } )
39+
3840 const blocks = useMemo ( ( ) => {
3941 const allBlocks = getBlocksForSidebar ( )
4042
@@ -87,143 +89,58 @@ export function Blocks({ disabled = false }: BlocksProps) {
8789 return [ ...regularBlockItems , ...toolItems ]
8890 } , [ ] )
8991
90- const handleDragStart = ( e : React . DragEvent , item : BlockItem ) => {
91- if ( disabled ) {
92- e . preventDefault ( )
93- return
94- }
95- e . dataTransfer . setData (
96- 'application/json' ,
97- JSON . stringify ( {
98- type : item . type ,
99- enableTriggerMode : false ,
100- } )
101- )
102- e . dataTransfer . effectAllowed = 'move'
103- }
104-
105- const handleClick = ( item : BlockItem ) => {
106- if ( item . type === 'connectionBlock' || disabled ) return
107-
108- const event = new CustomEvent ( 'add-block-from-toolbar' , {
109- detail : {
110- type : item . type ,
111- enableTriggerMode : false ,
112- } ,
113- } )
114- window . dispatchEvent ( event )
115- }
116-
117- const handleMouseDown = useCallback ( ( e : React . MouseEvent ) => {
118- setIsResizing ( true )
119- startYRef . current = e . clientY
120- const currentHeight = Number . parseInt (
121- getComputedStyle ( document . documentElement ) . getPropertyValue ( '--blocks-height' )
122- )
123- startHeightRef . current = currentHeight
124- } , [ ] )
125-
126- const handleToggle = useCallback ( ( ) => {
127- if ( blocksHeight <= MIN_HEIGHT ) {
128- // Expanding: set to default height, and ensure triggers has enough space for both sections
129- const currentTriggersHeight = Number . parseInt (
130- getComputedStyle ( document . documentElement ) . getPropertyValue ( '--triggers-height' )
131- )
132-
133- // Calculate what blocks height we want
134- const desiredBlocksHeight = DEFAULT_HEIGHT
135-
136- // Calculate minimum triggers height needed to show blocks content
137- const minRequiredTriggersHeight = desiredBlocksHeight + HEADER_HEIGHT
138-
139- // Calculate ideal triggers height to show both blocks and triggers content reasonably
140- // This gives DEFAULT_HEIGHT visible space for triggers content above blocks
141- const idealTriggersHeight = desiredBlocksHeight + HEADER_HEIGHT + DEFAULT_HEIGHT
142-
143- // If current triggers height is below ideal, expand triggers to show both sections properly
144- if ( currentTriggersHeight < idealTriggersHeight ) {
145- if ( containerRef . current ?. parentElement ) {
146- const parentHeight = containerRef . current . parentElement . getBoundingClientRect ( ) . height
147- setTriggersHeight ( Math . min ( idealTriggersHeight , parentHeight ) )
148- } else {
149- setTriggersHeight ( idealTriggersHeight )
150- }
151- }
152-
153- // Now expand blocks (store constraints will handle the sizing)
154- setBlocksHeight ( desiredBlocksHeight )
155- } else {
156- // Collapsing: simply collapse to minimum
157- setBlocksHeight ( MIN_HEIGHT )
158- }
159- } , [ blocksHeight , setBlocksHeight , setTriggersHeight ] )
160-
16192 /**
162- * Setup resize event listeners and body styles when resizing
163- * Event handlers are defined inline to avoid stale closure issues
93+ * Handle drag start for block items
94+ *
95+ * @param e - React drag event
96+ * @param item - Block item configuration
16497 */
165- useEffect ( ( ) => {
166- if ( ! isResizing || ! containerRef . current ) return
167-
168- const handleMouseMove = ( e : MouseEvent ) => {
169- const deltaY = startYRef . current - e . clientY
170- let newHeight = startHeightRef . current + deltaY
98+ const handleDragStart = useCallback (
99+ ( e : React . DragEvent < HTMLElement > , item : BlockItem ) => {
100+ if ( disabled ) {
101+ e . preventDefault ( )
102+ return
103+ }
171104
172- const parentContainer = containerRef . current ?. parentElement
173- if ( parentContainer ) {
174- const parentHeight = parentContainer . getBoundingClientRect ( ) . height
175- const currentTriggersHeight = Number . parseInt (
176- getComputedStyle ( document . documentElement ) . getPropertyValue ( '--triggers-height' )
105+ try {
106+ e . dataTransfer . setData (
107+ 'application/json' ,
108+ JSON . stringify ( {
109+ type : item . type ,
110+ enableTriggerMode : false ,
111+ } )
177112 )
178- const currentBlocksHeight = Number . parseInt (
179- getComputedStyle ( document . documentElement ) . getPropertyValue ( '--blocks-height' )
180- )
181-
182- const maxAllowedHeight = currentTriggersHeight - HEADER_HEIGHT
183-
184- // Special case: if blocks is at max height and user is expanding blocks (deltaY > 0)
185- // then expand both blocks and triggers together
186- const isAtMaxHeight = Math . abs ( currentBlocksHeight - maxAllowedHeight ) <= 2
187- const isExpandingBlocks = deltaY > 0
188-
189- if ( isAtMaxHeight && isExpandingBlocks ) {
190- // Calculate how much more the user wants to expand
191- const requestedIncrease = newHeight - currentBlocksHeight
192-
193- // Expand triggers by the same amount (respecting parent height limit)
194- const newTriggersHeight = Math . min (
195- currentTriggersHeight + requestedIncrease ,
196- parentHeight
197- )
198- setTriggersHeight ( newTriggersHeight )
199-
200- // Blocks will expand proportionally through the store constraint
201- setBlocksHeight ( newHeight )
202- } else {
203- // Normal behavior: constrain blocks within current triggers space
204- newHeight = Math . min ( newHeight , maxAllowedHeight )
205- newHeight = Math . max ( newHeight , MIN_HEIGHT )
206- setBlocksHeight ( newHeight )
207- }
113+ e . dataTransfer . effectAllowed = 'move'
114+ } catch ( error ) {
115+ console . error ( 'Failed to set drag data:' , error )
208116 }
209- }
210-
211- const handleMouseUp = ( ) => {
212- setIsResizing ( false )
213- }
214-
215- document . addEventListener ( 'mousemove' , handleMouseMove )
216- document . addEventListener ( 'mouseup' , handleMouseUp )
217- document . body . style . cursor = 'ns-resize'
218- document . body . style . userSelect = 'none'
117+ } ,
118+ [ disabled ]
119+ )
219120
220- return ( ) => {
221- document . removeEventListener ( 'mousemove' , handleMouseMove )
222- document . removeEventListener ( 'mouseup' , handleMouseUp )
223- document . body . style . cursor = ''
224- document . body . style . userSelect = ''
225- }
226- } , [ isResizing , setBlocksHeight , setTriggersHeight ] )
121+ /**
122+ * Handle click on block item to add to canvas
123+ *
124+ * @param item - Block item configuration
125+ */
126+ const handleClick = useCallback (
127+ ( item : BlockItem ) => {
128+ if ( item . type === 'connectionBlock' || disabled ) return
129+
130+ try {
131+ const event = new CustomEvent ( 'add-block-from-toolbar' , {
132+ detail : {
133+ type : item . type ,
134+ enableTriggerMode : false ,
135+ } ,
136+ } )
137+ window . dispatchEvent ( event )
138+ } catch ( error ) {
139+ console . error ( 'Failed to dispatch add-block event:' , error )
140+ }
141+ } ,
142+ [ disabled ]
143+ )
227144
228145 return (
229146 < div
0 commit comments