@ledgerhq/lumen-ui-rnative-visualization 0.1.17 → 0.1.19

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 (219) hide show
  1. package/dist/module/lib/Components/Axis/XAxis/XAxis.js +4 -3
  2. package/dist/module/lib/Components/Axis/XAxis/XAxis.js.map +1 -1
  3. package/dist/module/lib/Components/Axis/XAxis/XAxis.test.js +14 -0
  4. package/dist/module/lib/Components/Axis/XAxis/XAxis.test.js.map +1 -1
  5. package/dist/module/lib/Components/Axis/YAxis/YAxis.js +4 -3
  6. package/dist/module/lib/Components/Axis/YAxis/YAxis.js.map +1 -1
  7. package/dist/module/lib/Components/Axis/YAxis/YAxis.test.js +14 -0
  8. package/dist/module/lib/Components/Axis/YAxis/YAxis.test.js.map +1 -1
  9. package/dist/module/lib/Components/CartesianChart/CartesianChart.js +30 -23
  10. package/dist/module/lib/Components/CartesianChart/CartesianChart.js.map +1 -1
  11. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.js +61 -0
  12. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.js.map +1 -0
  13. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/index.js +4 -0
  14. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/index.js.map +1 -0
  15. package/dist/module/lib/Components/CartesianChart/{RevealClip/RevealClipDefs.js → RevealAnimation/RevealAnimationProvider.js} +13 -13
  16. package/dist/module/lib/Components/CartesianChart/RevealAnimation/RevealAnimationProvider.js.map +1 -0
  17. package/dist/module/lib/Components/CartesianChart/{RevealClip/RevealClipDefs.test.js → RevealAnimation/RevealAnimationProvider.test.js} +51 -12
  18. package/dist/module/lib/Components/CartesianChart/RevealAnimation/RevealAnimationProvider.test.js.map +1 -0
  19. package/dist/module/lib/Components/CartesianChart/RevealAnimation/context.js +35 -0
  20. package/dist/module/lib/Components/CartesianChart/RevealAnimation/context.js.map +1 -0
  21. package/dist/module/lib/Components/CartesianChart/RevealAnimation/index.js +5 -0
  22. package/dist/module/lib/Components/CartesianChart/RevealAnimation/index.js.map +1 -0
  23. package/dist/module/lib/Components/CartesianChart/RevealAnimation/types.js.map +1 -0
  24. package/dist/module/lib/Components/CartesianChart/RevealAnimation/utils.js +64 -0
  25. package/dist/module/lib/Components/CartesianChart/RevealAnimation/utils.js.map +1 -0
  26. package/dist/module/lib/Components/CartesianChart/hooks/useShimmerAnimation.js +37 -0
  27. package/dist/module/lib/Components/CartesianChart/hooks/useShimmerAnimation.js.map +1 -0
  28. package/dist/module/lib/Components/CartesianChart/utils.js +1 -1
  29. package/dist/module/lib/Components/CartesianChart/utils.js.map +1 -1
  30. package/dist/module/lib/Components/Line/Line.js +18 -11
  31. package/dist/module/lib/Components/Line/Line.js.map +1 -1
  32. package/dist/module/lib/Components/Line/constants.js +5 -0
  33. package/dist/module/lib/Components/Line/constants.js.map +1 -0
  34. package/dist/module/lib/Components/Line/types.js +2 -0
  35. package/dist/module/lib/Components/Line/utils.js +38 -11
  36. package/dist/module/lib/Components/Line/utils.js.map +1 -1
  37. package/dist/module/lib/Components/Line/utils.test.js +49 -3
  38. package/dist/module/lib/Components/Line/utils.test.js.map +1 -1
  39. package/dist/module/lib/Components/LineChart/LineChart.js +131 -27
  40. package/dist/module/lib/Components/LineChart/LineChart.js.map +1 -1
  41. package/dist/module/lib/Components/LineChart/LineChart.test.js +147 -0
  42. package/dist/module/lib/Components/LineChart/LineChart.test.js.map +1 -1
  43. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.js +72 -0
  44. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.js.map +1 -0
  45. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.js +47 -0
  46. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.js.map +1 -0
  47. package/dist/module/lib/Components/LineChart/LineChartEmptyState/index.js +4 -0
  48. package/dist/module/lib/Components/LineChart/LineChartEmptyState/index.js.map +1 -0
  49. package/dist/module/lib/Components/LineChart/LineChartEmptyState/types.js +4 -0
  50. package/dist/module/lib/Components/LineChart/LineChartEmptyState/types.js.map +1 -0
  51. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.js +22 -0
  52. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.js.map +1 -0
  53. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.test.js +21 -0
  54. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.test.js.map +1 -0
  55. package/dist/module/lib/Components/LineChart/utils.js +83 -0
  56. package/dist/module/lib/Components/LineChart/utils.js.map +1 -0
  57. package/dist/module/lib/Components/LineChart/utils.test.js +174 -0
  58. package/dist/module/lib/Components/LineChart/utils.test.js.map +1 -0
  59. package/dist/module/lib/Components/Point/Point.js +6 -4
  60. package/dist/module/lib/Components/Point/Point.js.map +1 -1
  61. package/dist/module/lib/Components/ReferenceLine/ReferenceLine.js +4 -4
  62. package/dist/module/lib/Components/ReferenceLine/ReferenceLine.js.map +1 -1
  63. package/dist/module/lib/Components/ReferenceLine/constants.js +2 -2
  64. package/dist/module/lib/Components/ReferenceLine/constants.js.map +1 -1
  65. package/dist/module/lib/Components/ReferenceLine/utils.js +2 -1
  66. package/dist/module/lib/Components/ReferenceLine/utils.js.map +1 -1
  67. package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js +2 -1
  68. package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js.map +1 -1
  69. package/dist/module/lib/Components/Scrubber/Scrubber.js +2 -2
  70. package/dist/module/lib/Components/Scrubber/Scrubber.js.map +1 -1
  71. package/dist/module/lib/Components/Scrubber/ScrubberProvider.js +10 -2
  72. package/dist/module/lib/Components/Scrubber/ScrubberProvider.js.map +1 -1
  73. package/dist/module/lib/Components/Scrubber/ScrubberProvider.test.js +79 -1
  74. package/dist/module/lib/Components/Scrubber/ScrubberProvider.test.js.map +1 -1
  75. package/dist/module/lib/Components/Scrubber/utils.js +3 -2
  76. package/dist/module/lib/Components/Scrubber/utils.js.map +1 -1
  77. package/dist/module/lib/utils/numbers.js +16 -0
  78. package/dist/module/lib/utils/numbers.js.map +1 -0
  79. package/dist/module/lib/utils/ticks/ticks.js +0 -16
  80. package/dist/module/lib/utils/ticks/ticks.js.map +1 -1
  81. package/dist/typescript/src/lib/Components/Axis/Axis.types.d.ts +6 -0
  82. package/dist/typescript/src/lib/Components/Axis/Axis.types.d.ts.map +1 -1
  83. package/dist/typescript/src/lib/Components/Axis/XAxis/XAxis.d.ts +1 -1
  84. package/dist/typescript/src/lib/Components/Axis/XAxis/XAxis.d.ts.map +1 -1
  85. package/dist/typescript/src/lib/Components/Axis/YAxis/YAxis.d.ts +1 -1
  86. package/dist/typescript/src/lib/Components/Axis/YAxis/YAxis.d.ts.map +1 -1
  87. package/dist/typescript/src/lib/Components/CartesianChart/CartesianChart.d.ts +1 -1
  88. package/dist/typescript/src/lib/Components/CartesianChart/CartesianChart.d.ts.map +1 -1
  89. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.d.ts +18 -0
  90. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.d.ts.map +1 -0
  91. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/index.d.ts +2 -0
  92. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/index.d.ts.map +1 -0
  93. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/RevealAnimationProvider.d.ts +3 -0
  94. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/RevealAnimationProvider.d.ts.map +1 -0
  95. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/context.d.ts +22 -0
  96. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/context.d.ts.map +1 -0
  97. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/index.d.ts +3 -0
  98. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/index.d.ts.map +1 -0
  99. package/dist/typescript/src/lib/Components/CartesianChart/{RevealClip → RevealAnimation}/types.d.ts +15 -2
  100. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/types.d.ts.map +1 -0
  101. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/utils.d.ts +33 -0
  102. package/dist/typescript/src/lib/Components/CartesianChart/RevealAnimation/utils.d.ts.map +1 -0
  103. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.d.ts +13 -0
  104. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.d.ts.map +1 -0
  105. package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts +12 -0
  106. package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts.map +1 -1
  107. package/dist/typescript/src/lib/Components/CartesianChart/utils.d.ts +1 -1
  108. package/dist/typescript/src/lib/Components/CartesianChart/utils.d.ts.map +1 -1
  109. package/dist/typescript/src/lib/Components/Line/Line.d.ts +1 -1
  110. package/dist/typescript/src/lib/Components/Line/Line.d.ts.map +1 -1
  111. package/dist/typescript/src/lib/Components/Line/constants.d.ts +3 -0
  112. package/dist/typescript/src/lib/Components/Line/constants.d.ts.map +1 -0
  113. package/dist/typescript/src/lib/Components/Line/index.d.ts +1 -1
  114. package/dist/typescript/src/lib/Components/Line/index.d.ts.map +1 -1
  115. package/dist/typescript/src/lib/Components/Line/types.d.ts +15 -0
  116. package/dist/typescript/src/lib/Components/Line/types.d.ts.map +1 -1
  117. package/dist/typescript/src/lib/Components/Line/utils.d.ts +11 -6
  118. package/dist/typescript/src/lib/Components/Line/utils.d.ts.map +1 -1
  119. package/dist/typescript/src/lib/Components/LineChart/LineChart.d.ts +1 -1
  120. package/dist/typescript/src/lib/Components/LineChart/LineChart.d.ts.map +1 -1
  121. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.d.ts +9 -0
  122. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.d.ts.map +1 -0
  123. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/index.d.ts +3 -0
  124. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/index.d.ts.map +1 -0
  125. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/types.d.ts +3 -0
  126. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/types.d.ts.map +1 -0
  127. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/utils.d.ts +14 -0
  128. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/utils.d.ts.map +1 -0
  129. package/dist/typescript/src/lib/Components/LineChart/types.d.ts +41 -1
  130. package/dist/typescript/src/lib/Components/LineChart/types.d.ts.map +1 -1
  131. package/dist/typescript/src/lib/Components/LineChart/utils.d.ts +43 -0
  132. package/dist/typescript/src/lib/Components/LineChart/utils.d.ts.map +1 -0
  133. package/dist/typescript/src/lib/Components/Point/Point.d.ts.map +1 -1
  134. package/dist/typescript/src/lib/Components/ReferenceLine/ReferenceLine.d.ts.map +1 -1
  135. package/dist/typescript/src/lib/Components/ReferenceLine/constants.d.ts +2 -2
  136. package/dist/typescript/src/lib/Components/ReferenceLine/constants.d.ts.map +1 -1
  137. package/dist/typescript/src/lib/Components/ReferenceLine/utils.d.ts.map +1 -1
  138. package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.d.ts.map +1 -1
  139. package/dist/typescript/src/lib/Components/Scrubber/Scrubber.d.ts.map +1 -1
  140. package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts.map +1 -1
  141. package/dist/typescript/src/lib/Components/Scrubber/utils.d.ts.map +1 -1
  142. package/dist/typescript/src/lib/utils/index.d.ts +1 -1
  143. package/dist/typescript/src/lib/utils/index.d.ts.map +1 -1
  144. package/dist/typescript/src/lib/utils/numbers.d.ts +13 -0
  145. package/dist/typescript/src/lib/utils/numbers.d.ts.map +1 -0
  146. package/dist/typescript/src/lib/utils/ticks/ticks.d.ts +1 -11
  147. package/dist/typescript/src/lib/utils/ticks/ticks.d.ts.map +1 -1
  148. package/dist/typescript/src/lib/utils/types.d.ts +27 -2
  149. package/dist/typescript/src/lib/utils/types.d.ts.map +1 -1
  150. package/package.json +3 -3
  151. package/src/lib/Components/Axis/Axis.types.ts +6 -0
  152. package/src/lib/Components/Axis/XAxis/XAxis.test.tsx +12 -0
  153. package/src/lib/Components/Axis/XAxis/XAxis.tsx +29 -32
  154. package/src/lib/Components/Axis/YAxis/YAxis.test.tsx +12 -0
  155. package/src/lib/Components/Axis/YAxis/YAxis.tsx +29 -32
  156. package/src/lib/Components/CartesianChart/CartesianChart.tsx +30 -24
  157. package/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.tsx +68 -0
  158. package/src/lib/Components/CartesianChart/ChartEmptyLabel/index.ts +1 -0
  159. package/src/lib/Components/CartesianChart/{RevealClip/RevealClipDefs.test.tsx → RevealAnimation/RevealAnimationProvider.test.tsx} +60 -17
  160. package/src/lib/Components/CartesianChart/{RevealClip/RevealClipDefs.tsx → RevealAnimation/RevealAnimationProvider.tsx} +11 -11
  161. package/src/lib/Components/CartesianChart/RevealAnimation/context.ts +39 -0
  162. package/src/lib/Components/CartesianChart/RevealAnimation/index.ts +2 -0
  163. package/src/lib/Components/CartesianChart/{RevealClip → RevealAnimation}/types.ts +16 -2
  164. package/src/lib/Components/CartesianChart/RevealAnimation/utils.ts +87 -0
  165. package/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.ts +52 -0
  166. package/src/lib/Components/CartesianChart/types.ts +12 -0
  167. package/src/lib/Components/CartesianChart/utils.ts +2 -1
  168. package/src/lib/Components/Line/Line.tsx +26 -14
  169. package/src/lib/Components/Line/constants.ts +2 -0
  170. package/src/lib/Components/Line/index.ts +1 -1
  171. package/src/lib/Components/Line/types.ts +17 -0
  172. package/src/lib/Components/Line/utils.test.ts +77 -3
  173. package/src/lib/Components/Line/utils.ts +63 -12
  174. package/src/lib/Components/LineChart/LineChart.test.tsx +135 -0
  175. package/src/lib/Components/LineChart/LineChart.tsx +157 -38
  176. package/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.tsx +39 -0
  177. package/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.tsx +72 -0
  178. package/src/lib/Components/LineChart/LineChartEmptyState/index.ts +2 -0
  179. package/src/lib/Components/LineChart/LineChartEmptyState/types.ts +3 -0
  180. package/src/lib/Components/LineChart/LineChartEmptyState/utils.test.ts +22 -0
  181. package/src/lib/Components/LineChart/LineChartEmptyState/utils.ts +24 -0
  182. package/src/lib/Components/LineChart/types.ts +49 -1
  183. package/src/lib/Components/LineChart/utils.test.ts +196 -0
  184. package/src/lib/Components/LineChart/utils.ts +107 -0
  185. package/src/lib/Components/Point/Point.tsx +7 -4
  186. package/src/lib/Components/ReferenceLine/ReferenceLine.tsx +8 -4
  187. package/src/lib/Components/ReferenceLine/constants.ts +2 -2
  188. package/src/lib/Components/ReferenceLine/utils.ts +2 -1
  189. package/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.ts +2 -1
  190. package/src/lib/Components/Scrubber/Scrubber.tsx +13 -2
  191. package/src/lib/Components/Scrubber/ScrubberProvider.test.tsx +83 -1
  192. package/src/lib/Components/Scrubber/ScrubberProvider.tsx +17 -2
  193. package/src/lib/Components/Scrubber/utils.ts +3 -5
  194. package/src/lib/utils/index.ts +1 -0
  195. package/src/lib/utils/numbers.ts +15 -0
  196. package/src/lib/utils/ticks/ticks.ts +1 -23
  197. package/src/lib/utils/types.ts +35 -2
  198. package/dist/module/lib/Components/CartesianChart/RevealClip/RevealClipDefs.js.map +0 -1
  199. package/dist/module/lib/Components/CartesianChart/RevealClip/RevealClipDefs.test.js.map +0 -1
  200. package/dist/module/lib/Components/CartesianChart/RevealClip/context.js +0 -8
  201. package/dist/module/lib/Components/CartesianChart/RevealClip/context.js.map +0 -1
  202. package/dist/module/lib/Components/CartesianChart/RevealClip/index.js +0 -5
  203. package/dist/module/lib/Components/CartesianChart/RevealClip/index.js.map +0 -1
  204. package/dist/module/lib/Components/CartesianChart/RevealClip/types.js.map +0 -1
  205. package/dist/module/lib/Components/CartesianChart/RevealClip/utils.js +0 -32
  206. package/dist/module/lib/Components/CartesianChart/RevealClip/utils.js.map +0 -1
  207. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/RevealClipDefs.d.ts +0 -3
  208. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/RevealClipDefs.d.ts.map +0 -1
  209. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/context.d.ts +0 -7
  210. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/context.d.ts.map +0 -1
  211. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/index.d.ts +0 -3
  212. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/index.d.ts.map +0 -1
  213. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/types.d.ts.map +0 -1
  214. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/utils.d.ts +0 -17
  215. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/utils.d.ts.map +0 -1
  216. package/src/lib/Components/CartesianChart/RevealClip/context.ts +0 -13
  217. package/src/lib/Components/CartesianChart/RevealClip/index.ts +0 -2
  218. package/src/lib/Components/CartesianChart/RevealClip/utils.ts +0 -51
  219. /package/dist/module/lib/Components/CartesianChart/{RevealClip → RevealAnimation}/types.js +0 -0
@@ -1,13 +1,111 @@
1
+ import { useTheme } from '@ledgerhq/lumen-ui-rnative';
1
2
  import { useMemo } from 'react';
3
+ import Animated from 'react-native-reanimated';
4
+ import { G } from 'react-native-svg';
2
5
 
3
- import type { ChartInset } from '../../utils/types';
4
6
  import { defaultXAxisProps, defaultYAxisProps } from '../Axis';
5
- import { DEFAULT_AXIS_HEIGHT, XAxis } from '../Axis/XAxis';
7
+ import { XAxis } from '../Axis/XAxis';
6
8
  import { YAxis } from '../Axis/YAxis';
7
9
  import { CartesianChart } from '../CartesianChart';
10
+ import { ChartEmptyLabel } from '../CartesianChart/ChartEmptyLabel';
11
+ import { useShimmerAnimation } from '../CartesianChart/hooks/useShimmerAnimation';
8
12
  import { Line } from '../Line';
9
13
 
10
- import type { LineChartProps } from './types';
14
+ import { LineChartEmptyState } from './LineChartEmptyState';
15
+ import type {
16
+ LineChartContentProps,
17
+ LineChartLinesProps,
18
+ LineChartProps,
19
+ LineChartTransitionLinesProps,
20
+ } from './types';
21
+ import {
22
+ canRenderLine,
23
+ computeAxisPadding,
24
+ getChartDisplayState,
25
+ } from './utils';
26
+
27
+ const AnimatedG = Animated.createAnimatedComponent(G);
28
+
29
+ const LineChartLines = ({
30
+ series,
31
+ showArea,
32
+ areaType,
33
+ stroke,
34
+ connectNulls,
35
+ }: Readonly<LineChartLinesProps>) => {
36
+ return (
37
+ <>
38
+ {series.map((s) => (
39
+ <Line
40
+ key={s.id}
41
+ seriesId={s.id}
42
+ stroke={stroke ?? s.stroke}
43
+ showArea={showArea}
44
+ areaType={areaType}
45
+ connectNulls={connectNulls}
46
+ />
47
+ ))}
48
+ </>
49
+ );
50
+ };
51
+
52
+ const LineChartTransitionLines = ({
53
+ series,
54
+ showArea,
55
+ areaType,
56
+ connectNulls,
57
+ }: Readonly<LineChartTransitionLinesProps>) => {
58
+ const { theme } = useTheme();
59
+ const { animatedProps } = useShimmerAnimation();
60
+
61
+ return (
62
+ <AnimatedG animatedProps={animatedProps}>
63
+ <LineChartLines
64
+ series={series}
65
+ showArea={showArea}
66
+ areaType={areaType}
67
+ stroke={theme.colors.border.mutedSubtle}
68
+ connectNulls={connectNulls}
69
+ />
70
+ </AnimatedG>
71
+ );
72
+ };
73
+
74
+ const LineChartContent = ({
75
+ series,
76
+ showArea,
77
+ areaType,
78
+ showXAxis,
79
+ showYAxis,
80
+ xAxisConfig,
81
+ yAxisConfig,
82
+ isTransitionLoading,
83
+ connectNulls,
84
+ children,
85
+ }: Readonly<LineChartContentProps>) => {
86
+ return (
87
+ <>
88
+ {showXAxis && <XAxis {...xAxisConfig} />}
89
+ {showYAxis && <YAxis {...yAxisConfig} />}
90
+ {isTransitionLoading ? (
91
+ <LineChartTransitionLines
92
+ series={series}
93
+ showArea={showArea}
94
+ areaType={areaType}
95
+ connectNulls={connectNulls}
96
+ />
97
+ ) : (
98
+ <LineChartLines
99
+ series={series}
100
+ showArea={showArea}
101
+ areaType={areaType}
102
+ connectNulls={connectNulls}
103
+ />
104
+ )}
105
+ {children}
106
+ </>
107
+ );
108
+ };
11
109
 
12
110
  export const LineChart = ({
13
111
  series,
@@ -18,47 +116,55 @@ export const LineChart = ({
18
116
  xAxis,
19
117
  yAxis,
20
118
  width,
21
- height = 160,
119
+ height = 228,
22
120
  inset,
23
121
  children,
24
122
  enableScrubbing = false,
25
123
  onScrubberPositionChange,
26
124
  animate,
27
125
  magnetRadius,
28
- }: LineChartProps) => {
126
+ loading = false,
127
+ emptyLabel = 'No data',
128
+ connectNulls,
129
+ }: Readonly<LineChartProps>) => {
29
130
  const xAxisConfig = {
30
131
  ...defaultXAxisProps,
31
132
  ...xAxis,
133
+ position: xAxis?.position ?? defaultXAxisProps.position,
32
134
  };
33
135
  const yAxisConfig = {
34
136
  ...defaultYAxisProps,
35
137
  ...yAxis,
138
+ position: yAxis?.position ?? defaultYAxisProps.position,
139
+ width: yAxis?.width ?? defaultYAxisProps.width,
36
140
  };
37
141
 
38
- const axisPadding: Partial<ChartInset> | undefined = useMemo(() => {
39
- if (!showXAxis && !showYAxis) {
40
- return undefined;
41
- }
142
+ const xAxisPosition = xAxisConfig.position;
143
+ const yAxisPosition = yAxisConfig.position;
144
+ const yAxisWidth = yAxisConfig.width;
42
145
 
43
- return {
44
- top:
45
- showXAxis && xAxisConfig.position === 'top' ? DEFAULT_AXIS_HEIGHT : 0,
46
- bottom:
47
- showXAxis && xAxisConfig.position === 'bottom'
48
- ? DEFAULT_AXIS_HEIGHT
49
- : 0,
50
- left:
51
- showYAxis && yAxisConfig.position === 'start' ? yAxisConfig.width : 0,
52
- right:
53
- showYAxis && yAxisConfig.position === 'end' ? yAxisConfig.width : 0,
54
- };
55
- }, [
56
- showXAxis,
57
- showYAxis,
58
- xAxisConfig?.position,
59
- yAxisConfig?.position,
60
- yAxisConfig?.width,
61
- ]);
146
+ const axisPadding = useMemo(
147
+ () =>
148
+ computeAxisPadding({
149
+ showXAxis,
150
+ showYAxis,
151
+ xAxisPosition,
152
+ yAxisPosition,
153
+ yAxisWidth,
154
+ }),
155
+ [showXAxis, showYAxis, xAxisPosition, yAxisPosition, yAxisWidth],
156
+ );
157
+
158
+ const hasData = canRenderLine(series, xAxisConfig.data);
159
+
160
+ const { status, ariaLabel } = getChartDisplayState({
161
+ loading,
162
+ hasData,
163
+ emptyLabel,
164
+ });
165
+
166
+ const isTransitionLoading = status === 'transition-loading';
167
+ const isPlaceholder = status === 'initial-loading' || status === 'empty';
62
168
 
63
169
  return (
64
170
  <CartesianChart
@@ -71,20 +177,33 @@ export const LineChart = ({
71
177
  axisPadding={axisPadding}
72
178
  enableScrubbing={enableScrubbing}
73
179
  onScrubberPositionChange={onScrubberPositionChange}
74
- animate={animate}
180
+ animate={isTransitionLoading ? false : animate}
75
181
  magnetRadius={magnetRadius}
182
+ ariaLabel={ariaLabel}
183
+ ariaBusy={loading}
184
+ overlay={
185
+ status === 'empty' ? (
186
+ <ChartEmptyLabel>{emptyLabel}</ChartEmptyLabel>
187
+ ) : undefined
188
+ }
76
189
  >
77
- {showXAxis && <XAxis {...xAxisConfig} />}
78
- {showYAxis && <YAxis {...yAxisConfig} />}
79
- {series?.map((s) => (
80
- <Line
81
- key={s.id}
82
- seriesId={s.id}
190
+ {isPlaceholder ? (
191
+ <LineChartEmptyState loading={status === 'initial-loading'} />
192
+ ) : (
193
+ <LineChartContent
194
+ series={series ?? []}
83
195
  showArea={showArea}
84
196
  areaType={areaType}
85
- />
86
- ))}
87
- {children}
197
+ showXAxis={showXAxis}
198
+ showYAxis={showYAxis}
199
+ xAxisConfig={xAxisConfig}
200
+ yAxisConfig={yAxisConfig}
201
+ isTransitionLoading={isTransitionLoading}
202
+ connectNulls={connectNulls}
203
+ >
204
+ {children}
205
+ </LineChartContent>
206
+ )}
88
207
  </CartesianChart>
89
208
  );
90
209
  };
@@ -0,0 +1,39 @@
1
+ import { describe, it } from '@jest/globals';
2
+ import { ledgerLiveThemes } from '@ledgerhq/lumen-design-core';
3
+ import { ThemeProvider } from '@ledgerhq/lumen-ui-rnative';
4
+ import { render } from '@testing-library/react-native';
5
+
6
+ import { CartesianChart } from '../../CartesianChart';
7
+ import { LineChartEmptyState } from './LineChartEmptyState';
8
+ import type { LineChartEmptyStateProps } from './types';
9
+
10
+ const renderInChart = (props: LineChartEmptyStateProps) => {
11
+ return render(
12
+ <ThemeProvider themes={ledgerLiveThemes} colorScheme='light'>
13
+ <CartesianChart series={[]} width={400} height={200}>
14
+ <LineChartEmptyState {...props} />
15
+ </CartesianChart>
16
+ </ThemeProvider>,
17
+ );
18
+ };
19
+
20
+ describe('LineChartEmptyState', () => {
21
+ it('renders the placeholder line', () => {
22
+ const { getByTestId } = renderInChart({});
23
+
24
+ getByTestId('chart-empty-state-line');
25
+ });
26
+
27
+ it('renders the grid lines', () => {
28
+ const { getByTestId } = renderInChart({});
29
+
30
+ getByTestId('chart-empty-state-grid');
31
+ });
32
+
33
+ it('renders the placeholder while loading', () => {
34
+ const { getByTestId } = renderInChart({ loading: true });
35
+
36
+ getByTestId('chart-empty-state');
37
+ getByTestId('chart-empty-state-line');
38
+ });
39
+ });
@@ -0,0 +1,72 @@
1
+ import { useTheme } from '@ledgerhq/lumen-ui-rnative';
2
+ import Animated from 'react-native-reanimated';
3
+ import { G, Line as SvgLine, Path } from 'react-native-svg';
4
+
5
+ import { useCartesianChartContext } from '../../CartesianChart/context';
6
+ import { useShimmerAnimation } from '../../CartesianChart/hooks/useShimmerAnimation';
7
+ import { usePathReveal } from '../../CartesianChart/RevealAnimation';
8
+
9
+ import type { LineChartEmptyStateProps } from './types';
10
+ import { buildPlaceholderTransform, PLACEHOLDER_LINE_PATH } from './utils';
11
+
12
+ const GRID_LINE_RATIOS = [0.3, 0.5, 0.7];
13
+ const GRID_STROKE_WIDTH = 1;
14
+ const PLACEHOLDER_STROKE_WIDTH = 2;
15
+
16
+ const AnimatedG = Animated.createAnimatedComponent(G);
17
+
18
+ /**
19
+ * SVG placeholder line shown when a LineChart is loading with no data yet (with
20
+ * a shimmer) or has no data to display (static). Uses a fixed line shape scaled
21
+ * into the chart's reserved drawing area, plus static horizontal grid lines, so
22
+ * axes are not needed.
23
+ */
24
+ export function LineChartEmptyState({
25
+ loading = false,
26
+ }: Readonly<LineChartEmptyStateProps>) {
27
+ const { drawingArea } = useCartesianChartContext();
28
+ const { theme } = useTheme();
29
+ const { animatedProps } = useShimmerAnimation(loading);
30
+ const clipPath = usePathReveal();
31
+
32
+ if (drawingArea.width <= 0 || drawingArea.height <= 0) {
33
+ return null;
34
+ }
35
+
36
+ return (
37
+ <G testID='chart-empty-state'>
38
+ <G testID='chart-empty-state-grid'>
39
+ {GRID_LINE_RATIOS.map((ratio) => {
40
+ const y = drawingArea.y + drawingArea.height * ratio;
41
+
42
+ return (
43
+ <SvgLine
44
+ key={ratio}
45
+ x1={drawingArea.x}
46
+ y1={y}
47
+ x2={drawingArea.x + drawingArea.width}
48
+ y2={y}
49
+ stroke={theme.colors.border.mutedSubtleTransparent}
50
+ strokeWidth={GRID_STROKE_WIDTH}
51
+ />
52
+ );
53
+ })}
54
+ </G>
55
+ <G clipPath={clipPath}>
56
+ <AnimatedG animatedProps={animatedProps}>
57
+ <Path
58
+ testID='chart-empty-state-line'
59
+ d={PLACEHOLDER_LINE_PATH}
60
+ transform={buildPlaceholderTransform(drawingArea)}
61
+ vectorEffect='non-scaling-stroke'
62
+ fill='none'
63
+ stroke={theme.colors.border.muted}
64
+ strokeWidth={PLACEHOLDER_STROKE_WIDTH}
65
+ strokeLinecap='round'
66
+ strokeLinejoin='round'
67
+ />
68
+ </AnimatedG>
69
+ </G>
70
+ </G>
71
+ );
72
+ }
@@ -0,0 +1,2 @@
1
+ export { LineChartEmptyState } from './LineChartEmptyState';
2
+ export type { LineChartEmptyStateProps } from './types';
@@ -0,0 +1,3 @@
1
+ import type { LineChartProps } from '../types';
2
+
3
+ export type LineChartEmptyStateProps = Pick<LineChartProps, 'loading'>;
@@ -0,0 +1,22 @@
1
+ import { describe, expect, it } from '@jest/globals';
2
+
3
+ import { buildPlaceholderTransform, PLACEHOLDER_LINE_PATH } from './utils';
4
+
5
+ describe('PLACEHOLDER_LINE_PATH', () => {
6
+ it('is an svg path starting with a move command', () => {
7
+ expect(PLACEHOLDER_LINE_PATH).toMatch(/^M/);
8
+ });
9
+ });
10
+
11
+ describe('buildPlaceholderTransform', () => {
12
+ it('translates to the drawing area origin and scales the viewBox to fit', () => {
13
+ const transform = buildPlaceholderTransform({
14
+ x: 10,
15
+ y: 20,
16
+ width: 364,
17
+ height: 104,
18
+ });
19
+
20
+ expect(transform).toBe('translate(10, 20) scale(0.5, 0.5)');
21
+ });
22
+ });
@@ -0,0 +1,24 @@
1
+ import type { DrawingArea } from '../../../utils/types';
2
+
3
+ /**
4
+ * Fixed placeholder line shape, authored against a {@link PLACEHOLDER_VIEW_WIDTH}
5
+ * x {@link PLACEHOLDER_VIEW_HEIGHT} viewBox. Reused for every empty/loading
6
+ * state so the placeholder always reads the same.
7
+ */
8
+ export const PLACEHOLDER_LINE_PATH =
9
+ 'M1.00 128.27 C4.02 127.46 13.09 125.96 19.13 123.47 C25.19 120.97 31.23 116.53 37.28 113.31 C43.33 110.10 49.38 106.15 55.42 104.20 C61.48 102.24 67.52 102.53 73.57 101.61 C79.61 100.69 85.65 99.89 91.71 98.70 C97.75 97.51 103.80 95.67 109.84 94.47 C115.90 93.27 121.94 91.71 127.99 91.49 C134.03 91.26 140.09 91.53 146.13 93.16 C152.19 94.79 158.23 98.37 164.27 101.25 C170.32 104.13 176.36 108.16 182.42 110.45 C188.46 112.74 194.51 114.41 200.55 115.00 C206.61 115.60 212.65 114.56 218.70 114.03 C224.75 113.50 230.80 112.56 236.84 111.86 C242.88 111.17 248.94 110.27 254.98 109.87 C261.03 109.48 267.07 109.14 273.13 109.49 C279.17 109.82 285.22 110.90 291.26 111.90 C297.32 112.90 303.36 114.47 309.41 115.50 C315.46 116.54 321.50 118.12 327.55 118.11 C333.59 118.10 339.65 118.08 345.69 115.45 C351.74 112.81 357.78 107.02 363.84 102.29 C369.88 97.54 375.93 90.87 381.97 87.01 C388.03 83.16 394.07 79.81 400.11 79.12 C406.17 78.43 412.21 80.79 418.26 82.88 C424.30 84.99 430.36 88.88 436.40 91.74 C442.45 94.59 448.49 98.24 454.55 100.02 C460.59 101.80 466.64 102.08 472.68 102.44 C478.72 102.81 484.78 102.31 490.82 102.21 C496.87 102.11 502.92 101.95 508.97 101.84 C515.01 101.74 521.07 101.47 527.11 101.58 C533.16 101.68 539.20 101.57 545.26 102.48 C551.30 103.39 557.34 105.37 563.39 107.02 C569.43 108.68 575.49 111.02 581.53 112.40 C587.59 113.79 593.63 114.62 599.68 115.30 C605.72 115.98 611.78 115.81 617.82 116.48 C623.87 117.16 629.91 118.39 635.95 119.32 C642.01 120.25 648.05 121.51 654.10 122.04 C660.15 122.57 666.20 123.89 672.24 122.47 C678.30 121.07 684.34 117.39 690.39 113.54 C696.43 109.69 702.49 103.53 708.53 99.38 C714.57 95.23 722.31 90.65 726.66 88.61';
10
+
11
+ const PLACEHOLDER_VIEW_WIDTH = 728;
12
+ const PLACEHOLDER_VIEW_HEIGHT = 208;
13
+
14
+ /**
15
+ * Transform that fits {@link PLACEHOLDER_LINE_PATH} into the drawing area. Pair
16
+ * with `vector-effect: non-scaling-stroke` on the path so the stroke keeps a
17
+ * constant width despite the (potentially non-uniform) scale.
18
+ */
19
+ export const buildPlaceholderTransform = (drawingArea: DrawingArea): string => {
20
+ const scaleX = drawingArea.width / PLACEHOLDER_VIEW_WIDTH;
21
+ const scaleY = drawingArea.height / PLACEHOLDER_VIEW_HEIGHT;
22
+
23
+ return `translate(${drawingArea.x}, ${drawingArea.y}) scale(${scaleX}, ${scaleY})`;
24
+ };
@@ -48,7 +48,7 @@ export type LineChartProps = {
48
48
  width?: number;
49
49
  /**
50
50
  * Height of the chart in pixels.
51
- * @default 160
51
+ * @default 228
52
52
  */
53
53
  height?: number;
54
54
  /**
@@ -83,4 +83,52 @@ export type LineChartProps = {
83
83
  * @default 6
84
84
  */
85
85
  magnetRadius?: number;
86
+ /**
87
+ * Whether the chart is loading. When there is no data, renders an animated
88
+ * shimmer placeholder line (initial loading). When data is present (e.g. a
89
+ * time-range change), the current line is recoloured to a muted grey and
90
+ * shimmers until the new `series` is provided (transition loading).
91
+ *
92
+ * To get the transition behaviour, keep passing the previous `series` while
93
+ * refetching; clearing it falls back to the initial placeholder.
94
+ * @default false
95
+ */
96
+ loading?: boolean;
97
+ /**
98
+ * Text shown in the centre of the chart when there is no data and the chart
99
+ * is not loading.
100
+ * @default 'No data'
101
+ */
102
+ emptyLabel?: string;
103
+ /**
104
+ * Chart-wide override controlling how null values are handled across all lines.
105
+ * When true, skips null values and draws continuous lines across gaps.
106
+ * When false, null values create gaps in the lines.
107
+ * When omitted, each series' own `connectNulls` value is used (defaulting to `false`).
108
+ */
109
+ connectNulls?: boolean;
86
110
  };
111
+
112
+ /**
113
+ * Series-render fields shared by `LineChart` and its internal line
114
+ * sub-components. Derived from {@link LineChartProps} so the option types stay
115
+ * in sync.
116
+ */
117
+ type LineSeriesRenderProps = Required<
118
+ Pick<LineChartProps, 'series' | 'showArea' | 'areaType'>
119
+ >;
120
+
121
+ export type LineChartLinesProps = LineSeriesRenderProps &
122
+ Pick<LineChartProps, 'connectNulls'> & {
123
+ stroke?: string;
124
+ };
125
+
126
+ export type LineChartTransitionLinesProps = Omit<LineChartLinesProps, 'stroke'>;
127
+
128
+ export type LineChartContentProps = LineChartLinesProps &
129
+ Required<Pick<LineChartProps, 'showXAxis' | 'showYAxis'>> &
130
+ Pick<LineChartProps, 'children'> & {
131
+ xAxisConfig: XAxisProps;
132
+ yAxisConfig: YAxisProps;
133
+ isTransitionLoading: boolean;
134
+ };
@@ -0,0 +1,196 @@
1
+ import { describe, expect, it } from '@jest/globals';
2
+
3
+ import type { Series } from '../../utils/types';
4
+ import { DEFAULT_AXIS_HEIGHT } from '../Axis/XAxis';
5
+
6
+ import {
7
+ canRenderLine,
8
+ computeAxisPadding,
9
+ getChartDisplayState,
10
+ } from './utils';
11
+
12
+ const makeSeries = (data: (number | null)[]): Series => ({
13
+ id: 'a',
14
+ stroke: '#000',
15
+ data,
16
+ });
17
+
18
+ describe('canRenderLine', () => {
19
+ it('returns false for undefined or empty series', () => {
20
+ expect(canRenderLine(undefined)).toBe(false);
21
+ expect(canRenderLine([])).toBe(false);
22
+ });
23
+
24
+ it('returns false when no series has at least two finite points', () => {
25
+ expect(canRenderLine([makeSeries([1])])).toBe(false);
26
+ expect(canRenderLine([makeSeries([1, null])])).toBe(false);
27
+ expect(canRenderLine([makeSeries([null, null])])).toBe(false);
28
+ });
29
+
30
+ it('returns true once a series has two finite points', () => {
31
+ expect(canRenderLine([makeSeries([1, 2])])).toBe(true);
32
+ });
33
+
34
+ it('ignores null gaps when counting drawable points', () => {
35
+ expect(canRenderLine([makeSeries([1, null, 3])])).toBe(true);
36
+ });
37
+
38
+ it('does not count NaN, Infinity, or holes as drawable points', () => {
39
+ expect(canRenderLine([makeSeries([NaN, NaN])])).toBe(false);
40
+ expect(canRenderLine([makeSeries([Infinity, -Infinity])])).toBe(false);
41
+ expect(canRenderLine([makeSeries([NaN, 1])])).toBe(false);
42
+ expect(
43
+ canRenderLine([makeSeries([1, undefined as unknown as number, 2])]),
44
+ ).toBe(true);
45
+ expect(
46
+ canRenderLine([makeSeries([1, undefined as unknown as number])]),
47
+ ).toBe(false);
48
+ });
49
+
50
+ it('returns true when any series is drawable', () => {
51
+ expect(canRenderLine([makeSeries([1]), makeSeries([1, 2, 3])])).toBe(true);
52
+ });
53
+
54
+ it('treats a missing data array as no points', () => {
55
+ expect(canRenderLine([{ id: 'a', stroke: '#000' }])).toBe(false);
56
+ });
57
+
58
+ it('caps counted points to the x-axis domain length (like toScaledPoints)', () => {
59
+ expect(canRenderLine([makeSeries([1, 2, 3])], ['Jan'])).toBe(false);
60
+ expect(canRenderLine([makeSeries([1, 2, 3])], ['Jan', 'Feb'])).toBe(true);
61
+ });
62
+
63
+ it('does not reduce drawable points when xData is longer than the series', () => {
64
+ expect(canRenderLine([makeSeries([1, 2])], ['a', 'b', 'c', 'd'])).toBe(
65
+ true,
66
+ );
67
+ });
68
+
69
+ it('counts only finite points within the capped range', () => {
70
+ expect(canRenderLine([makeSeries([null, 2, 3])], ['Jan', 'Feb'])).toBe(
71
+ false,
72
+ );
73
+ });
74
+ });
75
+
76
+ describe('computeAxisPadding', () => {
77
+ const base = {
78
+ xAxisPosition: 'bottom' as const,
79
+ yAxisPosition: 'start' as const,
80
+ yAxisWidth: 40,
81
+ };
82
+
83
+ it('returns undefined when no axis is shown', () => {
84
+ expect(
85
+ computeAxisPadding({ ...base, showXAxis: false, showYAxis: false }),
86
+ ).toBeUndefined();
87
+ });
88
+
89
+ it('reserves height on the side where the x-axis sits', () => {
90
+ expect(
91
+ computeAxisPadding({
92
+ ...base,
93
+ showXAxis: true,
94
+ showYAxis: false,
95
+ xAxisPosition: 'bottom',
96
+ }),
97
+ ).toEqual({ top: 0, bottom: DEFAULT_AXIS_HEIGHT, left: 0, right: 0 });
98
+
99
+ expect(
100
+ computeAxisPadding({
101
+ ...base,
102
+ showXAxis: true,
103
+ showYAxis: false,
104
+ xAxisPosition: 'top',
105
+ }),
106
+ ).toEqual({ top: DEFAULT_AXIS_HEIGHT, bottom: 0, left: 0, right: 0 });
107
+ });
108
+
109
+ it('reserves the y-axis width on the side where it sits', () => {
110
+ expect(
111
+ computeAxisPadding({
112
+ ...base,
113
+ showXAxis: false,
114
+ showYAxis: true,
115
+ yAxisPosition: 'start',
116
+ yAxisWidth: 56,
117
+ }),
118
+ ).toEqual({ top: 0, bottom: 0, left: 56, right: 0 });
119
+
120
+ expect(
121
+ computeAxisPadding({
122
+ ...base,
123
+ showXAxis: false,
124
+ showYAxis: true,
125
+ yAxisPosition: 'end',
126
+ yAxisWidth: 56,
127
+ }),
128
+ ).toEqual({ top: 0, bottom: 0, left: 0, right: 56 });
129
+ });
130
+
131
+ it('combines padding when both axes are shown', () => {
132
+ expect(
133
+ computeAxisPadding({
134
+ showXAxis: true,
135
+ showYAxis: true,
136
+ xAxisPosition: 'bottom',
137
+ yAxisPosition: 'start',
138
+ yAxisWidth: 40,
139
+ }),
140
+ ).toEqual({ top: 0, bottom: DEFAULT_AXIS_HEIGHT, left: 40, right: 0 });
141
+ });
142
+ });
143
+
144
+ describe('getChartDisplayState', () => {
145
+ it('is initial-loading when loading with no data', () => {
146
+ expect(
147
+ getChartDisplayState({
148
+ loading: true,
149
+ hasData: false,
150
+ emptyLabel: 'No data',
151
+ }),
152
+ ).toEqual({
153
+ status: 'initial-loading',
154
+ ariaLabel: 'Loading chart',
155
+ });
156
+ });
157
+
158
+ it('is empty when not loading with no data', () => {
159
+ expect(
160
+ getChartDisplayState({
161
+ loading: false,
162
+ hasData: false,
163
+ emptyLabel: 'Nothing here',
164
+ }),
165
+ ).toEqual({
166
+ status: 'empty',
167
+ ariaLabel: 'Nothing here',
168
+ });
169
+ });
170
+
171
+ it('is transition-loading when loading with data', () => {
172
+ expect(
173
+ getChartDisplayState({
174
+ loading: true,
175
+ hasData: true,
176
+ emptyLabel: 'No data',
177
+ }),
178
+ ).toEqual({
179
+ status: 'transition-loading',
180
+ ariaLabel: 'Loading chart',
181
+ });
182
+ });
183
+
184
+ it('is ready with no aria label when data is present and not loading', () => {
185
+ expect(
186
+ getChartDisplayState({
187
+ loading: false,
188
+ hasData: true,
189
+ emptyLabel: 'No data',
190
+ }),
191
+ ).toEqual({
192
+ status: 'ready',
193
+ ariaLabel: undefined,
194
+ });
195
+ });
196
+ });