@coinbase/cds-mobile-visualization 3.4.0-beta.2 → 3.4.0-beta.21

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.
Files changed (211) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/dts/chart/CartesianChart.d.ts +92 -34
  3. package/dts/chart/CartesianChart.d.ts.map +1 -1
  4. package/dts/chart/ChartContextBridge.d.ts +28 -0
  5. package/dts/chart/ChartContextBridge.d.ts.map +1 -0
  6. package/dts/chart/ChartProvider.d.ts +3 -0
  7. package/dts/chart/ChartProvider.d.ts.map +1 -1
  8. package/dts/chart/Path.d.ts +97 -32
  9. package/dts/chart/Path.d.ts.map +1 -1
  10. package/dts/chart/PeriodSelector.d.ts +6 -13
  11. package/dts/chart/PeriodSelector.d.ts.map +1 -1
  12. package/dts/chart/area/Area.d.ts +39 -28
  13. package/dts/chart/area/Area.d.ts.map +1 -1
  14. package/dts/chart/area/AreaChart.d.ts +51 -10
  15. package/dts/chart/area/AreaChart.d.ts.map +1 -1
  16. package/dts/chart/area/DottedArea.d.ts +21 -2
  17. package/dts/chart/area/DottedArea.d.ts.map +1 -1
  18. package/dts/chart/area/GradientArea.d.ts +19 -13
  19. package/dts/chart/area/GradientArea.d.ts.map +1 -1
  20. package/dts/chart/area/SolidArea.d.ts +17 -2
  21. package/dts/chart/area/SolidArea.d.ts.map +1 -1
  22. package/dts/chart/axis/Axis.d.ts +86 -118
  23. package/dts/chart/axis/Axis.d.ts.map +1 -1
  24. package/dts/chart/axis/DefaultAxisTickLabel.d.ts +8 -0
  25. package/dts/chart/axis/DefaultAxisTickLabel.d.ts.map +1 -0
  26. package/dts/chart/axis/XAxis.d.ts +1 -1
  27. package/dts/chart/axis/XAxis.d.ts.map +1 -1
  28. package/dts/chart/axis/YAxis.d.ts +2 -2
  29. package/dts/chart/axis/YAxis.d.ts.map +1 -1
  30. package/dts/chart/axis/index.d.ts +1 -0
  31. package/dts/chart/axis/index.d.ts.map +1 -1
  32. package/dts/chart/bar/Bar.d.ts +49 -12
  33. package/dts/chart/bar/Bar.d.ts.map +1 -1
  34. package/dts/chart/bar/BarChart.d.ts +40 -19
  35. package/dts/chart/bar/BarChart.d.ts.map +1 -1
  36. package/dts/chart/bar/BarPlot.d.ts +3 -1
  37. package/dts/chart/bar/BarPlot.d.ts.map +1 -1
  38. package/dts/chart/bar/BarStack.d.ts +41 -46
  39. package/dts/chart/bar/BarStack.d.ts.map +1 -1
  40. package/dts/chart/bar/BarStackGroup.d.ts +2 -0
  41. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -1
  42. package/dts/chart/bar/DefaultBar.d.ts +1 -1
  43. package/dts/chart/bar/DefaultBar.d.ts.map +1 -1
  44. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -1
  45. package/dts/chart/gradient/Gradient.d.ts +25 -0
  46. package/dts/chart/gradient/Gradient.d.ts.map +1 -0
  47. package/dts/chart/gradient/index.d.ts +2 -0
  48. package/dts/chart/gradient/index.d.ts.map +1 -0
  49. package/dts/chart/index.d.ts +4 -1
  50. package/dts/chart/index.d.ts.map +1 -1
  51. package/dts/chart/legend/DefaultLegendEntry.d.ts +5 -0
  52. package/dts/chart/legend/DefaultLegendEntry.d.ts.map +1 -0
  53. package/dts/chart/legend/DefaultLegendShape.d.ts +5 -0
  54. package/dts/chart/legend/DefaultLegendShape.d.ts.map +1 -0
  55. package/dts/chart/legend/Legend.d.ts +168 -0
  56. package/dts/chart/legend/Legend.d.ts.map +1 -0
  57. package/dts/chart/legend/index.d.ts +4 -0
  58. package/dts/chart/legend/index.d.ts.map +1 -0
  59. package/dts/chart/line/DefaultReferenceLineLabel.d.ts +9 -0
  60. package/dts/chart/line/DefaultReferenceLineLabel.d.ts.map +1 -0
  61. package/dts/chart/line/DottedLine.d.ts +13 -5
  62. package/dts/chart/line/DottedLine.d.ts.map +1 -1
  63. package/dts/chart/line/Line.d.ts +61 -27
  64. package/dts/chart/line/Line.d.ts.map +1 -1
  65. package/dts/chart/line/LineChart.d.ts +43 -9
  66. package/dts/chart/line/LineChart.d.ts.map +1 -1
  67. package/dts/chart/line/ReferenceLine.d.ts +68 -20
  68. package/dts/chart/line/ReferenceLine.d.ts.map +1 -1
  69. package/dts/chart/line/SolidLine.d.ts +8 -5
  70. package/dts/chart/line/SolidLine.d.ts.map +1 -1
  71. package/dts/chart/line/index.d.ts +1 -1
  72. package/dts/chart/line/index.d.ts.map +1 -1
  73. package/dts/chart/point/DefaultPointLabel.d.ts +10 -0
  74. package/dts/chart/point/DefaultPointLabel.d.ts.map +1 -0
  75. package/dts/chart/point/Point.d.ts +136 -0
  76. package/dts/chart/point/Point.d.ts.map +1 -0
  77. package/dts/chart/point/index.d.ts +3 -0
  78. package/dts/chart/point/index.d.ts.map +1 -0
  79. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts +38 -0
  80. package/dts/chart/scrubber/DefaultScrubberBeacon.d.ts.map +1 -0
  81. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts +12 -0
  82. package/dts/chart/scrubber/DefaultScrubberBeaconLabel.d.ts.map +1 -0
  83. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts +11 -0
  84. package/dts/chart/scrubber/DefaultScrubberLabel.d.ts.map +1 -0
  85. package/dts/chart/scrubber/Scrubber.d.ts +230 -42
  86. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -1
  87. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts +54 -0
  88. package/dts/chart/scrubber/ScrubberBeaconGroup.d.ts.map +1 -0
  89. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts +46 -0
  90. package/dts/chart/scrubber/ScrubberBeaconLabelGroup.d.ts.map +1 -0
  91. package/dts/chart/scrubber/ScrubberProvider.d.ts +6 -3
  92. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -1
  93. package/dts/chart/scrubber/index.d.ts +3 -0
  94. package/dts/chart/scrubber/index.d.ts.map +1 -1
  95. package/dts/chart/text/ChartText.d.ts +151 -77
  96. package/dts/chart/text/ChartText.d.ts.map +1 -1
  97. package/dts/chart/text/{SmartChartTextGroup.d.ts → ChartTextGroup.d.ts} +9 -3
  98. package/dts/chart/text/ChartTextGroup.d.ts.map +1 -0
  99. package/dts/chart/text/index.d.ts +1 -1
  100. package/dts/chart/text/index.d.ts.map +1 -1
  101. package/dts/chart/utils/axis.d.ts +25 -1
  102. package/dts/chart/utils/axis.d.ts.map +1 -1
  103. package/dts/chart/utils/bar.d.ts +34 -0
  104. package/dts/chart/utils/bar.d.ts.map +1 -1
  105. package/dts/chart/utils/chart.d.ts +52 -7
  106. package/dts/chart/utils/chart.d.ts.map +1 -1
  107. package/dts/chart/utils/context.d.ts +28 -7
  108. package/dts/chart/utils/context.d.ts.map +1 -1
  109. package/dts/chart/utils/gradient.d.ts +117 -0
  110. package/dts/chart/utils/gradient.d.ts.map +1 -0
  111. package/dts/chart/utils/index.d.ts +3 -0
  112. package/dts/chart/utils/index.d.ts.map +1 -1
  113. package/dts/chart/utils/path.d.ts +59 -0
  114. package/dts/chart/utils/path.d.ts.map +1 -1
  115. package/dts/chart/utils/point.d.ts +71 -7
  116. package/dts/chart/utils/point.d.ts.map +1 -1
  117. package/dts/chart/utils/scale.d.ts +102 -0
  118. package/dts/chart/utils/scale.d.ts.map +1 -1
  119. package/dts/chart/utils/scrubber.d.ts +40 -0
  120. package/dts/chart/utils/scrubber.d.ts.map +1 -0
  121. package/dts/chart/utils/transition.d.ts +178 -0
  122. package/dts/chart/utils/transition.d.ts.map +1 -0
  123. package/esm/chart/CartesianChart.js +199 -75
  124. package/esm/chart/ChartContextBridge.js +159 -0
  125. package/esm/chart/ChartProvider.js +2 -2
  126. package/esm/chart/Path.js +200 -114
  127. package/esm/chart/PeriodSelector.js +7 -3
  128. package/esm/chart/__stories__/CartesianChart.stories.js +307 -134
  129. package/esm/chart/__stories__/ChartTransitions.stories.js +629 -0
  130. package/esm/chart/__stories__/PeriodSelector.stories.js +201 -75
  131. package/esm/chart/area/Area.js +27 -35
  132. package/esm/chart/area/AreaChart.js +17 -12
  133. package/esm/chart/area/DottedArea.js +64 -108
  134. package/esm/chart/area/GradientArea.js +37 -91
  135. package/esm/chart/area/SolidArea.js +24 -8
  136. package/esm/chart/area/__stories__/AreaChart.stories.js +1 -1
  137. package/esm/chart/axis/Axis.js +5 -39
  138. package/esm/chart/axis/DefaultAxisTickLabel.js +11 -0
  139. package/esm/chart/axis/XAxis.js +148 -66
  140. package/esm/chart/axis/YAxis.js +149 -65
  141. package/esm/chart/axis/__stories__/Axis.stories.js +259 -1
  142. package/esm/chart/axis/index.js +1 -0
  143. package/esm/chart/bar/Bar.js +7 -1
  144. package/esm/chart/bar/BarChart.js +17 -37
  145. package/esm/chart/bar/BarPlot.js +43 -35
  146. package/esm/chart/bar/BarStack.js +84 -37
  147. package/esm/chart/bar/BarStackGroup.js +7 -17
  148. package/esm/chart/bar/DefaultBar.js +29 -51
  149. package/esm/chart/bar/DefaultBarStack.js +34 -58
  150. package/esm/chart/bar/__stories__/BarChart.stories.js +948 -88
  151. package/esm/chart/gradient/Gradient.js +53 -0
  152. package/esm/chart/gradient/index.js +1 -0
  153. package/esm/chart/index.js +4 -1
  154. package/esm/chart/legend/DefaultLegendEntry.js +42 -0
  155. package/esm/chart/legend/DefaultLegendShape.js +64 -0
  156. package/esm/chart/legend/Legend.js +59 -0
  157. package/esm/chart/legend/__stories__/Legend.stories.js +574 -0
  158. package/esm/chart/legend/index.js +3 -0
  159. package/esm/chart/line/DefaultReferenceLineLabel.js +66 -0
  160. package/esm/chart/line/DottedLine.js +31 -14
  161. package/esm/chart/line/Line.js +96 -68
  162. package/esm/chart/line/LineChart.js +21 -14
  163. package/esm/chart/line/ReferenceLine.js +80 -63
  164. package/esm/chart/line/SolidLine.js +27 -10
  165. package/esm/chart/line/__stories__/LineChart.stories.js +1748 -2048
  166. package/esm/chart/line/__stories__/ReferenceLine.stories.js +177 -28
  167. package/esm/chart/line/index.js +1 -1
  168. package/esm/chart/point/DefaultPointLabel.js +39 -0
  169. package/esm/chart/point/Point.js +186 -0
  170. package/esm/chart/point/index.js +2 -0
  171. package/esm/chart/scrubber/DefaultScrubberBeacon.js +180 -0
  172. package/esm/chart/scrubber/DefaultScrubberBeaconLabel.js +43 -0
  173. package/esm/chart/scrubber/DefaultScrubberLabel.js +28 -0
  174. package/esm/chart/scrubber/Scrubber.js +130 -144
  175. package/esm/chart/scrubber/ScrubberBeaconGroup.js +165 -0
  176. package/esm/chart/scrubber/ScrubberBeaconLabelGroup.js +208 -0
  177. package/esm/chart/scrubber/ScrubberProvider.js +46 -54
  178. package/esm/chart/scrubber/__stories__/Scrubber.stories.js +760 -0
  179. package/esm/chart/scrubber/index.js +3 -1
  180. package/esm/chart/text/ChartText.js +242 -174
  181. package/esm/chart/text/{SmartChartTextGroup.js → ChartTextGroup.js} +6 -5
  182. package/esm/chart/text/index.js +1 -1
  183. package/esm/chart/utils/axis.js +47 -31
  184. package/esm/chart/utils/bar.js +43 -0
  185. package/esm/chart/utils/chart.js +57 -3
  186. package/esm/chart/utils/gradient.js +305 -0
  187. package/esm/chart/utils/index.js +3 -0
  188. package/esm/chart/utils/path.js +84 -8
  189. package/esm/chart/utils/point.js +171 -17
  190. package/esm/chart/utils/scale.js +242 -2
  191. package/esm/chart/utils/scrubber.js +146 -0
  192. package/esm/chart/utils/transition.js +215 -0
  193. package/esm/sparkline/__figma__/Sparkline.figma.js +1 -1
  194. package/esm/sparkline/__stories__/Sparkline.stories.js +11 -7
  195. package/esm/sparkline/__stories__/SparklineGradient.stories.js +7 -4
  196. package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +1 -1
  197. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +51 -26
  198. package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +1 -1
  199. package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +17 -9
  200. package/package.json +15 -10
  201. package/dts/chart/Point.d.ts +0 -103
  202. package/dts/chart/Point.d.ts.map +0 -1
  203. package/dts/chart/line/GradientLine.d.ts +0 -45
  204. package/dts/chart/line/GradientLine.d.ts.map +0 -1
  205. package/dts/chart/scrubber/ScrubberBeacon.d.ts +0 -75
  206. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +0 -1
  207. package/dts/chart/text/SmartChartTextGroup.d.ts.map +0 -1
  208. package/esm/chart/Point.js +0 -111
  209. package/esm/chart/__stories__/Chart.stories.js +0 -79
  210. package/esm/chart/line/GradientLine.js +0 -62
  211. package/esm/chart/scrubber/ScrubberBeacon.js +0 -199
@@ -1,17 +1,18 @@
1
- const _excluded = ["position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "style", "className", "styles", "classNames", "GridLineComponent", "tickMarkLabelGap", "height", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "tickMinStep", "tickMaxStep"];
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); }
1
+ const _excluded = ["position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "TickLabelComponent", "GridLineComponent", "LineComponent", "TickMarkLineComponent", "tickMarkLabelGap", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "tickMinStep", "tickMaxStep", "label", "labelGap", "height", "bandGridLinePlacement", "bandTickMarkPlacement"];
3
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; }
4
3
  import { memo, useCallback, useEffect, useId, useMemo } from 'react';
5
- import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
6
- import { G, Line } from 'react-native-svg';
7
4
  import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
5
+ import { Group } from '@shopify/react-native-skia';
8
6
  import { useCartesianChartContext } from '../ChartProvider';
9
7
  import { DottedLine } from '../line/DottedLine';
10
- import { ReferenceLine } from '../line/ReferenceLine';
11
- import { SmartChartTextGroup } from '../text/SmartChartTextGroup';
12
- import { getAxisTicksData, isCategoricalScale } from '../utils';
8
+ import { SolidLine } from '../line/SolidLine';
9
+ import { ChartText } from '../text/ChartText';
10
+ import { ChartTextGroup } from '../text/ChartTextGroup';
11
+ import { getAxisTicksData, getPointOnScale, isCategoricalScale, lineToPath, toPointAnchor } from '../utils';
12
+ import { DefaultAxisTickLabel } from './DefaultAxisTickLabel';
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- const AnimatedG = Animated.createAnimatedComponent(G);
14
+ const AXIS_HEIGHT = 32;
15
+ const LABEL_SIZE = 20;
15
16
  export const XAxis = /*#__PURE__*/memo(_ref => {
16
17
  let {
17
18
  position = 'bottom',
@@ -19,24 +20,30 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
19
20
  requestedTickCount,
20
21
  ticks,
21
22
  tickLabelFormatter,
22
- styles,
23
- classNames,
23
+ TickLabelComponent = DefaultAxisTickLabel,
24
24
  GridLineComponent = DottedLine,
25
+ LineComponent = SolidLine,
26
+ TickMarkLineComponent = SolidLine,
25
27
  tickMarkLabelGap = 2,
26
- height = 32,
27
28
  minTickLabelGap = 4,
28
29
  showTickMarks,
29
30
  showLine,
30
31
  tickMarkSize = 4,
31
32
  tickInterval = 32,
32
33
  tickMinStep = 1,
33
- tickMaxStep
34
+ tickMaxStep,
35
+ label,
36
+ labelGap = 4,
37
+ height = label ? AXIS_HEIGHT + LABEL_SIZE : AXIS_HEIGHT,
38
+ bandGridLinePlacement = 'edges',
39
+ bandTickMarkPlacement = 'middle'
34
40
  } = _ref,
35
41
  props = _objectWithoutPropertiesLoose(_ref, _excluded);
36
42
  const theme = useTheme();
37
43
  const registrationId = useId();
38
44
  const {
39
45
  animate,
46
+ drawingArea,
40
47
  getXScale,
41
48
  getXAxis,
42
49
  registerAxis,
@@ -46,17 +53,6 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
46
53
  const xScale = getXScale();
47
54
  const xAxis = getXAxis();
48
55
  const axisBounds = getAxisBounds(registrationId);
49
- const gridOpacity = useSharedValue(1);
50
- const axisLineProps = useMemo(() => ({
51
- stroke: theme.color.fg,
52
- strokeLinecap: 'square',
53
- strokeWidth: 1
54
- }), [theme.color.fg]);
55
- const axisTickMarkProps = useMemo(() => ({
56
- stroke: theme.color.fg,
57
- strokeLinecap: 'square',
58
- strokeWidth: 1
59
- }), [theme.color.fg]);
60
56
  useEffect(() => {
61
57
  registerAxis(registrationId, position, height);
62
58
  return () => unregisterAxis(registrationId);
@@ -114,68 +110,154 @@ export const XAxis = /*#__PURE__*/memo(_ref => {
114
110
  }
115
111
  });
116
112
  }, [ticks, xScale, requestedTickCount, tickInterval, tickMinStep, tickMaxStep, xAxis == null ? void 0 : xAxis.data]);
113
+ const isBandScale = useMemo(() => {
114
+ if (!xScale) return false;
115
+ return isCategoricalScale(xScale);
116
+ }, [xScale]);
117
+
118
+ // Compute grid line positions (including bounds closing line for band scales)
119
+ const gridLinePositions = useMemo(() => {
120
+ if (!xScale) return [];
121
+ return ticksData.flatMap((tick, index) => {
122
+ if (!isBandScale) {
123
+ return [{
124
+ x: tick.position,
125
+ key: "grid-" + tick.tick + "-" + index
126
+ }];
127
+ }
128
+ const bandScale = xScale;
129
+ const isLastTick = index === ticksData.length - 1;
130
+ const isEdges = bandGridLinePlacement === 'edges';
131
+ const startX = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandGridLinePlacement));
132
+ const positions = [{
133
+ x: startX,
134
+ key: "grid-" + tick.tick + "-" + index
135
+ }];
136
+
137
+ // For edges on last tick, add the closing line at stepEnd
138
+ if (isLastTick && isEdges) {
139
+ const endX = getPointOnScale(tick.tick, bandScale, 'stepEnd');
140
+ positions.push({
141
+ x: endX,
142
+ key: "grid-" + tick.tick + "-" + index + "-end"
143
+ });
144
+ }
145
+ return positions;
146
+ });
147
+ }, [ticksData, xScale, isBandScale, bandGridLinePlacement]);
148
+
149
+ // Compute tick mark positions (including bounds closing tick for band scales)
150
+ const tickMarkPositions = useMemo(() => {
151
+ if (!xScale) return [];
152
+ return ticksData.flatMap((tick, index) => {
153
+ if (!isBandScale) {
154
+ return [{
155
+ x: tick.position,
156
+ key: "tick-mark-" + tick.tick + "-" + index
157
+ }];
158
+ }
159
+ const bandScale = xScale;
160
+ const isLastTick = index === ticksData.length - 1;
161
+ const isEdges = bandTickMarkPlacement === 'edges';
162
+ const startX = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandTickMarkPlacement));
163
+ const positions = [{
164
+ x: startX,
165
+ key: "tick-mark-" + tick.tick + "-" + index
166
+ }];
167
+
168
+ // For edges on last tick, add the closing tick mark at stepEnd
169
+ if (isLastTick && isEdges) {
170
+ const endX = getPointOnScale(tick.tick, bandScale, 'stepEnd');
171
+ positions.push({
172
+ x: endX,
173
+ key: "tick-mark-" + tick.tick + "-" + index + "-end"
174
+ });
175
+ }
176
+ return positions;
177
+ });
178
+ }, [ticksData, xScale, isBandScale, bandTickMarkPlacement]);
117
179
  const chartTextData = useMemo(() => {
118
180
  if (!axisBounds) return null;
119
181
  return ticksData.map(tick => {
120
182
  const tickOffset = tickMarkLabelGap + (showTickMarks ? tickMarkSize : 0);
121
- const availableSpace = axisBounds.height - tickOffset;
183
+
184
+ // Use AXIS_HEIGHT for centering, not full axisBounds.height
185
+ // This ensures tick labels are centered in the axis area, not including label space
186
+ const availableSpace = AXIS_HEIGHT - tickOffset;
122
187
  const labelOffset = availableSpace / 2;
123
- const labelY = position === 'top' ? axisBounds.y + labelOffset - tickOffset : axisBounds.y + labelOffset + tickOffset;
188
+ const labelY = position === 'top' ? axisBounds.y + axisBounds.height - tickOffset - labelOffset : axisBounds.y + labelOffset + tickOffset;
124
189
  return {
125
190
  x: tick.position,
126
191
  y: labelY,
127
192
  label: String(formatTick(tick.tick)),
128
193
  chartTextProps: {
129
- className: classNames == null ? void 0 : classNames.tickLabel,
130
194
  color: theme.color.fgMuted,
131
195
  verticalAlignment: 'middle',
132
- style: styles == null ? void 0 : styles.tickLabel,
133
196
  horizontalAlignment: 'center'
134
197
  }
135
198
  };
136
199
  });
137
- }, [axisBounds, ticksData, theme.color.fgMuted, tickMarkLabelGap, showTickMarks, tickMarkSize, position, formatTick, classNames == null ? void 0 : classNames.tickLabel, styles == null ? void 0 : styles.tickLabel]);
138
- const gridAnimatedStyle = useAnimatedStyle(() => ({
139
- opacity: gridOpacity.value
140
- }));
141
- if (!xScale) return;
142
- return /*#__PURE__*/_jsxs(G, _extends({
143
- "data-axis": "x",
144
- "data-position": position
145
- }, props, {
146
- children: [showGrid && /*#__PURE__*/_jsx(AnimatedG, {
147
- animatedProps: gridAnimatedStyle,
148
- children: ticksData.map((tick, index) => {
149
- const verticalLine = /*#__PURE__*/_jsx(ReferenceLine, {
150
- LineComponent: GridLineComponent,
151
- dataX: tick.tick
152
- });
153
- return /*#__PURE__*/_jsx(G, {
154
- children: verticalLine
155
- }, "grid-" + tick.tick + "-" + index);
200
+ }, [axisBounds, ticksData, theme.color.fgMuted, tickMarkLabelGap, showTickMarks, tickMarkSize, position, formatTick]);
201
+ if (!xScale || !axisBounds) return;
202
+ const labelX = axisBounds.x + axisBounds.width / 2;
203
+ const labelY = position === 'bottom' ? axisBounds.y + axisBounds.height - LABEL_SIZE / 2 : axisBounds.y + LABEL_SIZE / 2;
204
+
205
+ // Pre-compute tick mark Y coordinates
206
+ const tickYTop = axisBounds.y;
207
+ const tickYBottom = axisBounds.y + axisBounds.height;
208
+ const tickYStart = position === 'bottom' ? tickYTop : tickYBottom;
209
+ const tickYEnd = position === 'bottom' ? tickYTop + tickMarkSize : tickYBottom - tickMarkSize;
210
+
211
+ // Note: Unlike web, mobile renders grid lines and tick marks immediately without fade animation.
212
+ // This is because Skia can measure text dimensions synchronously, so there's no need to hide
213
+ // elements while waiting for measurements (web uses async ResizeObserver).
214
+ return /*#__PURE__*/_jsxs(Group, {
215
+ children: [showGrid && /*#__PURE__*/_jsx(Group, {
216
+ children: gridLinePositions.map(_ref2 => {
217
+ let {
218
+ x,
219
+ key
220
+ } = _ref2;
221
+ return /*#__PURE__*/_jsx(GridLineComponent, {
222
+ animate: false,
223
+ clipPath: null,
224
+ d: lineToPath(x, drawingArea.y, x, drawingArea.y + drawingArea.height),
225
+ stroke: theme.color.bgLine
226
+ }, key);
156
227
  })
157
- }), chartTextData && /*#__PURE__*/_jsx(SmartChartTextGroup, {
228
+ }), chartTextData && /*#__PURE__*/_jsx(ChartTextGroup, {
158
229
  prioritizeEndLabels: true,
230
+ LabelComponent: TickLabelComponent,
159
231
  labels: chartTextData,
160
232
  minGap: minTickLabelGap
161
- }), axisBounds && showTickMarks && /*#__PURE__*/_jsx(G, {
162
- "data-testid": "tick-marks",
163
- children: ticksData.map((tick, index) => {
164
- const tickY = position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height;
165
- const tickMarkSizePixels = tickMarkSize;
166
- const tickY2 = position === 'bottom' ? axisBounds.y + tickMarkSizePixels : axisBounds.y + axisBounds.height - tickMarkSizePixels;
167
- return /*#__PURE__*/_jsx(Line, _extends({}, axisTickMarkProps, {
168
- x1: tick.position,
169
- x2: tick.position,
170
- y1: tickY,
171
- y2: tickY2
172
- }), "tick-mark-" + tick.tick + "-" + index);
233
+ }), axisBounds && showTickMarks && /*#__PURE__*/_jsx(Group, {
234
+ children: tickMarkPositions.map(_ref3 => {
235
+ let {
236
+ x,
237
+ key
238
+ } = _ref3;
239
+ return /*#__PURE__*/_jsx(TickMarkLineComponent, {
240
+ animate: false,
241
+ clipPath: null,
242
+ d: lineToPath(x, tickYStart, x, tickYEnd),
243
+ stroke: theme.color.fg,
244
+ strokeCap: "square",
245
+ strokeWidth: 1
246
+ }, key);
173
247
  })
174
- }), axisBounds && showLine && /*#__PURE__*/_jsx(Line, _extends({}, axisLineProps, {
175
- x1: axisBounds.x,
176
- x2: axisBounds.x + axisBounds.width,
177
- y1: position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height,
178
- y2: position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height
179
- }))]
180
- }));
248
+ }), showLine && /*#__PURE__*/_jsx(LineComponent, {
249
+ animate: false,
250
+ clipPath: null,
251
+ d: lineToPath(axisBounds.x, position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height, axisBounds.x + axisBounds.width, position === 'bottom' ? axisBounds.y : axisBounds.y + axisBounds.height),
252
+ stroke: theme.color.fg,
253
+ strokeCap: "square",
254
+ strokeWidth: 1
255
+ }), label && /*#__PURE__*/_jsx(ChartText, {
256
+ horizontalAlignment: "center",
257
+ verticalAlignment: "middle",
258
+ x: labelX,
259
+ y: labelY,
260
+ children: label
261
+ })]
262
+ });
181
263
  });
@@ -1,17 +1,18 @@
1
- const _excluded = ["axisId", "position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "style", "className", "styles", "classNames", "GridLineComponent", "tickMarkLabelGap", "width", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval"];
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); }
1
+ const _excluded = ["axisId", "position", "showGrid", "requestedTickCount", "ticks", "tickLabelFormatter", "TickLabelComponent", "GridLineComponent", "LineComponent", "TickMarkLineComponent", "tickMarkLabelGap", "minTickLabelGap", "showTickMarks", "showLine", "tickMarkSize", "tickInterval", "label", "labelGap", "width", "bandGridLinePlacement", "bandTickMarkPlacement"];
3
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; }
4
3
  import { memo, useCallback, useEffect, useId, useMemo } from 'react';
5
- import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
6
- import { G, Line } from 'react-native-svg';
7
4
  import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
5
+ import { Group, vec } from '@shopify/react-native-skia';
8
6
  import { useCartesianChartContext } from '../ChartProvider';
9
7
  import { DottedLine } from '../line/DottedLine';
10
- import { ReferenceLine } from '../line/ReferenceLine';
11
- import { SmartChartTextGroup } from '../text/SmartChartTextGroup';
12
- import { getAxisTicksData, isCategoricalScale } from '../utils';
8
+ import { SolidLine } from '../line/SolidLine';
9
+ import { ChartText } from '../text/ChartText';
10
+ import { ChartTextGroup } from '../text/ChartTextGroup';
11
+ import { getAxisTicksData, getPointOnScale, isCategoricalScale, lineToPath, toPointAnchor } from '../utils';
12
+ import { DefaultAxisTickLabel } from './DefaultAxisTickLabel';
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- const AnimatedG = Animated.createAnimatedComponent(G);
14
+ const AXIS_WIDTH = 44;
15
+ const LABEL_SIZE = 20;
15
16
  export const YAxis = /*#__PURE__*/memo(_ref => {
16
17
  let {
17
18
  axisId,
@@ -20,22 +21,28 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
20
21
  requestedTickCount = 5,
21
22
  ticks,
22
23
  tickLabelFormatter,
23
- styles,
24
- classNames,
24
+ TickLabelComponent = DefaultAxisTickLabel,
25
25
  GridLineComponent = DottedLine,
26
+ LineComponent = SolidLine,
27
+ TickMarkLineComponent = SolidLine,
26
28
  tickMarkLabelGap = 8,
27
- width = 44,
28
29
  minTickLabelGap = 0,
29
30
  showTickMarks,
30
31
  showLine,
31
32
  tickMarkSize = 4,
32
- tickInterval
33
+ tickInterval,
34
+ label,
35
+ labelGap = 4,
36
+ width = label ? AXIS_WIDTH + LABEL_SIZE : AXIS_WIDTH,
37
+ bandGridLinePlacement = 'edges',
38
+ bandTickMarkPlacement = 'middle'
33
39
  } = _ref,
34
40
  props = _objectWithoutPropertiesLoose(_ref, _excluded);
35
41
  const theme = useTheme();
36
42
  const registrationId = useId();
37
43
  const {
38
44
  animate,
45
+ drawingArea,
39
46
  getYScale,
40
47
  getYAxis,
41
48
  registerAxis,
@@ -45,17 +52,6 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
45
52
  const yScale = getYScale(axisId);
46
53
  const yAxis = getYAxis(axisId);
47
54
  const axisBounds = getAxisBounds(registrationId);
48
- const gridOpacity = useSharedValue(1);
49
- const axisLineProps = useMemo(() => ({
50
- stroke: theme.color.fg,
51
- strokeLinecap: 'square',
52
- strokeWidth: 1
53
- }), [theme.color.fg]);
54
- const axisTickMarkProps = useMemo(() => ({
55
- stroke: theme.color.fg,
56
- strokeLinecap: 'square',
57
- strokeWidth: 1
58
- }), [theme.color.fg]);
59
55
  useEffect(() => {
60
56
  registerAxis(registrationId, position, width);
61
57
  return () => unregisterAxis(registrationId);
@@ -104,6 +100,72 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
104
100
  tickInterval: tickInterval
105
101
  });
106
102
  }, [ticks, yScale, requestedTickCount, tickInterval, yAxis == null ? void 0 : yAxis.data]);
103
+ const isBandScale = useMemo(() => {
104
+ if (!yScale) return false;
105
+ return isCategoricalScale(yScale);
106
+ }, [yScale]);
107
+
108
+ // Compute grid line positions (including bounds closing line for band scales)
109
+ const gridLinePositions = useMemo(() => {
110
+ if (!yScale) return [];
111
+ return ticksData.flatMap((tick, index) => {
112
+ if (!isBandScale) {
113
+ return [{
114
+ y: tick.position,
115
+ key: "grid-" + tick.tick + "-" + index
116
+ }];
117
+ }
118
+ const bandScale = yScale;
119
+ const isLastTick = index === ticksData.length - 1;
120
+ const isEdges = bandGridLinePlacement === 'edges';
121
+ const startY = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandGridLinePlacement));
122
+ const positions = [{
123
+ y: startY,
124
+ key: "grid-" + tick.tick + "-" + index
125
+ }];
126
+
127
+ // For edges on last tick, add the closing line at stepEnd
128
+ if (isLastTick && isEdges) {
129
+ const endY = getPointOnScale(tick.tick, bandScale, 'stepEnd');
130
+ positions.push({
131
+ y: endY,
132
+ key: "grid-" + tick.tick + "-" + index + "-end"
133
+ });
134
+ }
135
+ return positions;
136
+ });
137
+ }, [ticksData, yScale, isBandScale, bandGridLinePlacement]);
138
+
139
+ // Compute tick mark positions (including bounds closing tick for band scales)
140
+ const tickMarkPositions = useMemo(() => {
141
+ if (!yScale) return [];
142
+ return ticksData.flatMap((tick, index) => {
143
+ if (!isBandScale) {
144
+ return [{
145
+ y: tick.position,
146
+ key: "tick-mark-" + tick.tick + "-" + index
147
+ }];
148
+ }
149
+ const bandScale = yScale;
150
+ const isLastTick = index === ticksData.length - 1;
151
+ const isEdges = bandTickMarkPlacement === 'edges';
152
+ const startY = getPointOnScale(tick.tick, bandScale, toPointAnchor(bandTickMarkPlacement));
153
+ const positions = [{
154
+ y: startY,
155
+ key: "tick-mark-" + tick.tick + "-" + index
156
+ }];
157
+
158
+ // For edges on last tick, add the closing tick mark at stepEnd
159
+ if (isLastTick && isEdges) {
160
+ const endY = getPointOnScale(tick.tick, bandScale, 'stepEnd');
161
+ positions.push({
162
+ y: endY,
163
+ key: "tick-mark-" + tick.tick + "-" + index + "-end"
164
+ });
165
+ }
166
+ return positions;
167
+ });
168
+ }, [ticksData, yScale, isBandScale, bandTickMarkPlacement]);
107
169
  const chartTextData = useMemo(() => {
108
170
  if (!axisBounds) return null;
109
171
  return ticksData.map(tick => {
@@ -114,57 +176,79 @@ export const YAxis = /*#__PURE__*/memo(_ref => {
114
176
  y: tick.position,
115
177
  label: String(formatTick(tick.tick)),
116
178
  chartTextProps: {
117
- className: classNames == null ? void 0 : classNames.tickLabel,
118
179
  color: theme.color.fgMuted,
119
180
  verticalAlignment: 'middle',
120
- style: styles == null ? void 0 : styles.tickLabel,
121
181
  horizontalAlignment: position === 'left' ? 'right' : 'left'
122
182
  }
123
183
  };
124
184
  });
125
- }, [axisBounds, ticksData, theme.color.fgMuted, tickMarkLabelGap, showTickMarks, tickMarkSize, position, formatTick, classNames == null ? void 0 : classNames.tickLabel, styles == null ? void 0 : styles.tickLabel]);
126
- const gridAnimatedStyle = useAnimatedStyle(() => ({
127
- opacity: gridOpacity.value
128
- }));
129
- if (!yScale) return;
130
- return /*#__PURE__*/_jsxs(G, _extends({
131
- "data-axis": "y",
132
- "data-position": position
133
- }, props, {
134
- children: [showGrid && /*#__PURE__*/_jsx(AnimatedG, {
135
- animatedProps: gridAnimatedStyle,
136
- children: ticksData.map((tick, index) => {
137
- const horizontalLine = /*#__PURE__*/_jsx(ReferenceLine, {
138
- LineComponent: GridLineComponent,
139
- dataY: tick.tick,
140
- yAxisId: axisId
141
- });
142
- return /*#__PURE__*/_jsx(G, {
143
- children: horizontalLine
144
- }, "grid-" + tick.tick + "-" + index);
185
+ }, [axisBounds, ticksData, tickMarkLabelGap, showTickMarks, tickMarkSize, position, formatTick, theme.color.fgMuted]);
186
+ if (!yScale || !axisBounds) return;
187
+ const labelX = position === 'left' ? axisBounds.x + LABEL_SIZE / 2 : axisBounds.x + axisBounds.width - LABEL_SIZE / 2;
188
+ const labelY = axisBounds.y + axisBounds.height / 2;
189
+
190
+ // Pre-compute tick mark X coordinates
191
+ const tickXLeft = axisBounds.x;
192
+ const tickXRight = axisBounds.x + axisBounds.width;
193
+ const tickXStart = position === 'left' ? tickXRight : tickXLeft;
194
+ const tickXEnd = position === 'left' ? tickXRight - tickMarkSize : tickXLeft + tickMarkSize;
195
+
196
+ // Note: Unlike web, mobile renders grid lines and tick marks immediately without fade animation.
197
+ // This is because Skia can measure text dimensions synchronously, so there's no need to hide
198
+ // elements while waiting for measurements (web uses async ResizeObserver).
199
+ return /*#__PURE__*/_jsxs(Group, {
200
+ children: [showGrid && /*#__PURE__*/_jsx(Group, {
201
+ children: gridLinePositions.map(_ref2 => {
202
+ let {
203
+ y,
204
+ key
205
+ } = _ref2;
206
+ return /*#__PURE__*/_jsx(GridLineComponent, {
207
+ animate: false,
208
+ clipPath: null,
209
+ d: lineToPath(drawingArea.x, y, drawingArea.x + drawingArea.width, y),
210
+ stroke: theme.color.bgLine
211
+ }, key);
145
212
  })
146
- }), chartTextData && /*#__PURE__*/_jsx(SmartChartTextGroup, {
213
+ }), chartTextData && /*#__PURE__*/_jsx(ChartTextGroup, {
147
214
  prioritizeEndLabels: true,
215
+ LabelComponent: TickLabelComponent,
148
216
  labels: chartTextData,
149
217
  minGap: minTickLabelGap
150
- }), axisBounds && showTickMarks && /*#__PURE__*/_jsx(G, {
151
- "data-testid": "tick-marks",
152
- children: ticksData.map((tick, index) => {
153
- const tickX = position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x;
154
- const tickMarkSizePixels = tickMarkSize;
155
- const tickX2 = position === 'left' ? axisBounds.x + axisBounds.width - tickMarkSizePixels : axisBounds.x + tickMarkSizePixels;
156
- return /*#__PURE__*/_jsx(Line, _extends({}, axisTickMarkProps, {
157
- x1: tickX,
158
- x2: tickX2,
159
- y1: tick.position,
160
- y2: tick.position
161
- }), "tick-mark-" + tick.tick + "-" + index);
218
+ }), axisBounds && showTickMarks && /*#__PURE__*/_jsx(Group, {
219
+ children: tickMarkPositions.map(_ref3 => {
220
+ let {
221
+ y,
222
+ key
223
+ } = _ref3;
224
+ return /*#__PURE__*/_jsx(TickMarkLineComponent, {
225
+ animate: false,
226
+ clipPath: null,
227
+ d: lineToPath(tickXStart, y, tickXEnd, y),
228
+ stroke: theme.color.fg,
229
+ strokeCap: "square",
230
+ strokeWidth: 1
231
+ }, key);
232
+ })
233
+ }), showLine && /*#__PURE__*/_jsx(LineComponent, {
234
+ animate: false,
235
+ clipPath: null,
236
+ d: lineToPath(position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x, axisBounds.y, position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x, axisBounds.y + axisBounds.height),
237
+ stroke: theme.color.fg,
238
+ strokeCap: "square",
239
+ strokeWidth: 1
240
+ }), label && /*#__PURE__*/_jsx(Group, {
241
+ origin: vec(labelX, labelY),
242
+ transform: [{
243
+ rotate: position === 'left' ? -Math.PI / 2 : Math.PI / 2
244
+ }],
245
+ children: /*#__PURE__*/_jsx(ChartText, {
246
+ horizontalAlignment: "center",
247
+ verticalAlignment: "middle",
248
+ x: labelX,
249
+ y: labelY,
250
+ children: label
162
251
  })
163
- }), axisBounds && showLine && /*#__PURE__*/_jsx(Line, _extends({}, axisLineProps, {
164
- x1: position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x,
165
- x2: position === 'left' ? axisBounds.x + axisBounds.width : axisBounds.x,
166
- y1: axisBounds.y,
167
- y2: axisBounds.y + axisBounds.height
168
- }))]
169
- }));
252
+ })]
253
+ });
170
254
  });