@coinbase/cds-mobile-visualization 3.4.0-beta.9 → 3.6.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 +150 -0
- package/dts/chart/CartesianChart.d.ts +92 -7
- package/dts/chart/CartesianChart.d.ts.map +1 -1
- package/dts/chart/ChartContextBridge.d.ts.map +1 -1
- package/dts/chart/ChartProvider.d.ts +3 -0
- package/dts/chart/ChartProvider.d.ts.map +1 -1
- package/dts/chart/Path.d.ts +43 -13
- package/dts/chart/Path.d.ts.map +1 -1
- package/dts/chart/PeriodSelector.d.ts +20 -5
- package/dts/chart/PeriodSelector.d.ts.map +1 -1
- package/dts/chart/area/Area.d.ts +14 -11
- package/dts/chart/area/Area.d.ts.map +1 -1
- package/dts/chart/area/AreaChart.d.ts +33 -9
- package/dts/chart/area/AreaChart.d.ts.map +1 -1
- package/dts/chart/area/DottedArea.d.ts.map +1 -1
- package/dts/chart/area/GradientArea.d.ts.map +1 -1
- package/dts/chart/area/SolidArea.d.ts.map +1 -1
- package/dts/chart/axis/Axis.d.ts +22 -42
- package/dts/chart/axis/Axis.d.ts.map +1 -1
- package/dts/chart/axis/XAxis.d.ts +6 -0
- package/dts/chart/axis/XAxis.d.ts.map +1 -1
- package/dts/chart/axis/YAxis.d.ts +1 -0
- package/dts/chart/axis/YAxis.d.ts.map +1 -1
- package/dts/chart/bar/Bar.d.ts +59 -51
- package/dts/chart/bar/Bar.d.ts.map +1 -1
- package/dts/chart/bar/BarChart.d.ts +56 -11
- package/dts/chart/bar/BarChart.d.ts.map +1 -1
- package/dts/chart/bar/BarPlot.d.ts +2 -1
- package/dts/chart/bar/BarPlot.d.ts.map +1 -1
- package/dts/chart/bar/BarStack.d.ts +45 -20
- package/dts/chart/bar/BarStack.d.ts.map +1 -1
- package/dts/chart/bar/BarStackGroup.d.ts +2 -1
- package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
- package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
- package/dts/chart/bar/PercentageBarChart.d.ts +106 -0
- package/dts/chart/bar/PercentageBarChart.d.ts.map +1 -0
- package/dts/chart/bar/index.d.ts +1 -0
- package/dts/chart/bar/index.d.ts.map +1 -1
- package/dts/chart/gradient/Gradient.d.ts +5 -0
- package/dts/chart/gradient/Gradient.d.ts.map +1 -1
- package/dts/chart/index.d.ts +1 -0
- package/dts/chart/index.d.ts.map +1 -1
- package/dts/chart/legend/DefaultLegendEntry.d.ts +5 -0
- package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts +5 -0
- package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
- package/dts/chart/legend/Legend.d.ts +168 -0
- package/dts/chart/legend/Legend.d.ts.map +1 -0
- package/dts/chart/legend/index.d.ts +4 -0
- package/dts/chart/legend/index.d.ts.map +1 -0
- package/dts/chart/line/DottedLine.d.ts.map +1 -1
- package/dts/chart/line/Line.d.ts +23 -19
- package/dts/chart/line/Line.d.ts.map +1 -1
- package/dts/chart/line/LineChart.d.ts +26 -9
- package/dts/chart/line/LineChart.d.ts.map +1 -1
- package/dts/chart/line/ReferenceLine.d.ts +1 -0
- package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
- package/dts/chart/line/SolidLine.d.ts.map +1 -1
- package/dts/chart/point/Point.d.ts +26 -2
- package/dts/chart/point/Point.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +32 -2
- package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -1
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +2 -1
- package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -1
- package/dts/chart/scrubber/Scrubber.d.ts +86 -17
- package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts +12 -0
- package/dts/chart/scrubber/ScrubberAccessibilityView.d.ts.map +1 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +10 -0
- package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +16 -1
- package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -1
- package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
- package/dts/chart/utils/axis.d.ts +45 -10
- package/dts/chart/utils/axis.d.ts.map +1 -1
- package/dts/chart/utils/bar.d.ts +195 -0
- package/dts/chart/utils/bar.d.ts.map +1 -1
- package/dts/chart/utils/chart.d.ts +32 -0
- package/dts/chart/utils/chart.d.ts.map +1 -1
- package/dts/chart/utils/context.d.ts +21 -6
- package/dts/chart/utils/context.d.ts.map +1 -1
- package/dts/chart/utils/gradient.d.ts +3 -1
- package/dts/chart/utils/gradient.d.ts.map +1 -1
- package/dts/chart/utils/path.d.ts +26 -0
- package/dts/chart/utils/path.d.ts.map +1 -1
- package/dts/chart/utils/point.d.ts +24 -12
- package/dts/chart/utils/point.d.ts.map +1 -1
- package/dts/chart/utils/scale.d.ts +11 -0
- package/dts/chart/utils/scale.d.ts.map +1 -1
- package/dts/chart/utils/scrubber.d.ts +2 -1
- package/dts/chart/utils/scrubber.d.ts.map +1 -1
- package/dts/chart/utils/transition.d.ts +63 -22
- package/dts/chart/utils/transition.d.ts.map +1 -1
- package/dts/sparkline/Sparkline.d.ts +2 -1
- package/dts/sparkline/Sparkline.d.ts.map +1 -1
- package/dts/sparkline/SparklineArea.d.ts +2 -1
- package/dts/sparkline/SparklineArea.d.ts.map +1 -1
- package/dts/sparkline/SparklineGradient.d.ts +2 -1
- package/dts/sparkline/SparklineGradient.d.ts.map +1 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +2 -1
- package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -1
- package/esm/chart/CartesianChart.js +176 -82
- package/esm/chart/ChartContextBridge.js +14 -3
- package/esm/chart/ChartProvider.js +2 -2
- package/esm/chart/Path.js +68 -31
- package/esm/chart/PeriodSelector.js +5 -1
- package/esm/chart/__stories__/CartesianChart.stories.js +16 -80
- package/esm/chart/__stories__/ChartAccessibility.stories.js +721 -0
- package/esm/chart/__stories__/ChartTransitions.stories.js +625 -0
- package/esm/chart/__stories__/PeriodSelector.stories.js +99 -1
- package/esm/chart/area/Area.js +21 -9
- package/esm/chart/area/AreaChart.js +18 -13
- package/esm/chart/area/DottedArea.js +28 -18
- package/esm/chart/area/GradientArea.js +14 -7
- package/esm/chart/area/SolidArea.js +6 -2
- package/esm/chart/area/__stories__/AreaChart.stories.js +47 -5
- package/esm/chart/axis/Axis.js +5 -41
- package/esm/chart/axis/XAxis.js +116 -47
- package/esm/chart/axis/YAxis.js +105 -26
- package/esm/chart/axis/__stories__/Axis.stories.js +324 -48
- package/esm/chart/bar/Bar.js +17 -15
- package/esm/chart/bar/BarChart.js +38 -33
- package/esm/chart/bar/BarPlot.js +40 -45
- package/esm/chart/bar/BarStack.js +92 -475
- package/esm/chart/bar/BarStackGroup.js +37 -27
- package/esm/chart/bar/DefaultBar.js +41 -18
- package/esm/chart/bar/DefaultBarStack.js +25 -9
- package/esm/chart/bar/PercentageBarChart.js +99 -0
- package/esm/chart/bar/__stories__/BarChart.stories.js +721 -54
- package/esm/chart/bar/__stories__/PercentageBarChart.stories.js +833 -0
- package/esm/chart/bar/index.js +1 -0
- package/esm/chart/gradient/Gradient.js +2 -1
- package/esm/chart/index.js +1 -0
- package/esm/chart/legend/DefaultLegendEntry.js +42 -0
- package/esm/chart/legend/DefaultLegendShape.js +64 -0
- package/esm/chart/legend/Legend.js +59 -0
- package/esm/chart/legend/__stories__/Legend.stories.js +574 -0
- package/esm/chart/legend/index.js +3 -0
- package/esm/chart/line/DottedLine.js +6 -2
- package/esm/chart/line/Line.js +42 -38
- package/esm/chart/line/LineChart.js +36 -12
- package/esm/chart/line/SolidLine.js +6 -2
- package/esm/chart/line/__stories__/LineChart.stories.js +236 -590
- package/esm/chart/line/__stories__/ReferenceLine.stories.js +95 -1
- package/esm/chart/point/Point.js +35 -36
- package/esm/chart/scrubber/DefaultScrubberBeacon.js +41 -38
- package/esm/chart/scrubber/DefaultScrubberLabel.js +26 -10
- package/esm/chart/scrubber/Scrubber.js +67 -35
- package/esm/chart/scrubber/ScrubberAccessibilityView.js +177 -0
- package/esm/chart/scrubber/ScrubberBeaconGroup.js +30 -22
- package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +35 -8
- package/esm/chart/scrubber/ScrubberProvider.js +29 -24
- package/esm/chart/scrubber/__stories__/Scrubber.stories.js +946 -0
- package/esm/chart/utils/axis.js +88 -44
- package/esm/chart/utils/bar.js +829 -0
- package/esm/chart/utils/chart.js +34 -7
- package/esm/chart/utils/context.js +7 -0
- package/esm/chart/utils/gradient.js +8 -4
- package/esm/chart/utils/path.js +91 -61
- package/esm/chart/utils/point.js +92 -39
- package/esm/chart/utils/scale.js +13 -2
- package/esm/chart/utils/scrubber.js +12 -5
- package/esm/chart/utils/transition.js +116 -60
- package/esm/sparkline/Sparkline.js +2 -1
- package/esm/sparkline/SparklineArea.js +2 -1
- package/esm/sparkline/SparklineGradient.js +2 -1
- package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +2 -1
- package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
- package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +2 -0
- package/package.json +5 -6
- package/esm/chart/__stories__/Chart.stories.js +0 -77
|
@@ -6,6 +6,17 @@ function _extends() { return _extends = Object.assign ? Object.assign.bind() : f
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import * as React from 'react';
|
|
9
|
+
import { ThemeContext } from '@coinbase/cds-mobile/system/ThemeProvider';
|
|
10
|
+
import { ScrubberContext } from './utils/context';
|
|
11
|
+
import { CartesianChartContext } from './ChartProvider';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whitelist of contexts that should be bridged to the Skia canvas.
|
|
15
|
+
* Only these contexts will be made available inside the chart's Skia tree.
|
|
16
|
+
* This improves performance by avoiding the overhead of rendering every bridged context.
|
|
17
|
+
*/
|
|
18
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
19
|
+
const BRIDGED_CONTEXTS = [ThemeContext, CartesianChartContext, ScrubberContext];
|
|
9
20
|
|
|
10
21
|
/**
|
|
11
22
|
* Represents a react-internal tree node.
|
|
@@ -14,7 +25,7 @@ import * as React from 'react';
|
|
|
14
25
|
/**
|
|
15
26
|
* Represents a tree node selector for traversal.
|
|
16
27
|
*/
|
|
17
|
-
|
|
28
|
+
|
|
18
29
|
/**
|
|
19
30
|
* Traverses up or down a React tree, return `true` to stop and select a node.
|
|
20
31
|
*/
|
|
@@ -104,7 +115,7 @@ function useTreeNode() {
|
|
|
104
115
|
return treeNode;
|
|
105
116
|
}
|
|
106
117
|
/**
|
|
107
|
-
* Returns a map of
|
|
118
|
+
* Returns a map of whitelisted contexts and their values.
|
|
108
119
|
*/
|
|
109
120
|
function useContextMap() {
|
|
110
121
|
const treeNode = useTreeNode();
|
|
@@ -118,7 +129,7 @@ function useContextMap() {
|
|
|
118
129
|
// https://github.com/facebook/react/pull/28226
|
|
119
130
|
const enableRenderableContext = node.type._context === undefined && node.type.Provider === node.type;
|
|
120
131
|
const context = enableRenderableContext ? node.type : node.type._context;
|
|
121
|
-
if (context && context !== TreeNodeContext && !contextMap.has(context)) {
|
|
132
|
+
if (context && context !== TreeNodeContext && BRIDGED_CONTEXTS.includes(context) && !contextMap.has(context)) {
|
|
122
133
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
123
134
|
contextMap.set(context, React.useContext(wrapContext(context)));
|
|
124
135
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createContext, useContext } from 'react';
|
|
2
|
-
const CartesianChartContext = /*#__PURE__*/createContext(undefined);
|
|
2
|
+
export const CartesianChartContext = /*#__PURE__*/createContext(undefined);
|
|
3
3
|
export const useCartesianChartContext = () => {
|
|
4
4
|
const context = useContext(CartesianChartContext);
|
|
5
5
|
if (!context) {
|
|
6
|
-
throw new Error('useCartesianChartContext must be used within a CartesianChart component. See
|
|
6
|
+
throw new Error('useCartesianChartContext must be used within a CartesianChart component. See https://cds.coinbase.com/components/charts/CartesianChart.');
|
|
7
7
|
}
|
|
8
8
|
return context;
|
|
9
9
|
};
|
package/esm/chart/Path.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
const _excluded = ["d", "initialPath", "fill", "fillOpacity", "stroke", "strokeOpacity", "strokeWidth", "strokeCap", "strokeJoin", "children", "
|
|
2
|
-
_excluded2 = ["animate", "clipRect", "clipPath", "clipOffset", "d", "initialPath", "fill", "fillOpacity", "stroke", "strokeOpacity", "strokeWidth", "strokeCap", "strokeJoin", "children", "transition"];
|
|
1
|
+
const _excluded = ["d", "initialPath", "fill", "fillOpacity", "stroke", "strokeOpacity", "strokeWidth", "strokeCap", "strokeJoin", "children", "transitions"],
|
|
2
|
+
_excluded2 = ["animate", "clipRect", "clipPath", "clipOffset", "d", "initialPath", "fill", "fillOpacity", "stroke", "strokeOpacity", "strokeWidth", "strokeCap", "strokeJoin", "children", "transitions", "transition"];
|
|
3
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
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 { memo, useEffect, useMemo } from 'react';
|
|
6
|
-
import { useDerivedValue, useSharedValue
|
|
5
|
+
import { memo, useEffect, useMemo, useRef } from 'react';
|
|
6
|
+
import { useDerivedValue, useSharedValue } from 'react-native-reanimated';
|
|
7
7
|
import { Group, Path as SkiaPath, Skia, usePathInterpolation } from '@shopify/react-native-skia';
|
|
8
|
-
import {
|
|
8
|
+
import { defaultPathEnterTransition } from './utils/path';
|
|
9
|
+
import { buildTransition, defaultTransition, getTransition, usePathTransition } from './utils/transition';
|
|
9
10
|
import { useCartesianChartContext } from './ChartProvider';
|
|
10
11
|
import { unwrapAnimatedValue } from './utils';
|
|
11
12
|
|
|
@@ -26,17 +27,14 @@ const AnimatedPath = /*#__PURE__*/memo(_ref => {
|
|
|
26
27
|
strokeCap,
|
|
27
28
|
strokeJoin,
|
|
28
29
|
children,
|
|
29
|
-
|
|
30
|
+
transitions
|
|
30
31
|
} = _ref,
|
|
31
32
|
pathProps = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
32
33
|
const isDAnimated = typeof d !== 'string';
|
|
33
|
-
|
|
34
|
-
// When d is animated, usePathTransition handles static path transitions.
|
|
35
|
-
// For animated d values, we skip usePathTransition and use useDerivedValue directly.
|
|
36
34
|
const animatedPath = usePathTransition({
|
|
37
35
|
currentPath: isDAnimated ? '' : d,
|
|
38
36
|
initialPath,
|
|
39
|
-
|
|
37
|
+
transitions
|
|
40
38
|
});
|
|
41
39
|
const isFilled = fill !== undefined && fill !== 'none';
|
|
42
40
|
const isStroked = stroke !== undefined && stroke !== 'none';
|
|
@@ -84,28 +82,56 @@ export const Path = /*#__PURE__*/memo(props => {
|
|
|
84
82
|
strokeCap,
|
|
85
83
|
strokeJoin,
|
|
86
84
|
children,
|
|
85
|
+
transitions,
|
|
87
86
|
transition
|
|
88
87
|
} = props,
|
|
89
88
|
pathProps = _objectWithoutPropertiesLoose(props, _excluded2);
|
|
90
89
|
const context = useCartesianChartContext();
|
|
91
90
|
const rect = clipRect != null ? clipRect : context.drawingArea;
|
|
92
91
|
const animate = animateProp != null ? animateProp : context.animate;
|
|
92
|
+
const isReady = !!context.getXScale();
|
|
93
|
+
const enterTransition = useMemo(() => getTransition(transitions == null ? void 0 : transitions.enter, animate, defaultPathEnterTransition), [animate, transitions == null ? void 0 : transitions.enter]);
|
|
94
|
+
const updateTransition = useMemo(() => getTransition((transitions == null ? void 0 : transitions.update) !== undefined ? transitions.update : transition, animate, defaultTransition), [animate, transitions == null ? void 0 : transitions.update, transition]);
|
|
95
|
+
const enterOpacityTransition = useMemo(() => {
|
|
96
|
+
if (!animate) return null;
|
|
97
|
+
return transitions == null ? void 0 : transitions.enterOpacity;
|
|
98
|
+
}, [animate, transitions == null ? void 0 : transitions.enterOpacity]);
|
|
99
|
+
const animateEnterOpacity = Boolean(enterOpacityTransition);
|
|
100
|
+
const enterOpacity = useSharedValue(animateEnterOpacity ? 0 : 1);
|
|
101
|
+
const hasAnimatedEnterOpacity = useRef(false);
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (hasAnimatedEnterOpacity.current) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!animateEnterOpacity) {
|
|
107
|
+
hasAnimatedEnterOpacity.current = true;
|
|
108
|
+
enterOpacity.value = 1;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (!isReady) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (enterOpacityTransition === undefined || enterOpacityTransition === null) {
|
|
115
|
+
enterOpacity.value = 1;
|
|
116
|
+
hasAnimatedEnterOpacity.current = true;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
hasAnimatedEnterOpacity.current = true;
|
|
120
|
+
enterOpacity.value = buildTransition(1, enterOpacityTransition);
|
|
121
|
+
}, [animateEnterOpacity, isReady, enterOpacityTransition, enterOpacity]);
|
|
122
|
+
const animateClip = animate && enterTransition !== null;
|
|
93
123
|
|
|
94
124
|
// The clip offset provides extra padding to prevent path from being cut off
|
|
95
125
|
// Area charts typically use offset=0 for exact clipping, while lines use offset=2 for breathing room
|
|
96
126
|
const totalOffset = clipOffset * 2; // Applied on both sides
|
|
97
127
|
|
|
98
128
|
// Animation progress for clip path reveal
|
|
99
|
-
const clipProgress = useSharedValue(
|
|
100
|
-
|
|
101
|
-
// Trigger clip path animation when component mounts and animate is true
|
|
129
|
+
const clipProgress = useSharedValue(animateClip ? 0 : 1);
|
|
102
130
|
useEffect(() => {
|
|
103
|
-
if (
|
|
104
|
-
clipProgress.value =
|
|
105
|
-
duration: pathEnterTransitionDuration
|
|
106
|
-
});
|
|
131
|
+
if (animateClip && isReady) {
|
|
132
|
+
clipProgress.value = buildTransition(1, enterTransition);
|
|
107
133
|
}
|
|
108
|
-
}, [
|
|
134
|
+
}, [animateClip, isReady, clipProgress, enterTransition]);
|
|
109
135
|
|
|
110
136
|
// Create initial and target clip paths for animation
|
|
111
137
|
const {
|
|
@@ -116,32 +142,35 @@ export const Path = /*#__PURE__*/memo(props => {
|
|
|
116
142
|
initialClipPath: null,
|
|
117
143
|
targetClipPath: null
|
|
118
144
|
};
|
|
145
|
+
const categoryAxisIsX = context.layout !== 'horizontal';
|
|
146
|
+
const fullWidth = rect.width + totalOffset;
|
|
147
|
+
const fullHeight = rect.height + totalOffset;
|
|
119
148
|
|
|
120
|
-
// Initial clip path
|
|
149
|
+
// Initial clip path starts collapsed on the category axis.
|
|
121
150
|
const initial = Skia.Path.Make();
|
|
122
151
|
initial.addRect({
|
|
123
152
|
x: rect.x - clipOffset,
|
|
124
153
|
y: rect.y - clipOffset,
|
|
125
|
-
width: 0,
|
|
126
|
-
height:
|
|
154
|
+
width: categoryAxisIsX ? 0 : fullWidth,
|
|
155
|
+
height: categoryAxisIsX ? fullHeight : 0
|
|
127
156
|
});
|
|
128
157
|
|
|
129
|
-
// Target clip path
|
|
158
|
+
// Target clip path is fully expanded.
|
|
130
159
|
const target = Skia.Path.Make();
|
|
131
160
|
target.addRect({
|
|
132
161
|
x: rect.x - clipOffset,
|
|
133
162
|
y: rect.y - clipOffset,
|
|
134
|
-
width:
|
|
135
|
-
height:
|
|
163
|
+
width: fullWidth,
|
|
164
|
+
height: fullHeight
|
|
136
165
|
});
|
|
137
166
|
return {
|
|
138
167
|
initialClipPath: initial,
|
|
139
168
|
targetClipPath: target
|
|
140
169
|
};
|
|
141
|
-
}, [rect, clipOffset, totalOffset]);
|
|
170
|
+
}, [rect, clipOffset, totalOffset, context.layout]);
|
|
142
171
|
|
|
143
172
|
// Use usePathInterpolation for animated clip path
|
|
144
|
-
const animatedClipPath = usePathInterpolation(clipProgress, [0, 1],
|
|
173
|
+
const animatedClipPath = usePathInterpolation(clipProgress, [0, 1], animateClip && initialClipPath && targetClipPath ? [initialClipPath, targetClipPath] : targetClipPath ? [targetClipPath, targetClipPath] : [Skia.Path.Make(), Skia.Path.Make()]);
|
|
145
174
|
|
|
146
175
|
// Resolve the final clip path:
|
|
147
176
|
// 1. If clipPath prop was explicitly provided, use it (even if null = no clipping)
|
|
@@ -154,13 +183,13 @@ export const Path = /*#__PURE__*/memo(props => {
|
|
|
154
183
|
}
|
|
155
184
|
|
|
156
185
|
// If not animating or paths are null, return target clip path
|
|
157
|
-
if (!
|
|
186
|
+
if (!animateClip || !targetClipPath) {
|
|
158
187
|
return targetClipPath;
|
|
159
188
|
}
|
|
160
189
|
|
|
161
190
|
// Return undefined here since we'll use animatedClipPath directly
|
|
162
191
|
return undefined;
|
|
163
|
-
}, [clipPathProp,
|
|
192
|
+
}, [clipPathProp, animateClip, targetClipPath]);
|
|
164
193
|
|
|
165
194
|
// Convert SVG path string to SkPath for static rendering
|
|
166
195
|
const staticPath = useDerivedValue(() => {
|
|
@@ -200,19 +229,27 @@ export const Path = /*#__PURE__*/memo(props => {
|
|
|
200
229
|
strokeJoin: strokeJoin,
|
|
201
230
|
strokeOpacity: strokeOpacity,
|
|
202
231
|
strokeWidth: strokeWidth,
|
|
203
|
-
|
|
232
|
+
transitions: {
|
|
233
|
+
enter: enterTransition,
|
|
234
|
+
enterOpacity: enterOpacityTransition,
|
|
235
|
+
update: updateTransition
|
|
236
|
+
},
|
|
204
237
|
children: children
|
|
205
238
|
});
|
|
206
239
|
|
|
207
240
|
// Determine which clip path to use
|
|
208
|
-
const finalClipPath =
|
|
241
|
+
const finalClipPath = animateClip && resolvedClipPath === undefined ? animatedClipPath : resolvedClipPath;
|
|
209
242
|
|
|
210
243
|
// If finalClipPath is null, render without clipping
|
|
211
244
|
if (finalClipPath === null) {
|
|
212
|
-
return
|
|
245
|
+
return /*#__PURE__*/_jsx(Group, {
|
|
246
|
+
opacity: animateEnterOpacity ? enterOpacity : undefined,
|
|
247
|
+
children: content
|
|
248
|
+
});
|
|
213
249
|
}
|
|
214
250
|
return /*#__PURE__*/_jsx(Group, {
|
|
215
251
|
clip: finalClipPath,
|
|
252
|
+
opacity: animateEnterOpacity ? enterOpacity : undefined,
|
|
216
253
|
children: content
|
|
217
254
|
});
|
|
218
255
|
});
|
|
@@ -24,7 +24,8 @@ export const PeriodSelectorActiveIndicator = _ref => {
|
|
|
24
24
|
const {
|
|
25
25
|
width,
|
|
26
26
|
height,
|
|
27
|
-
x
|
|
27
|
+
x,
|
|
28
|
+
y
|
|
28
29
|
} = activeTabRect;
|
|
29
30
|
|
|
30
31
|
// Get the target background color
|
|
@@ -38,6 +39,7 @@ export const PeriodSelectorActiveIndicator = _ref => {
|
|
|
38
39
|
// Combined animated value for position, size, and color
|
|
39
40
|
const newAnimatedValues = {
|
|
40
41
|
x,
|
|
42
|
+
y,
|
|
41
43
|
width,
|
|
42
44
|
backgroundColor: targetColor
|
|
43
45
|
};
|
|
@@ -51,6 +53,8 @@ export const PeriodSelectorActiveIndicator = _ref => {
|
|
|
51
53
|
const animatedStyles = useAnimatedStyle(() => ({
|
|
52
54
|
transform: [{
|
|
53
55
|
translateX: animatedValues.value.x
|
|
56
|
+
}, {
|
|
57
|
+
translateY: animatedValues.value.y
|
|
54
58
|
}],
|
|
55
59
|
width: animatedValues.value.width,
|
|
56
60
|
backgroundColor: animatedValues.value.backgroundColor
|
|
@@ -7,7 +7,7 @@ import { Example, ExampleScreen } from '@coinbase/cds-mobile/examples/ExampleScr
|
|
|
7
7
|
import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
|
|
8
8
|
import { Box, HStack, VStack } from '@coinbase/cds-mobile/layout';
|
|
9
9
|
import { Text } from '@coinbase/cds-mobile/typography';
|
|
10
|
-
import { Circle, Group
|
|
10
|
+
import { Circle, Group } from '@shopify/react-native-skia';
|
|
11
11
|
import { Area } from '../area/Area';
|
|
12
12
|
import { XAxis, YAxis } from '../axis';
|
|
13
13
|
import { BarPlot } from '../bar/BarPlot';
|
|
@@ -155,7 +155,7 @@ const EarningsHistory = () => {
|
|
|
155
155
|
backgroundColor: theme.color.bgPositive
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
|
-
const
|
|
158
|
+
const LegendEntry = /*#__PURE__*/memo(_ref2 => {
|
|
159
159
|
let {
|
|
160
160
|
opacity = 1,
|
|
161
161
|
label
|
|
@@ -217,10 +217,10 @@ const EarningsHistory = () => {
|
|
|
217
217
|
}), /*#__PURE__*/_jsxs(HStack, {
|
|
218
218
|
gap: 2,
|
|
219
219
|
justifyContent: "flex-end",
|
|
220
|
-
children: [/*#__PURE__*/_jsx(
|
|
220
|
+
children: [/*#__PURE__*/_jsx(LegendEntry, {
|
|
221
221
|
label: "Estimated EPS",
|
|
222
222
|
opacity: 0.5
|
|
223
|
-
}), /*#__PURE__*/_jsx(
|
|
223
|
+
}), /*#__PURE__*/_jsx(LegendEntry, {
|
|
224
224
|
label: "Actual EPS"
|
|
225
225
|
})]
|
|
226
226
|
})]
|
|
@@ -250,11 +250,21 @@ const PriceWithVolumeChart = /*#__PURE__*/memo(_ref3 => {
|
|
|
250
250
|
day: 'numeric'
|
|
251
251
|
});
|
|
252
252
|
}, []);
|
|
253
|
+
const formatVolume = useCallback(volume => {
|
|
254
|
+
return (volume / 1000).toFixed(2) + "K";
|
|
255
|
+
}, []);
|
|
253
256
|
const scrubberLabel = useCallback(dataIndex => {
|
|
254
257
|
return formatDate(btcDates[dataIndex]);
|
|
255
258
|
}, [formatDate]);
|
|
259
|
+
const chartAccessibilityLabel = useMemo(() => {
|
|
260
|
+
const lastIndex = btcPrices.length - 1;
|
|
261
|
+
return "Bitcoin chart. Current date " + formatDate(btcDates[lastIndex]) + ". Current price " + formatPriceInThousands(btcPrices[lastIndex]) + ". Current volume " + formatVolume(btcVolumes[lastIndex]) + ".";
|
|
262
|
+
}, [formatDate, formatPriceInThousands, formatVolume]);
|
|
263
|
+
const getScrubberAccessibilityLabel = useCallback(dataIndex => "Bitcoin on " + formatDate(btcDates[dataIndex]) + ". Price " + formatPriceInThousands(btcPrices[dataIndex]) + ". Volume " + formatVolume(btcVolumes[dataIndex]) + ".", [formatDate, formatPriceInThousands, formatVolume]);
|
|
256
264
|
return /*#__PURE__*/_jsxs(CartesianChart, {
|
|
257
265
|
enableScrubbing: true,
|
|
266
|
+
accessibilityLabel: chartAccessibilityLabel,
|
|
267
|
+
getScrubberAccessibilityLabel: getScrubberAccessibilityLabel,
|
|
258
268
|
height: defaultChartHeight,
|
|
259
269
|
onScrubberPositionChange: onScrubberPositionChange,
|
|
260
270
|
series: [{
|
|
@@ -485,80 +495,6 @@ function TradingTrends() {
|
|
|
485
495
|
})]
|
|
486
496
|
});
|
|
487
497
|
}
|
|
488
|
-
const UVGradient = {
|
|
489
|
-
axis: 'y',
|
|
490
|
-
stops: [{
|
|
491
|
-
offset: 0,
|
|
492
|
-
color: 'green'
|
|
493
|
-
}, {
|
|
494
|
-
offset: 3,
|
|
495
|
-
color: 'yellow'
|
|
496
|
-
}, {
|
|
497
|
-
offset: 5,
|
|
498
|
-
color: 'orange'
|
|
499
|
-
}, {
|
|
500
|
-
offset: 8,
|
|
501
|
-
color: 'red'
|
|
502
|
-
}, {
|
|
503
|
-
offset: 10,
|
|
504
|
-
color: 'purple'
|
|
505
|
-
}]
|
|
506
|
-
};
|
|
507
|
-
const PreviousData = /*#__PURE__*/memo(_ref0 => {
|
|
508
|
-
let {
|
|
509
|
-
children,
|
|
510
|
-
currentHour,
|
|
511
|
-
clipOffset = 0
|
|
512
|
-
} = _ref0;
|
|
513
|
-
// we will clip the data to the current hour
|
|
514
|
-
const {
|
|
515
|
-
drawingArea,
|
|
516
|
-
getXScale
|
|
517
|
-
} = useCartesianChartContext();
|
|
518
|
-
const xScale = getXScale();
|
|
519
|
-
const currentHourX = xScale == null ? void 0 : xScale(currentHour);
|
|
520
|
-
const clipPath = useMemo(() => {
|
|
521
|
-
if (!xScale || currentHourX === undefined) return null;
|
|
522
|
-
|
|
523
|
-
// Create a rectangle from top-left of drawing area to currentHourX on the right
|
|
524
|
-
// Apply clipOffset to left, top, and bottom edges only (NOT to currentHourX)
|
|
525
|
-
const pathString = "M " + (drawingArea.x - clipOffset) + " " + (drawingArea.y - clipOffset) + " L " + currentHourX + " " + (drawingArea.y - clipOffset) + " L " + currentHourX + " " + (drawingArea.y + drawingArea.height + clipOffset) + " L " + (drawingArea.x - clipOffset) + " " + (drawingArea.y + drawingArea.height + clipOffset) + " Z";
|
|
526
|
-
return Skia.Path.MakeFromSVGString(pathString);
|
|
527
|
-
}, [xScale, currentHourX, drawingArea, clipOffset]);
|
|
528
|
-
if (!clipPath) return null;
|
|
529
|
-
return /*#__PURE__*/_jsx(Group, {
|
|
530
|
-
clip: clipPath,
|
|
531
|
-
opacity: 0.75,
|
|
532
|
-
children: children
|
|
533
|
-
});
|
|
534
|
-
});
|
|
535
|
-
const FutureData = /*#__PURE__*/memo(_ref1 => {
|
|
536
|
-
let {
|
|
537
|
-
children,
|
|
538
|
-
currentHour,
|
|
539
|
-
clipOffset = 0
|
|
540
|
-
} = _ref1;
|
|
541
|
-
// we will clip the data from the current hour to the right edge
|
|
542
|
-
const {
|
|
543
|
-
drawingArea,
|
|
544
|
-
getXScale
|
|
545
|
-
} = useCartesianChartContext();
|
|
546
|
-
const xScale = getXScale();
|
|
547
|
-
const currentHourX = xScale == null ? void 0 : xScale(currentHour);
|
|
548
|
-
const clipPath = useMemo(() => {
|
|
549
|
-
if (!xScale || currentHourX === undefined) return null;
|
|
550
|
-
|
|
551
|
-
// Create a rectangle from currentHourX to right edge of drawing area
|
|
552
|
-
// Apply clipOffset to top, bottom, and right, but NOT left (currentHourX)
|
|
553
|
-
const pathString = "M " + currentHourX + " " + (drawingArea.y - clipOffset) + " L " + (drawingArea.x + drawingArea.width + clipOffset) + " " + (drawingArea.y - clipOffset) + " L " + (drawingArea.x + drawingArea.width + clipOffset) + " " + (drawingArea.y + drawingArea.height + clipOffset) + " L " + currentHourX + " " + (drawingArea.y + drawingArea.height + clipOffset) + " Z";
|
|
554
|
-
return Skia.Path.MakeFromSVGString(pathString);
|
|
555
|
-
}, [xScale, currentHourX, drawingArea, clipOffset]);
|
|
556
|
-
if (!clipPath) return null;
|
|
557
|
-
return /*#__PURE__*/_jsx(Group, {
|
|
558
|
-
clip: clipPath,
|
|
559
|
-
children: children
|
|
560
|
-
});
|
|
561
|
-
});
|
|
562
498
|
const ScatterplotWithCustomLabels = /*#__PURE__*/memo(() => {
|
|
563
499
|
const theme = useTheme();
|
|
564
500
|
const dataPoints = useMemo(() => [{
|
|
@@ -642,13 +578,13 @@ const ScatterplotWithCustomLabels = /*#__PURE__*/memo(() => {
|
|
|
642
578
|
const yMax = Math.max(...yValues);
|
|
643
579
|
|
|
644
580
|
// Custom label component that places labels to the top-right
|
|
645
|
-
const TopRightPointLabel = useCallback(
|
|
581
|
+
const TopRightPointLabel = useCallback(_ref0 => {
|
|
646
582
|
let {
|
|
647
583
|
x,
|
|
648
584
|
y,
|
|
649
585
|
offset = 0,
|
|
650
586
|
children
|
|
651
|
-
} =
|
|
587
|
+
} = _ref0;
|
|
652
588
|
return /*#__PURE__*/_jsx(ChartText, {
|
|
653
589
|
font: "label1",
|
|
654
590
|
fontWeight: 600,
|