-
Notifications
You must be signed in to change notification settings - Fork 719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
new(xychart): add support for FocusEvents #959
Changes from all commits
04981a2
23983cf
f1e0895
1b6eb96
3cdab84
faff92c
7e81c27
da0715b
09cf4d0
65ee907
ca5bc8b
fcaa55c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,6 @@ export default function AnimatedAreaSeries< | |
XScale extends AxisScale, | ||
YScale extends AxisScale, | ||
Datum extends object | ||
>({ ...props }: Omit<BaseAreaSeriesProps<XScale, YScale, Datum>, 'PathComponent'>) { | ||
>(props: Omit<BaseAreaSeriesProps<XScale, YScale, Datum>, 'PathComponent'>) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these were all double spread unnecessarily |
||
return <BaseAreaSeries<XScale, YScale, Datum> {...props} PathComponent={AnimatedPath} />; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ export default function AnimatedBars<XScale extends AxisScale, YScale extends Ax | |
unique: true, | ||
...useBarTransitionConfig({ horizontal, scale: horizontal ? xScale : yScale }), | ||
}); | ||
const isFocusable = Boolean(rectProps.onFocus || rectProps.onBlur); | ||
|
||
return ( | ||
// eslint-disable-next-line react/jsx-no-useless-fragment | ||
|
@@ -65,6 +66,7 @@ export default function AnimatedBars<XScale extends AxisScale, YScale extends Ax | |
item == null || key == null ? null : ( | ||
<animated.rect | ||
key={key} | ||
tabIndex={isFocusable ? 0 : undefined} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. noting that this implementation requires the For now I think this more modern approach is more ideal since it's simpler and it is supported across all modern browsers |
||
className="visx-bar" | ||
x={x} | ||
y={y} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,15 +3,15 @@ import { AxisScale } from '@visx/axis'; | |
import Area, { AreaProps } from '@visx/shape/lib/shapes/Area'; | ||
import LinePath, { LinePathProps } from '@visx/shape/lib/shapes/LinePath'; | ||
import DataContext from '../../../context/DataContext'; | ||
import { PointerEventParams, SeriesProps, TooltipContextType } from '../../../types'; | ||
import { GlyphsProps, SeriesProps } from '../../../types'; | ||
import withRegisteredData, { WithRegisteredDataProps } from '../../../enhancers/withRegisteredData'; | ||
import getScaledValueFactory from '../../../utils/getScaledValueFactory'; | ||
import getScaleBaseline from '../../../utils/getScaleBaseline'; | ||
import isValidNumber from '../../../typeguards/isValidNumber'; | ||
import usePointerEventEmitters from '../../../hooks/usePointerEventEmitters'; | ||
import { AREASERIES_EVENT_SOURCE, XYCHART_EVENT_SOURCE } from '../../../constants'; | ||
import usePointerEventHandlers from '../../../hooks/usePointerEventHandlers'; | ||
import TooltipContext from '../../../context/TooltipContext'; | ||
import { BaseGlyphSeries } from './BaseGlyphSeries'; | ||
import defaultRenderGlyph from './defaultRenderGlyph'; | ||
import useSeriesEvents from '../../../hooks/useSeriesEvents'; | ||
|
||
export type BaseAreaSeriesProps< | ||
XScale extends AxisScale, | ||
|
@@ -26,21 +26,20 @@ export type BaseAreaSeriesProps< | |
lineProps?: Omit<LinePathProps<Datum>, 'data' | 'x' | 'y' | 'children' | 'defined'>; | ||
/** Rendered component which is passed path props by BaseAreaSeries after processing. */ | ||
PathComponent?: React.FC<Omit<React.SVGProps<SVGPathElement>, 'ref'>> | 'path'; | ||
} & Omit< | ||
React.SVGProps<SVGPathElement>, | ||
'x' | 'y' | 'x0' | 'x1' | 'y0' | 'y1' | 'ref' | 'pointerEvents' | ||
>; | ||
} & Omit<React.SVGProps<SVGPathElement>, 'x' | 'y' | 'x0' | 'x1' | 'y0' | 'y1' | 'ref'>; | ||
|
||
function BaseAreaSeries<XScale extends AxisScale, YScale extends AxisScale, Datum extends object>({ | ||
PathComponent = 'path', | ||
curve, | ||
data, | ||
dataKey, | ||
lineProps, | ||
onPointerMove: onPointerMoveProps, | ||
onPointerOut: onPointerOutProps, | ||
onPointerUp: onPointerUpProps, | ||
pointerEvents = true, | ||
onBlur, | ||
onFocus, | ||
onPointerMove, | ||
onPointerOut, | ||
onPointerUp, | ||
enableEvents = true, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
renderLine = true, | ||
xAccessor, | ||
xScale, | ||
|
@@ -57,36 +56,17 @@ function BaseAreaSeries<XScale extends AxisScale, YScale extends AxisScale, Datu | |
); | ||
const color = colorScale?.(dataKey) ?? theme?.colors?.[0] ?? '#222'; | ||
|
||
const { showTooltip, hideTooltip } = (useContext(TooltipContext) ?? {}) as TooltipContextType< | ||
Datum | ||
>; | ||
const onPointerMove = useCallback( | ||
(p: PointerEventParams<Datum>) => { | ||
showTooltip(p); | ||
if (onPointerMoveProps) onPointerMoveProps(p); | ||
}, | ||
[showTooltip, onPointerMoveProps], | ||
); | ||
const onPointerOut = useCallback( | ||
(event: React.PointerEvent) => { | ||
hideTooltip(); | ||
if (onPointerOutProps) onPointerOutProps(event); | ||
}, | ||
[hideTooltip, onPointerOutProps], | ||
); | ||
const ownEventSourceKey = `${AREASERIES_EVENT_SOURCE}-${dataKey}`; | ||
const pointerEventEmitters = usePointerEventEmitters({ | ||
source: ownEventSourceKey, | ||
onPointerMove: !!onPointerMoveProps && pointerEvents, | ||
onPointerOut: !!onPointerOutProps && pointerEvents, | ||
onPointerUp: !!onPointerUpProps && pointerEvents, | ||
}); | ||
usePointerEventHandlers({ | ||
const eventEmitters = useSeriesEvents<XScale, YScale, Datum>({ | ||
dataKey, | ||
onPointerMove: pointerEvents ? onPointerMove : undefined, | ||
onPointerOut: pointerEvents ? onPointerOut : undefined, | ||
onPointerUp: pointerEvents ? onPointerUpProps : undefined, | ||
sources: [XYCHART_EVENT_SOURCE, ownEventSourceKey], | ||
enableEvents, | ||
onBlur, | ||
onFocus, | ||
onPointerMove, | ||
onPointerOut, | ||
onPointerUp, | ||
source: ownEventSourceKey, | ||
allowedSources: [XYCHART_EVENT_SOURCE, ownEventSourceKey], | ||
}); | ||
|
||
const numericScaleBaseline = useMemo(() => getScaleBaseline(horizontal ? xScale : yScale), [ | ||
|
@@ -108,6 +88,25 @@ function BaseAreaSeries<XScale extends AxisScale, YScale extends AxisScale, Datu | |
} | ||
: { y0: numericScaleBaseline, y1: getScaledY }; | ||
|
||
// render invisible glyphs for focusing if onFocus/onBlur are defined | ||
const captureFocusEvents = Boolean(onFocus || onBlur); | ||
const renderGlyphs = useCallback( | ||
({ glyphs }: GlyphsProps<XScale, YScale, Datum>) => | ||
captureFocusEvents | ||
? glyphs.map(glyph => ( | ||
<React.Fragment key={glyph.key}> | ||
{defaultRenderGlyph({ | ||
...glyph, | ||
color: 'transparent', | ||
onFocus: eventEmitters.onFocus, | ||
onBlur: eventEmitters.onBlur, | ||
})} | ||
</React.Fragment> | ||
)) | ||
: null, | ||
[captureFocusEvents, eventEmitters.onFocus, eventEmitters.onBlur], | ||
); | ||
|
||
return ( | ||
<> | ||
<Area {...xAccessors} {...yAccessors} {...areaProps} curve={curve} defined={isDefined}> | ||
|
@@ -118,7 +117,7 @@ function BaseAreaSeries<XScale extends AxisScale, YScale extends AxisScale, Datu | |
fill={color} | ||
{...areaProps} | ||
d={path(data) || ''} | ||
{...pointerEventEmitters} | ||
{...eventEmitters} | ||
/> | ||
)} | ||
</Area> | ||
|
@@ -143,6 +142,17 @@ function BaseAreaSeries<XScale extends AxisScale, YScale extends AxisScale, Datu | |
)} | ||
</LinePath> | ||
)} | ||
{captureFocusEvents && ( | ||
<BaseGlyphSeries | ||
dataKey={dataKey} | ||
data={data} | ||
xAccessor={xAccessor} | ||
yAccessor={yAccessor} | ||
xScale={xScale} | ||
yScale={yScale} | ||
renderGlyphs={renderGlyphs} | ||
/> | ||
)} | ||
</> | ||
); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-named since no longer specific to
PointerEvent
s