11import React , { CSSProperties } from "react"
22import { hashToColor , withAlpha } from "../../utils"
33import { GanttProps } from "./Gantt"
4- import { GanttFooter } from "./GanttFooter"
54import { GanttItem } from "./GanttItem"
65import { GanttHeader } from "./GanttHeader"
76
@@ -34,6 +33,7 @@ export const GanttGroup: React.FC<GanttGroupProps> = (props) => {
3433
3534 const viewportRef = React . useRef < HTMLDivElement > ( null )
3635 const [ viewportWidth , setViewportWidth ] = React . useState ( 0 )
36+ const [ activeGroup , setActiveGroup ] = React . useState < string | undefined > ( undefined )
3737
3838 // Parse stepWidth to pixels
3939 const stepWidthPx = parseInt ( stepWidth as string )
@@ -62,9 +62,13 @@ export const GanttGroup: React.FC<GanttGroupProps> = (props) => {
6262 }
6363
6464 handleResize ( )
65+ viewportRef ?. current ?. addEventListener ( "resize" , handleResize )
6566 window . addEventListener ( "resize" , handleResize )
66- return ( ) => window . removeEventListener ( "resize" , handleResize )
67- } , [ ] )
67+ return ( ) => {
68+ window . removeEventListener ( "resize" , handleResize )
69+ viewportRef . current ?. removeEventListener ( "resize" , handleResize )
70+ }
71+ } )
6872
6973 // Calculate row assignments (non-overlapping rows)
7074 const itemRows = items ?. length ? items
@@ -81,8 +85,8 @@ export const GanttGroup: React.FC<GanttGroupProps> = (props) => {
8185 const containerStyles : CSSProperties = {
8286 display : "grid" ,
8387 gridTemplateColumns : `repeat(${ columnsToRender } , ${ stepWidth } )` ,
84- width : "100%" ,
85- minHeight : "100%"
88+ minWidth : "100%" ,
89+ gridColumn : "1 / -1" ,
8690 }
8791
8892 return (
@@ -94,29 +98,30 @@ export const GanttGroup: React.FC<GanttGroupProps> = (props) => {
9498 avgDuration = { avgDuration }
9599 stepWidth = { stepWidth } /> }
96100 { itemRows . map ( ( row , rowIndex ) => (
97- < div key = { `row-${ rowIndex } ` } style = { {
98- gridColumn : "1 / -1" ,
99- height : rowHeight ,
100- position : "relative" ,
101- backgroundColor : "transparent"
102- } } >
103- { Array . from ( { length : columnsToRender - 1 } ) . map ( ( _ , columnIndex ) => (
104- < div key = { `grid-${ columnIndex } ` } style = { {
105- position : "absolute" ,
106- left : ( columnIndex + 1 ) * stepWidthPx ,
107- top : 0 ,
108- bottom : 0 ,
109- width : "0px" ,
110- borderLeft : `1px dashed rgba(255, 255, 255, ${ hideScaling ? 0.05 : 0.1 } )`
111- } } />
112- ) ) }
113-
114- { hideScaling && (
115- < >
116- < div
117- className = "gantt__group-wrapper"
118- style = { {
119- backgroundImage : `
101+ < >
102+ < div key = { `row-${ rowIndex } ` } style = { {
103+ gridColumn : "1 / -1" ,
104+ minHeight : rowHeight ,
105+ position : "relative" ,
106+ backgroundColor : "transparent"
107+ } } >
108+ { Array . from ( { length : columnsToRender - 1 } ) . map ( ( _ , columnIndex ) => (
109+ < div key = { `grid-${ columnIndex } ` } style = { {
110+ position : "absolute" ,
111+ left : ( columnIndex + 1 ) * stepWidthPx ,
112+ top : 0 ,
113+ bottom : 0 ,
114+ width : "0px" ,
115+ borderLeft : `1px dashed rgba(255, 255, 255, ${ hideScaling ? 0.05 : 0.1 } )`
116+ } } />
117+ ) ) }
118+
119+ { hideScaling && (
120+ < >
121+ < div
122+ className = "gantt__group-wrapper"
123+ style = { {
124+ backgroundImage : `
120125 linear-gradient(to right, transparent, #070514),
121126 repeating-linear-gradient(
122127 45deg,
@@ -125,14 +130,14 @@ export const GanttGroup: React.FC<GanttGroupProps> = (props) => {
125130 ${ withAlpha ( hashToColor ( props . id ! . replace ( "target" , "source" ) ) , 0.5 ) } 4px
126131 )
127132 ` ,
128- left : `${ getItemPosition ( itemMinStart , itemMinStart + step , start , end , timeRange , totalTimelineWidth ) . left } px` ,
129- width : `${ getItemPosition ( itemMinStart , itemMinStart + step , start , end , timeRange , totalTimelineWidth ) . width } px` ,
130- } }
131- />
132- < div
133- className = "gantt__group-wrapper"
134- style = { {
135- backgroundImage : `
133+ left : `${ getItemPosition ( itemMinStart , itemMinStart + step , start , end , timeRange , totalTimelineWidth ) . left } px` ,
134+ width : `${ getItemPosition ( itemMinStart , itemMinStart + step , start , end , timeRange , totalTimelineWidth ) . width } px` ,
135+ } }
136+ />
137+ < div
138+ className = "gantt__group-wrapper"
139+ style = { {
140+ backgroundImage : `
136141 linear-gradient(to left, transparent, #070514),
137142 repeating-linear-gradient(
138143 45deg,
@@ -141,31 +146,45 @@ export const GanttGroup: React.FC<GanttGroupProps> = (props) => {
141146 ${ withAlpha ( hashToColor ( props . id ! . replace ( "target" , "source" ) ) , 0.5 ) } 4px
142147 )
143148 ` ,
144- left : `${ getItemPosition ( itemMaxEnd - step , itemMaxEnd , start , end , timeRange , totalTimelineWidth ) . left } px` ,
145- width : `${ getItemPosition ( itemMaxEnd - step , itemMaxEnd , start , end , timeRange , totalTimelineWidth ) . width } px` ,
146- } }
147- />
148- </ >
149- ) }
150-
149+ left : `${ getItemPosition ( itemMaxEnd - step , itemMaxEnd , start , end , timeRange , totalTimelineWidth ) . left } px` ,
150+ width : `${ getItemPosition ( itemMaxEnd - step , itemMaxEnd , start , end , timeRange , totalTimelineWidth ) . width } px` ,
151+ } }
152+ />
153+ </ >
154+ ) }
155+
156+ { row . map ( ( item , itemIndex ) => {
157+ const itemPosition = getItemPosition ( item . start , item . end , start , end , timeRange , totalTimelineWidth )
158+ const hasVisibleWidth = itemPosition . width > 0
159+
160+ return hasVisibleWidth && (
161+ < >
162+ < GanttItem
163+ key = { item . id }
164+ id = { item . id }
165+ w = { `${ itemPosition . width } px` }
166+ left = { `${ itemPosition . left } px` }
167+ onClick = { ( ) => {
168+ if ( item . type != "group" ) return
169+ setActiveGroup ( prevState => item . id === prevState ? undefined : item . id )
170+ } }
171+ >
172+ { children ?.( item , itemIndex ) }
173+ </ GanttItem >
174+ </ >
175+ )
176+ } ) }
177+ </ div >
151178 { row . map ( ( item , itemIndex ) => {
152- const itemPosition = getItemPosition ( item . start , item . end , start , end , timeRange , totalTimelineWidth )
153- const hasVisibleWidth = itemPosition . width > 0
154-
155- return hasVisibleWidth && (
156- < GanttItem
157- key = { item . id }
158- id = { item . id }
159- w = { `${ itemPosition . width } px` }
160- left = { `${ itemPosition . left } px` }
161- >
162- { children ?.( item , itemIndex ) }
163- </ GanttItem >
164- )
179+ return item . type === "group" && activeGroup === item . id && < GanttGroup children = { children }
180+ id = { `group-target-${ itemIndex } ` }
181+ start = { ( Math . min ( ...item . data . items . map ( ( item : any ) => item . start ) ) ) - ( ( ( ( Math . min ( ...item . data . items . map ( ( item : any ) => item . start ) ) ) / ( item . data . firstGroupStep * item . data . step ) ) * ( item . data . groupStep * item . data . step ) ) ) }
182+ step = { item . data . groupStep * item . data . step }
183+ stepWidth = { stepWidth } rowHeight = { rowHeight } items = { item . data . items }
184+ key = { `group-target-${ itemIndex } ` } />
165185 } ) }
166- </ div >
186+ </ >
167187 ) ) }
168- { ! hideScaling && < GanttFooter /> }
169188
170189 </ div >
171190 )
0 commit comments