@ledgerhq/lumen-ui-rnative-visualization 0.1.16 → 0.1.18

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 (166) hide show
  1. package/dist/module/lib/Components/Axis/XAxis/XAxis.js +2 -2
  2. package/dist/module/lib/Components/Axis/XAxis/XAxis.js.map +1 -1
  3. package/dist/module/lib/Components/Axis/YAxis/YAxis.js +2 -2
  4. package/dist/module/lib/Components/Axis/YAxis/YAxis.js.map +1 -1
  5. package/dist/module/lib/Components/CartesianChart/CartesianChart.js +29 -22
  6. package/dist/module/lib/Components/CartesianChart/CartesianChart.js.map +1 -1
  7. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.js +61 -0
  8. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.js.map +1 -0
  9. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/index.js +4 -0
  10. package/dist/module/lib/Components/CartesianChart/ChartEmptyLabel/index.js.map +1 -0
  11. package/dist/module/lib/Components/CartesianChart/RevealClip/RevealClipDefs.js +3 -4
  12. package/dist/module/lib/Components/CartesianChart/RevealClip/RevealClipDefs.js.map +1 -1
  13. package/dist/module/lib/Components/CartesianChart/hooks/useDataFingerprint.js +13 -0
  14. package/dist/module/lib/Components/CartesianChart/hooks/useDataFingerprint.js.map +1 -0
  15. package/dist/module/lib/Components/CartesianChart/{RevealClip/utils.js → hooks/useRevealClipAnimation.js} +1 -6
  16. package/dist/module/lib/Components/CartesianChart/hooks/useRevealClipAnimation.js.map +1 -0
  17. package/dist/module/lib/Components/CartesianChart/hooks/useShimmerAnimation.js +37 -0
  18. package/dist/module/lib/Components/CartesianChart/hooks/useShimmerAnimation.js.map +1 -0
  19. package/dist/module/lib/Components/Line/Line.js +13 -8
  20. package/dist/module/lib/Components/Line/Line.js.map +1 -1
  21. package/dist/module/lib/Components/Line/constants.js +5 -0
  22. package/dist/module/lib/Components/Line/constants.js.map +1 -0
  23. package/dist/module/lib/Components/Line/types.js +2 -0
  24. package/dist/module/lib/Components/Line/utils.js +24 -7
  25. package/dist/module/lib/Components/Line/utils.js.map +1 -1
  26. package/dist/module/lib/Components/Line/utils.test.js +27 -1
  27. package/dist/module/lib/Components/Line/utils.test.js.map +1 -1
  28. package/dist/module/lib/Components/LineChart/LineChart.js +116 -27
  29. package/dist/module/lib/Components/LineChart/LineChart.js.map +1 -1
  30. package/dist/module/lib/Components/LineChart/LineChart.test.js +78 -0
  31. package/dist/module/lib/Components/LineChart/LineChart.test.js.map +1 -1
  32. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.js +72 -0
  33. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.js.map +1 -0
  34. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.js +47 -0
  35. package/dist/module/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.js.map +1 -0
  36. package/dist/module/lib/Components/LineChart/LineChartEmptyState/index.js +4 -0
  37. package/dist/module/lib/Components/LineChart/LineChartEmptyState/index.js.map +1 -0
  38. package/dist/module/lib/Components/LineChart/LineChartEmptyState/types.js +4 -0
  39. package/dist/module/lib/Components/LineChart/LineChartEmptyState/types.js.map +1 -0
  40. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.js +22 -0
  41. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.js.map +1 -0
  42. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.test.js +21 -0
  43. package/dist/module/lib/Components/LineChart/LineChartEmptyState/utils.test.js.map +1 -0
  44. package/dist/module/lib/Components/LineChart/utils.js +83 -0
  45. package/dist/module/lib/Components/LineChart/utils.js.map +1 -0
  46. package/dist/module/lib/Components/LineChart/utils.test.js +174 -0
  47. package/dist/module/lib/Components/LineChart/utils.test.js.map +1 -0
  48. package/dist/module/lib/Components/ReferenceLine/ReferenceLine.js +4 -4
  49. package/dist/module/lib/Components/ReferenceLine/ReferenceLine.js.map +1 -1
  50. package/dist/module/lib/Components/ReferenceLine/constants.js +2 -2
  51. package/dist/module/lib/Components/ReferenceLine/constants.js.map +1 -1
  52. package/dist/module/lib/Components/ReferenceLine/utils.js +2 -1
  53. package/dist/module/lib/Components/ReferenceLine/utils.js.map +1 -1
  54. package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js +2 -1
  55. package/dist/module/lib/Components/Scrubber/DefaultScrubberTooltip/utils.js.map +1 -1
  56. package/dist/module/lib/Components/Scrubber/Scrubber.js +2 -2
  57. package/dist/module/lib/Components/Scrubber/Scrubber.js.map +1 -1
  58. package/dist/module/lib/Components/Scrubber/ScrubberProvider.js +2 -1
  59. package/dist/module/lib/Components/Scrubber/ScrubberProvider.js.map +1 -1
  60. package/dist/module/lib/Components/Scrubber/utils.js +3 -2
  61. package/dist/module/lib/Components/Scrubber/utils.js.map +1 -1
  62. package/dist/module/lib/utils/numbers.js +16 -0
  63. package/dist/module/lib/utils/numbers.js.map +1 -0
  64. package/dist/module/lib/utils/ticks/ticks.js +0 -16
  65. package/dist/module/lib/utils/ticks/ticks.js.map +1 -1
  66. package/dist/typescript/src/lib/Components/Axis/XAxis/XAxis.d.ts.map +1 -1
  67. package/dist/typescript/src/lib/Components/Axis/YAxis/YAxis.d.ts.map +1 -1
  68. package/dist/typescript/src/lib/Components/CartesianChart/CartesianChart.d.ts +1 -1
  69. package/dist/typescript/src/lib/Components/CartesianChart/CartesianChart.d.ts.map +1 -1
  70. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.d.ts +18 -0
  71. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.d.ts.map +1 -0
  72. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/index.d.ts +2 -0
  73. package/dist/typescript/src/lib/Components/CartesianChart/ChartEmptyLabel/index.d.ts.map +1 -0
  74. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/RevealClipDefs.d.ts.map +1 -1
  75. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/types.d.ts +1 -1
  76. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/types.d.ts.map +1 -1
  77. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useDataFingerprint.d.ts +9 -0
  78. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useDataFingerprint.d.ts.map +1 -0
  79. package/dist/typescript/src/lib/Components/CartesianChart/{RevealClip/utils.d.ts → hooks/useRevealClipAnimation.d.ts} +2 -5
  80. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useRevealClipAnimation.d.ts.map +1 -0
  81. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.d.ts +13 -0
  82. package/dist/typescript/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.d.ts.map +1 -0
  83. package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts +12 -0
  84. package/dist/typescript/src/lib/Components/CartesianChart/types.d.ts.map +1 -1
  85. package/dist/typescript/src/lib/Components/Line/Line.d.ts +1 -1
  86. package/dist/typescript/src/lib/Components/Line/Line.d.ts.map +1 -1
  87. package/dist/typescript/src/lib/Components/Line/constants.d.ts +3 -0
  88. package/dist/typescript/src/lib/Components/Line/constants.d.ts.map +1 -0
  89. package/dist/typescript/src/lib/Components/Line/index.d.ts +1 -1
  90. package/dist/typescript/src/lib/Components/Line/index.d.ts.map +1 -1
  91. package/dist/typescript/src/lib/Components/Line/types.d.ts +8 -0
  92. package/dist/typescript/src/lib/Components/Line/types.d.ts.map +1 -1
  93. package/dist/typescript/src/lib/Components/Line/utils.d.ts +5 -4
  94. package/dist/typescript/src/lib/Components/Line/utils.d.ts.map +1 -1
  95. package/dist/typescript/src/lib/Components/LineChart/LineChart.d.ts +1 -1
  96. package/dist/typescript/src/lib/Components/LineChart/LineChart.d.ts.map +1 -1
  97. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.d.ts +9 -0
  98. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.d.ts.map +1 -0
  99. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/index.d.ts +3 -0
  100. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/index.d.ts.map +1 -0
  101. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/types.d.ts +3 -0
  102. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/types.d.ts.map +1 -0
  103. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/utils.d.ts +14 -0
  104. package/dist/typescript/src/lib/Components/LineChart/LineChartEmptyState/utils.d.ts.map +1 -0
  105. package/dist/typescript/src/lib/Components/LineChart/types.d.ts +29 -1
  106. package/dist/typescript/src/lib/Components/LineChart/types.d.ts.map +1 -1
  107. package/dist/typescript/src/lib/Components/LineChart/utils.d.ts +43 -0
  108. package/dist/typescript/src/lib/Components/LineChart/utils.d.ts.map +1 -0
  109. package/dist/typescript/src/lib/Components/ReferenceLine/ReferenceLine.d.ts.map +1 -1
  110. package/dist/typescript/src/lib/Components/ReferenceLine/constants.d.ts +2 -2
  111. package/dist/typescript/src/lib/Components/ReferenceLine/constants.d.ts.map +1 -1
  112. package/dist/typescript/src/lib/Components/ReferenceLine/utils.d.ts.map +1 -1
  113. package/dist/typescript/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.d.ts.map +1 -1
  114. package/dist/typescript/src/lib/Components/Scrubber/Scrubber.d.ts.map +1 -1
  115. package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts.map +1 -1
  116. package/dist/typescript/src/lib/Components/Scrubber/utils.d.ts.map +1 -1
  117. package/dist/typescript/src/lib/utils/index.d.ts +1 -1
  118. package/dist/typescript/src/lib/utils/index.d.ts.map +1 -1
  119. package/dist/typescript/src/lib/utils/numbers.d.ts +13 -0
  120. package/dist/typescript/src/lib/utils/numbers.d.ts.map +1 -0
  121. package/dist/typescript/src/lib/utils/ticks/ticks.d.ts +1 -11
  122. package/dist/typescript/src/lib/utils/ticks/ticks.d.ts.map +1 -1
  123. package/dist/typescript/src/lib/utils/types.d.ts +20 -2
  124. package/dist/typescript/src/lib/utils/types.d.ts.map +1 -1
  125. package/package.json +3 -3
  126. package/src/lib/Components/Axis/XAxis/XAxis.tsx +13 -18
  127. package/src/lib/Components/Axis/YAxis/YAxis.tsx +13 -18
  128. package/src/lib/Components/CartesianChart/CartesianChart.tsx +29 -23
  129. package/src/lib/Components/CartesianChart/ChartEmptyLabel/ChartEmptyLabel.tsx +68 -0
  130. package/src/lib/Components/CartesianChart/ChartEmptyLabel/index.ts +1 -0
  131. package/src/lib/Components/CartesianChart/RevealClip/RevealClipDefs.tsx +3 -2
  132. package/src/lib/Components/CartesianChart/RevealClip/types.ts +1 -1
  133. package/src/lib/Components/CartesianChart/hooks/useDataFingerprint.ts +16 -0
  134. package/src/lib/Components/CartesianChart/{RevealClip/utils.ts → hooks/useRevealClipAnimation.ts} +1 -9
  135. package/src/lib/Components/CartesianChart/hooks/useShimmerAnimation.ts +52 -0
  136. package/src/lib/Components/CartesianChart/types.ts +12 -0
  137. package/src/lib/Components/Line/Line.tsx +13 -10
  138. package/src/lib/Components/Line/constants.ts +2 -0
  139. package/src/lib/Components/Line/index.ts +1 -1
  140. package/src/lib/Components/Line/types.ts +10 -0
  141. package/src/lib/Components/Line/utils.test.ts +41 -1
  142. package/src/lib/Components/Line/utils.ts +42 -6
  143. package/src/lib/Components/LineChart/LineChart.test.tsx +64 -0
  144. package/src/lib/Components/LineChart/LineChart.tsx +139 -38
  145. package/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.test.tsx +39 -0
  146. package/src/lib/Components/LineChart/LineChartEmptyState/LineChartEmptyState.tsx +72 -0
  147. package/src/lib/Components/LineChart/LineChartEmptyState/index.ts +2 -0
  148. package/src/lib/Components/LineChart/LineChartEmptyState/types.ts +3 -0
  149. package/src/lib/Components/LineChart/LineChartEmptyState/utils.test.ts +22 -0
  150. package/src/lib/Components/LineChart/LineChartEmptyState/utils.ts +24 -0
  151. package/src/lib/Components/LineChart/types.ts +35 -1
  152. package/src/lib/Components/LineChart/utils.test.ts +196 -0
  153. package/src/lib/Components/LineChart/utils.ts +107 -0
  154. package/src/lib/Components/ReferenceLine/ReferenceLine.tsx +8 -4
  155. package/src/lib/Components/ReferenceLine/constants.ts +2 -2
  156. package/src/lib/Components/ReferenceLine/utils.ts +2 -1
  157. package/src/lib/Components/Scrubber/DefaultScrubberTooltip/utils.ts +2 -1
  158. package/src/lib/Components/Scrubber/Scrubber.tsx +13 -2
  159. package/src/lib/Components/Scrubber/ScrubberProvider.tsx +2 -1
  160. package/src/lib/Components/Scrubber/utils.ts +3 -5
  161. package/src/lib/utils/index.ts +1 -0
  162. package/src/lib/utils/numbers.ts +15 -0
  163. package/src/lib/utils/ticks/ticks.ts +1 -23
  164. package/src/lib/utils/types.ts +28 -2
  165. package/dist/module/lib/Components/CartesianChart/RevealClip/utils.js.map +0 -1
  166. package/dist/typescript/src/lib/Components/CartesianChart/RevealClip/utils.d.ts.map +0 -1
@@ -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
+ });
@@ -0,0 +1,107 @@
1
+ import { isFiniteNumber } from '../../utils/numbers';
2
+ import type { ChartInset, Series } from '../../utils/types';
3
+ import { DEFAULT_AXIS_HEIGHT } from '../Axis/XAxis';
4
+ import type { XAxisProps } from '../Axis/XAxis';
5
+ import { DEFAULT_AXIS_WIDTH } from '../Axis/YAxis';
6
+ import type { YAxisProps } from '../Axis/YAxis';
7
+
8
+ /**
9
+ * Minimum number of finite points a series needs to be drawable as a line.
10
+ */
11
+ const MIN_DRAWABLE_POINTS = 2;
12
+ const LOADING_ARIA_LABEL = 'Loading chart';
13
+
14
+ type ComputeAxisPaddingParams = {
15
+ showXAxis: boolean;
16
+ showYAxis: boolean;
17
+ xAxisPosition: XAxisProps['position'];
18
+ yAxisPosition: YAxisProps['position'];
19
+ yAxisWidth: YAxisProps['width'];
20
+ };
21
+
22
+ type ChartDisplayStateParams = {
23
+ loading: boolean;
24
+ hasData: boolean;
25
+ emptyLabel: string;
26
+ };
27
+
28
+ type ChartStatus = 'initial-loading' | 'empty' | 'transition-loading' | 'ready';
29
+
30
+ type ChartDisplayState = {
31
+ status: ChartStatus;
32
+ ariaLabel: string | undefined;
33
+ };
34
+
35
+ /**
36
+ * Reserves space on the relevant sides of the drawing area for visible axes.
37
+ * Returns `undefined` when no axis is shown so the chart keeps its full area.
38
+ */
39
+ export const computeAxisPadding = ({
40
+ showXAxis,
41
+ showYAxis,
42
+ xAxisPosition,
43
+ yAxisPosition,
44
+ yAxisWidth,
45
+ }: ComputeAxisPaddingParams): Partial<ChartInset> | undefined => {
46
+ if (!showXAxis && !showYAxis) {
47
+ return undefined;
48
+ }
49
+
50
+ const resolvedYAxisWidth = yAxisWidth ?? DEFAULT_AXIS_WIDTH;
51
+
52
+ return {
53
+ top: showXAxis && xAxisPosition === 'top' ? DEFAULT_AXIS_HEIGHT : 0,
54
+ bottom: showXAxis && xAxisPosition === 'bottom' ? DEFAULT_AXIS_HEIGHT : 0,
55
+ left: showYAxis && yAxisPosition === 'start' ? resolvedYAxisWidth : 0,
56
+ right: showYAxis && yAxisPosition === 'end' ? resolvedYAxisWidth : 0,
57
+ };
58
+ };
59
+
60
+ /**
61
+ * Derives the chart's {@link ChartStatus} from its loading flag and whether it
62
+ * has drawable data, along with the matching accessibility label.
63
+ */
64
+ export const getChartDisplayState = ({
65
+ loading,
66
+ hasData,
67
+ emptyLabel,
68
+ }: ChartDisplayStateParams): ChartDisplayState => {
69
+ if (loading) {
70
+ return {
71
+ status: hasData ? 'transition-loading' : 'initial-loading',
72
+ ariaLabel: LOADING_ARIA_LABEL,
73
+ };
74
+ }
75
+
76
+ if (!hasData) {
77
+ return { status: 'empty', ariaLabel: emptyLabel };
78
+ }
79
+
80
+ return { status: 'ready', ariaLabel: undefined };
81
+ };
82
+
83
+ /**
84
+ * Whether any series has at least {@link MIN_DRAWABLE_POINTS} finite points,
85
+ * i.e. enough to actually draw a line. Drives the empty / loading / data states
86
+ * of the chart.
87
+ *
88
+ * When `xData` (the x-axis domain) is provided, only the first `xData.length`
89
+ * points of each series are considered — mirroring the cap in `toScaledPoints`
90
+ * (Line/utils.ts) — so a series longer than the axis cannot report drawable
91
+ * points that would never be plotted.
92
+ */
93
+ export const canRenderLine = (
94
+ series: Series[] | undefined,
95
+ xData?: readonly (string | number)[],
96
+ ): boolean => {
97
+ return (series ?? []).some((s) => {
98
+ const data = s.data ?? [];
99
+ const limit = xData ? Math.min(data.length, xData.length) : data.length;
100
+ let drawablePoints = 0;
101
+ for (let i = 0; i < limit; i++) {
102
+ if (isFiniteNumber(data[i])) drawablePoints++;
103
+ if (drawablePoints >= MIN_DRAWABLE_POINTS) return true;
104
+ }
105
+ return false;
106
+ });
107
+ };
@@ -3,7 +3,10 @@ import { G, Line as SvgLine, Text as SvgText } from 'react-native-svg';
3
3
 
4
4
  import { useCartesianChartContext } from '../CartesianChart/context';
5
5
 
6
- import { DASH_ARRAY, STROKE_WIDTH } from './constants';
6
+ import {
7
+ REFERENCE_LINE_DASH_ARRAY,
8
+ REFERENCE_LINE_STROKE_WIDTH,
9
+ } from './constants';
7
10
  import type { ReferenceLineProps } from './types';
8
11
  import {
9
12
  computeHorizontalLabelCoordinates,
@@ -28,7 +31,8 @@ export function ReferenceLine({
28
31
  const { theme } = useTheme();
29
32
 
30
33
  const resolvedStroke = stroke ?? theme.colors.border.muted;
31
- const dashArray = lineStyle === 'dashed' ? DASH_ARRAY : undefined;
34
+ const dashArray =
35
+ lineStyle === 'dashed' ? REFERENCE_LINE_DASH_ARRAY : undefined;
32
36
  const fontSize = theme.typographies.body4.fontSize;
33
37
 
34
38
  if (props.dataY !== undefined) {
@@ -65,7 +69,7 @@ export function ReferenceLine({
65
69
  x2={drawingArea.x + drawingArea.width}
66
70
  y2={yPixel}
67
71
  stroke={resolvedStroke}
68
- strokeWidth={STROKE_WIDTH}
72
+ strokeWidth={REFERENCE_LINE_STROKE_WIDTH}
69
73
  strokeDasharray={dashArray}
70
74
  strokeLinecap='round'
71
75
  />
@@ -122,7 +126,7 @@ export function ReferenceLine({
122
126
  x2={xPixel}
123
127
  y2={drawingArea.y + drawingArea.height}
124
128
  stroke={resolvedStroke}
125
- strokeWidth={STROKE_WIDTH}
129
+ strokeWidth={REFERENCE_LINE_STROKE_WIDTH}
126
130
  strokeDasharray={dashArray}
127
131
  strokeLinecap='round'
128
132
  />
@@ -1,2 +1,2 @@
1
- export const STROKE_WIDTH = 2;
2
- export const DASH_ARRAY = '0.1 6';
1
+ export const REFERENCE_LINE_STROKE_WIDTH = 2;
2
+ export const REFERENCE_LINE_DASH_ARRAY = '0.1 6';
@@ -1,3 +1,4 @@
1
+ import { isFiniteNumber } from '../../utils/numbers';
1
2
  import { getPointOnScale, isCategoricalScale } from '../../utils/scales/scales';
2
3
  import type { ChartScaleFunction, DrawingArea } from '../../utils/types';
3
4
  import type { BaseAxisProps } from '../Axis';
@@ -127,7 +128,7 @@ export const resolvePixel = ({
127
128
 
128
129
  const p = getPointOnScale(resolved, scale);
129
130
 
130
- if (!Number.isFinite(p) || !isPixelWithinDrawingArea(p, axis, drawingArea)) {
131
+ if (!isFiniteNumber(p) || !isPixelWithinDrawingArea(p, axis, drawingArea)) {
131
132
  return undefined;
132
133
  }
133
134
  return p;
@@ -1,6 +1,7 @@
1
1
  import type { RefObject } from 'react';
2
2
  import { useEffect, useMemo, useRef, useState } from 'react';
3
3
 
4
+ import { clamp } from '../../../utils/numbers';
4
5
  import type { DrawingArea } from '../../../utils/types';
5
6
  import type { ChartTooltipItemData, SvgBBoxElement } from '../types';
6
7
  import {
@@ -77,7 +78,7 @@ export const computeTooltipX = (
77
78
  drawingArea.x,
78
79
  drawingArea.x + drawingArea.width - tooltipWidth,
79
80
  );
80
- return Math.min(maxTooltipX, Math.max(drawingArea.x, preferredTooltipX));
81
+ return clamp(preferredTooltipX, drawingArea.x, maxTooltipX);
81
82
  };
82
83
 
83
84
  /**
@@ -80,12 +80,23 @@ export function Scrubber({
80
80
  const seriesData = seriesMap.get(s.id)?.data;
81
81
  const pixelY = resolvePixelY(scrubberPosition, seriesData, getYScale);
82
82
  if (pixelY === undefined) return null;
83
- return { id: s.id, stroke: s.stroke, pixelY };
83
+ return {
84
+ id: s.id,
85
+ stroke: s.stroke ?? theme.colors.border.muted,
86
+ pixelY,
87
+ };
84
88
  })
85
89
  .filter(
86
90
  (b): b is { id: string; stroke: string; pixelY: number } => b !== null,
87
91
  );
88
- }, [scrubberPosition, showBeacons, series, seriesMap, getYScale]);
92
+ }, [
93
+ scrubberPosition,
94
+ showBeacons,
95
+ series,
96
+ seriesMap,
97
+ getYScale,
98
+ theme.colors.border.muted,
99
+ ]);
89
100
 
90
101
  const tooltipPayload = useMemo(() => {
91
102
  if (scrubberPosition === undefined || !tooltip) {
@@ -4,6 +4,7 @@ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
4
  import Animated, { useSharedValue } from 'react-native-reanimated';
5
5
  import { scheduleOnRN } from 'react-native-worklets';
6
6
 
7
+ import { clamp } from '../../utils/numbers';
7
8
  import { useCartesianChartContext } from '../CartesianChart/context';
8
9
  import { useMagneticPointsContext } from '../Point/pointContext';
9
10
  import { ScrubberContextProvider } from './context';
@@ -83,7 +84,7 @@ export function ScrubberProvider({
83
84
  const clamped =
84
85
  index === undefined || ref.dataLength <= 0
85
86
  ? undefined
86
- : Math.max(0, Math.min(index, ref.dataLength - 1));
87
+ : clamp(index, 0, ref.dataLength - 1);
87
88
  if (clamped === ref.lastIndex) return;
88
89
  ref.lastIndex = clamped;
89
90
  setScrubberPosition(clamped);
@@ -1,3 +1,4 @@
1
+ import { clamp } from '../../utils/numbers';
1
2
  import {
2
3
  getPointOnScale,
3
4
  isCategoricalScale,
@@ -71,7 +72,7 @@ export const getDataIndexFromPosition = (
71
72
  const offset =
72
73
  rangeStart + scale.paddingOuter() * step + scale.bandwidth() / 2;
73
74
  const index = Math.round((pixelX - offset) / step);
74
- return Math.max(0, Math.min(index, dataLength - 1));
75
+ return clamp(index, 0, dataLength - 1);
75
76
  }
76
77
 
77
78
  if (isNumericScale(scale)) {
@@ -84,10 +85,7 @@ export const getDataIndexFromPosition = (
84
85
  }
85
86
 
86
87
  const inverted = scale.invert(pixelX);
87
- return Math.max(
88
- 0,
89
- Math.min(Math.round(inverted as number), dataLength - 1),
90
- );
88
+ return clamp(Math.round(inverted as number), 0, dataLength - 1);
91
89
  }
92
90
 
93
91
  return 0;
@@ -3,6 +3,7 @@ export type {
3
3
  CategoricalScale,
4
4
  ChartInset,
5
5
  ChartScaleFunction,
6
+ CurveType,
6
7
  DrawingArea,
7
8
  NumericScale,
8
9
  Series,
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Type guard for a finite number. Narrows out `null`, `undefined`, `NaN` and
3
+ * `Infinity`, i.e. any value that cannot be projected to a valid coordinate or
4
+ * counted as a drawable data point.
5
+ */
6
+ export const isFiniteNumber = (value: unknown): value is number =>
7
+ Number.isFinite(value);
8
+
9
+ /**
10
+ * Constrains `value` to the inclusive `[min, max]` range. For a degenerate
11
+ * range where `min > max` (e.g. an index range `[0, length - 1]` for empty
12
+ * data), `min` takes precedence and is returned — matching `lodash.clamp`.
13
+ */
14
+ export const clamp = (value: number, min: number, max: number): number =>
15
+ Math.max(Math.min(value, max), min);
@@ -1,6 +1,6 @@
1
1
  import type { BaseAxisProps } from '../../Components/Axis';
2
2
  import { isCategoricalScale, isNumericScale } from '../scales/scales';
3
- import type { ChartScaleFunction, DrawingArea } from '../types';
3
+ import type { ChartScaleFunction } from '../types';
4
4
 
5
5
  export const APPROXIMATE_TICK_COUNT = 5;
6
6
 
@@ -94,25 +94,3 @@ export const buildTicksData = (
94
94
  label: getTickLabel(tick, axisData, formatter),
95
95
  }));
96
96
  };
97
-
98
- /**
99
- * Excludes the X grid line at the Y-axis origin (left edge)
100
- * to prevent overlap with the Y-axis solid line.
101
- */
102
- export const isTickOnXAxisDomainEdge = (
103
- tick: TickData,
104
- drawingArea: DrawingArea,
105
- ): boolean => {
106
- return tick.position !== drawingArea.x;
107
- };
108
-
109
- /**
110
- * Excludes the Y grid line at the X-axis origin (bottom edge)
111
- * to prevent overlap with the X-axis solid line.
112
- */
113
- export const isTickOnYAxisDomainEdge = (
114
- tick: TickData,
115
- drawingArea: DrawingArea,
116
- ): boolean => {
117
- return tick.position !== drawingArea.y + drawingArea.height;
118
- };
@@ -19,6 +19,26 @@ export type DrawingArea = {
19
19
  height: number;
20
20
  };
21
21
 
22
+ /**
23
+ * Interpolation used to draw a line (and its area) between data points.
24
+ * Each value maps to a [d3-shape](https://d3js.org/d3-shape/curve) curve:
25
+ * - `'bump'` — smooth cubic curve with horizontal tangents (`curveBumpX`).
26
+ * - `'natural'` — natural cubic spline through every point (`curveNatural`).
27
+ * - `'monotone'` — smooth curve that preserves monotonicity (`curveMonotoneX`).
28
+ * - `'linear'` — straight segments between points (`curveLinear`).
29
+ * - `'step'` — stepped, piecewise-constant line (`curveStep`).
30
+ * - `'stepAfter'` — stepped line where changes occur after the x-coordinate (`curveStepAfter`).
31
+ * - `'stepBefore'` — stepped line where changes occur before the x-coordinate (`curveStepBefore`).
32
+ */
33
+ export type CurveType =
34
+ | 'bump'
35
+ | 'natural'
36
+ | 'monotone'
37
+ | 'linear'
38
+ | 'step'
39
+ | 'stepAfter'
40
+ | 'stepBefore';
41
+
22
42
  export type Series = {
23
43
  /**
24
44
  * Unique identifier for the series.
@@ -33,9 +53,15 @@ export type Series = {
33
53
  */
34
54
  label?: string;
35
55
  /**
36
- * CSS color applied to the series line/mark.
56
+ * Color applied to the series line/mark.
57
+ * @default border-muted
58
+ */
59
+ stroke?: string;
60
+ /**
61
+ * Interpolation used to draw the line between data points.
62
+ * @default 'bump'
37
63
  */
38
- stroke: string;
64
+ curve?: CurveType;
39
65
  };
40
66
 
41
67
  export type NumericScale =
@@ -1 +0,0 @@
1
- {"version":3,"names":["useEffect","useId","useAnimatedProps","useSharedValue","withTiming","OVERFLOW_BUFFER","useRevealClipAnimation","durationMs","drawingArea","dataFingerprint","clipId","width","value","left","right","duration","animatedRectProps","useComputeDataFingerprint","series","map","s","data","join"],"sourceRoot":"../../../../../../src","sources":["lib/Components/CartesianChart/RevealClip/utils.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,KAAK,QAAQ,OAAO;AACxC,SACEC,gBAAgB,EAChBC,cAAc,EACdC,UAAU,QACL,yBAAyB;AAGhC,SAASC,eAAe,QAAQ,aAAU;AAa1C,OAAO,MAAMC,sBAAsB,GAAGA,CAAC;EACrCC,UAAU;EACVC,WAAW;EACXC;AACyB,CAAC,KAAgC;EAC1D,MAAMC,MAAM,GAAGT,KAAK,CAAC,CAAC;EACtB,MAAMU,KAAK,GAAGR,cAAc,CAAC,CAAC,CAAC;EAE/BH,SAAS,CAAC,MAAM;IACdW,KAAK,CAACC,KAAK,GAAG,CAAC;IACfD,KAAK,CAACC,KAAK,GAAGR,UAAU,CACtBI,WAAW,CAACG,KAAK,GAAGN,eAAe,CAACQ,IAAI,GAAGR,eAAe,CAACS,KAAK,EAChE;MAAEC,QAAQ,EAAER;IAAW,CACzB,CAAC;EACH,CAAC,EAAE,CAACC,WAAW,CAACG,KAAK,EAAEJ,UAAU,EAAEI,KAAK,EAAEF,eAAe,CAAC,CAAC;EAE3D,MAAMO,iBAAiB,GAAGd,gBAAgB,CAAC,OAAO;IAChDS,KAAK,EAAEA,KAAK,CAACC;EACf,CAAC,CAAC,CAAC;EAEH,OAAO;IAAEF,MAAM;IAAEM;EAAkB,CAAC;AACtC,CAAC;AAED,OAAO,MAAMC,yBAAyB,GAAGA,CAAC;EACxCC;AAGF,CAAC,KAAa;EACZ,OAAOA,MAAM,CAACC,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,EAAEC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAACA,IAAI,CAAC,GAAG,CAAC;AAC7D,CAAC","ignoreList":[]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/Components/CartesianChart/RevealClip/utils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAGhE,KAAK,yBAAyB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;CACxD,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,+CAIpC,yBAAyB,KAAG,yBAiB9B,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,aAEvC;IACD,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,KAAG,MAEH,CAAC"}