react-native-livechart 2.0.1 → 3.1.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 (93) hide show
  1. package/README.md +9 -3
  2. package/dist/components/AxisLabelOverlay.d.ts +29 -0
  3. package/dist/components/AxisLabelOverlay.d.ts.map +1 -0
  4. package/dist/components/CrosshairLine.d.ts +12 -1
  5. package/dist/components/CrosshairLine.d.ts.map +1 -1
  6. package/dist/components/CrosshairOverlay.d.ts +15 -1
  7. package/dist/components/CrosshairOverlay.d.ts.map +1 -1
  8. package/dist/components/DegenParticlesOverlay.d.ts +17 -0
  9. package/dist/components/DegenParticlesOverlay.d.ts.map +1 -1
  10. package/dist/components/LiveChart.d.ts.map +1 -1
  11. package/dist/components/LiveChartSeries.d.ts.map +1 -1
  12. package/dist/components/LoadingOverlay.d.ts.map +1 -1
  13. package/dist/components/MarkerOverlay.d.ts.map +1 -1
  14. package/dist/components/MultiSeriesValueLines.d.ts.map +1 -1
  15. package/dist/components/ReferenceLineOverlay.d.ts.map +1 -1
  16. package/dist/components/SelectionDot.d.ts +32 -0
  17. package/dist/components/SelectionDot.d.ts.map +1 -0
  18. package/dist/components/ValueLineOverlay.d.ts.map +1 -1
  19. package/dist/components/XAxisOverlay.d.ts.map +1 -1
  20. package/dist/components/YAxisOverlay.d.ts.map +1 -1
  21. package/dist/core/resolveConfig.d.ts +46 -1
  22. package/dist/core/resolveConfig.d.ts.map +1 -1
  23. package/dist/core/useLiveChartEngine.d.ts +6 -0
  24. package/dist/core/useLiveChartEngine.d.ts.map +1 -1
  25. package/dist/draw/particleAtlas.d.ts +39 -0
  26. package/dist/draw/particleAtlas.d.ts.map +1 -0
  27. package/dist/hooks/crosshairShared.d.ts +10 -0
  28. package/dist/hooks/crosshairShared.d.ts.map +1 -1
  29. package/dist/hooks/useBadge.d.ts +2 -2
  30. package/dist/hooks/useBadge.d.ts.map +1 -1
  31. package/dist/hooks/useCandlePaths.d.ts +11 -11
  32. package/dist/hooks/useCandlePaths.d.ts.map +1 -1
  33. package/dist/hooks/useChartColors.d.ts +5 -0
  34. package/dist/hooks/useChartColors.d.ts.map +1 -1
  35. package/dist/hooks/useChartPaths.d.ts +8 -7
  36. package/dist/hooks/useChartPaths.d.ts.map +1 -1
  37. package/dist/hooks/useChartReveal.d.ts +3 -1
  38. package/dist/hooks/useChartReveal.d.ts.map +1 -1
  39. package/dist/hooks/useCrosshair.d.ts +1 -1
  40. package/dist/hooks/useCrosshair.d.ts.map +1 -1
  41. package/dist/hooks/useCrosshairSeries.d.ts +1 -1
  42. package/dist/hooks/useCrosshairSeries.d.ts.map +1 -1
  43. package/dist/hooks/useDegen.d.ts +3 -1
  44. package/dist/hooks/useDegen.d.ts.map +1 -1
  45. package/dist/hooks/useMarkers.d.ts +3 -1
  46. package/dist/hooks/useMarkers.d.ts.map +1 -1
  47. package/dist/hooks/useMultiSeriesLinePaths.d.ts +9 -8
  48. package/dist/hooks/useMultiSeriesLinePaths.d.ts.map +1 -1
  49. package/dist/hooks/usePathBuilder.d.ts +27 -0
  50. package/dist/hooks/usePathBuilder.d.ts.map +1 -0
  51. package/dist/hooks/useTradeStream.d.ts +3 -1
  52. package/dist/hooks/useTradeStream.d.ts.map +1 -1
  53. package/dist/index.d.ts +1 -1
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/math/spline.d.ts +10 -2
  56. package/dist/math/spline.d.ts.map +1 -1
  57. package/dist/types.d.ts +97 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/package.json +2 -2
  60. package/src/components/AxisLabelOverlay.tsx +133 -0
  61. package/src/components/CrosshairLine.tsx +27 -0
  62. package/src/components/CrosshairOverlay.tsx +50 -18
  63. package/src/components/DegenParticlesOverlay.tsx +93 -109
  64. package/src/components/LiveChart.tsx +66 -10
  65. package/src/components/LiveChartSeries.tsx +40 -0
  66. package/src/components/LoadingOverlay.tsx +15 -29
  67. package/src/components/MarkerOverlay.tsx +23 -28
  68. package/src/components/MultiSeriesValueLines.tsx +20 -40
  69. package/src/components/ReferenceLineOverlay.tsx +65 -107
  70. package/src/components/SelectionDot.tsx +92 -0
  71. package/src/components/ValueLineOverlay.tsx +9 -28
  72. package/src/components/XAxisOverlay.tsx +9 -29
  73. package/src/components/YAxisOverlay.tsx +6 -22
  74. package/src/core/resolveConfig.ts +98 -0
  75. package/src/core/useLiveChartEngine.ts +78 -27
  76. package/src/draw/markerAtlas.ts +9 -9
  77. package/src/draw/particleAtlas.ts +95 -0
  78. package/src/hooks/crosshairShared.ts +26 -0
  79. package/src/hooks/useBadge.ts +17 -32
  80. package/src/hooks/useCandlePaths.ts +27 -64
  81. package/src/hooks/useChartColors.ts +19 -0
  82. package/src/hooks/useChartPaths.ts +27 -39
  83. package/src/hooks/useChartReveal.ts +7 -4
  84. package/src/hooks/useCrosshair.ts +46 -7
  85. package/src/hooks/useCrosshairSeries.ts +47 -8
  86. package/src/hooks/useDegen.ts +6 -0
  87. package/src/hooks/useMarkers.ts +3 -0
  88. package/src/hooks/useMultiSeriesLinePaths.ts +26 -28
  89. package/src/hooks/usePathBuilder.ts +42 -0
  90. package/src/hooks/useTradeStream.ts +3 -0
  91. package/src/index.ts +4 -0
  92. package/src/math/spline.ts +22 -2
  93. package/src/types.ts +101 -0
@@ -20,6 +20,8 @@ export function useDegen(
20
20
  momentumSV: SharedValue<Momentum>,
21
21
  cfg: ResolvedDegenConfig | null,
22
22
  onShake?: (payload: DegenShakePayload) => void,
23
+ /** Static charts run no loops: register the frame callback without starting it. */
24
+ isStatic = false,
23
25
  ): {
24
26
  pack: SharedValue<Float64Array<ArrayBuffer>>;
25
27
  packRevision: SharedValue<number>;
@@ -248,6 +250,10 @@ export function useDegen(
248
250
  }
249
251
  prevActiveCount.set(activeCount);
250
252
  },
253
+ // Static charts register the callback but never start it, so no degen frame
254
+ // loop runs. Live charts keep the default (autostart) loop unchanged. The
255
+ // controller also forces `cfg` to null in static, so degen is doubly off.
256
+ !isStatic,
251
257
  );
252
258
 
253
259
  const shakeTransform = useDerivedValue(() => {
@@ -30,6 +30,8 @@ export function useMarkers(
30
30
  onMarkerHover?: (event: MarkerHoverEvent | null) => void,
31
31
  seriesSV?: SharedValue<SeriesConfig[]>,
32
32
  lineData?: SharedValue<LiveChartPoint[]>,
33
+ /** Static charts run no loops: register without starting. Default `true`. */
34
+ autostart = true,
33
35
  ): { projected: SharedValue<ProjectedMarker[]>; tapGesture: ReturnType<typeof Gesture.Tap> } {
34
36
  const projected = useSharedValue<ProjectedMarker[]>([]);
35
37
  const cacheRef = useRef<{
@@ -73,6 +75,7 @@ export function useMarkers(
73
75
  });
74
76
  projected.set(buf);
75
77
  },
78
+ autostart,
76
79
  );
77
80
 
78
81
  const tapGesture = Gesture.Tap().onEnd(
@@ -5,51 +5,46 @@ import { MAX_MULTI_SERIES } from "../constants";
5
5
  import type { MultiEngineState } from "../core/useLiveChartEngine";
6
6
  import { buildLinePoints, type ChartPadding } from "../draw/line";
7
7
  import { drawSpline, makeSplineScratch } from "../math/spline";
8
+ import { usePathBuilders } from "./usePathBuilder";
8
9
 
9
10
  /**
10
- * One derived shared value holding up to `MAX_MULTI_SERIES` Skia paths (unused slots are empty paths).
11
+ * One derived shared value holding up to `MAX_MULTI_SERIES` Skia paths (unused
12
+ * slots reuse one cached empty path).
11
13
  *
12
- * Each slot ping-pongs between two persistent `SkPath`s so `MultiSeriesStroke`'s
13
- * per-slot `useDerivedValue(() => paths.value[index])` sees a fresh reference each
14
- * tick (otherwise Reanimated's setter short-circuits and Skia never repaints).
15
- * No new JSI-backed `SkPath` is allocated per frame. See {@link useChartPaths}
16
- * for the memory rationale.
14
+ * Each visible series' path is built into a per-slot `Skia.PathBuilder` (reused
15
+ * across frames via a SharedValue) and finalized with `detach()` a fresh
16
+ * immutable `SkPath` per frame, so `MultiSeriesStroke`'s per-slot
17
+ * `useDerivedValue(() => paths.value[index])` repaints without the two-SkPath
18
+ * ping-pong. Only visible series allocate a path.
17
19
  */
18
20
  export function useMultiSeriesLinePaths(
19
21
  engine: MultiEngineState,
20
22
  padding: ChartPadding,
21
- ): SharedValue<ReturnType<typeof Skia.Path.Make>[]> {
23
+ ): SharedValue<SkPath[]> {
24
+ const builders = usePathBuilders(MAX_MULTI_SERIES);
25
+
22
26
  const poolRef = useRef<{
23
- a: SkPath[];
24
- b: SkPath[];
25
- tick: boolean;
27
+ empty: SkPath;
26
28
  ptsBuf: number[];
27
29
  scratch: ReturnType<typeof makeSplineScratch>;
28
30
  } | null>(null);
29
31
  if (poolRef.current === null) {
30
- const a: SkPath[] = [];
31
- const b: SkPath[] = [];
32
- for (let i = 0; i < MAX_MULTI_SERIES; i++) {
33
- a.push(Skia.Path.Make());
34
- b.push(Skia.Path.Make());
35
- }
36
- // One point buffer + spline scratch, reused across slots (built sequentially)
37
- // and across frames — no per-frame, per-series array allocation.
38
- poolRef.current = { a, b, tick: false, ptsBuf: [] as number[], scratch: makeSplineScratch() };
32
+ poolRef.current = {
33
+ empty: Skia.Path.Make(),
34
+ ptsBuf: [] as number[],
35
+ scratch: makeSplineScratch(),
36
+ };
39
37
  }
40
38
 
41
39
  return useDerivedValue(() => {
42
40
  const pool = poolRef.current!;
43
- pool.tick = !pool.tick;
44
- const slots = pool.tick ? pool.a : pool.b;
41
+ const slots = builders.value;
45
42
  const s = engine.series.get();
46
43
  const displays = engine.displaySeriesValues.get();
47
- const out: ReturnType<typeof Skia.Path.Make>[] = [];
44
+ const out: SkPath[] = [];
48
45
  for (let i = 0; i < MAX_MULTI_SERIES; i++) {
49
- const path = slots[i];
50
- path.reset();
51
46
  if (i >= s.length) {
52
- out.push(path);
47
+ out.push(pool.empty);
53
48
  continue;
54
49
  }
55
50
  const pts = buildLinePoints(
@@ -66,10 +61,13 @@ export function useMultiSeriesLinePaths(
66
61
  );
67
62
  const n = pts.length >> 1;
68
63
  if (n >= 2) {
69
- path.moveTo(pts[0], pts[1]);
70
- drawSpline(path, pts, pool.scratch);
64
+ const b = slots[i];
65
+ b.moveTo(pts[0], pts[1]);
66
+ drawSpline(b, pts, pool.scratch);
67
+ out.push(b.detach());
68
+ } else {
69
+ out.push(pool.empty);
71
70
  }
72
- out.push(path);
73
71
  }
74
72
  return out;
75
73
  });
@@ -0,0 +1,42 @@
1
+ import { Skia } from "@shopify/react-native-skia";
2
+ import { useMemo } from "react";
3
+ import { useSharedValue, type SharedValue } from "react-native-reanimated";
4
+
5
+ /** A `Skia.PathBuilder` instance (typed without depending on a named export). */
6
+ export type ReanimatedPathBuilder = ReturnType<typeof Skia.PathBuilder.Make>;
7
+
8
+ /**
9
+ * A `Skia.PathBuilder` made accessible inside Reanimated worklets.
10
+ *
11
+ * Unlike `SkPath`, an `SkPathBuilder` is **not** a Reanimated-shareable host
12
+ * object: stashing one in a `useRef` and reading it from a `useDerivedValue`
13
+ * worklet yields `undefined`. Wrapping it in a `SharedValue` is the supported
14
+ * way to cross the JS→UI boundary, so the builder is created once on the JS
15
+ * thread and reused every frame on the UI thread.
16
+ *
17
+ * Per-frame usage in a worklet:
18
+ *
19
+ * const b = builder.value;
20
+ * b.moveTo(x, y); b.lineTo(...); // emit verbs
21
+ * return b.detach(); // fresh immutable SkPath; resets the builder
22
+ *
23
+ * `detach()` returns a new `SkPath` and resets the builder for the next frame,
24
+ * so the returned reference changes every frame and Reanimated notifies
25
+ * subscribers without the two-path ping-pong the mutable-`SkPath` pool needs.
26
+ */
27
+ export function usePathBuilder(): SharedValue<ReanimatedPathBuilder> {
28
+ const builder = useMemo(() => Skia.PathBuilder.Make(), []);
29
+ return useSharedValue(builder);
30
+ }
31
+
32
+ /** Like {@link usePathBuilder} but a fixed-length array of builders (e.g. one per series). */
33
+ export function usePathBuilders(
34
+ count: number,
35
+ ): SharedValue<ReanimatedPathBuilder[]> {
36
+ const builders = useMemo(() => {
37
+ const arr: ReanimatedPathBuilder[] = [];
38
+ for (let i = 0; i < count; i++) arr.push(Skia.PathBuilder.Make());
39
+ return arr;
40
+ }, [count]);
41
+ return useSharedValue(builders);
42
+ }
@@ -25,6 +25,8 @@ export function useTradeStream(
25
25
  tradeStream: SharedValue<TradeEvent[]>,
26
26
  padding: ChartPadding,
27
27
  active: boolean,
28
+ /** Static charts run no loops: register without starting. Default `true`. */
29
+ autostart = true,
28
30
  ): SharedValue<TradeMarker[]> {
29
31
  const markers = useSharedValue<TradeMarker[]>([]);
30
32
  const state = useSharedValue<TradeStreamState>(createTradeStreamState());
@@ -58,6 +60,7 @@ export function useTradeStream(
58
60
  const chartH = chartBottom - chartTop;
59
61
  markers.set(projectLabels(s, chartTop, chartH));
60
62
  },
63
+ autostart,
61
64
  );
62
65
 
63
66
  return markers;
package/src/index.ts CHANGED
@@ -28,6 +28,7 @@ export { useTradeStream } from "./hooks/useTradeStream";
28
28
  // ── Types ────────────────────────────────────────────────────────────────────
29
29
 
30
30
  export type {
31
+ AxisLabelConfig,
31
32
  BadgeConfig,
32
33
  BadgeMetrics,
33
34
  BadgeVariant,
@@ -67,6 +68,9 @@ export type {
67
68
  ScrubPointCore,
68
69
  ScrubPointMulti,
69
70
  ScrubSeriesValue,
71
+ SelectionDotConfig,
72
+ SelectionDotProps,
73
+ SelectionDotRingConfig,
70
74
  SeriesConfig,
71
75
  ThemeMode,
72
76
  TradeEvent,
@@ -1,4 +1,3 @@
1
- import type { SkPath } from "@shopify/react-native-skia";
2
1
  import type { LiveChartPoint } from "../types";
3
2
 
4
3
  /**
@@ -33,7 +32,28 @@ export function makeSplineScratch(): SplineScratch {
33
32
  *
34
33
  * @see https://github.com/benjitaylor/liveline
35
34
  */
36
- export function drawSpline(path: SkPath, pts: number[], scratch?: SplineScratch) {
35
+ /**
36
+ * Minimal structural sink for {@link drawSpline}: just the verb-emitting methods
37
+ * it calls. Both `SkPath` and `SkPathBuilder` satisfy it, so the spline can be
38
+ * built into either a mutable `SkPath` or a `Skia.PathBuilder`.
39
+ */
40
+ export type SplinePathSink = {
41
+ lineTo: (x: number, y: number) => unknown;
42
+ cubicTo: (
43
+ c1x: number,
44
+ c1y: number,
45
+ c2x: number,
46
+ c2y: number,
47
+ x: number,
48
+ y: number,
49
+ ) => unknown;
50
+ };
51
+
52
+ export function drawSpline(
53
+ path: SplinePathSink,
54
+ pts: number[],
55
+ scratch?: SplineScratch,
56
+ ) {
37
57
  "worklet";
38
58
  const n = pts.length >> 1;
39
59
  if (n < 2) return;
package/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ComponentType, ReactElement } from "react";
1
2
  import type { ViewStyle } from "react-native";
2
3
  import type { SharedValue } from "react-native-reanimated";
3
4
 
@@ -150,6 +151,11 @@ export interface GradientConfig {
150
151
  topOpacity?: number;
151
152
  /** Opacity at the bottom of the gradient. Default `0`. */
152
153
  bottomOpacity?: number;
154
+ /** Explicit gradient color stops (top → bottom) for the area fill. Overrides
155
+ * topOpacity/bottomOpacity when provided. Must have at least 2 entries. */
156
+ colors?: string[];
157
+ /** Optional stop positions (0..1, ascending) matching `colors` length. */
158
+ positions?: number[];
153
159
  }
154
160
 
155
161
  /** Value badge pill configuration. */
@@ -170,6 +176,24 @@ export interface YAxisConfig {
170
176
  minGap?: number;
171
177
  }
172
178
 
179
+ /**
180
+ * Axis edge label — the value floated at the plot's top or bottom edge
181
+ * (Robinhood-style high/low). Pass `topLabel`/`bottomLabel` as `true` for the
182
+ * batteries-included value label (the chart's current top/bottom Y-axis bound,
183
+ * updated each frame), an object to configure it, or `{ render }` to float a
184
+ * fully custom element instead.
185
+ */
186
+ export interface AxisLabelConfig {
187
+ /** Formatter for the built-in value. Defaults to the chart's `formatValue`. */
188
+ format?: (v: number) => string;
189
+ /** Text color. Defaults to a muted label color (`palette.gridLabel`). */
190
+ color?: string;
191
+ /** Horizontal alignment within the plot width. Default `"right"`. */
192
+ position?: "left" | "right";
193
+ /** Full custom element, floated at the edge. Overrides the built-in value label. */
194
+ render?: () => ReactElement | null;
195
+ }
196
+
173
197
  /** X-axis (time) configuration. */
174
198
  export interface XAxisConfig {
175
199
  /** Minimum pixel gap between time labels. Default `60`. */
@@ -213,6 +237,55 @@ export interface ScrubConfig {
213
237
  panGestureDelay?: number;
214
238
  }
215
239
 
240
+ /**
241
+ * Props passed to a custom {@link SelectionDotConfig.component} — the dot drawn
242
+ * at the scrub intersection while scrubbing. All positional inputs are
243
+ * SharedValues so the dot animates on the UI thread without re-renders.
244
+ */
245
+ export interface SelectionDotProps {
246
+ /** Scrub X in canvas px. */
247
+ x: SharedValue<number>;
248
+ /** Scrub Y in canvas px (the line/value intersection). */
249
+ y: SharedValue<number>;
250
+ /** Whether scrubbing is active. */
251
+ active: SharedValue<boolean>;
252
+ /** Crosshair fade opacity (0..1), already ramped. */
253
+ opacity: SharedValue<number>;
254
+ /** Resolved dot color (accent/series color). */
255
+ color: string;
256
+ /** Suggested dot radius in px. */
257
+ size: number;
258
+ }
259
+
260
+ /** Outer ring drawn around the built-in selection dot (the subtle halo). */
261
+ export interface SelectionDotRingConfig {
262
+ /** Ring color. Defaults to the dot color. */
263
+ color?: string;
264
+ /** Ring thickness in pixels — how far the halo extends past the dot. Default `2`. */
265
+ width?: number;
266
+ }
267
+
268
+ /**
269
+ * Selection-dot styling — the dot drawn at the scrub intersection while
270
+ * scrubbing. Pass `selectionDot={false}` to hide it, an object to configure the
271
+ * built-in dot, or `{ component }` to supply a fully custom Skia dot.
272
+ */
273
+ export interface SelectionDotConfig {
274
+ /** Dot radius in px. Default `4`. */
275
+ size?: number;
276
+ /** Dot color. Defaults to the line / leading-series color. */
277
+ color?: string;
278
+ /**
279
+ * Outer ring around the dot. `true`/config = on, `false` = off. Default on.
280
+ */
281
+ ring?: boolean | SelectionDotRingConfig;
282
+ /**
283
+ * Fully custom Skia dot — receives the scrub position as SharedValues. When
284
+ * set, the `size` / `color` / `ring` knobs are ignored.
285
+ */
286
+ component?: ComponentType<SelectionDotProps>;
287
+ }
288
+
216
289
  /** Left-edge fade — soft erase so the chart blends into the left gutter (web liveline parity). */
217
290
  export interface LeftEdgeFadeConfig {
218
291
  /**
@@ -695,6 +768,20 @@ export interface LiveChartCoreProps {
695
768
  yAxis?: boolean | YAxisConfig;
696
769
  /** X-axis time labels. `true` = defaults, `false` = hidden, or pass `XAxisConfig`. Default `true`. */
697
770
  xAxis?: boolean | XAxisConfig;
771
+ /**
772
+ * Label floated at the top edge of the plot area. `true` = the built-in value
773
+ * label showing the chart's current TOP Y-axis bound (updated each frame),
774
+ * `false`/omitted = none, or pass `AxisLabelConfig` to configure it (or supply
775
+ * a custom `render`). Default off.
776
+ */
777
+ topLabel?: boolean | AxisLabelConfig;
778
+ /**
779
+ * Label floated at the bottom edge of the plot area. `true` = the built-in
780
+ * value label showing the chart's current BOTTOM Y-axis bound (updated each
781
+ * frame), `false`/omitted = none, or pass `AxisLabelConfig` (or a custom
782
+ * `render`). Default off.
783
+ */
784
+ bottomLabel?: boolean | AxisLabelConfig;
698
785
  /** Reference lines / bands drawn into the chart. Supports all three `ReferenceLine` forms. */
699
786
  referenceLines?: ReferenceLine[];
700
787
  /** Per-instance grid-line styling. Pass an object to override color / width / dash / opacity. */
@@ -737,6 +824,16 @@ export interface LiveChartCoreProps {
737
824
  accessibilityRole?: "image" | "none" | "adjustable" | "summary";
738
825
  /** Crosshair scrubbing on hover/drag. `true` = defaults, `false` = disabled, or pass `ScrubConfig`. Default `true`. */
739
826
  scrub?: boolean | ScrubConfig;
827
+ /**
828
+ * Selection dot drawn at the scrub intersection while scrubbing. `true`/omitted
829
+ * = built-in dot, `false` = hidden, or pass `SelectionDotConfig` (`size`,
830
+ * `color`, `ring`, or a custom `component`). Default `true`.
831
+ */
832
+ selectionDot?: boolean | SelectionDotConfig;
833
+ /** Called once when the user starts scrubbing/panning the chart. */
834
+ onGestureStart?: () => void;
835
+ /** Called once when the user stops scrubbing/panning the chart. */
836
+ onGestureEnd?: () => void;
740
837
  /**
741
838
  * Fade out chart content on the left (destination-out style). `true` = defaults, `false` = off,
742
839
  * or pass `LeftEdgeFadeConfig`. Default `true`.
@@ -796,6 +893,10 @@ export interface LiveChartProps extends LiveChartCoreProps {
796
893
  data: SharedValue<LiveChartPoint[]>;
797
894
  /** Latest live value for smooth interpolation between data updates. */
798
895
  value: SharedValue<number>;
896
+ /** Render once with no per-frame animation loop — for many small charts (sparklines)
897
+ * in a list. Pulse/scrub/degen and the entry animation are disabled. Frame the data
898
+ * with `timeWindow` + `nowOverride` (see the historical-data-fill pattern). */
899
+ static?: boolean;
799
900
  /** Called when the user scrubs the crosshair. `null` when scrub ends. */
800
901
  onScrub?: (point: ScrubPoint | null) => void;
801
902
  /**