Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 25 additions & 19 deletions packages/bar/src/Bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
import { useBar } from './hooks'
import { svgDefaultProps } from './defaults'
import {
BarAnnotationMatcher,
BarBorderColor,
BarComponent,
BarCustomLayerProps,
BarDatum,
BarIndex,
BarItemProps,
BarLayerId,
BarSvgProps,
Expand All @@ -29,12 +32,12 @@
import { BarTotals } from './BarTotals'
import { useComputeLabelLayout } from './compute/common'

type InnerBarProps<D extends BarDatum> = Omit<
BarSvgProps<D>,
type InnerBarProps<D extends BarDatum = BarDatum, I extends BarIndex = string> = Omit<
BarSvgProps<D, I>,
'animate' | 'motionConfig' | 'renderWrapper' | 'theme'
>

const InnerBar = <D extends BarDatum>({
const InnerBar = <D extends BarDatum = BarDatum, I extends BarIndex = string>({
data,
indexBy,
keys,
Expand All @@ -56,7 +59,7 @@
gridXValues,
gridYValues,
layers = svgDefaultProps.layers as BarLayerId[],
barComponent = svgDefaultProps.barComponent as unknown as BarComponent<D>,
barComponent = svgDefaultProps.barComponent as unknown as BarComponent<D, I>,
enableLabel = svgDefaultProps.enableLabel,
label,
labelSkipWidth = svgDefaultProps.labelSkipWidth,
Expand All @@ -65,19 +68,20 @@
labelPosition = svgDefaultProps.labelPosition,
labelOffset = svgDefaultProps.labelOffset,
markers = svgDefaultProps.markers,
colorBy,
colors,
colorBy,
defs = svgDefaultProps.defs,
// @ts-expect-error the typings for SVG fill are not easy to get right.
fill = svgDefaultProps.fill,
borderRadius = svgDefaultProps.borderRadius,
borderWidth = svgDefaultProps.borderWidth,
borderColor,
annotations = svgDefaultProps.annotations,
borderColor = svgDefaultProps.borderColor as BarBorderColor<D, I>,
annotations = svgDefaultProps.annotations as BarAnnotationMatcher<D, I>[],
legendLabel,
tooltipLabel,
valueFormat,
isInteractive = svgDefaultProps.isInteractive,
tooltip = svgDefaultProps.tooltip as BarTooltipComponent<D>,
tooltip = svgDefaultProps.tooltip as BarTooltipComponent<D, I>,
onClick,
onMouseEnter,
onMouseLeave,
Expand All @@ -96,7 +100,7 @@
enableTotals = svgDefaultProps.enableTotals,
totalsOffset = svgDefaultProps.totalsOffset,
forwardedRef,
}: InnerBarProps<D> & {
}: InnerBarProps<D, I> & {
forwardedRef: Ref<SVGSVGElement>
}) => {
const { animate, config: springConfig } = useMotionConfig()
Expand All @@ -120,7 +124,7 @@
legendsWithData,
barTotals,
getColor,
} = useBar<D>({
} = useBar<D, I>({
indexBy,
label,
tooltipLabel,
Expand Down Expand Up @@ -157,7 +161,7 @@
)

const transition = useTransition<
ComputedBarDatumWithValue<D>,
ComputedBarDatumWithValue<D, I>,
{
borderColor: string
color: string
Expand All @@ -169,7 +173,7 @@
opacity: number
transform: string
width: number
textAnchor: BarItemProps<D>['style']['textAnchor']
textAnchor: BarItemProps<D, I>['style']['textAnchor']
}
>(barsWithValue, {
keys: bar => bar.key,
Expand Down Expand Up @@ -293,7 +297,7 @@

if (layers.includes('annotations')) {
layerById.annotations = (
<BarAnnotations key="annotations" bars={bars} annotations={annotations} />
<BarAnnotations<D, I> key="annotations" bars={bars} annotations={annotations} />
)
}

Expand Down Expand Up @@ -322,7 +326,7 @@
bar,
style,
shouldRenderLabel: shouldRenderBarLabel(bar),
label: getLabel(bar.data),

Check failure on line 329 in packages/bar/src/Bar.tsx

View workflow job for this annotation

GitHub Actions / End-to-End Tests

Argument of type 'ComputedDatum<D, I> & { value: number; }' is not assignable to parameter of type 'ComputedBarDatum<D, I>'.

Check failure on line 329 in packages/bar/src/Bar.tsx

View workflow job for this annotation

GitHub Actions / Tests

Argument of type 'ComputedDatum<D, I> & { value: number; }' is not assignable to parameter of type 'ComputedBarDatum<D, I>'.

Check failure on line 329 in packages/bar/src/Bar.tsx

View workflow job for this annotation

GitHub Actions / Storybook Tests

Argument of type 'ComputedDatum<D, I> & { value: number; }' is not assignable to parameter of type 'ComputedBarDatum<D, I>'.
})
)}
</Fragment>
Expand Down Expand Up @@ -370,7 +374,7 @@

if (layers.includes('totals') && enableTotals) {
layerById.totals = (
<BarTotals
<BarTotals<D, I>
key="totals"
data={barTotals}
springConfig={springConfig}
Expand All @@ -380,7 +384,7 @@
)
}

const layerContext: BarCustomLayerProps<D> = {
const layerContext: BarCustomLayerProps<D, I> = {
...commonProps,
margin,
width,
Expand All @@ -393,7 +397,7 @@
xScale,
yScale,
tooltip,
getTooltipLabel,

Check failure on line 400 in packages/bar/src/Bar.tsx

View workflow job for this annotation

GitHub Actions / End-to-End Tests

Type '(datum: ComputedBarDatum<D, I>) => string' is not assignable to type '(datum: ComputedDatum<D, I>) => string | number'.

Check failure on line 400 in packages/bar/src/Bar.tsx

View workflow job for this annotation

GitHub Actions / Tests

Type '(datum: ComputedBarDatum<D, I>) => string' is not assignable to type '(datum: ComputedDatum<D, I>) => string | number'.

Check failure on line 400 in packages/bar/src/Bar.tsx

View workflow job for this annotation

GitHub Actions / Storybook Tests

Type '(datum: ComputedBarDatum<D, I>) => string' is not assignable to type '(datum: ComputedDatum<D, I>) => string | number'.
onClick,
onMouseEnter,
onMouseLeave,
Expand Down Expand Up @@ -425,15 +429,15 @@
}

export const Bar = forwardRef(
<D extends BarDatum>(
<D extends BarDatum = BarDatum, I extends BarIndex = string>(
{
isInteractive = svgDefaultProps.isInteractive,
animate = svgDefaultProps.animate,
motionConfig = svgDefaultProps.motionConfig,
theme,
renderWrapper,
...props
}: BarSvgProps<D>,
}: BarSvgProps<D, I>,
ref: Ref<SVGSVGElement>
) => (
<Container
Expand All @@ -443,7 +447,9 @@
renderWrapper={renderWrapper}
theme={theme}
>
<InnerBar<D> {...props} isInteractive={isInteractive} forwardedRef={ref} />
<InnerBar<D, I> {...props} isInteractive={isInteractive} forwardedRef={ref} />
</Container>
)
) as <D extends BarDatum>(props: WithChartRef<BarSvgProps<D>, SVGSVGElement>) => ReactElement
) as <D extends BarDatum = BarDatum, I extends BarIndex = string>(
props: WithChartRef<BarSvgProps<D, I>, SVGSVGElement>
) => ReactElement
6 changes: 3 additions & 3 deletions packages/bar/src/BarAnnotations.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Annotation, useAnnotations } from '@nivo/annotations'
import { BarAnnotationsProps, BarDatum } from './types'
import { BarAnnotationsProps, BarDatum, BarIndex } from './types'

export const BarAnnotations = <D extends BarDatum>({
export const BarAnnotations = <D extends BarDatum = BarDatum, I extends BarIndex = string>({
bars,
annotations,
}: BarAnnotationsProps<D>) => {
}: BarAnnotationsProps<D, I>) => {
const boundAnnotations = useAnnotations({
data: bars,
annotations,
Expand Down
49 changes: 26 additions & 23 deletions packages/bar/src/BarCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,24 @@
import { renderLegendToCanvas } from '@nivo/legends'
import { useTooltip } from '@nivo/tooltip'
import {
BarAnnotationMatcher,
BarCanvasCustomLayerProps,
BarCanvasLayer,
BarCanvasProps,
BarCanvasRenderer,
BarCommonProps,
BarDatum,
BarIndex,
BarLabel,
BarTooltipComponent,
ComputedBarDatum,
} from './types'
import { useBar } from './hooks'
import { BarTotalsData } from './compute/totals'
import { useComputeLabelLayout } from './compute/common'

const findBarUnderCursor = <D extends BarDatum>(
nodes: ComputedBarDatum<D>[],
const findBarUnderCursor = <D extends BarDatum = BarDatum, I extends BarIndex = string>(
nodes: readonly ComputedBarDatum<D, I>[],
margin: Margin,
x: number,
y: number
Expand All @@ -55,11 +58,11 @@

const isNumber = (value: unknown): value is number => typeof value === 'number'

function renderTotalsToCanvas<D extends BarDatum>(
function renderTotalsToCanvas<D extends BarDatum = BarDatum, I extends BarIndex = string>(
ctx: CanvasRenderingContext2D,
barTotals: BarTotalsData[],
barTotals: readonly BarTotalsData[],
theme: Theme,
layout: BarCommonProps<D>['layout'] = canvasDefaultProps.layout
layout: BarCommonProps<D, I>['layout'] = canvasDefaultProps.layout
) {
setCanvasFont(ctx, theme.labels.text)
ctx.textBaseline = layout === 'vertical' ? 'alphabetic' : 'middle'
Expand All @@ -70,14 +73,14 @@
})
}

type InnerBarCanvasProps<RawDatum extends BarDatum> = Omit<
BarCanvasProps<RawDatum>,
type InnerBarCanvasProps<D extends BarDatum, I extends BarIndex = string> = Omit<
BarCanvasProps<D, I>,
'renderWrapper' | 'theme'
> & {
forwardedRef: Ref<HTMLCanvasElement>
}

const InnerBarCanvas = <D extends BarDatum>({
const InnerBarCanvas = <D extends BarDatum = BarDatum, I extends BarIndex = string>({
data,
indexBy,
keys,
Expand All @@ -100,10 +103,10 @@
gridYValues,
labelPosition = canvasDefaultProps.labelPosition,
labelOffset = canvasDefaultProps.labelOffset,
layers = canvasDefaultProps.layers as BarCanvasLayer<D>[],
renderBar = canvasDefaultProps.renderBar as unknown as BarCanvasRenderer<D>,
layers = canvasDefaultProps.layers as BarCanvasLayer<D, I>[],
renderBar = canvasDefaultProps.renderBar as unknown as BarCanvasRenderer<D, I>,
enableLabel = canvasDefaultProps.enableLabel,
label,
label = canvasDefaultProps.label as BarLabel<D, I>,
labelSkipWidth = canvasDefaultProps.labelSkipWidth,
labelSkipHeight = canvasDefaultProps.labelSkipHeight,
labelTextColor,
Expand All @@ -112,12 +115,12 @@
borderRadius = canvasDefaultProps.borderRadius,
borderWidth = canvasDefaultProps.borderWidth,
borderColor,
annotations = canvasDefaultProps.annotations,
annotations = canvasDefaultProps.annotations as BarAnnotationMatcher<D, I>[],
legendLabel,
tooltipLabel,
tooltipLabel = canvasDefaultProps.tooltipLabel as BarLabel<D, I>,
valueFormat,
isInteractive = canvasDefaultProps.isInteractive,
tooltip = canvasDefaultProps.tooltip as BarTooltipComponent<D>,
tooltip = canvasDefaultProps.tooltip as BarTooltipComponent<D, I>,
onClick,
onMouseEnter,
onMouseLeave,
Expand All @@ -127,7 +130,7 @@
forwardedRef,
enableTotals = canvasDefaultProps.enableTotals,
totalsOffset = canvasDefaultProps.totalsOffset,
}: InnerBarCanvasProps<D>) => {
}: InnerBarCanvasProps<D, I>) => {
const canvasEl = useRef<HTMLCanvasElement | null>(null)

const theme = useTheme()
Expand All @@ -150,7 +153,7 @@
legendsWithData,
barTotals,
getColor,
} = useBar<D>({
} = useBar<D, I>({
indexBy,
label,
tooltipLabel,
Expand Down Expand Up @@ -181,7 +184,7 @@
const { showTooltipFromEvent, hideTooltip } = useTooltip()

// Using any because return type isn't correct
const boundAnnotations: any = useComputedAnnotations({
const boundAnnotations: any = useComputedAnnotations<ComputedBarDatum<D, I>>({
annotations: useAnnotations({
data: bars,
annotations,
Expand All @@ -198,7 +201,7 @@
})

// We use `any` here until we can figure out the best way to type xScale/yScale
const layerContext: BarCanvasCustomLayerProps<D> = useMemo(
const layerContext: BarCanvasCustomLayerProps<D, I> = useMemo(

Check failure on line 204 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / End-to-End Tests

Type '{ borderRadius: number; borderWidth: number; isInteractive: boolean; isFocusable: false; labelSkipWidth: number; labelSkipHeight: number; margin: Margin; width: number; height: number; ... 12 more ...; getColor: OrdinalColorScale<...>; }' is not assignable to type 'BarCanvasCustomLayerProps<D, I>'.

Check failure on line 204 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / Tests

Type '{ borderRadius: number; borderWidth: number; isInteractive: boolean; isFocusable: false; labelSkipWidth: number; labelSkipHeight: number; margin: Margin; width: number; height: number; ... 12 more ...; getColor: OrdinalColorScale<...>; }' is not assignable to type 'BarCanvasCustomLayerProps<D, I>'.

Check failure on line 204 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / Storybook Tests

Type '{ borderRadius: number; borderWidth: number; isInteractive: boolean; isFocusable: false; labelSkipWidth: number; labelSkipHeight: number; margin: Margin; width: number; height: number; ... 12 more ...; getColor: OrdinalColorScale<...>; }' is not assignable to type 'BarCanvasCustomLayerProps<D, I>'.
() => ({
borderRadius,
borderWidth,
Expand Down Expand Up @@ -317,7 +320,7 @@
borderColor: getBorderColor(bar) as string,
borderRadius,
borderWidth,
label: getLabel(bar.data),

Check failure on line 323 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / End-to-End Tests

Argument of type 'ComputedDatum<D, I> & { value: number; }' is not assignable to parameter of type 'ComputedBarDatum<D, I>'.

Check failure on line 323 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / Tests

Argument of type 'ComputedDatum<D, I> & { value: number; }' is not assignable to parameter of type 'ComputedBarDatum<D, I>'.

Check failure on line 323 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / Storybook Tests

Argument of type 'ComputedDatum<D, I> & { value: number; }' is not assignable to parameter of type 'ComputedBarDatum<D, I>'.
shouldRenderLabel: shouldRenderBarLabel(bar),
labelStyle: {
...theme.labels.text,
Expand Down Expand Up @@ -442,7 +445,7 @@
const bar = findBarUnderCursor(bars, margin, x, y)

if (bar !== undefined) {
onClick?.({ ...bar.data, color: bar.color }, event)

Check failure on line 448 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / End-to-End Tests

Object literal may only specify known properties, and 'color' does not exist in type 'ComputedDatum<D, I>'.

Check failure on line 448 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / Tests

Object literal may only specify known properties, and 'color' does not exist in type 'ComputedDatum<D, I>'.

Check failure on line 448 in packages/bar/src/BarCanvas.tsx

View workflow job for this annotation

GitHub Actions / Storybook Tests

Object literal may only specify known properties, and 'color' does not exist in type 'ComputedDatum<D, I>'.
}
},
[margin, onClick, bars]
Expand All @@ -468,8 +471,8 @@
}

export const BarCanvas = forwardRef(
<RawDatum extends BarDatum>(
{ isInteractive, renderWrapper, theme, ...props }: BarCanvasProps<RawDatum>,
<D extends BarDatum = BarDatum, I extends BarIndex = string>(
{ isInteractive, renderWrapper, theme, ...props }: BarCanvasProps<D, I>,
ref: Ref<HTMLCanvasElement>
) => (
<Container
Expand All @@ -478,9 +481,9 @@
theme={theme}
animate={false}
>
<InnerBarCanvas<RawDatum> {...props} isInteractive={isInteractive} forwardedRef={ref} />
<InnerBarCanvas<D, I> {...props} isInteractive={isInteractive} forwardedRef={ref} />
</Container>
)
) as <RawDatum extends BarDatum>(
props: WithChartRef<BarCanvasProps<RawDatum>, HTMLCanvasElement>
) as <D extends BarDatum = BarDatum, I extends BarIndex = string>(
props: WithChartRef<BarCanvasProps<D, I>, HTMLCanvasElement>
) => ReactElement
6 changes: 3 additions & 3 deletions packages/bar/src/BarItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import { useTheme } from '@nivo/theming'
import { useTooltip } from '@nivo/tooltip'
import { Text } from '@nivo/text'
import { BarDatum, BarItemProps } from './types'
import { BarDatum, BarIndex, BarItemProps } from './types'

export const BarItem = <D extends BarDatum>({
export const BarItem = <D extends BarDatum = BarDatum, I extends BarIndex = string>({
bar: { data, ...bar },
style: {
borderColor,
Expand Down Expand Up @@ -34,7 +34,7 @@
ariaDescribedBy,
ariaDisabled,
ariaHidden,
}: BarItemProps<D>) => {
}: BarItemProps<D, I>) => {
const theme = useTheme()
const { showTooltipFromEvent, showTooltipAt, hideTooltip } = useTooltip()

Expand All @@ -45,7 +45,7 @@

const handleClick = useCallback(
(event: MouseEvent<SVGRectElement>) => {
onClick?.({ color: bar.color, ...data }, event)

Check failure on line 48 in packages/bar/src/BarItem.tsx

View workflow job for this annotation

GitHub Actions / End-to-End Tests

Object literal may only specify known properties, and 'color' does not exist in type 'ComputedDatum<D, I>'.

Check failure on line 48 in packages/bar/src/BarItem.tsx

View workflow job for this annotation

GitHub Actions / Tests

Object literal may only specify known properties, and 'color' does not exist in type 'ComputedDatum<D, I>'.

Check failure on line 48 in packages/bar/src/BarItem.tsx

View workflow job for this annotation

GitHub Actions / Storybook Tests

Object literal may only specify known properties, and 'color' does not exist in type 'ComputedDatum<D, I>'.
},
[bar, data, onClick]
)
Expand Down
8 changes: 6 additions & 2 deletions packages/bar/src/BarTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { BasicTooltip } from '@nivo/tooltip'
import { BarDatum, BarTooltipProps } from './types'
import { BarDatum, BarIndex, BarTooltipProps } from './types'

export const BarTooltip = <D extends BarDatum>({ color, label, ...data }: BarTooltipProps<D>) => {
export const BarTooltip = <D extends BarDatum = BarDatum, I extends BarIndex = string>({
color,
label,
...data
}: BarTooltipProps<D, I>) => {
return <BasicTooltip id={label} value={data.formattedValue} enableChip={true} color={color} />
}
10 changes: 5 additions & 5 deletions packages/bar/src/BarTotals.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import { useTheme } from '@nivo/theming'
import { AnimationConfig, animated, useTransition } from '@react-spring/web'
import { BarCommonProps, BarDatum } from './types'
import { BarCommonProps, BarDatum, BarIndex } from './types'
import { svgDefaultProps } from './defaults'
import { BarTotalsData } from './compute/totals'

interface Props<RawDatum extends BarDatum> {
interface Props<D extends BarDatum = BarDatum, I extends BarIndex = string> {
data: BarTotalsData[]
springConfig: Partial<AnimationConfig>
animate: boolean
layout?: BarCommonProps<RawDatum>['layout']
layout?: BarCommonProps<D, I>['layout']
}

export const BarTotals = <RawDatum extends BarDatum>({
export const BarTotals = <D extends BarDatum = BarDatum, I extends BarIndex = string>({
data,
springConfig,
animate,
layout = svgDefaultProps.layout,
}: Props<RawDatum>) => {
}: Props<D, I>) => {
const theme = useTheme()
const totalsTransition = useTransition<
BarTotalsData,
Expand Down
Loading