import React, { CSSProperties, forwardRef, ReactElement, useContext, } from 'react'; import { rangeInclusive } from './utils/range'; import TimelineContext from './context'; import { getPositionAtTime } from './utils/time'; import { ChildGroup, Item } from './timeline-data'; import eachDayOfInterval from './utils/each-day-of-interval'; export default forwardRef( function TimelineInner({ style }, ref) { const { BodyRenderer, ColumnRenderer, GroupRenderer, ItemRenderer, RowRenderer, SidebarHeaderRenderer, SidebarRenderer, TimebarHeaderRenderer, TimebarIntervalRenderer, children: childrenFromProps, intervalDuration, intervalWidth, itemHeight, itemMap, minItemWidth, overscanColumnStartIndex, overscanColumnStopIndex, overscanRowStartIndex, overscanRowStopIndex, rowMap, collectionSidebarWidth, groupSidebarWidth, startTime, endTime, stickyItemIds, timebarHeaderHeight, timebarIntervalHeight, } = useContext(TimelineContext); const stickyItems = stickyItemIds.map(id => itemMap.get(id)!); const stickyRows = stickyItems.map(item => item.row); const visibleRows = rowMap.size > 0 ? rangeInclusive(overscanRowStartIndex, overscanRowStopIndex).map( rowIndex => rowMap.get(rowIndex)! ) : []; const visibleCollections = new Set(visibleRows.map(row => row.collection)); const sidebarWidth = collectionSidebarWidth + groupSidebarWidth; const timebarHeight = timebarHeaderHeight + timebarIntervalHeight; const rows = Array.from(new Set([...stickyRows, ...visibleRows])).sort( (a, b) => a.index - b.index ); const columns = rangeInclusive( overscanColumnStartIndex, overscanColumnStopIndex ); const days = eachDayOfInterval({ start: startTime, end: endTime - 1, }); return ( <> {childrenFromProps} {ColumnRenderer && (
{columns.map(column => ( ))}
)} {RowRenderer && (
{visibleRows.flatMap(row => ( ))}
)} {rows.map(row => { const rowStickyItems = stickyItems.filter( item => item.groupId === row.group.id ); const isStickyRow = row.index < overscanRowStartIndex || row.index > overscanRowStopIndex; function renderItem(item: Item): ReactElement { const left = getPositionAtTime( item.start, startTime, intervalDuration, intervalWidth ); const width = Math.max( getPositionAtTime( item.end, startTime, intervalDuration, intervalWidth ) - left, minItemWidth ); const top = row.top + row.getItemTopOffset(item, itemHeight); const isStickyItem = rowStickyItems.some( ({ id }) => id === item.id ); return ( ); } // Only render the items if this is a sticky row if (isStickyRow) { return rowStickyItems.map(item => renderItem(item)); } return Array.from( new Set([ ...rowStickyItems, ...row.getItemsByIntervalRange( overscanColumnStartIndex, overscanColumnStopIndex ), ]) ).map(item => renderItem(item)); })} {Array.from(visibleCollections.values()).map(collection => { return [ collectionSidebarWidth > 0 && GroupRenderer && ( { return acc + row.height; }, 0), left: 0, userSelect: 'none', }} /> ), ]; })} {visibleRows.flatMap(row => { return [ groupSidebarWidth > 0 && GroupRenderer && ( ), ]; })}
{days.map((day, index) => { if (!TimebarIntervalRenderer) { return null; } return ( ); })}
{columns.flatMap(column => [ TimebarIntervalRenderer && ( ), ])}
{timebarHeaderHeight > 0 && TimebarHeaderRenderer && ( )} ); } );