react-native-livechart 1.0.0

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 (243) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +198 -0
  3. package/dist/components/AnimatedLabel.d.ts +21 -0
  4. package/dist/components/AnimatedLabel.d.ts.map +1 -0
  5. package/dist/components/BadgeOverlay.d.ts +16 -0
  6. package/dist/components/BadgeOverlay.d.ts.map +1 -0
  7. package/dist/components/CrosshairLine.d.ts +20 -0
  8. package/dist/components/CrosshairLine.d.ts.map +1 -0
  9. package/dist/components/CrosshairOverlay.d.ts +29 -0
  10. package/dist/components/CrosshairOverlay.d.ts.map +1 -0
  11. package/dist/components/DegenParticlesOverlay.d.ts +16 -0
  12. package/dist/components/DegenParticlesOverlay.d.ts.map +1 -0
  13. package/dist/components/DotOverlay.d.ts +17 -0
  14. package/dist/components/DotOverlay.d.ts.map +1 -0
  15. package/dist/components/LeftEdgeFade.d.ts +9 -0
  16. package/dist/components/LeftEdgeFade.d.ts.map +1 -0
  17. package/dist/components/LiveChart.d.ts +3 -0
  18. package/dist/components/LiveChart.d.ts.map +1 -0
  19. package/dist/components/LiveChartSeries.d.ts +3 -0
  20. package/dist/components/LiveChartSeries.d.ts.map +1 -0
  21. package/dist/components/LiveChartTransition.d.ts +28 -0
  22. package/dist/components/LiveChartTransition.d.ts.map +1 -0
  23. package/dist/components/LoadingOverlay.d.ts +24 -0
  24. package/dist/components/LoadingOverlay.d.ts.map +1 -0
  25. package/dist/components/MarkerOverlay.d.ts +25 -0
  26. package/dist/components/MarkerOverlay.d.ts.map +1 -0
  27. package/dist/components/MultiSeriesDots.d.ts +11 -0
  28. package/dist/components/MultiSeriesDots.d.ts.map +1 -0
  29. package/dist/components/MultiSeriesStroke.d.ts +14 -0
  30. package/dist/components/MultiSeriesStroke.d.ts.map +1 -0
  31. package/dist/components/MultiSeriesTooltipStack.d.ts +10 -0
  32. package/dist/components/MultiSeriesTooltipStack.d.ts.map +1 -0
  33. package/dist/components/MultiSeriesValueLabels.d.ts +11 -0
  34. package/dist/components/MultiSeriesValueLabels.d.ts.map +1 -0
  35. package/dist/components/MultiSeriesValueLines.d.ts +10 -0
  36. package/dist/components/MultiSeriesValueLines.d.ts.map +1 -0
  37. package/dist/components/ReferenceLineOverlay.d.ts +19 -0
  38. package/dist/components/ReferenceLineOverlay.d.ts.map +1 -0
  39. package/dist/components/SeriesToggleChips.d.ts +15 -0
  40. package/dist/components/SeriesToggleChips.d.ts.map +1 -0
  41. package/dist/components/TradeStreamOverlay.d.ts +14 -0
  42. package/dist/components/TradeStreamOverlay.d.ts.map +1 -0
  43. package/dist/components/ValueLineOverlay.d.ts +16 -0
  44. package/dist/components/ValueLineOverlay.d.ts.map +1 -0
  45. package/dist/components/ValueTextOverlay.d.ts +20 -0
  46. package/dist/components/ValueTextOverlay.d.ts.map +1 -0
  47. package/dist/components/XAxisOverlay.d.ts +14 -0
  48. package/dist/components/XAxisOverlay.d.ts.map +1 -0
  49. package/dist/components/YAxisOverlay.d.ts +23 -0
  50. package/dist/components/YAxisOverlay.d.ts.map +1 -0
  51. package/dist/components/seriesMetaSig.d.ts +4 -0
  52. package/dist/components/seriesMetaSig.d.ts.map +1 -0
  53. package/dist/constants.d.ts +38 -0
  54. package/dist/constants.d.ts.map +1 -0
  55. package/dist/core/liveChartEngineTick.d.ts +45 -0
  56. package/dist/core/liveChartEngineTick.d.ts.map +1 -0
  57. package/dist/core/liveChartSeriesEngineTick.d.ts +38 -0
  58. package/dist/core/liveChartSeriesEngineTick.d.ts.map +1 -0
  59. package/dist/core/multiSeriesLayout.d.ts +22 -0
  60. package/dist/core/multiSeriesLayout.d.ts.map +1 -0
  61. package/dist/core/resolveConfig.d.ts +188 -0
  62. package/dist/core/resolveConfig.d.ts.map +1 -0
  63. package/dist/core/useLiveChartEngine.d.ts +79 -0
  64. package/dist/core/useLiveChartEngine.d.ts.map +1 -0
  65. package/dist/core/useLiveChartSeriesEngine.d.ts +68 -0
  66. package/dist/core/useLiveChartSeriesEngine.d.ts.map +1 -0
  67. package/dist/draw/candle.d.ts +25 -0
  68. package/dist/draw/candle.d.ts.map +1 -0
  69. package/dist/draw/grid.d.ts +24 -0
  70. package/dist/draw/grid.d.ts.map +1 -0
  71. package/dist/draw/line.d.ts +86 -0
  72. package/dist/draw/line.d.ts.map +1 -0
  73. package/dist/draw/trade.d.ts +38 -0
  74. package/dist/draw/trade.d.ts.map +1 -0
  75. package/dist/hooks/crosshairSeries.d.ts +13 -0
  76. package/dist/hooks/crosshairSeries.d.ts.map +1 -0
  77. package/dist/hooks/crosshairShared.d.ts +72 -0
  78. package/dist/hooks/crosshairShared.d.ts.map +1 -0
  79. package/dist/hooks/index.d.ts +24 -0
  80. package/dist/hooks/index.d.ts.map +1 -0
  81. package/dist/hooks/resolveChartLayout.d.ts +42 -0
  82. package/dist/hooks/resolveChartLayout.d.ts.map +1 -0
  83. package/dist/hooks/useBadge.d.ts +14 -0
  84. package/dist/hooks/useBadge.d.ts.map +1 -0
  85. package/dist/hooks/useCandlePaths.d.ts +19 -0
  86. package/dist/hooks/useCandlePaths.d.ts.map +1 -0
  87. package/dist/hooks/useCanvasLayout.d.ts +12 -0
  88. package/dist/hooks/useCanvasLayout.d.ts.map +1 -0
  89. package/dist/hooks/useChartColors.d.ts +20 -0
  90. package/dist/hooks/useChartColors.d.ts.map +1 -0
  91. package/dist/hooks/useChartPaths.d.ts +19 -0
  92. package/dist/hooks/useChartPaths.d.ts.map +1 -0
  93. package/dist/hooks/useChartReveal.d.ts +30 -0
  94. package/dist/hooks/useChartReveal.d.ts.map +1 -0
  95. package/dist/hooks/useChartSkiaFont.d.ts +8 -0
  96. package/dist/hooks/useChartSkiaFont.d.ts.map +1 -0
  97. package/dist/hooks/useCrosshair.d.ts +20 -0
  98. package/dist/hooks/useCrosshair.d.ts.map +1 -0
  99. package/dist/hooks/useCrosshairSeries.d.ts +10 -0
  100. package/dist/hooks/useCrosshairSeries.d.ts.map +1 -0
  101. package/dist/hooks/useDegen.d.ts +17 -0
  102. package/dist/hooks/useDegen.d.ts.map +1 -0
  103. package/dist/hooks/useLiveChartHasData.d.ts +17 -0
  104. package/dist/hooks/useLiveChartHasData.d.ts.map +1 -0
  105. package/dist/hooks/useLiveDot.d.ts +12 -0
  106. package/dist/hooks/useLiveDot.d.ts.map +1 -0
  107. package/dist/hooks/useMarkers.d.ts +15 -0
  108. package/dist/hooks/useMarkers.d.ts.map +1 -0
  109. package/dist/hooks/useModeBlend.d.ts +18 -0
  110. package/dist/hooks/useModeBlend.d.ts.map +1 -0
  111. package/dist/hooks/useMomentum.d.ts +16 -0
  112. package/dist/hooks/useMomentum.d.ts.map +1 -0
  113. package/dist/hooks/useMultiSeriesDegen.d.ts +25 -0
  114. package/dist/hooks/useMultiSeriesDegen.d.ts.map +1 -0
  115. package/dist/hooks/useMultiSeriesLinePaths.d.ts +15 -0
  116. package/dist/hooks/useMultiSeriesLinePaths.d.ts.map +1 -0
  117. package/dist/hooks/useReferenceLine.d.ts +32 -0
  118. package/dist/hooks/useReferenceLine.d.ts.map +1 -0
  119. package/dist/hooks/useReverseMorphEngineInputs.d.ts +24 -0
  120. package/dist/hooks/useReverseMorphEngineInputs.d.ts.map +1 -0
  121. package/dist/hooks/useTradeStream.d.ts +12 -0
  122. package/dist/hooks/useTradeStream.d.ts.map +1 -0
  123. package/dist/hooks/useXAxis.d.ts +32 -0
  124. package/dist/hooks/useXAxis.d.ts.map +1 -0
  125. package/dist/hooks/useYAxis.d.ts +13 -0
  126. package/dist/hooks/useYAxis.d.ts.map +1 -0
  127. package/dist/index.d.ts +18 -0
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/lib/format.d.ts +5 -0
  130. package/dist/lib/format.d.ts.map +1 -0
  131. package/dist/lib/measureFontTextWidth.d.ts +7 -0
  132. package/dist/lib/measureFontTextWidth.d.ts.map +1 -0
  133. package/dist/lib/monoFontFamily.d.ts +6 -0
  134. package/dist/lib/monoFontFamily.d.ts.map +1 -0
  135. package/dist/math/color.d.ts +5 -0
  136. package/dist/math/color.d.ts.map +1 -0
  137. package/dist/math/degenTick.d.ts +57 -0
  138. package/dist/math/degenTick.d.ts.map +1 -0
  139. package/dist/math/interpolate.d.ts +7 -0
  140. package/dist/math/interpolate.d.ts.map +1 -0
  141. package/dist/math/intervals.d.ts +3 -0
  142. package/dist/math/intervals.d.ts.map +1 -0
  143. package/dist/math/lerp.d.ts +7 -0
  144. package/dist/math/lerp.d.ts.map +1 -0
  145. package/dist/math/markers.d.ts +44 -0
  146. package/dist/math/markers.d.ts.map +1 -0
  147. package/dist/math/momentum.d.ts +8 -0
  148. package/dist/math/momentum.d.ts.map +1 -0
  149. package/dist/math/pickCandle.d.ts +8 -0
  150. package/dist/math/pickCandle.d.ts.map +1 -0
  151. package/dist/math/range.d.ts +10 -0
  152. package/dist/math/range.d.ts.map +1 -0
  153. package/dist/math/referenceLines.d.ts +20 -0
  154. package/dist/math/referenceLines.d.ts.map +1 -0
  155. package/dist/math/spline.d.ts +45 -0
  156. package/dist/math/spline.d.ts.map +1 -0
  157. package/dist/math/squiggly.d.ts +36 -0
  158. package/dist/math/squiggly.d.ts.map +1 -0
  159. package/dist/theme.d.ts +30 -0
  160. package/dist/theme.d.ts.map +1 -0
  161. package/dist/types.d.ts +720 -0
  162. package/dist/types.d.ts.map +1 -0
  163. package/package.json +72 -0
  164. package/src/components/AnimatedLabel.tsx +41 -0
  165. package/src/components/BadgeOverlay.tsx +39 -0
  166. package/src/components/CrosshairLine.tsx +90 -0
  167. package/src/components/CrosshairOverlay.tsx +170 -0
  168. package/src/components/DegenParticlesOverlay.tsx +141 -0
  169. package/src/components/DotOverlay.tsx +69 -0
  170. package/src/components/LeftEdgeFade.tsx +36 -0
  171. package/src/components/LiveChart.tsx +821 -0
  172. package/src/components/LiveChartSeries.tsx +607 -0
  173. package/src/components/LiveChartTransition.tsx +135 -0
  174. package/src/components/LoadingOverlay.tsx +301 -0
  175. package/src/components/MarkerOverlay.tsx +331 -0
  176. package/src/components/MultiSeriesDots.tsx +117 -0
  177. package/src/components/MultiSeriesStroke.tsx +79 -0
  178. package/src/components/MultiSeriesTooltipStack.tsx +78 -0
  179. package/src/components/MultiSeriesValueLabels.tsx +103 -0
  180. package/src/components/MultiSeriesValueLines.tsx +115 -0
  181. package/src/components/ReferenceLineOverlay.tsx +317 -0
  182. package/src/components/SeriesToggleChips.tsx +201 -0
  183. package/src/components/TradeStreamOverlay.tsx +117 -0
  184. package/src/components/ValueLineOverlay.tsx +63 -0
  185. package/src/components/ValueTextOverlay.tsx +43 -0
  186. package/src/components/XAxisOverlay.tsx +109 -0
  187. package/src/components/YAxisOverlay.tsx +135 -0
  188. package/src/components/seriesMetaSig.ts +13 -0
  189. package/src/constants.ts +44 -0
  190. package/src/core/liveChartEngineTick.ts +185 -0
  191. package/src/core/liveChartSeriesEngineTick.ts +163 -0
  192. package/src/core/multiSeriesLayout.ts +80 -0
  193. package/src/core/resolveConfig.ts +538 -0
  194. package/src/core/useLiveChartEngine.ts +207 -0
  195. package/src/core/useLiveChartSeriesEngine.ts +215 -0
  196. package/src/draw/candle.ts +210 -0
  197. package/src/draw/grid.ts +174 -0
  198. package/src/draw/line.ts +257 -0
  199. package/src/draw/trade.ts +202 -0
  200. package/src/hooks/crosshairSeries.ts +78 -0
  201. package/src/hooks/crosshairShared.ts +296 -0
  202. package/src/hooks/index.ts +26 -0
  203. package/src/hooks/resolveChartLayout.ts +144 -0
  204. package/src/hooks/useBadge.ts +192 -0
  205. package/src/hooks/useCandlePaths.ts +165 -0
  206. package/src/hooks/useCanvasLayout.ts +22 -0
  207. package/src/hooks/useChartColors.ts +48 -0
  208. package/src/hooks/useChartPaths.ts +121 -0
  209. package/src/hooks/useChartReveal.ts +123 -0
  210. package/src/hooks/useChartSkiaFont.ts +34 -0
  211. package/src/hooks/useCrosshair.ts +250 -0
  212. package/src/hooks/useCrosshairSeries.ts +163 -0
  213. package/src/hooks/useDegen.ts +262 -0
  214. package/src/hooks/useLiveChartHasData.ts +31 -0
  215. package/src/hooks/useLiveDot.ts +31 -0
  216. package/src/hooks/useMarkers.ts +95 -0
  217. package/src/hooks/useModeBlend.ts +52 -0
  218. package/src/hooks/useMomentum.ts +37 -0
  219. package/src/hooks/useMultiSeriesDegen.ts +260 -0
  220. package/src/hooks/useMultiSeriesLinePaths.ts +76 -0
  221. package/src/hooks/useReferenceLine.ts +212 -0
  222. package/src/hooks/useReverseMorphEngineInputs.ts +154 -0
  223. package/src/hooks/useTradeStream.ts +64 -0
  224. package/src/hooks/useXAxis.ts +200 -0
  225. package/src/hooks/useYAxis.ts +48 -0
  226. package/src/index.ts +69 -0
  227. package/src/lib/format.ts +36 -0
  228. package/src/lib/measureFontTextWidth.ts +10 -0
  229. package/src/lib/monoFontFamily.ts +8 -0
  230. package/src/math/color.ts +31 -0
  231. package/src/math/degenTick.ts +151 -0
  232. package/src/math/interpolate.ts +32 -0
  233. package/src/math/intervals.ts +17 -0
  234. package/src/math/lerp.ts +17 -0
  235. package/src/math/markers.ts +175 -0
  236. package/src/math/momentum.ts +38 -0
  237. package/src/math/pickCandle.ts +42 -0
  238. package/src/math/range.ts +54 -0
  239. package/src/math/referenceLines.ts +56 -0
  240. package/src/math/spline.ts +183 -0
  241. package/src/math/squiggly.ts +108 -0
  242. package/src/theme.ts +231 -0
  243. package/src/types.ts +789 -0
@@ -0,0 +1,538 @@
1
+ import type {
2
+ BadgeConfig,
3
+ BadgeVariant,
4
+ DegenOptions,
5
+ FontConfig,
6
+ FontWeight,
7
+ GradientConfig,
8
+ GridStyleConfig,
9
+ LeftEdgeFadeConfig,
10
+ LegendConfig,
11
+ LegendStyle,
12
+ MultiSeriesDotConfig,
13
+ PulseConfig,
14
+ ReferenceLine,
15
+ ScrubConfig,
16
+ TradeEvent,
17
+ ValueLineConfig,
18
+ XAxisConfig,
19
+ YAxisConfig,
20
+ } from "../types";
21
+
22
+ import type { SharedValue } from "react-native-reanimated";
23
+ import { FADE_EDGE_WIDTH } from "../constants";
24
+
25
+ // ─── Resolved types (all fields required, no optionals) ──────────────────────
26
+
27
+ export interface ResolvedValueLineConfig {
28
+ strokeWidth: number;
29
+ intervals: [number, number];
30
+ /** undefined → use palette.dashLine at render time */
31
+ color: string | undefined;
32
+ }
33
+
34
+ export interface ResolvedBadgeConfig {
35
+ variant: BadgeVariant;
36
+ tail: boolean;
37
+ position: "right" | "left";
38
+ background: string | undefined;
39
+ }
40
+
41
+ export interface ResolvedYAxisConfig {
42
+ minGap: number;
43
+ }
44
+
45
+ export interface ResolvedXAxisConfig {
46
+ minGap: number;
47
+ }
48
+
49
+ export interface ResolvedScrubConfig {
50
+ tooltip: boolean;
51
+ /** Opacity of content right of the crosshair while scrubbing (dstOut fade). */
52
+ dimOpacity: number;
53
+ /** undefined → palette.crosshairLine */
54
+ crosshairLineColor: string | undefined;
55
+ /** undefined → palette.crosshairDim */
56
+ crosshairDimColor: string | undefined;
57
+ /** undefined → palette.tooltipBg */
58
+ tooltipBackground: string | undefined;
59
+ /** undefined → palette.tooltipText */
60
+ tooltipColor: string | undefined;
61
+ /** undefined → palette.tooltipBorder */
62
+ tooltipBorderColor: string | undefined;
63
+ }
64
+
65
+ export interface ResolvedGradientConfig {
66
+ /** undefined → use palette.fillTop (theme-aware) at render time */
67
+ topOpacity: number | undefined;
68
+ /** undefined → use palette.fillBottom (transparent) at render time */
69
+ bottomOpacity: number | undefined;
70
+ }
71
+
72
+ export interface ResolvedPulseConfig {
73
+ interval: number;
74
+ duration: number;
75
+ maxRadius: number;
76
+ opacity: number;
77
+ strokeWidth: number;
78
+ }
79
+
80
+ export interface ResolvedReferenceLineConfig {
81
+ strokeWidth: number;
82
+ intervals: [number, number];
83
+ /** undefined → use palette.refLine at render time */
84
+ color: string | undefined;
85
+ }
86
+
87
+ export interface ResolvedGridStyleConfig {
88
+ /** undefined → use palette.gridLine at render time */
89
+ color: string | undefined;
90
+ strokeWidth: number;
91
+ /** Empty array → solid stroke (no dash effect). */
92
+ intervals: number[];
93
+ opacity: number;
94
+ }
95
+
96
+ export interface ResolvedFontConfig {
97
+ fontFamily: string;
98
+ fontSize: number;
99
+ fontWeight: FontWeight;
100
+ }
101
+
102
+ export interface ResolvedDegenConfig {
103
+ scale: number;
104
+ downMomentum: boolean;
105
+ shake: boolean;
106
+ shakeIntensity: number;
107
+ shakeDurationSec: number;
108
+ particleSlotCount: number;
109
+ particleBurstDurationSec: number;
110
+ burstParticleCount: number;
111
+ drag: number;
112
+ particleSizeMin: number;
113
+ particleSizeMax: number;
114
+ particleOpacity: number;
115
+ spreadAngle: number;
116
+ positionJitterX: number;
117
+ positionJitterY: number;
118
+ speedMin: number;
119
+ speedMax: number;
120
+ /** `null` = use palette.line at render time. */
121
+ colors: string[] | null;
122
+ }
123
+
124
+ export interface ResolvedTradeStreamConfig {
125
+ maxCount: number;
126
+ /** Horizontal offset from `padding.left` for the label text (default 8). */
127
+ labelOffsetX: number;
128
+ }
129
+
130
+ export interface ResolvedLeftEdgeFadeConfig {
131
+ width: number;
132
+ startColor: string;
133
+ endColor: string;
134
+ }
135
+
136
+ // ─── Resolver functions ───────────────────────────────────────────────────────
137
+
138
+ const VALUE_LINE_DEFAULTS: ResolvedValueLineConfig = {
139
+ strokeWidth: 1,
140
+ intervals: [4, 4],
141
+ color: undefined,
142
+ };
143
+
144
+ /**
145
+ * Resolves `valueLine` prop to a fully-typed config or null (disabled).
146
+ * `true` → defaults, object → merged with defaults, falsy → null.
147
+ */
148
+ export function resolveValueLine(
149
+ prop: boolean | ValueLineConfig | undefined,
150
+ ): ResolvedValueLineConfig | null {
151
+ if (!prop) return null;
152
+ if (prop === true) return VALUE_LINE_DEFAULTS;
153
+ return { ...VALUE_LINE_DEFAULTS, ...prop };
154
+ }
155
+
156
+ const BADGE_DEFAULTS: ResolvedBadgeConfig = {
157
+ variant: "default",
158
+ tail: true,
159
+ position: "right",
160
+ background: undefined,
161
+ };
162
+
163
+ /**
164
+ * Resolves `badge` prop to a fully-typed config or null (disabled).
165
+ * `true` → defaults, object → merged with defaults, falsy → null.
166
+ */
167
+ export function resolveBadge(
168
+ prop: boolean | BadgeConfig | undefined,
169
+ ): ResolvedBadgeConfig | null {
170
+ if (!prop) return null;
171
+ if (prop === true) return BADGE_DEFAULTS;
172
+ return { ...BADGE_DEFAULTS, ...prop };
173
+ }
174
+
175
+ const Y_AXIS_DEFAULTS: ResolvedYAxisConfig = {
176
+ minGap: 36,
177
+ };
178
+
179
+ /**
180
+ * Resolves `yAxis` prop to a fully-typed config or null (disabled).
181
+ * `true` → defaults, object → merged with defaults, falsy → null.
182
+ */
183
+ export function resolveYAxis(
184
+ prop: boolean | YAxisConfig | undefined,
185
+ ): ResolvedYAxisConfig | null {
186
+ if (!prop) return null;
187
+ if (prop === true) return Y_AXIS_DEFAULTS;
188
+ return { ...Y_AXIS_DEFAULTS, ...prop };
189
+ }
190
+
191
+ const X_AXIS_DEFAULTS: ResolvedXAxisConfig = {
192
+ minGap: 60,
193
+ };
194
+
195
+ /**
196
+ * Resolves `xAxis` prop to a fully-typed config or null (disabled).
197
+ * Defaults to enabled (`true`) so `undefined` also returns the defaults.
198
+ */
199
+ export function resolveXAxis(
200
+ prop: boolean | XAxisConfig | undefined,
201
+ ): ResolvedXAxisConfig | null {
202
+ if (prop === false) return null;
203
+ if (prop === undefined || prop === true) return X_AXIS_DEFAULTS;
204
+ return { ...X_AXIS_DEFAULTS, ...prop };
205
+ }
206
+
207
+ const SCRUB_DEFAULTS: ResolvedScrubConfig = {
208
+ tooltip: true,
209
+ dimOpacity: 0.3,
210
+ crosshairLineColor: undefined,
211
+ crosshairDimColor: undefined,
212
+ tooltipBackground: undefined,
213
+ tooltipColor: undefined,
214
+ tooltipBorderColor: undefined,
215
+ };
216
+
217
+ /**
218
+ * Resolves `scrub` prop to a fully-typed config or null (disabled).
219
+ * `true` → defaults, object → merged with defaults, falsy → null.
220
+ */
221
+ export function resolveScrub(
222
+ prop: boolean | ScrubConfig | undefined,
223
+ ): ResolvedScrubConfig | null {
224
+ if (!prop) return null;
225
+ if (prop === true) return SCRUB_DEFAULTS;
226
+ return { ...SCRUB_DEFAULTS, ...prop };
227
+ }
228
+
229
+ const GRADIENT_DEFAULTS: ResolvedGradientConfig = {
230
+ topOpacity: undefined,
231
+ bottomOpacity: undefined,
232
+ };
233
+
234
+ /**
235
+ * Resolves `gradient` prop to a fully-typed config or null (disabled).
236
+ * `true` → defaults (use palette colors), object → merged with defaults, falsy → null.
237
+ */
238
+ export function resolveGradient(
239
+ prop: boolean | GradientConfig | undefined,
240
+ ): ResolvedGradientConfig | null {
241
+ if (!prop) return null;
242
+ if (prop === true) return GRADIENT_DEFAULTS;
243
+ return { ...GRADIENT_DEFAULTS, ...prop };
244
+ }
245
+
246
+ /** Fallback when no theme background is passed (e.g. unit tests). */
247
+ const LEFT_EDGE_FADE_COLOR_FALLBACK: Pick<
248
+ ResolvedLeftEdgeFadeConfig,
249
+ "startColor" | "endColor"
250
+ > = {
251
+ startColor: "rgba(0, 0, 0, 1)",
252
+ endColor: "rgba(0, 0, 0, 0)",
253
+ };
254
+
255
+ /**
256
+ * Resolves `leftEdgeFade` prop to a fully-typed config or null (disabled).
257
+ * `true` → defaults, object → merged with defaults, falsy → null.
258
+ *
259
+ * Pass `colorDefaults` from `leftEdgeFadeColorsFromBgRgb(palette.bgRgb)` so default
260
+ * stops match the chart background; omit for black alpha-gradient fallback.
261
+ */
262
+ export function resolveLeftEdgeFade(
263
+ prop: boolean | LeftEdgeFadeConfig | undefined,
264
+ colorDefaults: {
265
+ startColor: string;
266
+ endColor: string;
267
+ } = LEFT_EDGE_FADE_COLOR_FALLBACK,
268
+ ): ResolvedLeftEdgeFadeConfig | null {
269
+ if (!prop) return null;
270
+ const base: ResolvedLeftEdgeFadeConfig = {
271
+ width: FADE_EDGE_WIDTH,
272
+ ...colorDefaults,
273
+ };
274
+ if (prop === true) return base;
275
+ return { ...base, ...prop };
276
+ }
277
+
278
+ const PULSE_DEFAULTS: ResolvedPulseConfig = {
279
+ interval: 1500,
280
+ duration: 900,
281
+ maxRadius: 21,
282
+ opacity: 0.35,
283
+ strokeWidth: 1.5,
284
+ };
285
+
286
+ /**
287
+ * Resolves `pulse` prop to a fully-typed config or null (disabled).
288
+ * `true` → defaults, object → merged with defaults, falsy → null.
289
+ */
290
+ export function resolvePulse(
291
+ prop: boolean | PulseConfig | undefined,
292
+ ): ResolvedPulseConfig | null {
293
+ if (!prop) return null;
294
+ if (prop === true) return PULSE_DEFAULTS;
295
+ return { ...PULSE_DEFAULTS, ...prop };
296
+ }
297
+
298
+ const REFERENCE_LINE_VISUAL_DEFAULTS = {
299
+ strokeWidth: 1,
300
+ intervals: [4, 4] as [number, number],
301
+ color: undefined as string | undefined,
302
+ };
303
+
304
+ /**
305
+ * Resolves the `font` prop into a fully-typed config ready for `matchFont`.
306
+ * `defaultFamily` is the platform-specific fallback resolved by the caller.
307
+ */
308
+ export function resolveFontConfig(
309
+ config: FontConfig | undefined,
310
+ defaultFamily: string,
311
+ defaultSize: number,
312
+ ): ResolvedFontConfig {
313
+ return {
314
+ fontFamily: config?.fontFamily ?? defaultFamily,
315
+ fontSize: config?.fontSize ?? defaultSize,
316
+ fontWeight: config?.fontWeight ?? "500",
317
+ };
318
+ }
319
+
320
+ /**
321
+ * Extracts the visual rendering config from a `ReferenceLine` prop.
322
+ * Returns null when no reference line is set.
323
+ */
324
+ export function resolveReferenceLineConfig(
325
+ rl: ReferenceLine | undefined,
326
+ ): ResolvedReferenceLineConfig | null {
327
+ if (!rl) return null;
328
+ return {
329
+ strokeWidth: rl.strokeWidth ?? REFERENCE_LINE_VISUAL_DEFAULTS.strokeWidth,
330
+ intervals: rl.intervals ?? REFERENCE_LINE_VISUAL_DEFAULTS.intervals,
331
+ color: rl.color,
332
+ };
333
+ }
334
+
335
+ const GRID_STYLE_DEFAULTS: ResolvedGridStyleConfig = {
336
+ color: undefined,
337
+ strokeWidth: 1,
338
+ intervals: [],
339
+ opacity: 1,
340
+ };
341
+
342
+ /**
343
+ * Resolves the `gridStyle` prop into a fully-typed config. Always returns a
344
+ * config (the grid always needs concrete defaults); omitted fields fall back to
345
+ * the legacy solid 1px grid line.
346
+ */
347
+ export function resolveGridStyle(
348
+ prop: GridStyleConfig | undefined,
349
+ ): ResolvedGridStyleConfig {
350
+ if (!prop) return GRID_STYLE_DEFAULTS;
351
+ return {
352
+ color: prop.color,
353
+ strokeWidth: prop.strokeWidth ?? GRID_STYLE_DEFAULTS.strokeWidth,
354
+ intervals: prop.intervals ?? GRID_STYLE_DEFAULTS.intervals,
355
+ opacity: prop.opacity ?? GRID_STYLE_DEFAULTS.opacity,
356
+ };
357
+ }
358
+
359
+ const DEGEN_SHAKE_DURATION_DEFAULT_SEC = 0.45;
360
+ const DEGEN_PARTICLE_SLOT_DEFAULT = 60;
361
+ const DEGEN_PARTICLE_BURST_DURATION_DEFAULT_SEC = 1.0;
362
+ const DEGEN_BURST_PARTICLE_DEFAULT = 20;
363
+
364
+ function clampDegenParticleSlotCount(n: number): number {
365
+ return Math.max(4, Math.min(80, Math.round(n)));
366
+ }
367
+
368
+ function clampDegenParticleBurstDurationSec(n: number): number {
369
+ return Math.max(0.05, Math.min(5, n));
370
+ }
371
+
372
+ function clampDegenBurstParticleCount(n: number, slotCount: number): number {
373
+ return Math.max(1, Math.min(slotCount, Math.round(n)));
374
+ }
375
+
376
+ const DEGEN_DEFAULTS: ResolvedDegenConfig = {
377
+ scale: 1,
378
+ downMomentum: false,
379
+ shake: true,
380
+ shakeIntensity: 1,
381
+ shakeDurationSec: DEGEN_SHAKE_DURATION_DEFAULT_SEC,
382
+ particleSlotCount: DEGEN_PARTICLE_SLOT_DEFAULT,
383
+ particleBurstDurationSec: DEGEN_PARTICLE_BURST_DURATION_DEFAULT_SEC,
384
+ burstParticleCount: DEGEN_BURST_PARTICLE_DEFAULT,
385
+ drag: 0.95,
386
+ particleSizeMin: 1,
387
+ particleSizeMax: 2.2,
388
+ particleOpacity: 0.55,
389
+ spreadAngle: Math.PI * 1.2,
390
+ positionJitterX: 24,
391
+ positionJitterY: 8,
392
+ speedMin: 60,
393
+ speedMax: 160,
394
+ colors: null,
395
+ };
396
+
397
+ function resolveDegenColors(
398
+ input: string | string[] | undefined,
399
+ ): string[] | null {
400
+ if (!input) return null;
401
+ if (typeof input === "string") return [input];
402
+ return input.length > 0 ? input : null;
403
+ }
404
+
405
+ /**
406
+ * Resolves `degen` prop to a fully-typed config or null (disabled).
407
+ */
408
+ export function resolveDegen(
409
+ prop: boolean | DegenOptions | undefined,
410
+ ): ResolvedDegenConfig | null {
411
+ if (!prop) return null;
412
+ if (prop === true) return DEGEN_DEFAULTS;
413
+ const slots = clampDegenParticleSlotCount(
414
+ prop.particleSlotCount ?? DEGEN_DEFAULTS.particleSlotCount,
415
+ );
416
+ return {
417
+ scale: prop.scale ?? DEGEN_DEFAULTS.scale,
418
+ downMomentum: prop.downMomentum ?? DEGEN_DEFAULTS.downMomentum,
419
+ shake: prop.shake ?? DEGEN_DEFAULTS.shake,
420
+ shakeIntensity: prop.shakeIntensity ?? DEGEN_DEFAULTS.shakeIntensity,
421
+ shakeDurationSec: prop.shakeDurationSec ?? DEGEN_DEFAULTS.shakeDurationSec,
422
+ particleSlotCount: slots,
423
+ particleBurstDurationSec: clampDegenParticleBurstDurationSec(
424
+ prop.particleBurstDurationSec ?? DEGEN_DEFAULTS.particleBurstDurationSec,
425
+ ),
426
+ burstParticleCount: clampDegenBurstParticleCount(
427
+ prop.burstParticleCount ?? DEGEN_DEFAULTS.burstParticleCount,
428
+ slots,
429
+ ),
430
+ drag: Math.max(0, Math.min(1, prop.drag ?? DEGEN_DEFAULTS.drag)),
431
+ particleSizeMin: Math.max(
432
+ 0.1,
433
+ prop.particleSizeMin ?? DEGEN_DEFAULTS.particleSizeMin,
434
+ ),
435
+ particleSizeMax: Math.max(
436
+ 0.1,
437
+ prop.particleSizeMax ?? DEGEN_DEFAULTS.particleSizeMax,
438
+ ),
439
+ particleOpacity: Math.max(
440
+ 0,
441
+ Math.min(1, prop.particleOpacity ?? DEGEN_DEFAULTS.particleOpacity),
442
+ ),
443
+ spreadAngle: prop.spreadAngle ?? DEGEN_DEFAULTS.spreadAngle,
444
+ positionJitterX: Math.max(
445
+ 0,
446
+ prop.positionJitterX ?? DEGEN_DEFAULTS.positionJitterX,
447
+ ),
448
+ positionJitterY: Math.max(
449
+ 0,
450
+ prop.positionJitterY ?? DEGEN_DEFAULTS.positionJitterY,
451
+ ),
452
+ speedMin: Math.max(0, prop.speedMin ?? DEGEN_DEFAULTS.speedMin),
453
+ speedMax: Math.max(0, prop.speedMax ?? DEGEN_DEFAULTS.speedMax),
454
+ colors: resolveDegenColors(prop.colors),
455
+ };
456
+ }
457
+
458
+ const TRADE_STREAM_DEFAULTS: ResolvedTradeStreamConfig = {
459
+ maxCount: 50,
460
+ labelOffsetX: 8,
461
+ };
462
+
463
+ /**
464
+ * Whether trade stream markers should run, and cap for mapped trades per frame.
465
+ * Extend `options` when display options are added to props.
466
+ */
467
+ export function resolveTradeStream(
468
+ stream: SharedValue<TradeEvent[]> | undefined,
469
+ options?: boolean | { maxCount?: number; labelOffsetX?: number },
470
+ ): ResolvedTradeStreamConfig | null {
471
+ if (stream === undefined) return null;
472
+ if (options === false) return null;
473
+ if (options === undefined || options === true) return TRADE_STREAM_DEFAULTS;
474
+ return {
475
+ maxCount: options.maxCount ?? TRADE_STREAM_DEFAULTS.maxCount,
476
+ labelOffsetX: options.labelOffsetX ?? TRADE_STREAM_DEFAULTS.labelOffsetX,
477
+ };
478
+ }
479
+
480
+ // ─── Multi-series dot ─────────────────────────────────────────────────────────
481
+
482
+ export interface ResolvedMultiSeriesDotConfig {
483
+ radius: number;
484
+ pulse: ResolvedPulseConfig | null;
485
+ valueLine: ResolvedValueLineConfig | null;
486
+ valueLabel: boolean;
487
+ }
488
+
489
+ const MULTI_DOT_DEFAULTS: ResolvedMultiSeriesDotConfig = {
490
+ radius: 3.5,
491
+ pulse: PULSE_DEFAULTS,
492
+ valueLine: null,
493
+ valueLabel: true,
494
+ };
495
+
496
+ export function resolveMultiSeriesDot(
497
+ prop: MultiSeriesDotConfig | undefined,
498
+ ): ResolvedMultiSeriesDotConfig {
499
+ if (!prop) return MULTI_DOT_DEFAULTS;
500
+ return {
501
+ radius: prop.radius ?? MULTI_DOT_DEFAULTS.radius,
502
+ pulse: resolvePulse(prop.pulse ?? true),
503
+ valueLine: resolveValueLine(prop.valueLine),
504
+ valueLabel: prop.valueLabel ?? MULTI_DOT_DEFAULTS.valueLabel,
505
+ };
506
+ }
507
+
508
+ // ─── Legend ───────────────────────────────────────────────────────────────────
509
+
510
+ export interface ResolvedLegendConfig {
511
+ visible: boolean;
512
+ compact: boolean;
513
+ position: "top" | "bottom";
514
+ /** Raw style overrides; the chip row applies its own fallbacks. */
515
+ style: LegendStyle | undefined;
516
+ }
517
+
518
+ const LEGEND_DEFAULTS: ResolvedLegendConfig = {
519
+ visible: true,
520
+ compact: false,
521
+ position: "top",
522
+ style: undefined,
523
+ };
524
+
525
+ export function resolveLegend(
526
+ prop: boolean | LegendConfig | undefined,
527
+ ): ResolvedLegendConfig {
528
+ if (prop === false) return { ...LEGEND_DEFAULTS, visible: false };
529
+ if (prop === undefined || prop === true) {
530
+ return { ...LEGEND_DEFAULTS, compact: false };
531
+ }
532
+ return {
533
+ visible: prop.visible ?? LEGEND_DEFAULTS.visible,
534
+ compact: prop.compact ?? LEGEND_DEFAULTS.compact,
535
+ position: prop.position ?? LEGEND_DEFAULTS.position,
536
+ style: prop.style,
537
+ };
538
+ }