Skip to content

Commit

Permalink
fix(Timeline): Render events beyond range
Browse files Browse the repository at this point in the history
  • Loading branch information
m7kvqbe1 committed Oct 27, 2020
1 parent e225901 commit cfcc847
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 38 deletions.
6 changes: 3 additions & 3 deletions packages/docs-site/src/library/pages/timeline/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,11 @@ const CustomTimelineComponent = ({
const {
width,
offset,
isBeforeStart,
isAfterEnd
startsBeforeStart,
startsAfterEnd
} = useTimelinePosition(startDate, endDate)

if (isBeforeStart || isAfterEnd) return null
if (startsBeforeStart || startsAfterEnd) return null

return (
<div style={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const WithSidebar = () => (
<TimelineRow name="Row 1">
<TimelineEvents>
<TimelineEvent
startDate={new Date(2020, 3, 14)}
startDate={new Date(2020, 2, 14)}
endDate={new Date(2020, 3, 18)}
>
Event 1
Expand All @@ -125,6 +125,16 @@ export const WithSidebar = () => (
</TimelineEvent>
</TimelineEvents>
</TimelineRow>
<TimelineRow name="Row 3">
<TimelineEvents>
<TimelineEvent
startDate={new Date(2020, 1, 3)}
endDate={new Date(2020, 7, 8)}
>
Event 2
</TimelineEvent>
</TimelineEvents>
</TimelineRow>
</TimelineRows>
</Timeline>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from 'react'
import styled from 'styled-components'
import styled, { css } from 'styled-components'
import { format } from 'date-fns'
import { selectors } from '@royalnavy/design-tokens'
import { isString } from 'lodash'

import { ACCESSIBLE_DATE_FORMAT, TIMELINE_BG_COLOR } from './constants'
import { ACCESSIBLE_DATE_FORMAT } from './constants'
import { ComponentWithClass } from '../../common/ComponentWithClass'
import { DATE_FORMAT } from '../../constants'
import { useTimelinePosition } from './hooks/useTimelinePosition'
Expand All @@ -18,7 +18,8 @@ export interface TimelineEventWithRenderContentProps
endDate: Date,
startDate: Date,
widthPx: string,
offsetPx: string
offsetPx: string,
maxWidthPx: string
) => React.ReactNode
startDate: Date
}
Expand Down Expand Up @@ -58,15 +59,73 @@ const StyledEventTitle = styled.span`
`

interface StyledEventBarProps {
width: string
maxWidth?: string
barColor: string
startsBeforeStart?: boolean
endsAfterEnd?: boolean
}

const StyledEventBar = styled.div<StyledEventBarProps>`
order: 1;
position: relative;
display: inline-block;
background-color: ${({ barColor = color('success', '500') }) => barColor};
border-radius: 4px;
background-color: ${({ barColor = color('success', '500') }) => barColor};
height: 16px;
min-width: 1rem;
width: ${({ width }) => width};
max-width: ${({ maxWidth }) => maxWidth};
${({ startsBeforeStart, width, barColor = color('success', '500') }) =>
startsBeforeStart &&
css`
border-top-left-radius: unset;
border-bottom-left-radius: unset;
margin-left: 14px;
width: calc(${width} - 14px);
&::before {
content: '';
position: absolute;
left: -14px;
width: 0;
height: 0;
border-style: solid;
border-width: 8px 14px 8px 0;
border-color: transparent ${barColor} transparent transparent;
}
+ ${StyledEventTitle} {
margin-left: 14px;
}
`}
${({ endsAfterEnd, maxWidth, barColor = color('success', '500') }) =>
endsAfterEnd &&
css`
border-top-right-radius: unset;
border-bottom-right-radius: unset;
max-width: calc(${maxWidth} - 14px);
&::after {
content: '';
position: absolute;
right: -14px;
width: 0;
height: 0;
border-style: solid;
border-width: 8px 0 8px 14px;
border-color: transparent transparent transparent ${barColor};
}
`}
${({ startsBeforeStart, endsAfterEnd, maxWidth }) =>
startsBeforeStart &&
endsAfterEnd &&
css`
max-width: calc(${maxWidth} - 28px);
`}
`

function renderDefault({
Expand All @@ -75,26 +134,35 @@ function renderDefault({
offsetPx,
startDate,
widthPx,
maxWidthPx,
startsBeforeStart,
endsAfterEnd,
}: {
barColor: string
children: React.ReactNode
offsetPx: string
startDate: Date
widthPx: string
maxWidthPx: string
startsBeforeStart: boolean
endsAfterEnd: boolean
}) {
return (
<StyledTimelineEvent
style={{ left: offsetPx }}
data-testid="timeline-event"
>
<StyledEventTitle data-testid="timeline-event-title">
{children || `Task ${format(new Date(startDate), DATE_FORMAT.SHORT)}`}
</StyledEventTitle>
<StyledEventBar
barColor={barColor}
style={{ width: widthPx }}
width={widthPx}
maxWidth={maxWidthPx}
startsBeforeStart={startsBeforeStart}
endsAfterEnd={endsAfterEnd}
data-testid="timeline-event-bar"
/>
<StyledEventTitle data-testid="timeline-event-title">
{children || `Task ${format(new Date(startDate), DATE_FORMAT.SHORT)}`}
</StyledEventTitle>
</StyledTimelineEvent>
)
}
Expand All @@ -116,17 +184,29 @@ export const TimelineEvent: React.FC<TimelineEventProps> = ({
startDate,
}) => {
const {
startsBeforeStart,
startsAfterEnd,
endsBeforeStart,
endsAfterEnd,
offset: offsetPx,
width: widthPx,
isBeforeStart,
isAfterEnd,
maxWidth: maxWidthPx,
} = useTimelinePosition(startDate, endDate)

if (isBeforeStart || isAfterEnd) return null
if (startsAfterEnd || endsBeforeStart) return null

const event = render
? render(startDate, endDate, widthPx, offsetPx)
: renderDefault({ barColor, children, offsetPx, startDate, widthPx })
? render(startDate, endDate, widthPx, offsetPx, maxWidthPx)
: renderDefault({
barColor,
children,
offsetPx,
startDate,
widthPx,
maxWidthPx,
startsBeforeStart,
endsAfterEnd,
})

const title = getTitle(children, startDate, endDate)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ export const TimelineTodayMarker: React.FC<TimelineTodayMarkerProps> = ({
state: { today },
} = useContext(TimelineContext)

const { offset, isBeforeStart, isAfterEnd } = useTimelinePosition(today, null)
const { offset, startsBeforeStart, startsAfterEnd } = useTimelinePosition(
today,
null
)

if (isBeforeStart || isAfterEnd) return null
if (startsBeforeStart || startsAfterEnd) return null

return (
<StyledTimelineTodayMarkerWrapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,6 @@ describe('Timeline', () => {
})

it('should warn the consumer about using the deprecated component', () => {
expect(consoleWarnSpy).toHaveBeenCalledTimes(1)
expect(consoleWarnSpy).toHaveBeenCalledWith(
'Component `TimelineSide` is deprecated'
)
Expand Down Expand Up @@ -530,7 +529,6 @@ describe('Timeline', () => {
})

it('should warn the consumer about using the deprecated prop', () => {
expect(consoleWarnSpy).toHaveBeenCalledTimes(1)
expect(consoleWarnSpy).toHaveBeenCalledWith(
'Prop `dayWidth` is deprecated'
)
Expand Down Expand Up @@ -859,12 +857,6 @@ describe('Timeline', () => {
left: '405px',
})
})

it('sets the event width correctly', () => {
expect(wrapper.getByTestId('timeline-event-bar')).toHaveStyle({
width: '120px',
})
})
})

describe('when rows has `renderColumns` specified', () => {
Expand Down Expand Up @@ -1332,4 +1324,68 @@ describe('Timeline', () => {
)
})
})

describe('when an event has a startDate out of bounds of the displayed range', () => {
beforeEach(() => {
wrapper = render(
<Timeline
startDate={new Date(2020, 3, 1)}
today={new Date(2020, 3, 15)}
>
<TimelineTodayMarker />
<TimelineMonths />
<TimelineWeeks />
<TimelineDays />
<TimelineRows>
<TimelineRow name="Row 1">
<TimelineEvents>
<TimelineEvent
startDate={new Date(2020, 2, 14)}
endDate={new Date(2020, 3, 18)}
>
Event 1
</TimelineEvent>
</TimelineEvents>
</TimelineRow>
</TimelineRows>
</Timeline>
)
})

it('renders the event', () => {
expect(wrapper.queryByTestId('timeline-event')).toBeInTheDocument()
})
})

describe('when an event has an endDate out of bounds of the displayed range', () => {
beforeEach(() => {
wrapper = render(
<Timeline
startDate={new Date(2020, 2, 1)}
today={new Date(2020, 2, 15)}
>
<TimelineTodayMarker />
<TimelineMonths />
<TimelineWeeks />
<TimelineDays />
<TimelineRows>
<TimelineRow name="Row 1">
<TimelineEvents>
<TimelineEvent
startDate={new Date(2020, 2, 14)}
endDate={new Date(2020, 3, 18)}
>
Event 1
</TimelineEvent>
</TimelineEvents>
</TimelineRow>
</TimelineRows>
</Timeline>
)
})

it('renders the event', () => {
expect(wrapper.queryByTestId('timeline-event')).toBeInTheDocument()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ export function useTimelinePosition(
): {
width: string
offset: string
maxWidth: string
isBeforeStart: boolean
isAfterEnd: boolean
startsBeforeStart: boolean
startsAfterEnd: boolean
endsBeforeStart: boolean
endsAfterEnd: boolean
} {
const {
state: { days, options },
Expand All @@ -47,19 +52,34 @@ export function useTimelinePosition(
const firstDateDisplayed = days[0].date
const lastDateDisplayed = days[days.length - 1].date

const isBeforeStart = isBefore(new Date(startDate), firstDateDisplayed)
const isAfterEnd = isAfter(new Date(startDate), lastDateDisplayed)
const startsBeforeStart = isBefore(new Date(startDate), firstDateDisplayed)
const startsAfterEnd = isAfter(new Date(startDate), lastDateDisplayed)
const endsBeforeStart = isBefore(new Date(endDate), firstDateDisplayed)
const endsAfterEnd = isAfter(new Date(endDate), lastDateDisplayed)

const width = formatPx(options.dayWidth, getWidth(startDate, endDate))
const offset = formatPx(
options.dayWidth,
getOffset(startDate, firstDateDisplayed)
)
const width = startsBeforeStart
? getWidth(firstDateDisplayed, endDate)
: getWidth(startDate, endDate)

const offset = startsBeforeStart
? 0
: getOffset(startDate, firstDateDisplayed)

const maxWidth = (startsBeforeStart && endsAfterEnd)
? getWidth(firstDateDisplayed, lastDateDisplayed) + 1
: getWidth(startDate, lastDateDisplayed) + 1

console.warn('`isBeforeStart` and `isAfterEnd` are deprecated')

return {
width,
offset,
isBeforeStart,
isAfterEnd,
width: formatPx(options.dayWidth, width),
offset: formatPx(options.dayWidth, offset),
maxWidth: formatPx(options.dayWidth, maxWidth),
startsBeforeStart,
startsAfterEnd,
endsBeforeStart,
endsAfterEnd,
isBeforeStart: startsBeforeStart,
isAfterEnd: startsAfterEnd,
}
}

0 comments on commit cfcc847

Please sign in to comment.