@coinbase/cds-mobile-visualization 0.0.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.
Files changed (245) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +3 -0
  3. package/dts/chart/CartesianChart.d.ts +101 -0
  4. package/dts/chart/CartesianChart.d.ts.map +1 -0
  5. package/dts/chart/ChartProvider.d.ts +6 -0
  6. package/dts/chart/ChartProvider.d.ts.map +1 -0
  7. package/dts/chart/Path.d.ts +48 -0
  8. package/dts/chart/Path.d.ts.map +1 -0
  9. package/dts/chart/PeriodSelector.d.ts +85 -0
  10. package/dts/chart/PeriodSelector.d.ts.map +1 -0
  11. package/dts/chart/Point.d.ts +103 -0
  12. package/dts/chart/Point.d.ts.map +1 -0
  13. package/dts/chart/area/Area.d.ts +62 -0
  14. package/dts/chart/area/Area.d.ts.map +1 -0
  15. package/dts/chart/area/AreaChart.d.ts +90 -0
  16. package/dts/chart/area/AreaChart.d.ts.map +1 -0
  17. package/dts/chart/area/DottedArea.d.ts +27 -0
  18. package/dts/chart/area/DottedArea.d.ts.map +1 -0
  19. package/dts/chart/area/GradientArea.d.ts +30 -0
  20. package/dts/chart/area/GradientArea.d.ts.map +1 -0
  21. package/dts/chart/area/SolidArea.d.ts +8 -0
  22. package/dts/chart/area/SolidArea.d.ts.map +1 -0
  23. package/dts/chart/area/index.d.ts +6 -0
  24. package/dts/chart/area/index.d.ts.map +1 -0
  25. package/dts/chart/axis/Axis.d.ts +204 -0
  26. package/dts/chart/axis/Axis.d.ts.map +1 -0
  27. package/dts/chart/axis/XAxis.d.ts +16 -0
  28. package/dts/chart/axis/XAxis.d.ts.map +1 -0
  29. package/dts/chart/axis/YAxis.d.ts +21 -0
  30. package/dts/chart/axis/YAxis.d.ts.map +1 -0
  31. package/dts/chart/axis/index.d.ts +4 -0
  32. package/dts/chart/axis/index.d.ts.map +1 -0
  33. package/dts/chart/bar/Bar.d.ts +89 -0
  34. package/dts/chart/bar/Bar.d.ts.map +1 -0
  35. package/dts/chart/bar/BarChart.d.ts +97 -0
  36. package/dts/chart/bar/BarChart.d.ts.map +1 -0
  37. package/dts/chart/bar/BarPlot.d.ts +29 -0
  38. package/dts/chart/bar/BarPlot.d.ts.map +1 -0
  39. package/dts/chart/bar/BarStack.d.ts +111 -0
  40. package/dts/chart/bar/BarStack.d.ts.map +1 -0
  41. package/dts/chart/bar/BarStackGroup.d.ts +35 -0
  42. package/dts/chart/bar/BarStackGroup.d.ts.map +1 -0
  43. package/dts/chart/bar/DefaultBar.d.ts +7 -0
  44. package/dts/chart/bar/DefaultBar.d.ts.map +1 -0
  45. package/dts/chart/bar/DefaultBarStack.d.ts +7 -0
  46. package/dts/chart/bar/DefaultBarStack.d.ts.map +1 -0
  47. package/dts/chart/bar/index.d.ts +8 -0
  48. package/dts/chart/bar/index.d.ts.map +1 -0
  49. package/dts/chart/index.d.ts +13 -0
  50. package/dts/chart/index.d.ts.map +1 -0
  51. package/dts/chart/line/DottedLine.d.ts +12 -0
  52. package/dts/chart/line/DottedLine.d.ts.map +1 -0
  53. package/dts/chart/line/GradientLine.d.ts +45 -0
  54. package/dts/chart/line/GradientLine.d.ts.map +1 -0
  55. package/dts/chart/line/Line.d.ts +78 -0
  56. package/dts/chart/line/Line.d.ts.map +1 -0
  57. package/dts/chart/line/LineChart.d.ts +84 -0
  58. package/dts/chart/line/LineChart.d.ts.map +1 -0
  59. package/dts/chart/line/ReferenceLine.d.ts +91 -0
  60. package/dts/chart/line/ReferenceLine.d.ts.map +1 -0
  61. package/dts/chart/line/SolidLine.d.ts +12 -0
  62. package/dts/chart/line/SolidLine.d.ts.map +1 -0
  63. package/dts/chart/line/index.d.ts +7 -0
  64. package/dts/chart/line/index.d.ts.map +1 -0
  65. package/dts/chart/scrubber/Scrubber.d.ts +104 -0
  66. package/dts/chart/scrubber/Scrubber.d.ts.map +1 -0
  67. package/dts/chart/scrubber/ScrubberBeacon.d.ts +75 -0
  68. package/dts/chart/scrubber/ScrubberBeacon.d.ts.map +1 -0
  69. package/dts/chart/scrubber/ScrubberProvider.d.ts +17 -0
  70. package/dts/chart/scrubber/ScrubberProvider.d.ts.map +1 -0
  71. package/dts/chart/scrubber/index.d.ts +2 -0
  72. package/dts/chart/scrubber/index.d.ts.map +1 -0
  73. package/dts/chart/text/ChartText.d.ts +90 -0
  74. package/dts/chart/text/ChartText.d.ts.map +1 -0
  75. package/dts/chart/text/SmartChartTextGroup.d.ts +55 -0
  76. package/dts/chart/text/SmartChartTextGroup.d.ts.map +1 -0
  77. package/dts/chart/text/index.d.ts +3 -0
  78. package/dts/chart/text/index.d.ts.map +1 -0
  79. package/dts/chart/utils/axis.d.ts +342 -0
  80. package/dts/chart/utils/axis.d.ts.map +1 -0
  81. package/dts/chart/utils/bar.d.ts +20 -0
  82. package/dts/chart/utils/bar.d.ts.map +1 -0
  83. package/dts/chart/utils/chart.d.ts +97 -0
  84. package/dts/chart/utils/chart.d.ts.map +1 -0
  85. package/dts/chart/utils/context.d.ts +95 -0
  86. package/dts/chart/utils/context.d.ts.map +1 -0
  87. package/dts/chart/utils/index.d.ts +8 -0
  88. package/dts/chart/utils/index.d.ts.map +1 -0
  89. package/dts/chart/utils/path.d.ts +107 -0
  90. package/dts/chart/utils/path.d.ts.map +1 -0
  91. package/dts/chart/utils/point.d.ts +75 -0
  92. package/dts/chart/utils/point.d.ts.map +1 -0
  93. package/dts/chart/utils/scale.d.ts +43 -0
  94. package/dts/chart/utils/scale.d.ts.map +1 -0
  95. package/dts/index.d.ts +3 -0
  96. package/dts/index.d.ts.map +1 -0
  97. package/dts/sparkline/Counter.d.ts +8 -0
  98. package/dts/sparkline/Counter.d.ts.map +1 -0
  99. package/dts/sparkline/Sparkline.d.ts +73 -0
  100. package/dts/sparkline/Sparkline.d.ts.map +1 -0
  101. package/dts/sparkline/SparklineArea.d.ts +14 -0
  102. package/dts/sparkline/SparklineArea.d.ts.map +1 -0
  103. package/dts/sparkline/SparklineAreaPattern.d.ts +14 -0
  104. package/dts/sparkline/SparklineAreaPattern.d.ts.map +1 -0
  105. package/dts/sparkline/SparklineGradient.d.ts +23 -0
  106. package/dts/sparkline/SparklineGradient.d.ts.map +1 -0
  107. package/dts/sparkline/__figma__/Sparkline.figma.d.ts +2 -0
  108. package/dts/sparkline/__figma__/Sparkline.figma.d.ts.map +1 -0
  109. package/dts/sparkline/generateSparklineWithId.d.ts +11 -0
  110. package/dts/sparkline/generateSparklineWithId.d.ts.map +1 -0
  111. package/dts/sparkline/index.d.ts +6 -0
  112. package/dts/sparkline/index.d.ts.map +1 -0
  113. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts +23 -0
  114. package/dts/sparkline/sparkline-interactive/SparklineAccessibleView.d.ts.map +1 -0
  115. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts +184 -0
  116. package/dts/sparkline/sparkline-interactive/SparklineInteractive.d.ts.map +1 -0
  117. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts +25 -0
  118. package/dts/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.d.ts.map +1 -0
  119. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts +28 -0
  120. package/dts/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.d.ts.map +1 -0
  121. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts +13 -0
  122. package/dts/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.d.ts.map +1 -0
  123. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts +17 -0
  124. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.d.ts.map +1 -0
  125. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts +11 -0
  126. package/dts/sparkline/sparkline-interactive/SparklineInteractiveMinMax.d.ts.map +1 -0
  127. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts +26 -0
  128. package/dts/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.d.ts.map +1 -0
  129. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts +25 -0
  130. package/dts/sparkline/sparkline-interactive/SparklineInteractivePaths.d.ts.map +1 -0
  131. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts +25 -0
  132. package/dts/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.d.ts.map +1 -0
  133. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts +39 -0
  134. package/dts/sparkline/sparkline-interactive/SparklineInteractiveProvider.d.ts.map +1 -0
  135. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts +31 -0
  136. package/dts/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.d.ts.map +1 -0
  137. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts +2 -0
  138. package/dts/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.d.ts.map +1 -0
  139. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts +13 -0
  140. package/dts/sparkline/sparkline-interactive/useInterruptiblePathAnimation.d.ts.map +1 -0
  141. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts +16 -0
  142. package/dts/sparkline/sparkline-interactive/useMinMaxTransform.d.ts.map +1 -0
  143. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts +6 -0
  144. package/dts/sparkline/sparkline-interactive/useOpacityAnimation.d.ts.map +1 -0
  145. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts +22 -0
  146. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveConstants.d.ts.map +1 -0
  147. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts +34 -0
  148. package/dts/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.d.ts.map +1 -0
  149. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts +118 -0
  150. package/dts/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.d.ts.map +1 -0
  151. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts +2 -0
  152. package/dts/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.d.ts.map +1 -0
  153. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts +29 -0
  154. package/dts/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.d.ts.map +1 -0
  155. package/esm/chart/CartesianChart.js +241 -0
  156. package/esm/chart/ChartProvider.js +10 -0
  157. package/esm/chart/Path.js +133 -0
  158. package/esm/chart/PeriodSelector.js +136 -0
  159. package/esm/chart/Point.js +111 -0
  160. package/esm/chart/__stories__/CartesianChart.stories.js +476 -0
  161. package/esm/chart/__stories__/Chart.stories.js +79 -0
  162. package/esm/chart/__stories__/PeriodSelector.stories.js +294 -0
  163. package/esm/chart/area/Area.js +85 -0
  164. package/esm/chart/area/AreaChart.js +146 -0
  165. package/esm/chart/area/DottedArea.js +128 -0
  166. package/esm/chart/area/GradientArea.js +110 -0
  167. package/esm/chart/area/SolidArea.js +24 -0
  168. package/esm/chart/area/__stories__/AreaChart.stories.js +100 -0
  169. package/esm/chart/area/index.js +7 -0
  170. package/esm/chart/axis/Axis.js +43 -0
  171. package/esm/chart/axis/XAxis.js +181 -0
  172. package/esm/chart/axis/YAxis.js +170 -0
  173. package/esm/chart/axis/__stories__/Axis.stories.js +277 -0
  174. package/esm/chart/axis/index.js +5 -0
  175. package/esm/chart/bar/Bar.js +67 -0
  176. package/esm/chart/bar/BarChart.js +147 -0
  177. package/esm/chart/bar/BarPlot.js +96 -0
  178. package/esm/chart/bar/BarStack.js +514 -0
  179. package/esm/chart/bar/BarStackGroup.js +89 -0
  180. package/esm/chart/bar/DefaultBar.js +78 -0
  181. package/esm/chart/bar/DefaultBarStack.js +82 -0
  182. package/esm/chart/bar/__stories__/BarChart.stories.js +282 -0
  183. package/esm/chart/bar/index.js +9 -0
  184. package/esm/chart/index.js +14 -0
  185. package/esm/chart/line/DottedLine.js +35 -0
  186. package/esm/chart/line/GradientLine.js +62 -0
  187. package/esm/chart/line/Line.js +139 -0
  188. package/esm/chart/line/LineChart.js +115 -0
  189. package/esm/chart/line/ReferenceLine.js +115 -0
  190. package/esm/chart/line/SolidLine.js +31 -0
  191. package/esm/chart/line/__stories__/LineChart.stories.js +2248 -0
  192. package/esm/chart/line/__stories__/ReferenceLine.stories.js +77 -0
  193. package/esm/chart/line/index.js +8 -0
  194. package/esm/chart/scrubber/Scrubber.js +186 -0
  195. package/esm/chart/scrubber/ScrubberBeacon.js +199 -0
  196. package/esm/chart/scrubber/ScrubberProvider.js +143 -0
  197. package/esm/chart/scrubber/index.js +2 -0
  198. package/esm/chart/text/ChartText.js +237 -0
  199. package/esm/chart/text/SmartChartTextGroup.js +210 -0
  200. package/esm/chart/text/index.js +4 -0
  201. package/esm/chart/utils/axis.js +592 -0
  202. package/esm/chart/utils/bar.js +24 -0
  203. package/esm/chart/utils/chart.js +229 -0
  204. package/esm/chart/utils/context.js +15 -0
  205. package/esm/chart/utils/index.js +9 -0
  206. package/esm/chart/utils/path.js +206 -0
  207. package/esm/chart/utils/point.js +118 -0
  208. package/esm/chart/utils/scale.js +48 -0
  209. package/esm/index.js +4 -0
  210. package/esm/sparkline/Counter.js +45 -0
  211. package/esm/sparkline/Sparkline.js +164 -0
  212. package/esm/sparkline/SparklineArea.js +19 -0
  213. package/esm/sparkline/SparklineAreaPattern.js +38 -0
  214. package/esm/sparkline/SparklineGradient.js +76 -0
  215. package/esm/sparkline/__figma__/Sparkline.figma.js +22 -0
  216. package/esm/sparkline/__stories__/Sparkline.stories.js +120 -0
  217. package/esm/sparkline/__stories__/SparklineGradient.stories.js +123 -0
  218. package/esm/sparkline/generateSparklineWithId.js +7 -0
  219. package/esm/sparkline/index.js +5 -0
  220. package/esm/sparkline/sparkline-interactive/SparklineAccessibleView.js +75 -0
  221. package/esm/sparkline/sparkline-interactive/SparklineInteractive.js +307 -0
  222. package/esm/sparkline/sparkline-interactive/SparklineInteractiveAnimatedPath.js +116 -0
  223. package/esm/sparkline/sparkline-interactive/SparklineInteractiveHoverDate.js +131 -0
  224. package/esm/sparkline/sparkline-interactive/SparklineInteractiveLineVertical.js +99 -0
  225. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMarkerDates.js +82 -0
  226. package/esm/sparkline/sparkline-interactive/SparklineInteractiveMinMax.js +103 -0
  227. package/esm/sparkline/sparkline-interactive/SparklineInteractivePanGestureHandler.js +104 -0
  228. package/esm/sparkline/sparkline-interactive/SparklineInteractivePaths.js +57 -0
  229. package/esm/sparkline/sparkline-interactive/SparklineInteractivePeriodSelector.js +124 -0
  230. package/esm/sparkline/sparkline-interactive/SparklineInteractiveProvider.js +80 -0
  231. package/esm/sparkline/sparkline-interactive/SparklineInteractiveTimeseriesPaths.js +109 -0
  232. package/esm/sparkline/sparkline-interactive/__figma__/SparklineInteractive.figma.js +85 -0
  233. package/esm/sparkline/sparkline-interactive/__stories__/SparklineInteractive.stories.js +501 -0
  234. package/esm/sparkline/sparkline-interactive/useInterruptiblePathAnimation.js +58 -0
  235. package/esm/sparkline/sparkline-interactive/useInterruptiblePathAnimation.test.disable.js +37 -0
  236. package/esm/sparkline/sparkline-interactive/useMinMaxTransform.js +56 -0
  237. package/esm/sparkline/sparkline-interactive/useOpacityAnimation.js +23 -0
  238. package/esm/sparkline/sparkline-interactive/useSparklineInteractiveConstants.js +47 -0
  239. package/esm/sparkline/sparkline-interactive/useSparklineInteractiveLineStyles.js +34 -0
  240. package/esm/sparkline/sparkline-interactive-header/SparklineInteractiveHeader.js +233 -0
  241. package/esm/sparkline/sparkline-interactive-header/__figma__/SparklineInteractiveHeader.figma.js +104 -0
  242. package/esm/sparkline/sparkline-interactive-header/__stories__/SparklineInteractiveHeader.stories.js +555 -0
  243. package/esm/sparkline/sparkline-interactive-header/useSparklineInteractiveHeaderStyles.js +117 -0
  244. package/package.json +65 -6
  245. package/index.js +0 -1
@@ -0,0 +1,237 @@
1
+ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { G, Rect as SvgRect, Text } from 'react-native-svg';
3
+ import { useTheme } from '@coinbase/cds-mobile/hooks/useTheme';
4
+ import { useCartesianChartContext } from '../ChartProvider';
5
+ import { getChartInset } from '../utils';
6
+
7
+ /**
8
+ * The supported content types for ChartText.
9
+ */
10
+
11
+ /**
12
+ * Horizontal alignment options for chart text.
13
+ */
14
+
15
+ /**
16
+ * Vertical alignment options for chart text.
17
+ */
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ /**
20
+ * Maps horizontal alignment to SVG textAnchor.
21
+ * This abstraction allows us to provide a consistent alignment API across web and mobile platforms,
22
+ * hiding the platform-specific SVG property differences.
23
+ */
24
+ const getTextAnchor = alignment => {
25
+ switch (alignment) {
26
+ case 'left':
27
+ return 'start';
28
+ case 'center':
29
+ return 'middle';
30
+ case 'right':
31
+ return 'end';
32
+ }
33
+ };
34
+
35
+ /**
36
+ * Maps vertical alignment to SVG alignmentBaseline.
37
+ * This abstraction allows us to provide a consistent alignment API across web and mobile platforms,
38
+ * hiding the platform-specific SVG property differences.
39
+ */
40
+ const getAlignmentBaseline = alignment => {
41
+ switch (alignment) {
42
+ case 'top':
43
+ return 'hanging';
44
+ case 'middle':
45
+ return 'central';
46
+ case 'bottom':
47
+ return 'ideographic';
48
+ }
49
+ };
50
+ const ChartTextVisible = /*#__PURE__*/memo(_ref => {
51
+ let {
52
+ children,
53
+ background,
54
+ textAnchor,
55
+ alignmentBaseline,
56
+ fontSize,
57
+ fontWeight,
58
+ fill,
59
+ borderRadius,
60
+ inset: insetInput,
61
+ textDimensions,
62
+ dx,
63
+ dy
64
+ } = _ref;
65
+ const theme = useTheme();
66
+ const inset = useMemo(() => getChartInset(insetInput), [insetInput]);
67
+ const rectHeight = useMemo(() => textDimensions.height + inset.top + inset.bottom, [textDimensions, inset]);
68
+ const rectWidth = useMemo(() => textDimensions.width + inset.left + inset.right, [textDimensions, inset]);
69
+ return /*#__PURE__*/_jsxs(G, {
70
+ children: [background !== 'transparent' && /*#__PURE__*/_jsx(SvgRect, {
71
+ fill: background,
72
+ height: rectHeight,
73
+ rx: borderRadius,
74
+ ry: borderRadius,
75
+ width: rectWidth,
76
+ x: textDimensions.x - inset.left,
77
+ y: textDimensions.y - inset.top
78
+ }), /*#__PURE__*/_jsx(Text, {
79
+ alignmentBaseline: alignmentBaseline,
80
+ dx: dx,
81
+ dy: dy,
82
+ fill: fill != null ? fill : theme.color.fgMuted,
83
+ fontSize: fontSize,
84
+ fontWeight: fontWeight,
85
+ textAnchor: textAnchor,
86
+ children: children
87
+ })]
88
+ });
89
+ });
90
+ export const ChartText = /*#__PURE__*/memo(_ref2 => {
91
+ let {
92
+ children,
93
+ x,
94
+ y,
95
+ horizontalAlignment = 'center',
96
+ verticalAlignment = 'middle',
97
+ dx,
98
+ dy,
99
+ disableRepositioning = false,
100
+ bounds,
101
+ testID,
102
+ fontSize = 12,
103
+ fontWeight,
104
+ color,
105
+ background = 'transparent',
106
+ borderRadius,
107
+ inset: insetInput,
108
+ onDimensionsChange,
109
+ opacity = 1
110
+ } = _ref2;
111
+ const {
112
+ width: chartWidth,
113
+ height: chartHeight
114
+ } = useCartesianChartContext();
115
+ const textAnchor = useMemo(() => getTextAnchor(horizontalAlignment), [horizontalAlignment]);
116
+ const alignmentBaseline = useMemo(() => getAlignmentBaseline(verticalAlignment), [verticalAlignment]);
117
+ const fullChartBounds = useMemo(() => ({
118
+ x: 0,
119
+ y: 0,
120
+ width: chartWidth,
121
+ height: chartHeight
122
+ }), [chartWidth, chartHeight]);
123
+ const [textSize, setTextSize] = useState(null);
124
+ const textBBox = useMemo(() => {
125
+ if (!textSize) {
126
+ return null;
127
+ }
128
+ return {
129
+ x: x + textSize.x,
130
+ y: y + textSize.y,
131
+ width: textSize.width,
132
+ height: textSize.height
133
+ };
134
+ }, [x, y, textSize]);
135
+ const isDimensionsReady = disableRepositioning || textBBox !== null;
136
+ const backgroundRectDimensions = useMemo(() => {
137
+ if (!textBBox) {
138
+ return null;
139
+ }
140
+ const inset = getChartInset(insetInput);
141
+ return {
142
+ x: textBBox.x - inset.left,
143
+ y: textBBox.y - inset.top,
144
+ width: textBBox.width + inset.left + inset.right,
145
+ height: textBBox.height + inset.top + inset.bottom
146
+ };
147
+ }, [textBBox, insetInput]);
148
+ const overflowAmount = useMemo(() => {
149
+ if (disableRepositioning) {
150
+ return {
151
+ x: 0,
152
+ y: 0
153
+ };
154
+ }
155
+ const parentBounds = bounds != null ? bounds : fullChartBounds;
156
+ if (!backgroundRectDimensions || !parentBounds || parentBounds.width <= 0 || parentBounds.height <= 0) {
157
+ return {
158
+ x: 0,
159
+ y: 0
160
+ };
161
+ }
162
+ let x = 0;
163
+ let y = 0;
164
+
165
+ // X-axis overflow
166
+ if (backgroundRectDimensions.x < parentBounds.x) {
167
+ x = parentBounds.x - backgroundRectDimensions.x; // positive = shift right
168
+ } else if (backgroundRectDimensions.x + backgroundRectDimensions.width > parentBounds.x + parentBounds.width) {
169
+ x = parentBounds.x + parentBounds.width - (backgroundRectDimensions.x + backgroundRectDimensions.width); // negative = shift left
170
+ }
171
+
172
+ // Y-axis overflow
173
+ if (backgroundRectDimensions.y < parentBounds.y) {
174
+ y = parentBounds.y - backgroundRectDimensions.y; // positive = shift down
175
+ } else if (backgroundRectDimensions.y + backgroundRectDimensions.height > parentBounds.y + parentBounds.height) {
176
+ y = parentBounds.y + parentBounds.height - (backgroundRectDimensions.y + backgroundRectDimensions.height); // negative = shift up
177
+ }
178
+ return {
179
+ x,
180
+ y
181
+ };
182
+ }, [backgroundRectDimensions, fullChartBounds, bounds, disableRepositioning]);
183
+ const reportedRect = useMemo(() => {
184
+ if (!backgroundRectDimensions) return null;
185
+ return {
186
+ x: backgroundRectDimensions.x + overflowAmount.x,
187
+ y: backgroundRectDimensions.y + overflowAmount.y,
188
+ width: backgroundRectDimensions.width,
189
+ height: backgroundRectDimensions.height
190
+ };
191
+ }, [backgroundRectDimensions, overflowAmount.x, overflowAmount.y]);
192
+ useEffect(() => {
193
+ if (onDimensionsChange && reportedRect !== null) {
194
+ onDimensionsChange(reportedRect);
195
+ }
196
+ }, [reportedRect, onDimensionsChange]);
197
+ const onLayout = useCallback(event => {
198
+ if (event.nativeEvent.layout.width > 0 && event.nativeEvent.layout.height > 0) {
199
+ setTextSize(event.nativeEvent.layout);
200
+ }
201
+ }, []);
202
+ return /*#__PURE__*/_jsxs(G, {
203
+ opacity: isDimensionsReady ? opacity : 0,
204
+ children: [textSize && /*#__PURE__*/_jsx(G, {
205
+ transform: [{
206
+ translateX: x + overflowAmount.x
207
+ }, {
208
+ translateY: y + overflowAmount.y
209
+ }],
210
+ children: /*#__PURE__*/_jsx(ChartTextVisible, {
211
+ alignmentBaseline: alignmentBaseline,
212
+ background: background,
213
+ borderRadius: borderRadius,
214
+ dx: dx,
215
+ dy: dy,
216
+ fill: color,
217
+ fontSize: fontSize,
218
+ fontWeight: fontWeight,
219
+ inset: insetInput,
220
+ textAnchor: textAnchor,
221
+ textDimensions: textSize,
222
+ children: children
223
+ })
224
+ }), /*#__PURE__*/_jsx(Text, {
225
+ alignmentBaseline: alignmentBaseline,
226
+ dx: dx,
227
+ dy: dy,
228
+ fill: "transparent",
229
+ fontSize: fontSize,
230
+ fontWeight: fontWeight,
231
+ onLayout: onLayout,
232
+ opacity: 0,
233
+ textAnchor: textAnchor,
234
+ children: children
235
+ })]
236
+ });
237
+ });
@@ -0,0 +1,210 @@
1
+ const _excluded = ["onDimensionsChange"];
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 { memo, useEffect, useMemo, useState } from 'react';
5
+ import { G } from 'react-native-svg';
6
+ import { ChartText } from './ChartText';
7
+
8
+ /**
9
+ * Configuration for a single text label in the display list
10
+ */
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ /**
13
+ * Overlap check that enforces a minimum pixel gap between two rectangles.
14
+ * We inflate each rect by gap/2 on all sides so two neighbors must be at
15
+ * least `gap` pixels apart to be considered non-overlapping.
16
+ */
17
+ function doRectsOverlapWithGap(a, b, gap) {
18
+ const g = gap / 2;
19
+ const overlapX = a.x - g < b.x + b.width + g && a.x + a.width + g > b.x - g;
20
+ const overlapY = a.y - g < b.y + b.height + g && a.y + a.height + g > b.y - g;
21
+ return overlapX && overlapY;
22
+ }
23
+
24
+ // Suppress state churn due to sub-pixel jitter in measurements
25
+ const EPSILON_PX = 0.5;
26
+
27
+ /**
28
+ * A smart text display component that prevents label overlap through collision detection.
29
+ *
30
+ * This component renders a list of ChartText components and automatically hides overlapping elements
31
+ * to ensure readability.
32
+ *
33
+ * The component focuses solely on overlap prevention logic for better separation of concerns.
34
+ */
35
+ export const SmartChartTextGroup = /*#__PURE__*/memo(_ref => {
36
+ let {
37
+ labels,
38
+ minGap = 8,
39
+ prioritizeEndLabels = true,
40
+ chartTextProps
41
+ } = _ref;
42
+ const [boundingBoxes, setBoundingBoxes] = useState(new Map());
43
+ const _ref2 = chartTextProps != null ? chartTextProps : {},
44
+ {
45
+ onDimensionsChange: propsOnDimensionsChange
46
+ } = _ref2,
47
+ restChartTextProps = _objectWithoutPropertiesLoose(_ref2, _excluded);
48
+
49
+ // Generate a unique key to reference each label with.
50
+ const labelsWithKeys = useMemo(() => {
51
+ return labels.map((labelData, index) => _extends({}, labelData, {
52
+ key: labelData.label + "-" + index
53
+ }));
54
+ }, [labels]);
55
+
56
+ // Cleans up `boundingBoxes` state so that it only includes entries for the current set of labels
57
+ useEffect(() => {
58
+ const allLabelsKeys = new Set(labelsWithKeys.map(l => l.key));
59
+ setBoundingBoxes(prev => {
60
+ let changed = false;
61
+ const next = new Map();
62
+ for (const [k, v] of prev) {
63
+ if (allLabelsKeys.has(k)) next.set(k, v);else changed = true;
64
+ }
65
+ return changed ? next : prev;
66
+ });
67
+ }, [labelsWithKeys]);
68
+
69
+ // Build stable per-label measurement callbacks that recreate when labels change
70
+ const onDimensionsChangeByKey = useMemo(() => {
71
+ const map = new Map();
72
+ for (const labelData of labelsWithKeys) {
73
+ const {
74
+ key,
75
+ chartTextProps: labelChartTextProps
76
+ } = labelData;
77
+ map.set(key, bounds => {
78
+ labelChartTextProps == null || labelChartTextProps.onDimensionsChange == null || labelChartTextProps.onDimensionsChange(bounds);
79
+ propsOnDimensionsChange == null || propsOnDimensionsChange(bounds);
80
+ // Ignore zero-sized bounds and no-op updates (epsilon compare)
81
+ if (bounds.width === 0 || bounds.height === 0) return;
82
+ setBoundingBoxes(prev => {
83
+ const prevRect = prev.get(key);
84
+ const nearlyEqual = (a, b) => Math.abs(a - b) <= EPSILON_PX;
85
+ const isSame = prevRect !== undefined && nearlyEqual(prevRect.x, bounds.x) && nearlyEqual(prevRect.y, bounds.y) && nearlyEqual(prevRect.width, bounds.width) && nearlyEqual(prevRect.height, bounds.height);
86
+ if (isSame) return prev;
87
+ const newMap = new Map(prev);
88
+ newMap.set(key, bounds);
89
+ return newMap;
90
+ });
91
+ });
92
+ }
93
+ return map;
94
+ }, [labelsWithKeys, propsOnDimensionsChange]);
95
+
96
+ // Determine readiness: all current labels have measured bounding boxes
97
+ const isReady = useMemo(() => labelsWithKeys.every(l => boundingBoxes.has(l.key)), [labelsWithKeys, boundingBoxes]);
98
+
99
+ // Compute visible keys using stride attempts then greedy fallback
100
+ const visibleKeySet = useMemo(() => {
101
+ // Build ordered set of labels with rects for collision detection algorithm
102
+ const orderedWithRects = labelsWithKeys.map((l, idx) => _extends({}, l, {
103
+ rect: boundingBoxes.get(l.key)
104
+ })).filter(x => x.rect !== undefined);
105
+
106
+ // 1) Sort by horizontal position so neighbor checks are O(1)
107
+ // For ties, sort bottom-to-top (higher y first) to get stable ordering
108
+ orderedWithRects.sort((a, b) => a.x === b.x ? b.y - a.y : a.x - b.x);
109
+
110
+ // 2) Defer selection until all labels have measured to avoid flicker and early hiding
111
+ if (!isReady) return null;
112
+ const n = orderedWithRects.length;
113
+ // 3) Trivial cases
114
+ if (n === 0) return new Set();
115
+ if (n === 1) return new Set([orderedWithRects[0].key]);
116
+
117
+ // 4) Two-label rule: if overlapping, prefer the first label (original order)
118
+ if (n === 2) {
119
+ const a = orderedWithRects[0];
120
+ const b = orderedWithRects[1];
121
+ const overlap = doRectsOverlapWithGap(a.rect, b.rect, minGap);
122
+ if (overlap) {
123
+ var _labelsWithKeys$;
124
+ const firstOriginal = (_labelsWithKeys$ = labelsWithKeys[0]) == null ? void 0 : _labelsWithKeys$.key;
125
+ return new Set([firstOriginal != null ? firstOriginal : a.key]);
126
+ }
127
+ return new Set([a.key, b.key]);
128
+ }
129
+
130
+ // 5) Utility: check only adjacent neighbors in x-order for overlap with gap
131
+ const hasNeighborOverlap = keysOrdered => {
132
+ for (let i = 0; i < keysOrdered.length - 1; i++) {
133
+ const ra = boundingBoxes.get(keysOrdered[i]);
134
+ const rb = boundingBoxes.get(keysOrdered[i + 1]);
135
+ if (doRectsOverlapWithGap(ra, rb, minGap)) return true;
136
+ }
137
+ return false;
138
+ };
139
+
140
+ // 6) Fast path: if every label fits, show them all without reduction
141
+ const allKeys = orderedWithRects.map(l => l.key);
142
+ if (!hasNeighborOverlap(allKeys)) {
143
+ return new Set(allKeys);
144
+ }
145
+
146
+ // 7) Try stride patterns: every 2nd, every 3rd, ... while ensuring ends when prioritized
147
+ const tryStride = stride => {
148
+ const selected = [];
149
+ for (let i = 0; i < n; i += stride) selected.push(orderedWithRects[i].key);
150
+ if (prioritizeEndLabels) {
151
+ const firstKey = orderedWithRects[0].key;
152
+ const lastKey = orderedWithRects[n - 1].key;
153
+ if (selected[0] !== firstKey) selected.unshift(firstKey);
154
+ if (selected[selected.length - 1] !== lastKey) selected.push(lastKey);
155
+ }
156
+ // Deduplicate while preserving order
157
+ const unique = Array.from(new Set(selected));
158
+ return hasNeighborOverlap(unique) ? new Set() : new Set(unique);
159
+ };
160
+
161
+ // 8) Increase stride until something fits or we exhaust options
162
+ for (let stride = 2; stride <= n; stride++) {
163
+ const attempt = tryStride(stride);
164
+ if (attempt.size > 0) return attempt;
165
+ }
166
+
167
+ // 9) Greedy fallback: walk left-to-right and keep a label only if it
168
+ // does not overlap the previously accepted label. Optionally ensure last.
169
+ const greedy = [];
170
+ const firstKey = orderedWithRects[0].key;
171
+ const lastKey = orderedWithRects[n - 1].key;
172
+ greedy.push(firstKey);
173
+ for (let i = 1; i < n - 1; i++) {
174
+ const k = orderedWithRects[i].key;
175
+ const prevKey = greedy[greedy.length - 1];
176
+ const ra = boundingBoxes.get(prevKey);
177
+ const rb = boundingBoxes.get(k);
178
+ if (!doRectsOverlapWithGap(ra, rb, minGap)) {
179
+ greedy.push(k);
180
+ }
181
+ }
182
+ // Ensure last key when prioritized
183
+ if (prioritizeEndLabels) {
184
+ const lastIncluded = greedy[greedy.length - 1];
185
+ const ra = boundingBoxes.get(lastIncluded);
186
+ const rb = boundingBoxes.get(lastKey);
187
+ if (doRectsOverlapWithGap(ra, rb, minGap)) {
188
+ // Replace the last conflicting with the lastKey
189
+ greedy[greedy.length - 1] = lastKey;
190
+ } else if (lastIncluded !== lastKey) {
191
+ greedy.push(lastKey);
192
+ }
193
+ }
194
+ return new Set(greedy);
195
+ }, [isReady, boundingBoxes, minGap, prioritizeEndLabels, labelsWithKeys]);
196
+ return /*#__PURE__*/_jsx(G, {
197
+ children: labelsWithKeys.map(labelData => {
198
+ const hasMeasurement = boundingBoxes.has(labelData.key);
199
+ const isVisible = hasMeasurement && isReady && (visibleKeySet == null ? void 0 : visibleKeySet.has(labelData.key));
200
+ return /*#__PURE__*/_jsx(ChartText, _extends({
201
+ opacity: isVisible ? 1 : 0,
202
+ x: labelData.x,
203
+ y: labelData.y
204
+ }, restChartTextProps, labelData.chartTextProps, {
205
+ onDimensionsChange: onDimensionsChangeByKey.get(labelData.key),
206
+ children: labelData.label
207
+ }), labelData.key);
208
+ })
209
+ });
210
+ });
@@ -0,0 +1,4 @@
1
+ // codegen:start {preset: barrel, include: ./*.tsx, exclude: ./__stories__/*.tsx}
2
+ export * from './ChartText';
3
+ export * from './SmartChartTextGroup';
4
+ // codegen:end