import { Ref , DateMarker , BaseComponent , createElement , EventSegUiInteractionState , Seg , getSegMeta , DateRange , Fragment , DayCellRoot , NowIndicatorRoot , BgEvent , renderFill , buildIsoString , computeEarliestSegStart , DateProfile , buildEventRangeKey , sortEventSegs , memoize , SegEntryGroup , SegEntry , Dictionary , SegSpan , CssDimValue , } from '@fullcalendar/common' ; import { TimeColMoreLink } from './TimeColMoreLink' ; import { TimeColsSeg } from './TimeColsSeg' ; import { TimeColsSlatsCoords } from './TimeColsSlatsCoords' ; import { SegWebRect } from './seg-web' ; import { computeFgSegPlacements , computeSegVCoords } from './event-placement' ; import { TimeColEvent } from './TimeColEvent' ; import { TimeColMisc } from './TimeColMisc' ; export interface TimeColProps { elRef ? : Ref < HTMLTableCellElement > ; dateProfile : DateProfile ; date : DateMarker ; nowDate : DateMarker ; todayRange : DateRange ; extraDataAttrs ? : any ; extraHookProps ? : any ; extraClassNames ? : string [ ] ; extraDateSpan ? : Dictionary ; fgEventSegs : TimeColsSeg [ ] ; bgEventSegs : TimeColsSeg [ ] ; businessHourSegs : TimeColsSeg [ ] ; nowIndicatorSegs : TimeColsSeg [ ] ; dateSelectionSegs : TimeColsSeg [ ] ; eventSelection : string ; eventDrag : EventSegUiInteractionState | null ; eventResize : EventSegUiInteractionState | null ; slatCoords : TimeColsSlatsCoords ; forPrint : boolean ; } export class TimeCol extends BaseComponent < TimeColProps > { sortEventSegs = memoize ( sortEventSegs ) ; render ( ) { let { props , context } = this ; let isSelectMirror = context . options . selectMirror ; let mirrorSegs = ( props . eventDrag && props . eventDrag . segs ) || ( props . eventResize && props . eventResize . segs ) || ( isSelectMirror && props . dateSelectionSegs ) || [ ] ; let interactionAffectedInstances = ( props . eventDrag && props . eventDrag . affectedInstances ) || ( props . eventResize && props . eventResize . affectedInstances ) || { } ; let sortedFgSegs = this . sortEventSegs ( props . fgEventSegs , context . options . eventOrder ) as TimeColsSeg [ ] ; return ( < DayCellRoot elRef = { props . elRef } date = { props . date } dateProfile = { props . dateProfile } todayRange = { props . todayRange } extraHookProps = { props . extraHookProps } > { ( rootElRef , classNames , dataAttrs ) => ( < td ref = { rootElRef } role = "gridcell" className = { [ 'fc-timegrid-col' ] . concat ( classNames , props . extraClassNames || [ ] ) . join ( ' ' ) } { ... dataAttrs } { ... props . extraDataAttrs } > < div className = "fc-timegrid-col-frame" > < div className = "fc-timegrid-col-bg" > { this . renderFillSegs ( props . businessHourSegs , 'non-business' ) } { this . renderFillSegs ( props . bgEventSegs , 'bg-event' ) } { this . renderFillSegs ( props . dateSelectionSegs , 'highlight' ) } < /div> < div className = "fc-timegrid-col-events" > { this . renderFgSegs ( sortedFgSegs , interactionAffectedInstances , false , false , false ) } < /div> < div className = "fc-timegrid-col-events" > { this . renderFgSegs ( mirrorSegs as TimeColsSeg [ ] , { } , Boolean ( props . eventDrag ) , Boolean ( props . eventResize ) , Boolean ( isSelectMirror ) ) } < /div> < div className = "fc-timegrid-now-indicator-container" > { this . renderNowIndicator ( props . nowIndicatorSegs ) } < /div> < TimeColMisc date = { props . date } dateProfile = { props . dateProfile } todayRange = { props . todayRange } extraHookProps = { props . extraHookProps } / > < /div> < /td>)} < /DayCellRoot>); } renderFgSegs ( sortedFgSegs , segIsInvisible , isDragging , isResizing , isDateSelecting ) { let { props } = this ; if ( props . forPrint ) { return renderPlainFgSegs ( sortedFgSegs , props ) ; } return this . renderPositionedFgSegs ( sortedFgSegs , segIsInvisible , isDragging , isResizing , isDateSelecting ) ; } renderPositionedFgSegs ( segs , segIsInvisible , isDragging , isResizing , isDateSelecting ) { let { eventMaxStack , eventShortHeight , eventOrderStrict , eventMinHeight } = this . context . options ; let { date , slatCoords , eventSelection , todayRange , nowDate } = this . props ; let isMirror = isDragging || isResizing || isDateSelecting ; let segVCoords = computeSegVCoords ( segs , date , slatCoords , eventMinHeight ) ; let { segPlacements , hiddenGroups } = computeFgSegPlacements ( segs , segVCoords , eventOrderStrict , eventMaxStack ) ; return ( < Fragment > { this . renderHiddenGroups ( hiddenGroups , segs ) } { segPlacements . map ( ( segPlacement ) => { let { seg , rect } = segPlacement ; let instanceId = seg . eventRange . instance . instanceId ; let isVisible = isMirror || Boolean ( ! segIsInvisible [ instanceId ] && rect ) ; let vStyle = computeSegVStyle ( rect && rect . span ) ; let hStyle = ( ! isMirror && rect ) ? this . computeSegHStyle ( rect ) : { left : 0 , right : 0 } ; let isInset = Boolean ( rect ) && rect . stackForward > 0 ; let isShort = Boolean ( rect ) && ( rect . span . end - rect . span . start ) < eventShortHeight ; return ( < div className = { 'fc-timegrid-event-harness' + ( isInset ? ' fc-timegrid-event-harness-inset' : '' ) } key = { instanceId } style = { { visibility : isVisible ? ( '' as any ) : 'hidden' , ... vStyle , ... hStyle , } } > < TimeColEvent seg = { seg } isDragging = { isDragging } isResizing = { isResizing } isDateSelecting = { isDateSelecting } isSelected = { instanceId === eventSelection } isShort = { isShort } { ... getSegMeta ( seg , todayRange , nowDate ) } /> < /div>); } ) } < /Fragment>); } renderHiddenGroups ( hiddenGroups , segs ) { let { extraDateSpan , dateProfile , todayRange , nowDate , eventSelection , eventDrag , eventResize } = this . props ; return ( < Fragment > { hiddenGroups . map ( ( hiddenGroup ) => { let positionCss = computeSegVStyle ( hiddenGroup . span ) ; let hiddenSegs = compileSegsFromEntries ( hiddenGroup . entries , segs ) ; return ( < TimeColMoreLink key = { buildIsoString ( computeEarliestSegStart ( hiddenSegs ) ) } hiddenSegs = { hiddenSegs } top = { positionCss . top } bottom = { positionCss . bottom } extraDateSpan = { extraDateSpan } dateProfile = { dateProfile } todayRange = { todayRange } nowDate = { nowDate } eventSelection = { eventSelection } eventDrag = { eventDrag } eventResize = { eventResize } / > ) ; } ) } < /Fragment>); } renderFillSegs ( segs , fillType ) { let { props , context } = this ; let segVCoords = computeSegVCoords ( segs , props . date , props . slatCoords , context . options . eventMinHeight ) ; let children = segVCoords . map ( ( vcoords , i ) => { let seg = segs [ i ] ; return ( < div key = { buildEventRangeKey ( seg . eventRange ) } className = "fc-timegrid-bg-harness" style = { computeSegVStyle ( vcoords ) } > { fillType === 'bg-event' ? < BgEvent seg = { seg } { ... getSegMeta ( seg , props . todayRange , props . nowDate ) } /> : renderFill ( fillType ) } < /div>); } ) ; return < Fragment > { children } < /Fragment>; } renderNowIndicator ( segs ) { let { slatCoords , date } = this . props ; if ( ! slatCoords ) { return null ; } return segs . map ( ( seg , i ) => ( < NowIndicatorRoot isAxis = { false } date = { date } key = { i } > { ( rootElRef , classNames , innerElRef , innerContent ) => ( < div ref = { rootElRef } className = { [ 'fc-timegrid-now-indicator-line' ] . concat ( classNames ) . join ( ' ' ) } style = { { top : slatCoords . computeDateTop ( seg . start , date ) } } > { innerContent } < /div>)} < /NowIndicatorRoot>)); } computeSegHStyle ( segHCoords ) { let { isRtl , options } = this . context ; let shouldOverlap = options . slotEventOverlap ; let nearCoord = segHCoords . levelCoord ; let farCoord = segHCoords . levelCoord + segHCoords . thickness ; let left ; let right ; if ( shouldOverlap ) { farCoord = Math . min ( 1 , nearCoord + ( farCoord - nearCoord ) * 2 ) ; } if ( isRtl ) { left = 1 - farCoord ; right = nearCoord ; } else { left = nearCoord ; right = 1 - farCoord ; } let props = { zIndex : segHCoords . stackDepth + 1 , left : left * 100 + '%' , right : right * 100 + '%' , } ; if ( shouldOverlap && ! segHCoords . stackForward ) { props [ isRtl ? 'marginLeft' : 'marginRight' ] = 10 * 2 ; } return props ; } } export function renderPlainFgSegs ( sortedFgSegs , { todayRange , nowDate , eventSelection , eventDrag , eventResize } ) { let hiddenInstances = ( eventDrag ? eventDrag . affectedInstances : null ) || ( eventResize ? eventResize . affectedInstances : null ) || { } ; return ( < Fragment > { sortedFgSegs . map ( ( seg ) => { let instanceId = seg . eventRange . instance . instanceId ; return ( < div key = { instanceId } style = { { visibility : hiddenInstances [ instanceId ] ? 'hidden' : ( '' as any ) } } > < TimeColEvent seg = { seg } isDragging = { false } isResizing = { false } isDateSelecting = { false } isSelected = { instanceId === eventSelection } isShort = { false } { ... getSegMeta ( seg , todayRange , nowDate ) } /> < /div>); } ) } < /Fragment>); } function computeSegVStyle ( segVCoords ) { if ( ! segVCoords ) { return { top : '' , bottom : '' } ; } return { top : segVCoords . start , bottom : - segVCoords . end , } ; } function compileSegsFromEntries ( segEntries , allSegs ) { return segEntries . map ( ( segEntry ) => allSegs [ segEntry . index ] ) ; }