Subrow

When you have two or more items who's span's intersect, you would expect them to stack on top of each other.

Each item in that stack should be rendered inside a subrow of some kind, that will seprate stacked items into different containers inside the same row.

dnd-timeline does not have this behaviour by default, but provides you with a simple util to help you stack.

Timeline.tsx
function Timeline(props: TimelineProps) {  
  const { setTimelineRef, style, range } = useTimelineContext()

  const groupedSubrows = useMemo(
    () => groupItemsToSubrows(items, range),
    [items, range]
  )

  return (
    <div ref={setTimelineRef} style={style}>
      {props.rows.map((row) => 
        <Row key={row.id} id={row.id} sidebar={<Sidebar row={row} />}>
          {groupedSubrows[row.id]?.map((subrow, index) => 
            <div key={`${row.id}-${index}`}>
              {subrow.map((item) => 
                // Render item here...
              )}
            </div>
          )}
        </Row>
      )}
    </div>
  )
}

You might need to apply some basic CSS to the subrow element for it to work.

settings the properties:

position: relative;
height: 50px; // replace with your own row height

should be enough, but it depends on your implementation.

groupItemsToSubrows

A helper function to group intersecting items of the same row into different subrows.

The function receives and returns items of a certain type. If your items are of a different shape, you have to solutions:

  1. Serialize and deserialize you own items into and out of this type.

  2. Implement you own helper function. The code is pretty simple, and available here for you.

API

groupItemsToSubrows: 
    (items: ItemDefinition[], range?: Span) =>
    Record<string, ItemDefinition[][]>

The function returns an object where the key is a rowId, and the value is a matrix of items, where the first index is the subrow index, and the second index the the index of an item inside of that subrow.

Props

items

items: ItemDefinition[]

An array of items in the shape of ItemDefinition

type ItemDefinition = {
    id: string
    rowId: string
    span: Span
    disabled?: boolean
}

range?

range?: Span

An optional range object to filter out items that do not intersect with the current range. This is to reduce the amount of items rendered at a time.

Last updated