55import { TanStackDevtools } from '@tanstack/react-devtools'
66import { timeDevtoolsPlugin } from '@tanstack/react-time-devtools'
77import {
8+ getTimeClient ,
89 toPlainDateString ,
910 toPlainDateTimeString ,
1011 toPlainTimeString ,
@@ -38,6 +39,7 @@ import type {
3839 Event ,
3940 ResizeError ,
4041 Resource ,
42+ TimelineLayout ,
4143 TimelineResourceRow ,
4244} from '@tanstack/time'
4345import type { Connection , Edge , Node , NodeProps } from '@xyflow/react'
@@ -190,7 +192,6 @@ function getSampleEvents(): Array<Event<Resource>> {
190192 start : weekdayAt ( 3 , 10 , 0 ) ,
191193 end : weekdayAt ( 3 , 15 , 0 ) ,
192194 resources : [ resourceQA ] ,
193- dependsOn : [ '3' ] ,
194195 } ,
195196 {
196197 id : '6' ,
@@ -205,31 +206,27 @@ function getSampleEvents(): Array<Event<Resource>> {
205206 start : weekdayAt ( 3 , 10 , 0 ) ,
206207 end : weekdayAt ( 3 , 12 , 30 ) ,
207208 resources : [ resourceDesign ] ,
208- dependsOn : [ '1' ] ,
209209 } ,
210210 {
211211 id : '8' ,
212212 title : 'Auth Module' ,
213- start : weekdayAt ( 4 , 0 , 0 ) ,
213+ start : weekdayAt ( 5 , 6 , 0 ) ,
214214 end : weekdayAt ( 5 , 10 , 0 ) ,
215215 resources : [ resourceBackend ] ,
216- dependsOn : [ '3' ] ,
217216 } ,
218217 {
219218 id : '9' ,
220219 title : 'Load Testing' ,
221220 start : weekdayAt ( 4 , 10 , 30 ) ,
222221 end : weekdayAt ( 4 , 14 , 30 ) ,
223222 resources : [ resourceQA ] ,
224- dependsOn : [ '8' ] ,
225223 } ,
226224 {
227225 id : '10' ,
228226 title : 'Deployment' ,
229227 start : weekdayAt ( 5 , 7 , 30 ) ,
230228 end : weekdayAt ( 5 , 13 , 0 ) ,
231229 resources : [ resourceDevOps ] ,
232- dependsOn : [ '6' ] ,
233230 } ,
234231 ]
235232}
@@ -578,8 +575,14 @@ const DEP_CANVAS_NODE_TYPES = { depCanvas: DepCanvasNode }
578575const CANVAS_NODE_ID = '__dep_canvas__'
579576
580577function buildTimelineEdges ( events : Array < Event < Resource > > ) : Array < Edge > {
581- return events . flatMap ( ( event ) =>
582- ( event . dependsOn ?? [ ] ) . map ( ( sourceId ) => ( {
578+ const visibleEventIds = new Set ( events . map ( ( e ) => e . id ) )
579+
580+ return events . flatMap ( ( event ) => {
581+ const deps = ( event . dependsOn ?? [ ] ) . filter ( ( sourceId ) =>
582+ visibleEventIds . has ( sourceId ) ,
583+ )
584+
585+ return deps . map ( ( sourceId ) => ( {
583586 id : `dep-${ sourceId } -${ event . id } ` ,
584587 source : CANVAS_NODE_ID ,
585588 sourceHandle : `${ sourceId } -source` ,
@@ -589,12 +592,12 @@ function buildTimelineEdges(events: Array<Event<Resource>>): Array<Edge> {
589592 animated : true ,
590593 markerEnd : { type : MarkerType . ArrowClosed , color : '#f59e0b' } ,
591594 style : { stroke : '#f59e0b' , strokeWidth : 2 } ,
592- } ) ) ,
593- )
595+ } ) )
596+ } )
594597}
595598
596599interface TimelineDependencyOverlayProps {
597- calendarEvents : Array < Event < Resource > >
600+ timelineLayout : TimelineLayout < Resource , Event < Resource > >
598601 eventBarRefs : React . MutableRefObject < Map < string , HTMLDivElement > >
599602 rowsContainerRef : React . RefObject < HTMLDivElement | null >
600603 resizeState : {
@@ -608,12 +611,12 @@ interface TimelineDependencyOverlayProps {
608611}
609612
610613function TimelineDependencyOverlay ( {
611- calendarEvents,
612- eventBarRefs,
614+ timelineLayout,
613615 rowsContainerRef,
614616 resizeState,
615617 activeDragEvent,
616618 onDependencyCreate,
619+ eventBarRefs,
617620} : TimelineDependencyOverlayProps ) {
618621 const [ rfNodes , setRfNodes , onNodesChangeBase ] = useNodesState < Node > ( [ ] )
619622 const [ rfEdges , setRfEdges , onEdgesChange ] = useEdgesState < Edge > ( [ ] )
@@ -644,16 +647,24 @@ function TimelineDependencyOverlay({
644647 const containerRect = container . getBoundingClientRect ( )
645648 const positions : Array < HandlePosition > = [ ]
646649
647- for ( const [ eventId , el ] of eventBarRefs . current ) {
648- const rect = el . getBoundingClientRect ( )
649- positions . push ( {
650- eventId,
651- x : rect . left - containerRect . left ,
652- y : rect . top - containerRect . top ,
653- width : rect . width ,
654- height : rect . height ,
650+ // Use actual event-bar DOM rects so handles follow resize previews
651+ // (resize updates styles on the event bar element, while timelineLayout
652+ // may remain based on the committed start/end).
653+ timelineLayout . rows . forEach ( ( row : TimelineResourceRow ) => {
654+ row . events . forEach ( ( e : any ) => {
655+ const el = eventBarRefs . current . get ( e . event . id )
656+ if ( ! el ) return
657+
658+ const rect = el . getBoundingClientRect ( )
659+ positions . push ( {
660+ eventId : e . event . id ,
661+ x : rect . left - containerRect . left ,
662+ y : rect . top - containerRect . top ,
663+ width : rect . width ,
664+ height : rect . height ,
665+ } )
655666 } )
656- }
667+ } )
657668
658669 setRfNodes ( [
659670 {
@@ -668,8 +679,15 @@ function TimelineDependencyOverlay({
668679 draggable : false ,
669680 } ,
670681 ] )
671- setRfEdges ( buildTimelineEdges ( calendarEvents ) )
672- } , [ calendarEvents , eventBarRefs , rowsContainerRef , setRfNodes , setRfEdges ] )
682+ const allEvents = Array . from (
683+ new Map (
684+ timelineLayout . rows
685+ . flatMap ( ( r : any ) => r . events . map ( ( e : any ) => e . event ) )
686+ . map ( ( e : any ) => [ e . id , e ] ) ,
687+ ) . values ( ) ,
688+ )
689+ setRfEdges ( buildTimelineEdges ( allEvents ) )
690+ } , [ timelineLayout , rowsContainerRef , eventBarRefs , setRfNodes , setRfEdges ] )
673691
674692 useLayoutEffect ( ( ) => {
675693 updatePositions ( )
@@ -1013,11 +1031,6 @@ function TimelineDemo() {
10131031 return map
10141032 } , [ ] )
10151033
1016- const calendarEvents = useMemo (
1017- ( ) => calendar . getEvents ( ) ,
1018- [ calendar . days , calendar ] ,
1019- )
1020-
10211034 const timelineLayout = useMemo (
10221035 ( ) => calendar . getTimelineLayout ( ) ,
10231036 [ calendar . days ] ,
@@ -1189,6 +1202,18 @@ function TimelineDemo() {
11891202 )
11901203
11911204 if ( validation . blocked ) {
1205+ getTimeClient ( ) . emit ( 'event:update:error' , {
1206+ eventId : draggedEvent . id ,
1207+ eventTitle : draggedEvent . title ,
1208+ reason : 'unavailable-time' ,
1209+ message :
1210+ validation . message ?? 'This move is blocked by availability.' ,
1211+ originalStart : draggedEvent . start ,
1212+ originalEnd : draggedEvent . end ,
1213+ attemptedStart : nextStart ,
1214+ attemptedEnd : nextEnd ,
1215+ } )
1216+
11921217 setResizeError ( {
11931218 eventId : draggedEvent . id ,
11941219 eventTitle : draggedEvent . title ,
@@ -1432,7 +1457,7 @@ function TimelineDemo() {
14321457 style = { { overflow : 'hidden' } }
14331458 >
14341459 < TimelineDependencyOverlay
1435- calendarEvents = { calendarEvents }
1460+ timelineLayout = { timelineLayout }
14361461 eventBarRefs = { eventBarRefsMap }
14371462 rowsContainerRef = { rowsContainerRef }
14381463 resizeState = { resizeState }
0 commit comments