@coinbase/cds-mobile-visualization 3.3.0 → 3.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dts/chart/CartesianChart.d.ts +101 -0
- package/dts/chart/CartesianChart.d.ts.map +1 -0
- package/dts/chart/ChartProvider.d.ts +6 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -0
- package/dts/chart/Path.d.ts +48 -0
- package/dts/chart/Path.d.ts.map +1 -0
- package/dts/chart/PeriodSelector.d.ts +85 -0
- package/dts/chart/PeriodSelector.d.ts.map +1 -0
- package/dts/chart/Point.d.ts +103 -0
- package/dts/chart/Point.d.ts.map +1 -0
- package/dts/chart/area/Area.d.ts +62 -0
- package/dts/chart/area/Area.d.ts.map +1 -0
- package/dts/chart/area/AreaChart.d.ts +90 -0
- package/dts/chart/area/AreaChart.d.ts.map +1 -0
- package/dts/chart/area/DottedArea.d.ts +27 -0
- package/dts/chart/area/DottedArea.d.ts.map +1 -0
- package/dts/chart/area/GradientArea.d.ts +30 -0
- package/dts/chart/area/GradientArea.d.ts.map +1 -0
- package/dts/chart/area/SolidArea.d.ts +8 -0
- package/dts/chart/area/SolidArea.d.ts.map +1 -0
- package/dts/chart/area/index.d.ts +6 -0
- package/dts/chart/area/index.d.ts.map +1 -0
- package/dts/chart/axis/Axis.d.ts +204 -0
- package/dts/chart/axis/Axis.d.ts.map +1 -0
- package/dts/chart/axis/XAxis.d.ts +16 -0
- package/dts/chart/axis/XAxis.d.ts.map +1 -0
- package/dts/chart/axis/YAxis.d.ts +21 -0
- package/dts/chart/axis/YAxis.d.ts.map +1 -0
- package/dts/chart/axis/index.d.ts +4 -0
- package/dts/chart/axis/index.d.ts.map +1 -0
- package/dts/chart/bar/Bar.d.ts +89 -0
- package/dts/chart/bar/Bar.d.ts.map +1 -0
- package/dts/chart/bar/BarChart.d.ts +97 -0
- package/dts/chart/bar/BarChart.d.ts.map +1 -0
- package/dts/chart/bar/BarPlot.d.ts +29 -0
- package/dts/chart/bar/BarPlot.d.ts.map +1 -0
- package/dts/chart/bar/BarStack.d.ts +111 -0
- package/dts/chart/bar/BarStack.d.ts.map +1 -0
- package/dts/chart/bar/BarStackGroup.d.ts +35 -0
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
- package/dts/chart/bar/DefaultBar.d.ts +7 -0
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
- package/dts/chart/bar/DefaultBarStack.d.ts +7 -0
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
- package/dts/chart/bar/index.d.ts +8 -0
- package/dts/chart/bar/index.d.ts.map +1 -0
- package/dts/chart/index.d.ts +13 -0
- package/dts/chart/index.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts +12 -0
- package/dts/chart/line/DottedLine.d.ts.map +1 -0
- package/dts/chart/line/GradientLine.d.ts +45 -0
- package/dts/chart/line/GradientLine.d.ts.map +1 -0
- package/dts/chart/line/Line.d.ts +78 -0
- package/dts/chart/line/Line.d.ts.map +1 -0
- package/dts/chart/line/LineChart.d.ts +84 -0
- package/dts/chart/line/LineChart.d.ts.map +1 -0
- package/dts/chart/line/ReferenceLine.d.ts +91 -0
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
- package/dts/chart/line/SolidLine.d.ts +12 -0
- package/dts/chart/line/SolidLine.d.ts.map +1 -0
- package/dts/chart/line/index.d.ts +7 -0
- package/dts/chart/line/index.d.ts.map +1 -0
- package/dts/chart/scrubber/Scrubber.d.ts +104 -0
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeacon.d.ts +75 -0
- package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberProvider.d.ts +17 -0
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
- package/dts/chart/scrubber/index.d.ts +2 -0
- package/dts/chart/scrubber/index.d.ts.map +1 -0
- package/dts/chart/text/ChartText.d.ts +90 -0
- package/dts/chart/text/ChartText.d.ts.map +1 -0
- package/dts/chart/text/SmartChartTextGroup.d.ts +55 -0
- package/dts/chart/text/SmartChartTextGroup.d.ts.map +1 -0
- package/dts/chart/text/index.d.ts +3 -0
- package/dts/chart/text/index.d.ts.map +1 -0
- package/dts/chart/utils/axis.d.ts +342 -0
- package/dts/chart/utils/axis.d.ts.map +1 -0
- package/dts/chart/utils/bar.d.ts +20 -0
- package/dts/chart/utils/bar.d.ts.map +1 -0
- package/dts/chart/utils/chart.d.ts +97 -0
- package/dts/chart/utils/chart.d.ts.map +1 -0
- package/dts/chart/utils/context.d.ts +95 -0
- package/dts/chart/utils/context.d.ts.map +1 -0
- package/dts/chart/utils/index.d.ts +8 -0
- package/dts/chart/utils/index.d.ts.map +1 -0
- package/dts/chart/utils/path.d.ts +107 -0
- package/dts/chart/utils/path.d.ts.map +1 -0
- package/dts/chart/utils/point.d.ts +75 -0
- package/dts/chart/utils/point.d.ts.map +1 -0
- package/dts/chart/utils/scale.d.ts +43 -0
- package/dts/chart/utils/scale.d.ts.map +1 -0
- package/dts/index.d.ts +2 -1
- package/dts/index.d.ts.map +1 -1
- package/dts/sparkline/Counter.d.ts +7 -2
- package/dts/sparkline/Sparkline.d.ts +67 -16
- package/dts/sparkline/Sparkline.d.ts.map +1 -1
- package/dts/sparkline/SparklineArea.d.ts +10 -4
- package/dts/sparkline/SparklineArea.d.ts.map +1 -1
- package/dts/sparkline/SparklineAreaPattern.d.ts +12 -4
- package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -1
- package/dts/sparkline/SparklineGradient.d.ts +21 -10
- package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
- package/dts/sparkline/__figma__/Sparkline.figma.d.ts +1 -1
- package/dts/sparkline/generateSparklineWithId.d.ts +8 -2
- package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -1
- package/dts/sparkline/index.d.ts +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +8 -3
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +132 -110
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +22 -9
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +18 -7
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +9 -4
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +11 -6
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +7 -5
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +22 -10
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +21 -7
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +21 -16
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +29 -23
- package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +22 -14
- package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +1 -1
- package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +9 -5
- package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +11 -6
- package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +5 -2
- package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +17 -17
- package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +16 -13
- package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +106 -98
- package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +1 -1
- package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +22 -19
- package/esm/chart/CartesianChart.js +241 -0
- package/esm/chart/ChartProvider.js +10 -0
- package/esm/chart/Path.js +133 -0
- package/esm/chart/PeriodSelector.js +136 -0
- package/esm/chart/Point.js +111 -0
- package/esm/chart/__stories__/CartesianChart.stories.js +476 -0
- package/esm/chart/__stories__/Chart.stories.js +79 -0
- package/esm/chart/__stories__/PeriodSelector.stories.js +294 -0
- package/esm/chart/area/Area.js +85 -0
- package/esm/chart/area/AreaChart.js +146 -0
- package/esm/chart/area/DottedArea.js +128 -0
- package/esm/chart/area/GradientArea.js +110 -0
- package/esm/chart/area/SolidArea.js +24 -0
- package/esm/chart/area/__stories__/AreaChart.stories.js +100 -0
- package/esm/chart/area/index.js +7 -0
- package/esm/chart/axis/Axis.js +43 -0
- package/esm/chart/axis/XAxis.js +181 -0
- package/esm/chart/axis/YAxis.js +170 -0
- package/esm/chart/axis/__stories__/Axis.stories.js +277 -0
- package/esm/chart/axis/index.js +5 -0
- package/esm/chart/bar/Bar.js +67 -0
- package/esm/chart/bar/BarChart.js +147 -0
- package/esm/chart/bar/BarPlot.js +96 -0
- package/esm/chart/bar/BarStack.js +514 -0
- package/esm/chart/bar/BarStackGroup.js +89 -0
- package/esm/chart/bar/DefaultBar.js +78 -0
- package/esm/chart/bar/DefaultBarStack.js +82 -0
- package/esm/chart/bar/__stories__/BarChart.stories.js +282 -0
- package/esm/chart/bar/index.js +9 -0
- package/esm/chart/index.js +14 -0
- package/esm/chart/line/DottedLine.js +35 -0
- package/esm/chart/line/GradientLine.js +62 -0
- package/esm/chart/line/Line.js +139 -0
- package/esm/chart/line/LineChart.js +115 -0
- package/esm/chart/line/ReferenceLine.js +115 -0
- package/esm/chart/line/SolidLine.js +31 -0
- package/esm/chart/line/__stories__/LineChart.stories.js +2248 -0
- package/esm/chart/line/__stories__/ReferenceLine.stories.js +77 -0
- package/esm/chart/line/index.js +8 -0
- package/esm/chart/scrubber/Scrubber.js +186 -0
- package/esm/chart/scrubber/ScrubberBeacon.js +199 -0
- package/esm/chart/scrubber/ScrubberProvider.js +143 -0
- package/esm/chart/scrubber/index.js +2 -0
- package/esm/chart/text/ChartText.js +237 -0
- package/esm/chart/text/SmartChartTextGroup.js +210 -0
- package/esm/chart/text/index.js +4 -0
- package/esm/chart/utils/axis.js +592 -0
- package/esm/chart/utils/bar.js +24 -0
- package/esm/chart/utils/chart.js +229 -0
- package/esm/chart/utils/context.js +15 -0
- package/esm/chart/utils/index.js +9 -0
- package/esm/chart/utils/path.js +206 -0
- package/esm/chart/utils/point.js +118 -0
- package/esm/chart/utils/scale.js +48 -0
- package/esm/index.js +4 -1
- package/esm/sparkline/Sparkline.js +129 -16
- package/esm/sparkline/SparklineArea.js +7 -2
- package/esm/sparkline/SparklineAreaPattern.js +4 -2
- package/esm/sparkline/SparklineGradient.js +4 -0
- package/esm/sparkline/generateSparklineWithId.js +3 -2
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +5 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +5 -2
- package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +4 -0
- package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +27 -0
- package/package.json +11 -11
- package/dts/sparkline/__stories__/Sparkline.stories.d.ts +0 -3
- package/dts/sparkline/__stories__/Sparkline.stories.d.ts.map +0 -1
- package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts +0 -3
- package/dts/sparkline/__stories__/SparklineGradient.stories.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts +0 -3
- package/dts/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractive.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveHoverDate.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePanGestureHandler.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractivePeriodSelector.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/SparklineInteractiveTimeseriesPaths.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/__tests__/useMinMaxTransform.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts +0 -4
- package/dts/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive-header/__tests__/SparklineInteractiveHeader.test.d.ts.map +0 -1
- package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts +0 -2
- package/dts/sparkline/sparkline-interactive-header/__tests__/useSparklineInteractiveHeaderStyles.test.d.ts.map +0 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
const _excluded = ["series", "animate", "enableScrubbing", "xAxis", "yAxis", "inset", "onScrubberPositionChange", "children", "width", "height", "style", "allowOverflowGestures"];
|
|
2
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
3
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
4
|
+
import React, { forwardRef, memo, useCallback, useMemo } from 'react';
|
|
5
|
+
import { Svg } from 'react-native-svg';
|
|
6
|
+
import { useLayout } from '@coinbase/cds-mobile/hooks/useLayout';
|
|
7
|
+
import { Box } from '@coinbase/cds-mobile/layout';
|
|
8
|
+
import { ScrubberProvider } from './scrubber/ScrubberProvider';
|
|
9
|
+
import { CartesianChartProvider } from './ChartProvider';
|
|
10
|
+
import { defaultAxisId, defaultChartInset, getAxisConfig, getAxisDomain, getAxisRange, getAxisScale, getChartInset, getStackedSeriesData as calculateStackedSeriesData, useTotalAxisPadding } from './utils';
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
export const CartesianChart = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
|
|
13
|
+
let {
|
|
14
|
+
series,
|
|
15
|
+
animate = true,
|
|
16
|
+
enableScrubbing,
|
|
17
|
+
xAxis: xAxisConfigInput,
|
|
18
|
+
yAxis: yAxisConfigInput,
|
|
19
|
+
inset: insetInput,
|
|
20
|
+
onScrubberPositionChange,
|
|
21
|
+
children,
|
|
22
|
+
width = '100%',
|
|
23
|
+
height = '100%',
|
|
24
|
+
style,
|
|
25
|
+
allowOverflowGestures
|
|
26
|
+
} = _ref,
|
|
27
|
+
props = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
28
|
+
const [containerLayout, onContainerLayout] = useLayout();
|
|
29
|
+
const chartWidth = typeof width === 'number' ? width : containerLayout.width;
|
|
30
|
+
const chartHeight = typeof height === 'number' ? height : containerLayout.height;
|
|
31
|
+
const userInset = useMemo(() => {
|
|
32
|
+
return getChartInset(insetInput, defaultChartInset);
|
|
33
|
+
}, [insetInput]);
|
|
34
|
+
|
|
35
|
+
// there can only be one x axis but the helper function always returns an array
|
|
36
|
+
const xAxisConfig = useMemo(() => getAxisConfig('x', xAxisConfigInput)[0], [xAxisConfigInput]);
|
|
37
|
+
const yAxisConfig = useMemo(() => getAxisConfig('y', yAxisConfigInput), [yAxisConfigInput]);
|
|
38
|
+
const {
|
|
39
|
+
renderedAxes,
|
|
40
|
+
registerAxis,
|
|
41
|
+
unregisterAxis,
|
|
42
|
+
axisPadding
|
|
43
|
+
} = useTotalAxisPadding();
|
|
44
|
+
const totalInset = useMemo(() => ({
|
|
45
|
+
top: userInset.top + axisPadding.top,
|
|
46
|
+
right: userInset.right + axisPadding.right,
|
|
47
|
+
bottom: userInset.bottom + axisPadding.bottom,
|
|
48
|
+
left: userInset.left + axisPadding.left
|
|
49
|
+
}), [userInset, axisPadding]);
|
|
50
|
+
const chartRect = useMemo(() => {
|
|
51
|
+
if (chartWidth <= 0 || chartHeight <= 0) return {
|
|
52
|
+
x: 0,
|
|
53
|
+
y: 0,
|
|
54
|
+
width: 0,
|
|
55
|
+
height: 0
|
|
56
|
+
};
|
|
57
|
+
const availableWidth = chartWidth - totalInset.left - totalInset.right;
|
|
58
|
+
const availableHeight = chartHeight - totalInset.top - totalInset.bottom;
|
|
59
|
+
return {
|
|
60
|
+
x: totalInset.left,
|
|
61
|
+
y: totalInset.top,
|
|
62
|
+
width: availableWidth > 0 ? availableWidth : 0,
|
|
63
|
+
height: availableHeight > 0 ? availableHeight : 0
|
|
64
|
+
};
|
|
65
|
+
}, [chartHeight, chartWidth, totalInset]);
|
|
66
|
+
const xAxis = useMemo(() => {
|
|
67
|
+
if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return undefined;
|
|
68
|
+
const domain = getAxisDomain(xAxisConfig, series != null ? series : [], 'x');
|
|
69
|
+
const range = getAxisRange(xAxisConfig, chartRect, 'x');
|
|
70
|
+
const axisConfig = {
|
|
71
|
+
scaleType: xAxisConfig.scaleType,
|
|
72
|
+
domain,
|
|
73
|
+
range,
|
|
74
|
+
data: xAxisConfig.data,
|
|
75
|
+
categoryPadding: xAxisConfig.categoryPadding,
|
|
76
|
+
domainLimit: xAxisConfig.domainLimit
|
|
77
|
+
};
|
|
78
|
+
return axisConfig;
|
|
79
|
+
}, [xAxisConfig, series, chartRect]);
|
|
80
|
+
const yAxes = useMemo(() => {
|
|
81
|
+
const axes = new Map();
|
|
82
|
+
if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return axes;
|
|
83
|
+
yAxisConfig.forEach(axisParam => {
|
|
84
|
+
var _axisParam$id, _series$filter, _axisParam$domainLimi;
|
|
85
|
+
const axisId = (_axisParam$id = axisParam.id) != null ? _axisParam$id : defaultAxisId;
|
|
86
|
+
|
|
87
|
+
// Get relevant series data
|
|
88
|
+
const relevantSeries = (_series$filter = series == null ? void 0 : series.filter(s => {
|
|
89
|
+
var _s$yAxisId;
|
|
90
|
+
return ((_s$yAxisId = s.yAxisId) != null ? _s$yAxisId : defaultAxisId) === axisId;
|
|
91
|
+
})) != null ? _series$filter : [];
|
|
92
|
+
|
|
93
|
+
// Calculate domain and range in one pass
|
|
94
|
+
const domain = getAxisDomain(axisParam, relevantSeries, 'y');
|
|
95
|
+
const range = getAxisRange(axisParam, chartRect, 'y');
|
|
96
|
+
axes.set(axisId, {
|
|
97
|
+
scaleType: axisParam.scaleType,
|
|
98
|
+
domain,
|
|
99
|
+
range,
|
|
100
|
+
data: axisParam.data,
|
|
101
|
+
categoryPadding: axisParam.categoryPadding,
|
|
102
|
+
domainLimit: (_axisParam$domainLimi = axisParam.domainLimit) != null ? _axisParam$domainLimi : 'nice'
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
return axes;
|
|
106
|
+
}, [yAxisConfig, series, chartRect]);
|
|
107
|
+
const xScale = useMemo(() => {
|
|
108
|
+
if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0 || xAxis === undefined) return undefined;
|
|
109
|
+
return getAxisScale({
|
|
110
|
+
config: xAxis,
|
|
111
|
+
type: 'x',
|
|
112
|
+
range: xAxis.range,
|
|
113
|
+
dataDomain: xAxis.domain
|
|
114
|
+
});
|
|
115
|
+
}, [chartRect, xAxis]);
|
|
116
|
+
const yScales = useMemo(() => {
|
|
117
|
+
const scales = new Map();
|
|
118
|
+
if (!chartRect || chartRect.width <= 0 || chartRect.height <= 0) return scales;
|
|
119
|
+
yAxes.forEach((axisConfig, axisId) => {
|
|
120
|
+
const scale = getAxisScale({
|
|
121
|
+
config: axisConfig,
|
|
122
|
+
type: 'y',
|
|
123
|
+
range: axisConfig.range,
|
|
124
|
+
dataDomain: axisConfig.domain
|
|
125
|
+
});
|
|
126
|
+
if (scale) {
|
|
127
|
+
scales.set(axisId, scale);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
return scales;
|
|
131
|
+
}, [chartRect, yAxes]);
|
|
132
|
+
const getXAxis = useCallback(() => xAxis, [xAxis]);
|
|
133
|
+
const getYAxis = useCallback(id => yAxes.get(id != null ? id : defaultAxisId), [yAxes]);
|
|
134
|
+
const getXScale = useCallback(() => xScale, [xScale]);
|
|
135
|
+
const getYScale = useCallback(id => yScales.get(id != null ? id : defaultAxisId), [yScales]);
|
|
136
|
+
const getSeries = useCallback(seriesId => series == null ? void 0 : series.find(s => s.id === seriesId), [series]);
|
|
137
|
+
|
|
138
|
+
// Compute stacked data for series with stack properties
|
|
139
|
+
const stackedDataMap = useMemo(() => {
|
|
140
|
+
if (!series) return new Map();
|
|
141
|
+
return calculateStackedSeriesData(series);
|
|
142
|
+
}, [series]);
|
|
143
|
+
const getStackedSeriesData = useCallback(seriesId => {
|
|
144
|
+
if (!seriesId) return undefined;
|
|
145
|
+
return stackedDataMap.get(seriesId);
|
|
146
|
+
}, [stackedDataMap]);
|
|
147
|
+
const getAxisBounds = useCallback(axisId => {
|
|
148
|
+
const axis = renderedAxes.get(axisId);
|
|
149
|
+
if (!axis || !chartRect) return;
|
|
150
|
+
const axesAtPosition = Array.from(renderedAxes.values()).filter(a => a.position === axis.position).sort((a, b) => a.id.localeCompare(b.id));
|
|
151
|
+
const axisIndex = axesAtPosition.findIndex(a => a.id === axisId);
|
|
152
|
+
if (axisIndex === -1) return;
|
|
153
|
+
|
|
154
|
+
// Calculate offset from previous axes at the same position
|
|
155
|
+
const offsetFromPreviousAxes = axesAtPosition.slice(0, axisIndex).reduce((sum, a) => sum + a.size, 0);
|
|
156
|
+
if (axis.position === 'top') {
|
|
157
|
+
// Position above the chart rect, accounting for user inset
|
|
158
|
+
const startY = userInset.top + offsetFromPreviousAxes;
|
|
159
|
+
return {
|
|
160
|
+
x: chartRect.x,
|
|
161
|
+
y: startY,
|
|
162
|
+
width: chartRect.width,
|
|
163
|
+
height: axis.size
|
|
164
|
+
};
|
|
165
|
+
} else if (axis.position === 'bottom') {
|
|
166
|
+
// Position below the chart rect, accounting for user inset
|
|
167
|
+
const startY = chartRect.y + chartRect.height + offsetFromPreviousAxes;
|
|
168
|
+
return {
|
|
169
|
+
x: chartRect.x,
|
|
170
|
+
y: startY,
|
|
171
|
+
width: chartRect.width,
|
|
172
|
+
height: axis.size
|
|
173
|
+
};
|
|
174
|
+
} else if (axis.position === 'left') {
|
|
175
|
+
// Position to the left of the chart rect, accounting for user inset
|
|
176
|
+
const startX = userInset.left + offsetFromPreviousAxes;
|
|
177
|
+
return {
|
|
178
|
+
x: startX,
|
|
179
|
+
y: chartRect.y,
|
|
180
|
+
width: axis.size,
|
|
181
|
+
height: chartRect.height
|
|
182
|
+
};
|
|
183
|
+
} else {
|
|
184
|
+
// right - position to the right of the chart rect, accounting for user inset
|
|
185
|
+
const startX = chartRect.x + chartRect.width + offsetFromPreviousAxes;
|
|
186
|
+
return {
|
|
187
|
+
x: startX,
|
|
188
|
+
y: chartRect.y,
|
|
189
|
+
width: axis.size,
|
|
190
|
+
height: chartRect.height
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}, [renderedAxes, chartRect, userInset]);
|
|
194
|
+
const contextValue = useMemo(() => ({
|
|
195
|
+
series: series != null ? series : [],
|
|
196
|
+
getSeries,
|
|
197
|
+
getSeriesData: getStackedSeriesData,
|
|
198
|
+
animate,
|
|
199
|
+
width: chartWidth,
|
|
200
|
+
height: chartHeight,
|
|
201
|
+
getXAxis,
|
|
202
|
+
getYAxis,
|
|
203
|
+
getXScale,
|
|
204
|
+
getYScale,
|
|
205
|
+
drawingArea: chartRect,
|
|
206
|
+
registerAxis,
|
|
207
|
+
unregisterAxis,
|
|
208
|
+
getAxisBounds
|
|
209
|
+
}), [series, getSeries, getStackedSeriesData, animate, chartWidth, chartHeight, getXAxis, getYAxis, getXScale, getYScale, chartRect, registerAxis, unregisterAxis, getAxisBounds]);
|
|
210
|
+
const containerStyles = useMemo(() => {
|
|
211
|
+
const dynamicStyles = {};
|
|
212
|
+
if (typeof width === 'string') {
|
|
213
|
+
dynamicStyles.width = width;
|
|
214
|
+
}
|
|
215
|
+
if (typeof height === 'string') {
|
|
216
|
+
dynamicStyles.height = height;
|
|
217
|
+
}
|
|
218
|
+
return [style, dynamicStyles];
|
|
219
|
+
}, [style, width, height]);
|
|
220
|
+
return /*#__PURE__*/_jsx(CartesianChartProvider, {
|
|
221
|
+
value: contextValue,
|
|
222
|
+
children: /*#__PURE__*/_jsx(ScrubberProvider, {
|
|
223
|
+
allowOverflowGestures: allowOverflowGestures,
|
|
224
|
+
enableScrubbing: enableScrubbing,
|
|
225
|
+
onScrubberPositionChange: onScrubberPositionChange,
|
|
226
|
+
children: /*#__PURE__*/_jsx(Box, _extends({
|
|
227
|
+
ref: ref,
|
|
228
|
+
accessibilityLiveRegion: "polite",
|
|
229
|
+
accessibilityRole: "image",
|
|
230
|
+
onLayout: onContainerLayout,
|
|
231
|
+
style: containerStyles
|
|
232
|
+
}, props, {
|
|
233
|
+
children: /*#__PURE__*/_jsx(Svg, {
|
|
234
|
+
height: chartHeight,
|
|
235
|
+
width: chartWidth,
|
|
236
|
+
children: children
|
|
237
|
+
})
|
|
238
|
+
}))
|
|
239
|
+
})
|
|
240
|
+
});
|
|
241
|
+
}));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
const CartesianChartContext = /*#__PURE__*/createContext(undefined);
|
|
3
|
+
export const useCartesianChartContext = () => {
|
|
4
|
+
const context = useContext(CartesianChartContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error('useCartesianChartContext must be used within a CartesianChart component. See http://cds.coinbase.com/components/graphs/CartesianChart.');
|
|
7
|
+
}
|
|
8
|
+
return context;
|
|
9
|
+
};
|
|
10
|
+
export const CartesianChartProvider = CartesianChartContext.Provider;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const _excluded = ["clipRect", "clipOffset", "d", "fill", "stroke", "strokeWidth", "strokeOpacity", "fillOpacity", "strokeDasharray", "testID", "animate"];
|
|
2
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
3
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
4
|
+
import { memo, useCallback, useEffect, useId, useMemo, useRef } from 'react';
|
|
5
|
+
import Reanimated, { runOnJS, useAnimatedProps, useAnimatedReaction, useSharedValue, withTiming } from 'react-native-reanimated';
|
|
6
|
+
import { ClipPath, Defs, G, Path as SvgPath, Rect } from 'react-native-svg';
|
|
7
|
+
import { usePreviousValue } from '@coinbase/cds-common/hooks/usePreviousValue';
|
|
8
|
+
import * as interpolate from 'd3-interpolate-path';
|
|
9
|
+
import { useCartesianChartContext } from './ChartProvider';
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
const AnimatedRect = Reanimated.createAnimatedComponent(Rect);
|
|
12
|
+
const AnimatedSvgRect = /*#__PURE__*/memo(_ref => {
|
|
13
|
+
let {
|
|
14
|
+
width,
|
|
15
|
+
totalOffset,
|
|
16
|
+
rectProps
|
|
17
|
+
} = _ref;
|
|
18
|
+
const animatedWidth = useSharedValue(width + totalOffset);
|
|
19
|
+
const animatedProps = useAnimatedProps(() => {
|
|
20
|
+
return {
|
|
21
|
+
width: animatedWidth.value
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
animatedWidth.value = withTiming(width + totalOffset, {
|
|
26
|
+
duration: 1000
|
|
27
|
+
});
|
|
28
|
+
}, [animatedWidth, width, totalOffset]);
|
|
29
|
+
return /*#__PURE__*/_jsx(AnimatedRect, _extends({
|
|
30
|
+
animatedProps: animatedProps
|
|
31
|
+
}, rectProps));
|
|
32
|
+
});
|
|
33
|
+
export const Path = /*#__PURE__*/memo(_ref2 => {
|
|
34
|
+
let {
|
|
35
|
+
clipRect,
|
|
36
|
+
clipOffset,
|
|
37
|
+
d = '',
|
|
38
|
+
fill,
|
|
39
|
+
stroke,
|
|
40
|
+
strokeWidth,
|
|
41
|
+
strokeOpacity,
|
|
42
|
+
fillOpacity,
|
|
43
|
+
strokeDasharray,
|
|
44
|
+
testID,
|
|
45
|
+
animate: animateProp
|
|
46
|
+
} = _ref2,
|
|
47
|
+
pathProps = _objectWithoutPropertiesLoose(_ref2, _excluded);
|
|
48
|
+
const pathRef = useRef(null);
|
|
49
|
+
const {
|
|
50
|
+
animate: animateContext,
|
|
51
|
+
drawingArea: contextRect
|
|
52
|
+
} = useCartesianChartContext();
|
|
53
|
+
const rect = clipRect != null ? clipRect : contextRect;
|
|
54
|
+
const animate = animateProp != null ? animateProp : animateContext;
|
|
55
|
+
const clipPathId = useId();
|
|
56
|
+
const animationProgress = useSharedValue(0);
|
|
57
|
+
const targetPath = useMemo(() => d, [d]);
|
|
58
|
+
const previousPath = usePreviousValue(targetPath);
|
|
59
|
+
const fromPath = useMemo(() => {
|
|
60
|
+
if (!animate) return targetPath;
|
|
61
|
+
return previousPath != null ? previousPath : targetPath;
|
|
62
|
+
}, [animate, previousPath, targetPath]);
|
|
63
|
+
const pathInterpolator = useMemo(() => interpolate.interpolatePath(fromPath, targetPath), [fromPath, targetPath]);
|
|
64
|
+
const updatePath = useCallback(progress => {
|
|
65
|
+
var _pathRef$current;
|
|
66
|
+
if (!pathInterpolator) return;
|
|
67
|
+
const val = Number(progress.toFixed(4));
|
|
68
|
+
(_pathRef$current = pathRef.current) == null || _pathRef$current.setNativeProps({
|
|
69
|
+
d: pathInterpolator(val)
|
|
70
|
+
});
|
|
71
|
+
}, [pathInterpolator]);
|
|
72
|
+
useAnimatedReaction(() => animationProgress.value, progress => {
|
|
73
|
+
'worklet';
|
|
74
|
+
|
|
75
|
+
runOnJS(updatePath)(progress);
|
|
76
|
+
}, [updatePath]);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (!pathRef.current) return;
|
|
79
|
+
if (!animate || !pathInterpolator) {
|
|
80
|
+
pathRef.current.setNativeProps({
|
|
81
|
+
d: targetPath
|
|
82
|
+
});
|
|
83
|
+
animationProgress.value = 1;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
animationProgress.value = 0;
|
|
87
|
+
animationProgress.value = withTiming(1, {
|
|
88
|
+
duration: 200
|
|
89
|
+
});
|
|
90
|
+
}, [animate, animationProgress, targetPath, pathInterpolator]);
|
|
91
|
+
if (!d || !rect) return;
|
|
92
|
+
|
|
93
|
+
// The clip offset provides extra padding to prevent path from being cut off
|
|
94
|
+
// Area charts typically use offset=0 for exact clipping, while lines use offset=2 for breathing room
|
|
95
|
+
const totalOffset = (clipOffset != null ? clipOffset : 0) * 2; // Applied on both sides
|
|
96
|
+
|
|
97
|
+
return /*#__PURE__*/_jsxs(G, {
|
|
98
|
+
children: [/*#__PURE__*/_jsx(Defs, {
|
|
99
|
+
children: animate ? /*#__PURE__*/_jsx(ClipPath, {
|
|
100
|
+
id: clipPathId,
|
|
101
|
+
children: /*#__PURE__*/_jsx(AnimatedSvgRect, {
|
|
102
|
+
rectProps: {
|
|
103
|
+
height: rect.height + totalOffset,
|
|
104
|
+
x: rect.x - (clipOffset != null ? clipOffset : 0),
|
|
105
|
+
y: rect.y - (clipOffset != null ? clipOffset : 0)
|
|
106
|
+
},
|
|
107
|
+
totalOffset: totalOffset,
|
|
108
|
+
width: rect.width
|
|
109
|
+
})
|
|
110
|
+
}) : /*#__PURE__*/_jsx(ClipPath, {
|
|
111
|
+
id: clipPathId,
|
|
112
|
+
children: /*#__PURE__*/_jsx(Rect, {
|
|
113
|
+
height: contextRect.height + totalOffset,
|
|
114
|
+
width: contextRect.width + totalOffset,
|
|
115
|
+
x: contextRect.x - (clipOffset != null ? clipOffset : 0),
|
|
116
|
+
y: contextRect.y - (clipOffset != null ? clipOffset : 0)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
}), /*#__PURE__*/_jsx(SvgPath, _extends({
|
|
120
|
+
ref: pathRef,
|
|
121
|
+
clipPath: "url(#" + clipPathId + ")",
|
|
122
|
+
clipRule: "nonzero",
|
|
123
|
+
d: fromPath,
|
|
124
|
+
fill: fill,
|
|
125
|
+
fillOpacity: fillOpacity,
|
|
126
|
+
stroke: stroke,
|
|
127
|
+
strokeDasharray: strokeDasharray,
|
|
128
|
+
strokeOpacity: strokeOpacity,
|
|
129
|
+
strokeWidth: strokeWidth,
|
|
130
|
+
testID: testID
|
|
131
|
+
}, pathProps))]
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const _excluded = ["color", "label", "font", "hideDot", "style"],
|
|
2
|
+
_excluded2 = ["background", "activeBackground", "width", "justifyContent", "TabComponent", "TabsActiveIndicatorComponent"];
|
|
3
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
4
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
5
|
+
import React, { forwardRef, memo, useMemo } from 'react';
|
|
6
|
+
import { StyleSheet, View } from 'react-native';
|
|
7
|
+
import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
|
8
|
+
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
9
|
+
import { SegmentedTabs } from '@coinbase/cds-mobile/tabs';
|
|
10
|
+
import { SegmentedTab } from '@coinbase/cds-mobile/tabs/SegmentedTab';
|
|
11
|
+
import { tabsSpringConfig } from '@coinbase/cds-mobile/tabs/Tabs';
|
|
12
|
+
import { Text } from '@coinbase/cds-mobile/typography/Text';
|
|
13
|
+
|
|
14
|
+
// Animated active indicator to support smooth transition of background color
|
|
15
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
16
|
+
export const PeriodSelectorActiveIndicator = _ref => {
|
|
17
|
+
let {
|
|
18
|
+
activeTabRect,
|
|
19
|
+
background = 'bgPrimaryWash',
|
|
20
|
+
position = 'absolute',
|
|
21
|
+
borderRadius = 1000
|
|
22
|
+
} = _ref;
|
|
23
|
+
const theme = useTheme();
|
|
24
|
+
const {
|
|
25
|
+
width,
|
|
26
|
+
height,
|
|
27
|
+
x
|
|
28
|
+
} = activeTabRect;
|
|
29
|
+
|
|
30
|
+
// Get the target background color
|
|
31
|
+
const backgroundColorKey = background;
|
|
32
|
+
const targetColor = theme.color[backgroundColorKey] || background;
|
|
33
|
+
|
|
34
|
+
// Track previous values for first render detection
|
|
35
|
+
const previousActiveTabRect = React.useRef(activeTabRect);
|
|
36
|
+
const previousColor = React.useRef(targetColor);
|
|
37
|
+
|
|
38
|
+
// Combined animated value for position, size, and color
|
|
39
|
+
const newAnimatedValues = {
|
|
40
|
+
x,
|
|
41
|
+
width,
|
|
42
|
+
backgroundColor: targetColor
|
|
43
|
+
};
|
|
44
|
+
const animatedValues = useSharedValue(newAnimatedValues);
|
|
45
|
+
const isFirstRenderWithWidth = previousActiveTabRect.current.width === 0 && activeTabRect.width > 0;
|
|
46
|
+
if (previousActiveTabRect.current !== activeTabRect || previousColor.current !== targetColor) {
|
|
47
|
+
previousActiveTabRect.current = activeTabRect;
|
|
48
|
+
previousColor.current = targetColor;
|
|
49
|
+
animatedValues.value = isFirstRenderWithWidth ? newAnimatedValues : withSpring(newAnimatedValues, tabsSpringConfig);
|
|
50
|
+
}
|
|
51
|
+
const animatedStyles = useAnimatedStyle(() => ({
|
|
52
|
+
transform: [{
|
|
53
|
+
translateX: animatedValues.value.x
|
|
54
|
+
}],
|
|
55
|
+
width: animatedValues.value.width,
|
|
56
|
+
backgroundColor: animatedValues.value.backgroundColor
|
|
57
|
+
}), [animatedValues]);
|
|
58
|
+
if (!width) return null;
|
|
59
|
+
return /*#__PURE__*/_jsx(Animated.View, {
|
|
60
|
+
style: [{
|
|
61
|
+
position: position,
|
|
62
|
+
height,
|
|
63
|
+
borderRadius
|
|
64
|
+
}, animatedStyles],
|
|
65
|
+
testID: "period-selector-active-indicator"
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
const styles = StyleSheet.create({
|
|
69
|
+
liveContainer: {
|
|
70
|
+
flexDirection: 'row',
|
|
71
|
+
alignItems: 'center'
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
export const LiveTabLabel = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
75
|
+
let {
|
|
76
|
+
color = 'fgNegative',
|
|
77
|
+
label = 'LIVE',
|
|
78
|
+
font = 'label1',
|
|
79
|
+
hideDot,
|
|
80
|
+
style
|
|
81
|
+
} = _ref2,
|
|
82
|
+
props = _objectWithoutPropertiesLoose(_ref2, _excluded);
|
|
83
|
+
const theme = useTheme();
|
|
84
|
+
const colorKey = color;
|
|
85
|
+
const textColor = theme.color[colorKey] || color;
|
|
86
|
+
const dotStyle = useMemo(() => ({
|
|
87
|
+
width: theme.space[1],
|
|
88
|
+
height: theme.space[1],
|
|
89
|
+
borderRadius: 1000,
|
|
90
|
+
marginRight: theme.space[0.75],
|
|
91
|
+
backgroundColor: textColor
|
|
92
|
+
}), [theme.space, textColor]);
|
|
93
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
94
|
+
ref: ref,
|
|
95
|
+
style: [styles.liveContainer, style],
|
|
96
|
+
children: [!hideDot && /*#__PURE__*/_jsx(View, {
|
|
97
|
+
style: dotStyle
|
|
98
|
+
}), /*#__PURE__*/_jsx(Text, _extends({
|
|
99
|
+
color: color,
|
|
100
|
+
font: font
|
|
101
|
+
}, props, {
|
|
102
|
+
children: label
|
|
103
|
+
}))]
|
|
104
|
+
});
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
// Custom tab component with primary color for active state
|
|
108
|
+
const PeriodSelectorTab = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/_jsx(SegmentedTab, _extends({
|
|
109
|
+
ref: ref,
|
|
110
|
+
activeColor: "fgPrimary",
|
|
111
|
+
font: "label1"
|
|
112
|
+
}, props))));
|
|
113
|
+
/**
|
|
114
|
+
* PeriodSelector is a specialized version of SegmentedTabs optimized for chart period selection.
|
|
115
|
+
* It provides transparent background, primary wash active state, and full-width layout by default.
|
|
116
|
+
*/
|
|
117
|
+
export const PeriodSelector = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref3, ref) => {
|
|
118
|
+
let {
|
|
119
|
+
background = 'transparent',
|
|
120
|
+
activeBackground = 'bgPrimaryWash',
|
|
121
|
+
width = '100%',
|
|
122
|
+
justifyContent = 'space-between',
|
|
123
|
+
TabComponent = PeriodSelectorTab,
|
|
124
|
+
TabsActiveIndicatorComponent = PeriodSelectorActiveIndicator
|
|
125
|
+
} = _ref3,
|
|
126
|
+
props = _objectWithoutPropertiesLoose(_ref3, _excluded2);
|
|
127
|
+
return /*#__PURE__*/_jsx(SegmentedTabs, _extends({
|
|
128
|
+
ref: ref,
|
|
129
|
+
TabComponent: TabComponent,
|
|
130
|
+
TabsActiveIndicatorComponent: TabsActiveIndicatorComponent,
|
|
131
|
+
activeBackground: activeBackground,
|
|
132
|
+
background: background,
|
|
133
|
+
justifyContent: justifyContent,
|
|
134
|
+
width: width
|
|
135
|
+
}, props));
|
|
136
|
+
}));
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import { memo, useEffect, useMemo } from 'react';
|
|
3
|
+
import { Circle, G } from 'react-native-svg';
|
|
4
|
+
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
5
|
+
import { useCartesianChartContext } from './ChartProvider';
|
|
6
|
+
import { ChartText } from './text';
|
|
7
|
+
import { projectPoint, useScrubberContext } from './utils';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Parameters passed to renderPoints callback function.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Shared configuration for point appearance and behavior.
|
|
15
|
+
* Used by line-associated points rendered via Line/LineChart components.
|
|
16
|
+
*/
|
|
17
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
export const Point = /*#__PURE__*/memo(_ref => {
|
|
19
|
+
let {
|
|
20
|
+
dataX,
|
|
21
|
+
dataY,
|
|
22
|
+
yAxisId,
|
|
23
|
+
fill,
|
|
24
|
+
radius = 4,
|
|
25
|
+
opacity,
|
|
26
|
+
onPress,
|
|
27
|
+
onScrubberEnter,
|
|
28
|
+
stroke,
|
|
29
|
+
strokeWidth = 2,
|
|
30
|
+
accessibilityLabel,
|
|
31
|
+
label,
|
|
32
|
+
labelProps,
|
|
33
|
+
pixelCoordinates,
|
|
34
|
+
testID
|
|
35
|
+
} = _ref;
|
|
36
|
+
const theme = useTheme();
|
|
37
|
+
const effectiveStroke = stroke != null ? stroke : theme.color.bg;
|
|
38
|
+
const {
|
|
39
|
+
getXScale,
|
|
40
|
+
getYScale
|
|
41
|
+
} = useCartesianChartContext();
|
|
42
|
+
const {
|
|
43
|
+
scrubberPosition
|
|
44
|
+
} = useScrubberContext();
|
|
45
|
+
const xScale = getXScale();
|
|
46
|
+
const yScale = getYScale(yAxisId);
|
|
47
|
+
|
|
48
|
+
// Scrubber detection: check if this point is highlighted by the scrubber
|
|
49
|
+
const isScrubberHighlighted = scrubberPosition !== undefined && scrubberPosition === dataX;
|
|
50
|
+
|
|
51
|
+
// Use provided pixelCoordinates or calculate from data coordinates
|
|
52
|
+
const pixelCoordinate = useMemo(() => {
|
|
53
|
+
if (pixelCoordinates) {
|
|
54
|
+
return pixelCoordinates;
|
|
55
|
+
}
|
|
56
|
+
if (!xScale || !yScale) {
|
|
57
|
+
return {
|
|
58
|
+
x: 0,
|
|
59
|
+
y: 0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return projectPoint({
|
|
63
|
+
x: dataX,
|
|
64
|
+
y: dataY,
|
|
65
|
+
xScale,
|
|
66
|
+
yScale
|
|
67
|
+
});
|
|
68
|
+
}, [pixelCoordinates, xScale, yScale, dataX, dataY]);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (isScrubberHighlighted && onScrubberEnter) {
|
|
71
|
+
onScrubberEnter({
|
|
72
|
+
x: pixelCoordinate.x,
|
|
73
|
+
y: pixelCoordinate.y
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}, [isScrubberHighlighted, onScrubberEnter, pixelCoordinate.x, pixelCoordinate.y]);
|
|
77
|
+
if (!xScale || !yScale) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
81
|
+
children: [/*#__PURE__*/_jsx(G, {
|
|
82
|
+
opacity: opacity,
|
|
83
|
+
testID: testID,
|
|
84
|
+
transform: [{
|
|
85
|
+
translateX: pixelCoordinate.x
|
|
86
|
+
}, {
|
|
87
|
+
translateY: pixelCoordinate.y
|
|
88
|
+
}],
|
|
89
|
+
children: /*#__PURE__*/_jsx(Circle, {
|
|
90
|
+
accessibilityLabel: accessibilityLabel,
|
|
91
|
+
cx: 0,
|
|
92
|
+
cy: 0,
|
|
93
|
+
fill: fill != null ? fill : theme.color.fgPrimary,
|
|
94
|
+
onPress: onPress ? event => onPress({
|
|
95
|
+
dataX,
|
|
96
|
+
dataY,
|
|
97
|
+
x: pixelCoordinate.x,
|
|
98
|
+
y: pixelCoordinate.y
|
|
99
|
+
}) : undefined,
|
|
100
|
+
r: radius,
|
|
101
|
+
stroke: effectiveStroke,
|
|
102
|
+
strokeWidth: strokeWidth
|
|
103
|
+
})
|
|
104
|
+
}), label && /*#__PURE__*/_jsx(ChartText, _extends({
|
|
105
|
+
x: pixelCoordinate.x,
|
|
106
|
+
y: pixelCoordinate.y
|
|
107
|
+
}, labelProps, {
|
|
108
|
+
children: label
|
|
109
|
+
}))]
|
|
110
|
+
});
|
|
111
|
+
});
|