1- import { Thread } from "@liveblocks/react-ui" ;
2- import { ThreadData } from "@liveblocks/core" ;
1+ import { ThreadData } from "@liveblocks/client" ;
32import { useThreads , useEditThreadMetadata } from "@liveblocks/react/suspense" ;
4- import { useUser } from "@liveblocks/react" ;
53import {
64 DataRef ,
75 DndContext ,
86 DragEndEvent ,
97 PointerSensor ,
108 TouchSensor ,
11- useDraggable ,
129 useSensor ,
1310 useSensors ,
1411} from "@dnd-kit/core" ;
15- import { useCallback , useMemo , useRef , useState } from "react" ;
16- import styles from "./CommentsCanvas.module.css" ;
17- import { Toolbar } from "./Toolbar" ;
18- import { useMaxZIndex , useNearEdge } from "../hooks" ;
12+ import { useCallback } from "react" ;
13+ import { PlaceThreadButton } from "./PlaceThreadButton" ;
14+ import { DraggableThread } from "./DraggableThread" ;
1915
2016export function CommentsCanvas ( ) {
2117 const { threads } = useThreads ( ) ;
@@ -36,103 +32,41 @@ export function CommentsCanvas() {
3632 ) ;
3733
3834 // On drag end, update thread metadata with new coords
39- const handleDragEnd = useCallback ( ( { active, delta } : DragEndEvent ) => {
40- const thread = ( active . data as DataRef < { thread : ThreadData } > ) . current
41- ?. thread ;
42-
43- if ( ! thread ) {
44- return ;
45- }
46-
47- editThreadMetadata ( {
48- threadId : thread . id ,
49- metadata : {
50- x : thread . metadata . x + delta . x ,
51- y : thread . metadata . y + delta . y ,
52- } ,
53- } ) ;
54- } , [ ] ) ;
55-
56- return (
57- < div className = { `${ styles . wrapper } lb-root` } >
58- < div className = { styles . threads } >
59- < DndContext onDragEnd = { handleDragEnd } sensors = { sensors } >
60- { threads . map ( ( thread ) => (
61- < DraggableThread key = { thread . id } thread = { thread } />
62- ) ) }
63- </ DndContext >
64- </ div >
65- < Toolbar />
66- </ div >
35+ const handleDragEnd = useCallback (
36+ ( { active, delta } : DragEndEvent ) => {
37+ const thread = ( active . data as DataRef < { thread : ThreadData } > ) . current
38+ ?. thread ;
39+ if ( ! thread ) {
40+ return ;
41+ }
42+ editThreadMetadata ( {
43+ threadId : thread . id ,
44+ metadata : {
45+ x : thread . metadata . x + delta . x ,
46+ y : thread . metadata . y + delta . y ,
47+ } ,
48+ } ) ;
49+ } ,
50+ [ editThreadMetadata ]
6751 ) ;
68- }
69-
70- // A draggable thread
71- function DraggableThread ( { thread } : { thread : ThreadData } ) {
72- // Open threads that have just been created
73- const startOpen = useMemo ( ( ) => {
74- return Number ( new Date ( ) ) - Number ( new Date ( thread . createdAt ) ) <= 100 ;
75- } , [ thread ] ) ;
76- const [ open , setOpen ] = useState ( startOpen ) ;
77-
78- // Enable drag
79- const { attributes, listeners, setNodeRef, transform, node } = useDraggable ( {
80- id : thread . id ,
81- data : { thread } , // Pass thread to DndContext drag end event
82- } ) ;
83-
84- // If currently dragging, add drag values to current metadata
85- const x = transform ? transform . x + thread . metadata . x : thread . metadata . x ;
86- const y = transform ? transform . y + thread . metadata . y : thread . metadata . y ;
87-
88- // Get the creator of the thread
89- const { user : creator } = useUser ( thread . comments [ 0 ] . userId ) ;
90-
91- // Used to set z-index higher than other threads when pointer down
92- const editThreadMetadata = useEditThreadMetadata ( ) ;
93- const maxZIndex = useMaxZIndex ( ) ;
94-
95- // Used to flip thread near edge of screen
96- const { nearRightEdge, nearBottomEdge } = useNearEdge ( node ) ;
9752
9853 return (
9954 < div
100- ref = { setNodeRef }
101- className = { styles . draggableThread }
102- onPointerDown = { ( ) =>
103- editThreadMetadata ( {
104- threadId : thread . id ,
105- metadata : { zIndex : maxZIndex + 1 } ,
106- } )
107- }
10855 style = { {
109- transform : `translate3d(${ x } px, ${ y } px, 0)` ,
110- zIndex : thread . metadata ?. zIndex || 0 ,
56+ position : "relative" ,
57+ width : "100vw" ,
58+ height : "100vh" ,
59+ overflow : "hidden" ,
11160 } }
11261 >
113- < div { ...listeners } { ...attributes } >
114- < div className = { styles . avatar } onClick = { ( ) => setOpen ( ! open ) } >
115- { creator ? (
116- < img
117- src = { creator . avatar }
118- alt = { creator . name }
119- width = "28px"
120- height = "28px"
121- draggable = { false }
122- />
123- ) : (
124- < div />
125- ) }
126- </ div >
62+ < div style = { { isolation : "isolate" } } >
63+ < DndContext onDragEnd = { handleDragEnd } sensors = { sensors } >
64+ { threads . map ( ( thread ) => (
65+ < DraggableThread key = { thread . id } thread = { thread } />
66+ ) ) }
67+ </ DndContext >
12768 </ div >
128- { open ? (
129- < Thread
130- thread = { thread }
131- className = "thread"
132- data-flip-vertical = { nearBottomEdge || undefined }
133- data-flip-horizontal = { nearRightEdge || undefined }
134- />
135- ) : null }
69+ < PlaceThreadButton />
13670 </ div >
13771 ) ;
13872}
0 commit comments