Skip to content

Commit

Permalink
feat(core): improve property accessor utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Dec 18, 2020
1 parent 640393b commit 90958bd
Show file tree
Hide file tree
Showing 10 changed files with 47 additions and 31 deletions.
4 changes: 2 additions & 2 deletions packages/bar/src/enhance.js
Expand Up @@ -14,7 +14,7 @@ import {
withTheme,
withDimensions,
withMotion,
getAccessorFor,
getPropertyAccessor,
getLabelGenerator,
} from '@nivo/core'
import { getOrdinalColorScale, getInheritedColorGenerator } from '@nivo/colors'
Expand All @@ -30,7 +30,7 @@ export default Component =>
getColor: getOrdinalColorScale(colors, colorBy),
})),
withPropsOnChange(['indexBy'], ({ indexBy }) => ({
getIndex: getAccessorFor(indexBy),
getIndex: getPropertyAccessor(indexBy),
})),
withPropsOnChange(['labelTextColor', 'theme'], ({ labelTextColor, theme }) => ({
getLabelTextColor: getInheritedColorGenerator(labelTextColor, theme),
Expand Down
4 changes: 2 additions & 2 deletions packages/circle-packing/src/enhance.js
Expand Up @@ -17,7 +17,7 @@ import {
withDimensions,
withTheme,
withMotion,
getAccessorFor,
getPropertyAccessor,
getLabelGenerator,
bindDefs,
} from '@nivo/core'
Expand All @@ -37,7 +37,7 @@ const commonEnhancers = [
})),

withPropsOnChange(['identity'], ({ identity }) => ({
getIdentity: getAccessorFor(identity),
getIdentity: getPropertyAccessor(identity),
})),

// border
Expand Down
25 changes: 16 additions & 9 deletions packages/core/index.d.ts
@@ -1,6 +1,5 @@
import * as React from 'react'
import { OpaqueInterpolation, SpringConfig } from 'react-spring'
import { number } from 'prop-types'

declare module '@nivo/core' {
export type DatumValue = string | number | Date
Expand Down Expand Up @@ -279,10 +278,6 @@ declare module '@nivo/core' {

export type DatumPropertyAccessor<RawDatum, T> = (datum: RawDatum) => T

export function getAccessorFor<RawDatum, T>(
directive: string | number | DatumPropertyAccessor<RawDatum, T>
): DatumPropertyAccessor<RawDatum, T>

export function useDimensions(
width: number,
height: number,
Expand Down Expand Up @@ -335,11 +330,23 @@ declare module '@nivo/core' {
y: number
}

export type ValueFormat<V> =
export type ValueFormat<Value> =
// d3 formatter
| string
// explicit formatting function
| ((value: V) => string)
export function getValueFormatter<V>(format?: ValueFormat<V>): (value: V) => string
export function useValueFormatter<V>(format?: ValueFormat<V>): (value: V) => string
| ((value: Value) => string)
export function getValueFormatter<Value>(format?: ValueFormat<Value>): (value: Value) => string
export function useValueFormatter<Value>(format?: ValueFormat<Value>): (value: Value) => string

export type PropertyAccessor<Datum, Value> =
// path to use with `lodash.get()`
| string
// explicit accessor function
| ((datum: Datum) => Value)
export function getPropertyAccessor<Datum, Value>(
accessor: PropertyAccessor<Datum, Value>
): (datum: Datum) => Value
export function usePropertyAccessor<Datum, Value>(
accessor: PropertyAccessor<Datum, Value>
): (datum: Datum) => Value
}
4 changes: 2 additions & 2 deletions packages/core/src/hocs/withHierarchy.js
Expand Up @@ -12,7 +12,7 @@ import defaultProps from 'recompose/defaultProps'
import setPropTypes from 'recompose/setPropTypes'
import withPropsOnChange from 'recompose/withPropsOnChange'
import { hierarchy } from 'd3-hierarchy'
import { getAccessorFor } from '../lib/propertiesConverters'
import { getPropertyAccessor } from '../lib/propertiesConverters'

/**
* This HOC watch hierarchical data props change
Expand All @@ -35,6 +35,6 @@ export default ({
[valueKey]: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
}),
withPropsOnChange([srcKey, valueKey], props => ({
[destKey]: hierarchy(props[srcKey]).sum(getAccessorFor(props[valueKey])),
[destKey]: hierarchy(props[srcKey]).sum(getPropertyAccessor(props[valueKey])),
}))
)
4 changes: 2 additions & 2 deletions packages/core/src/hooks/useValueFormatter.js
Expand Up @@ -9,11 +9,11 @@ export const getValueFormatter = format => {
if (typeof format === 'string') {
// time format specifier
if (format.indexOf('time:') === 0) {
return `${d3TimeFormat(format.slice('5'))}`
return d3TimeFormat(format.slice('5'))
}

// standard format specifier
return `${d3Format(format)}`
return d3Format(format)
}

// no formatting
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/lib/propertiesConverters.js
@@ -1,6 +1,7 @@
import isFunction from 'lodash/isFunction'
import get from 'lodash/get'
import { format } from 'd3-format'
import { useMemo } from 'react'

export const getLabelGenerator = (_label, labelFormat) => {
const getRawLabel = isFunction(_label) ? _label : d => get(d, _label)
Expand All @@ -13,7 +14,8 @@ export const getLabelGenerator = (_label, labelFormat) => {
return getRawLabel
}

export const getAccessorFor = directive =>
isFunction(directive) ? directive : d => get(d, directive)
export const getPropertyAccessor = accessor =>
isFunction(accessor) ? accessor : d => get(d, accessor)

export const getAccessorOrValue = value => (isFunction(value) ? value : () => value)
export const usePropertyAccessor = accessor =>
useMemo(() => getPropertyAccessor(accessor), [accessor])
4 changes: 2 additions & 2 deletions packages/heatmap/src/hooks.js
@@ -1,6 +1,6 @@
import { useState, useMemo } from 'react'
import { scaleOrdinal, scaleLinear } from 'd3-scale'
import { useTheme, getAccessorFor, guessQuantizeColorScale } from '@nivo/core'
import { useTheme, usePropertyAccessor, guessQuantizeColorScale } from '@nivo/core'
import { useInheritedColor } from '@nivo/colors'

const computeX = (column, cellWidth, padding) => {
Expand Down Expand Up @@ -83,7 +83,7 @@ export const useHeatMap = ({
}) => {
const [currentCellId, setCurrentCellId] = useState(null)

const getIndex = useMemo(() => getAccessorFor(indexBy), [indexBy])
const getIndex = usePropertyAccessor(indexBy)
const indices = useMemo(() => data.map(getIndex), [data, getIndex])

const layoutConfig = useMemo(() => {
Expand Down
4 changes: 2 additions & 2 deletions packages/radar/src/Radar.js
Expand Up @@ -13,7 +13,7 @@ import {
useTheme,
useCurveInterpolation,
useDimensions,
getAccessorFor,
usePropertyAccessor,
SvgWrapper,
} from '@nivo/core'
import { useOrdinalColorScale } from '@nivo/colors'
Expand Down Expand Up @@ -58,7 +58,7 @@ const Radar = memo(
legends,
role,
}) => {
const getIndex = useMemo(() => getAccessorFor(indexBy), [indexBy])
const getIndex = usePropertyAccessor(indexBy)
const indices = useMemo(() => data.map(getIndex), [data, getIndex])

const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
Expand Down
6 changes: 3 additions & 3 deletions packages/sunburst/src/hooks.ts
Expand Up @@ -2,7 +2,7 @@ import pick from 'lodash/pick'
import sortBy from 'lodash/sortBy'
import cloneDeep from 'lodash/cloneDeep'
import React, { createElement, useCallback, useMemo } from 'react'
import { getAccessorFor, useTheme, useValueFormatter } from '@nivo/core'
import { usePropertyAccessor, useTheme, useValueFormatter } from '@nivo/core'
import { arc, Arc } from 'd3-shape'
import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors'
import { useTooltip } from '@nivo/tooltip'
Expand Down Expand Up @@ -108,8 +108,8 @@ export const useSunburst = <RawDatum extends MaybeColor>({
datum: NormalizedDatum<RawDatum>
) => string

const getId = useMemo(() => getAccessorFor(id), [id])
const getValue = useMemo(() => getAccessorFor(value), [value])
const getId = usePropertyAccessor(id)
const getValue = usePropertyAccessor(value)

const formatValue = useValueFormatter<number>(valueFormat)

Expand Down
15 changes: 11 additions & 4 deletions packages/sunburst/src/types.ts
@@ -1,12 +1,19 @@
import { Arc } from 'd3-shape'
import { HierarchyRectangularNode } from 'd3-hierarchy'
import { OrdinalColorScaleConfig, InheritedColorConfig } from '@nivo/colors'
import { Theme, Dimensions, Box, ValueFormat, SvgDefsAndFill, ModernMotionProps } from '@nivo/core'
import {
Theme,
Dimensions,
Box,
ValueFormat,
SvgDefsAndFill,
ModernMotionProps,
PropertyAccessor,
} from '@nivo/core'

export type DatumId = string | number
export type DatumValue = number

export type DatumPropertyAccessor<RawDatum, T> = (datum: RawDatum) => T
export type LabelAccessorFunction<RawDatum> = (datum: RawDatum) => string | number

export type SunburstLayerId = 'slices' | 'sliceLabels'
Expand All @@ -25,8 +32,8 @@ export type SunburstLayer<RawDatum> = SunburstLayerId | SunburstCustomLayer<RawD

export interface DataProps<RawDatum> {
data: RawDatum
id?: string | number | DatumPropertyAccessor<RawDatum, DatumId>
value?: string | number | DatumPropertyAccessor<RawDatum, DatumValue>
id?: PropertyAccessor<RawDatum, DatumId>
value?: PropertyAccessor<RawDatum, DatumValue>
valueFormat?: ValueFormat<number>
}

Expand Down

0 comments on commit 90958bd

Please sign in to comment.