Skip to content

Commit

Permalink
feat(calendar): remove recompose and convert to hooks (#1040)
Browse files Browse the repository at this point in the history
Co-authored-by: Neil Kistner <neil.kistner@gmail.com>
Co-authored-by: Diego <diego@localhost.localdomain>
  • Loading branch information
3 people committed Aug 2, 2020
1 parent c10edbf commit daebd61
Show file tree
Hide file tree
Showing 15 changed files with 742 additions and 503 deletions.
1 change: 1 addition & 0 deletions .storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function loadStories() {
require('../packages/bullet/stories/bullet.stories')
require('../packages/bump/stories/bump.stories')
require('../packages/calendar/stories/calendar.stories')
require('../packages/calendar/stories/calendarCanvas.stories')
require('../packages/chord/stories/chord.stories')
require('../packages/circle-packing/stories/bubble.stories')
require('../packages/circle-packing/stories/bubbleHtml.stories')
Expand Down
30 changes: 29 additions & 1 deletion packages/calendar/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/*
* This file is part of the nivo project.
*
* Copyright 2016-present, Raphaël Benitte.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import * as React from 'react'
import { Dimensions, Theme, Box, BoxAlign } from '@nivo/core'
import { LegendProps } from '@nivo/legends'
Expand All @@ -16,12 +24,18 @@ declare module '@nivo/calendar' {
data: CalendarDatum[]
}

type ValueFormatter = (
datum: Omit<CalendarDayData, 'formattedValue' | 'label'>
) => string | number

export type CalendarDirection = 'horizontal' | 'vertical'

export type CalendarLegend = LegendProps & {
itemCount: number
}

export type CalendarMouseHandler = (data: CalendarDayData, event: React.MouseEvent<any>) => void

export interface CalendarDayData {
date: Date
day: string
Expand All @@ -32,18 +46,25 @@ declare module '@nivo/calendar' {
y: number
}

export interface ColorScale {
(value: number | { valueOf(): number }): Range
ticks(count?: number): number[]
}

export type CalendarCommonProps = Partial<{
minValue: 'auto' | number
maxValue: 'auto' | number

direction: CalendarDirection
colors: string[]
colorScale: ColorScale
margin: Box
align: BoxAlign

yearLegend: (year: number) => string | number
yearSpacing: number
yearLegendOffset: number
yearLegendPosition: 'before' | 'after'

monthLegend: (year: number, month: number, date: Date) => string | number
monthSpacing: number
Expand All @@ -59,9 +80,16 @@ declare module '@nivo/calendar' {

isInteractive: boolean

tooltipFormat: (value: number) => string | number
onClick?: CalendarMouseHandler
onMouseMove?: CalendarMouseHandler
onMouseLeave?: CalendarMouseHandler
onMouseEnter?: CalendarMouseHandler

tooltip: React.StatelessComponent<CalendarDayData>

valueFormat?: string | ValueFormatter
legendFormat?: string | ValueFormatter

legends: CalendarLegend[]

theme: Theme
Expand Down
5 changes: 2 additions & 3 deletions packages/calendar/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
"d3-time-format": "^2.1.3",
"lodash.isdate": "^4.0.1",
"lodash.memoize": "^4.1.2",
"lodash.range": "^3.2.0",
"recompose": "^0.30.0"
"lodash.range": "^3.2.0"
},
"peerDependencies": {
"prop-types": ">= 15.5.10 < 16.0.0",
Expand All @@ -41,4 +40,4 @@
"publishConfig": {
"access": "public"
}
}
}
187 changes: 110 additions & 77 deletions packages/calendar/src/Calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,111 +7,144 @@
* file that was distributed with this source code.
*/
import React from 'react'
import { Container, SvgWrapper } from '@nivo/core'
import { SvgWrapper, useTheme, useDimensions, withContainer, useValueFormatter } from '@nivo/core'
import { BoxLegendSvg } from '@nivo/legends'
import { setDisplayName } from 'recompose'
import { CalendarPropTypes } from './props'
import enhance from './enhance'
import { CalendarPropTypes, CalendarDefaultProps } from './props'
import CalendarYearLegends from './CalendarYearLegends'
import CalendarMonthPath from './CalendarMonthPath'
import CalendarMonthLegends from './CalendarMonthLegends'
import { useMonthLegends, useYearLegends, useCalendarLayout, useDays, useColorScale } from './hooks'
import CalendarDay from './CalendarDay'

const Calendar = ({
colorScale,

margin,
margin: partialMargin,
width,
height,
outerWidth,
outerHeight,

yearLegends,
align,
colors,
colorScale,
data,
direction,
emptyColor,
from,
to,
minValue,
maxValue,
valueFormat,
legendFormat,

yearLegend,
yearLegendOffset,
yearLegendPosition,
yearSpacing,

monthLegends,
monthLegend,
monthBorderWidth,
monthBorderColor,
monthBorderWidth,
monthLegend,
monthLegendOffset,
monthLegendPosition,
monthSpacing,

daySpacing,
dayBorderWidth,
dayBorderColor,

theme,
dayBorderWidth,
daySpacing,

isInteractive,
tooltipFormat,
tooltip,
onClick,
onMouseEnter,
onMouseLeave,
onMouseMove,

legends,

months,
days,
}) => {
const theme = useTheme()
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
width,
height,
partialMargin
)
const { months, years, ...rest } = useCalendarLayout({
width: innerWidth,
height: innerHeight,
from,
to,
direction,
yearSpacing,
monthSpacing,
daySpacing,
align,
})
const colorScaleFn = useColorScale({ data, minValue, maxValue, colors, colorScale })
const monthLegends = useMonthLegends({
months,
direction,
monthLegendPosition,
monthLegendOffset,
})
const yearLegends = useYearLegends({ years, direction, yearLegendPosition, yearLegendOffset })
const days = useDays({ days: rest.days, data, colorScale: colorScaleFn, emptyColor })
const formatLegend = useValueFormatter(legendFormat)
const formatValue = useValueFormatter(valueFormat)

return (
<Container isInteractive={isInteractive} theme={theme} animate={false}>
{({ showTooltip, hideTooltip }) => (
<SvgWrapper width={outerWidth} height={outerHeight} margin={margin} theme={theme}>
{days.map(d => (
<CalendarDay
key={d.date.toString()}
data={d}
x={d.x}
y={d.y}
size={d.size}
spacing={daySpacing}
color={d.color}
borderWidth={dayBorderWidth}
borderColor={dayBorderColor}
showTooltip={showTooltip}
hideTooltip={hideTooltip}
tooltipFormat={tooltipFormat}
tooltip={tooltip}
theme={theme}
onClick={onClick}
/>
))}
{months.map(m => (
<CalendarMonthPath
key={m.date.toString()}
path={m.path}
borderWidth={monthBorderWidth}
borderColor={monthBorderColor}
/>
))}
<CalendarMonthLegends
months={monthLegends}
legend={monthLegend}
<SvgWrapper width={outerWidth} height={outerHeight} margin={margin} theme={theme}>
{days.map(d => (
<CalendarDay
key={d.date.toString()}
data={d}
x={d.x}
y={d.y}
size={d.size}
spacing={daySpacing}
color={d.color}
borderWidth={dayBorderWidth}
borderColor={dayBorderColor}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
isInteractive={isInteractive}
tooltip={tooltip}
theme={theme}
onClick={onClick}
formatValue={formatValue}
/>
))}
{months.map(m => (
<CalendarMonthPath
key={m.date.toString()}
path={m.path}
borderWidth={monthBorderWidth}
borderColor={monthBorderColor}
/>
))}
<CalendarMonthLegends months={monthLegends} legend={monthLegend} theme={theme} />
<CalendarYearLegends years={yearLegends} legend={yearLegend} theme={theme} />
{legends.map((legend, i) => {
const legendData = colorScaleFn.ticks(legend.itemCount).map(value => ({
id: value,
label: formatLegend(value),
color: colorScaleFn(value),
}))

return (
<BoxLegendSvg
key={i}
{...legend}
containerWidth={width}
containerHeight={height}
data={legendData}
theme={theme}
/>
<CalendarYearLegends years={yearLegends} legend={yearLegend} theme={theme} />
{legends.map((legend, i) => {
const legendData = colorScale.ticks(legend.itemCount).map(value => ({
id: value,
label: value,
color: colorScale(value),
}))

return (
<BoxLegendSvg
key={i}
{...legend}
containerWidth={width}
containerHeight={height}
data={legendData}
theme={theme}
/>
)
})}
</SvgWrapper>
)}
</Container>
)
})}
</SvgWrapper>
)
}

Calendar.displayName = 'Calendar'
Calendar.defaultProps = CalendarDefaultProps
Calendar.propTypes = CalendarPropTypes

export default setDisplayName('Calendar')(enhance(Calendar))
export default withContainer(Calendar)
Loading

0 comments on commit daebd61

Please sign in to comment.