@@ -3,15 +3,15 @@ import { defaultCategories as categories, PaletteMode } from '../utils/categorie
3
3
4
4
import bricksData from '../config/brick-config.json' ;
5
5
import type { BrickConfig } from '../utils/types' ;
6
- import { brickViews } from './registry' ;
6
+ import { brickViews , BrickType } from './registry' ;
7
7
import '../palette.css' ;
8
8
import flow from '../assets/icons/flow.svg' ;
9
9
import music from '../assets/icons/music.svg' ;
10
10
import graphics from '../assets/icons/graphics.svg' ;
11
11
12
12
import { useDrag } from '@react-aria/dnd' ;
13
- import { useSetRecoilState } from 'recoil' ;
14
- import { dragStateAtom } from '../../state/dragState' ;
13
+ import { useSetRecoilState , SetterOrUpdater } from 'recoil' ;
14
+ import { dragStateAtom , DragState } from '../../state/dragState' ;
15
15
16
16
interface BrickListPanelProps {
17
17
categoryId : string ;
@@ -38,6 +38,65 @@ const groupBricksByCategory = (bricks: BrickConfig[]) => {
38
38
return grouped ;
39
39
} ;
40
40
41
+ const BrickItem : React . FC < {
42
+ brick : BrickConfig ;
43
+ draggedBrickId : string | null ;
44
+ setDraggedBrickId : ( id : string | null ) => void ;
45
+ brickViews : Record < BrickType , React . FC < BrickConfig > > ;
46
+ setDrag : SetterOrUpdater < DragState > ;
47
+ } > = ( { brick, draggedBrickId, setDraggedBrickId, brickViews, setDrag } ) => {
48
+ const { dragProps } = useDrag ( {
49
+ getItems ( ) {
50
+ return [
51
+ {
52
+ 'application/json' : JSON . stringify ( {
53
+ brickType : brick . type ,
54
+ origin : 'palette' ,
55
+ } ) ,
56
+ } ,
57
+ ] ;
58
+ } ,
59
+ } ) ;
60
+ return (
61
+ < div
62
+ key = { brick . id }
63
+ className = { `brick-item${ draggedBrickId === brick . id ? ' dragging' : '' } ` }
64
+ draggable
65
+ { ...dragProps }
66
+ onDragStart = { ( e ) => {
67
+ setDraggedBrickId ( brick . id ) ;
68
+ // Find the SVG element inside the brick item
69
+ const svg = e . currentTarget . querySelector ( 'svg' ) ;
70
+ if ( svg ) {
71
+ // Clone the SVG for a cleaner drag image
72
+ const clone = svg . cloneNode ( true ) ;
73
+ ( clone as SVGElement ) . style . position = 'absolute' ;
74
+ ( clone as SVGElement ) . style . top = '-9999px' ;
75
+ document . body . appendChild ( clone ) ;
76
+ const width = ( clone as SVGSVGElement ) . width . baseVal . value || 40 ;
77
+ const height = ( clone as SVGSVGElement ) . height . baseVal . value || 40 ;
78
+ e . dataTransfer . setDragImage ( clone as Element , width / 2 , height / 2 ) ;
79
+ setTimeout ( ( ) => document . body . removeChild ( clone ) , 0 ) ;
80
+ }
81
+ e . dataTransfer . setData (
82
+ 'application/json' ,
83
+ JSON . stringify ( { brickId : brick . id } ) ,
84
+ ) ;
85
+ e . dataTransfer . effectAllowed = 'copy' ;
86
+ setDrag ( { brickType : brick . type , origin : 'palette' } ) ;
87
+ } }
88
+ onDragEnd = { ( ) => setDraggedBrickId ( null ) }
89
+ onDrop = { ( ) => setDraggedBrickId ( null ) }
90
+ >
91
+ { /* Directly render the brick component from the registry */ }
92
+ { ( ( ) => {
93
+ const BrickComponent = brickViews [ brick . type ] ;
94
+ return BrickComponent ? < BrickComponent { ...brick } /> : null ;
95
+ } ) ( ) }
96
+ </ div >
97
+ ) ;
98
+ } ;
99
+
41
100
const BrickListPanel : React . FC < BrickListPanelProps > = ( {
42
101
categoryId,
43
102
query,
@@ -55,6 +114,8 @@ const BrickListPanel: React.FC<BrickListPanelProps> = ({
55
114
const [ draggedBrickId , setDraggedBrickId ] = useState < string | null > ( null ) ;
56
115
const [ dragPos , setDragPos ] = useState < { x : number ; y : number } | null > ( null ) ;
57
116
117
+ const setDrag = useSetRecoilState ( dragStateAtom ) ;
118
+
58
119
useEffect ( ( ) => {
59
120
setSearchQuery ( query ) ;
60
121
} , [ query ] ) ;
@@ -126,14 +187,14 @@ const BrickListPanel: React.FC<BrickListPanelProps> = ({
126
187
const handleMouseUp = ( ) => {
127
188
setDraggedBrickId ( null ) ;
128
189
setDragPos ( null ) ;
129
- window . removeEventListener ( 'mousemove' , handleMouseMove ) ;
130
- window . removeEventListener ( 'mouseup' , handleMouseUp ) ;
190
+ window . removeEventListener ( 'mousemove' , handleMouseMove as EventListener ) ;
191
+ window . removeEventListener ( 'mouseup' , handleMouseUp as EventListener ) ;
131
192
} ;
132
- window . addEventListener ( 'mousemove' , handleMouseMove ) ;
133
- window . addEventListener ( 'mouseup' , handleMouseUp ) ;
193
+ window . addEventListener ( 'mousemove' , handleMouseMove as EventListener ) ;
194
+ window . addEventListener ( 'mouseup' , handleMouseUp as EventListener ) ;
134
195
return ( ) => {
135
- window . removeEventListener ( 'mousemove' , handleMouseMove ) ;
136
- window . removeEventListener ( 'mouseup' , handleMouseUp ) ;
196
+ window . removeEventListener ( 'mousemove' , handleMouseMove as EventListener ) ;
197
+ window . removeEventListener ( 'mouseup' , handleMouseUp as EventListener ) ;
137
198
} ;
138
199
} , [ draggedBrickId ] ) ;
139
200
@@ -215,7 +276,8 @@ const BrickListPanel: React.FC<BrickListPanelProps> = ({
215
276
</ div >
216
277
) ;
217
278
} ,
218
- ( prevProps , nextProps ) => prevProps . brick . id === nextProps . brick . id && prevProps . onClick === nextProps . onClick
279
+ ( prevProps , nextProps ) =>
280
+ prevProps . brick . id === nextProps . brick . id && prevProps . onClick === nextProps . onClick ,
219
281
) ;
220
282
221
283
return (
@@ -275,56 +337,16 @@ const BrickListPanel: React.FC<BrickListPanelProps> = ({
275
337
< h4 className = "category-header" > { category } </ h4 >
276
338
</ div >
277
339
< div className = "brick-category-list" >
278
- { categoryBricks . map ( ( brick ) => {
279
- const setDrag = useSetRecoilState ( dragStateAtom ) ;
280
- const { dragProps } = useDrag ( {
281
- getItems ( ) {
282
- return [
283
- {
284
- 'application/json' : JSON . stringify ( {
285
- brickType : brick . type ,
286
- origin : 'palette' ,
287
- } ) ,
288
- } ,
289
- ] ;
290
- } ,
291
- } ) ;
292
-
293
- return (
294
- < div
295
- key = { brick . id }
296
- className = { `brick-item${ draggedBrickId === brick . id ? ' dragging' : '' } ` }
297
- draggable
298
- onDragStart = { ( e ) => {
299
- setDraggedBrickId ( brick . id ) ;
300
- // Find the SVG element inside the brick item
301
- const svg = e . currentTarget . querySelector ( 'svg' ) ;
302
- if ( svg ) {
303
- // Clone the SVG for a cleaner drag image
304
- const clone = svg . cloneNode ( true ) ;
305
- ( clone as SVGElement ) . style . position = 'absolute' ;
306
- ( clone as SVGElement ) . style . top = '-9999px' ;
307
- document . body . appendChild ( clone ) ;
308
- const width = ( clone as SVGSVGElement ) . width . baseVal . value || 40 ;
309
- const height = ( clone as SVGSVGElement ) . height . baseVal . value || 40 ;
310
- e . dataTransfer . setDragImage ( clone as Element , width / 2 , height / 2 ) ;
311
- setTimeout ( ( ) => document . body . removeChild ( clone ) , 0 ) ;
312
- }
313
- e . dataTransfer . setData ( 'application/json' , JSON . stringify ( { brickId : brick . id } ) ) ;
314
- e . dataTransfer . effectAllowed = 'copy' ;
315
- setDrag ( { brickType : brick . type , origin : 'palette' } ) ;
316
- } }
317
- onDragEnd = { ( ) => setDraggedBrickId ( null ) }
318
- onDrop = { ( ) => setDraggedBrickId ( null ) }
319
- >
320
- { /* Directly render the brick component from the registry */ }
321
- { ( ( ) => {
322
- const BrickComponent = brickViews [ brick . type ] ;
323
- return BrickComponent ? < BrickComponent { ...brick } /> : null ;
324
- } ) ( ) }
325
- </ div >
326
- ) ;
327
- } ) }
340
+ { categoryBricks . map ( ( brick ) => (
341
+ < BrickItem
342
+ key = { brick . id }
343
+ brick = { brick }
344
+ draggedBrickId = { draggedBrickId }
345
+ setDraggedBrickId = { setDraggedBrickId }
346
+ brickViews = { brickViews }
347
+ setDrag = { setDrag }
348
+ />
349
+ ) ) }
328
350
</ div >
329
351
</ div >
330
352
) ,
@@ -341,7 +363,7 @@ const BrickListPanel: React.FC<BrickListPanelProps> = ({
341
363
} }
342
364
>
343
365
{ ( ( ) => {
344
- const draggedBrick = bricks . find ( b => b . id === draggedBrickId ) ;
366
+ const draggedBrick = bricks . find ( ( b ) => b . id === draggedBrickId ) ;
345
367
if ( ! draggedBrick ) return null ;
346
368
const BrickComponent = brickViews [ draggedBrick . type ] ;
347
369
return BrickComponent ? < BrickComponent { ...draggedBrick } /> : null ;
@@ -415,7 +437,8 @@ const AsyncBrickView = React.memo(
415
437
</ div >
416
438
) ;
417
439
} ,
418
- ( prevProps , nextProps ) => prevProps . brick . id === nextProps . brick . id && prevProps . onClick === nextProps . onClick
440
+ ( prevProps , nextProps ) =>
441
+ prevProps . brick . id === nextProps . brick . id && prevProps . onClick === nextProps . onClick ,
419
442
) ;
420
443
421
444
export default BrickListPanel ;
0 commit comments