react-native-vroom-chart 0.7.0 → 0.8.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.
package/lib/index.d.mts CHANGED
@@ -134,7 +134,7 @@ type ChartType = 'candles' | 'line';
134
134
  */
135
135
  type TransitionEasing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
136
136
  /** Active drawing tool while in `draw` mode. `null` draws nothing. */
137
- type DrawTool = null | 'line' | 'box' | 'pencil';
137
+ type DrawTool = null | 'line' | 'box' | 'pencil' | 'path';
138
138
  /** A drawing anchor in data space, so it stays glued to the candles on pan/zoom. */
139
139
  type DrawPoint = {
140
140
  /** Anchor time as Unix epoch milliseconds (not snapped to a candle slot). */
@@ -176,16 +176,27 @@ type PencilDrawing = DrawingBase & {
176
176
  /** The path's points in draw order (at least 2), in data space. */
177
177
  points: DrawPoint[];
178
178
  };
179
+ /**
180
+ * A multi-segment path: straight segments through `points`, in order, ending in
181
+ * an arrowhead on the last vertex. Like a pencil stroke it holds a variable
182
+ * number of points, but every one was placed deliberately (one click each), so
183
+ * each is an individually draggable handle once the path is committed.
184
+ */
185
+ type PathDrawing = DrawingBase & {
186
+ type: 'path';
187
+ /** The path's vertices in draw order (at least 2), in data space. */
188
+ points: DrawPoint[];
189
+ };
179
190
  /**
180
191
  * A committed drawing. Pass an array of these via the `drawings` prop to render
181
192
  * persisted annotations; the chart appends a new one (via `onDrawingComplete`)
182
193
  * each time the user finishes drawing.
183
194
  *
184
195
  * This is a discriminated union on `type` — narrow on it before reading
185
- * `points[1]`, since a `'pencil'` stroke has a variable-length array while
196
+ * `points[1]`, since `'pencil'` and `'path'` have variable-length arrays while
186
197
  * `'line'` and `'box'` are always exactly two points.
187
198
  */
188
- type Drawing = LineDrawing | BoxDrawing | PencilDrawing;
199
+ type Drawing = LineDrawing | BoxDrawing | PencilDrawing | PathDrawing;
189
200
  /**
190
201
  * Storage adapter for **managed** drawing persistence. Provide it via the
191
202
  * `drawingStore` prop and the chart owns the drawings array itself — loading and
@@ -783,4 +794,35 @@ declare global {
783
794
  */
784
795
  declare function VroomChart(props: VroomChartProps): React.JSX.Element;
785
796
 
786
- export { type BollingerBandsConfig, type Candle, type ChartType, type CrosshairEvent, type MACDConfig, type MAKind, type MASource, type MovingAverageOverlay, type PriceLine, type PriceLinesStyle, type RSIConfig, type TransitionEasing, type VWAPConfig, type VisibleRange, type VolumeConfig, VroomChart, type VroomChartProps, type VroomColor, type VroomTheme };
797
+ /**
798
+ * How a new `candles` array relates to the one the chart already holds:
799
+ * `'initial'` is the first data, `'stream'` a live update to the same series,
800
+ * `'timeframe'` the same asset re-bucketed into a different interval, and
801
+ * `'reset'` a different series entirely.
802
+ */
803
+ type DataTransition = 'initial' | 'stream' | 'timeframe' | 'reset';
804
+ /**
805
+ * The candle period in ms, inferred as the median of the first few intervals
806
+ * (robust to a single gap). Null when there are fewer than two candles.
807
+ */
808
+ declare function inferStepMs(candles: Candle[]): number | null;
809
+ /**
810
+ * Classify a candles-prop change. `prev` is the previously rendered array
811
+ * (null on first render); `seriesKeyChanged` forces `reset` regardless of the
812
+ * data (the explicit escape hatch).
813
+ *
814
+ * Constraint: detection compares two immutable snapshots. An array mutated in
815
+ * place (same reference) never reaches this code — React props must change
816
+ * identity to re-render.
817
+ */
818
+ declare function classifyTransition(prev: Candle[] | null, next: Candle[], seriesKeyChanged: boolean): DataTransition;
819
+ /**
820
+ * The visible window to apply after a timeframe switch so each candle keeps
821
+ * the exact pixel width it had before: the visible slot count is preserved and
822
+ * the right edge re-anchors on the newest candle (any future-gap overshoot is
823
+ * carried over in slots, clamped to the core's 3/4-window cap). The new start
824
+ * may precede the first candle — that gap is intentional, width wins.
825
+ */
826
+ declare function timeframeWindow(oldWindow: VisibleRange, oldStepMs: number, oldLastMs: number, newStepMs: number, newLastMs: number): VisibleRange;
827
+
828
+ export { type BollingerBandsConfig, type Candle, type ChartType, type CrosshairEvent, type DataTransition, type MACDConfig, type MAKind, type MASource, type MovingAverageOverlay, type PriceLine, type PriceLinesStyle, type RSIConfig, type TransitionEasing, type VWAPConfig, type VisibleRange, type VolumeConfig, VroomChart, type VroomChartProps, type VroomColor, type VroomTheme, classifyTransition, inferStepMs, timeframeWindow };
package/lib/index.d.ts CHANGED
@@ -134,7 +134,7 @@ type ChartType = 'candles' | 'line';
134
134
  */
135
135
  type TransitionEasing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
136
136
  /** Active drawing tool while in `draw` mode. `null` draws nothing. */
137
- type DrawTool = null | 'line' | 'box' | 'pencil';
137
+ type DrawTool = null | 'line' | 'box' | 'pencil' | 'path';
138
138
  /** A drawing anchor in data space, so it stays glued to the candles on pan/zoom. */
139
139
  type DrawPoint = {
140
140
  /** Anchor time as Unix epoch milliseconds (not snapped to a candle slot). */
@@ -176,16 +176,27 @@ type PencilDrawing = DrawingBase & {
176
176
  /** The path's points in draw order (at least 2), in data space. */
177
177
  points: DrawPoint[];
178
178
  };
179
+ /**
180
+ * A multi-segment path: straight segments through `points`, in order, ending in
181
+ * an arrowhead on the last vertex. Like a pencil stroke it holds a variable
182
+ * number of points, but every one was placed deliberately (one click each), so
183
+ * each is an individually draggable handle once the path is committed.
184
+ */
185
+ type PathDrawing = DrawingBase & {
186
+ type: 'path';
187
+ /** The path's vertices in draw order (at least 2), in data space. */
188
+ points: DrawPoint[];
189
+ };
179
190
  /**
180
191
  * A committed drawing. Pass an array of these via the `drawings` prop to render
181
192
  * persisted annotations; the chart appends a new one (via `onDrawingComplete`)
182
193
  * each time the user finishes drawing.
183
194
  *
184
195
  * This is a discriminated union on `type` — narrow on it before reading
185
- * `points[1]`, since a `'pencil'` stroke has a variable-length array while
196
+ * `points[1]`, since `'pencil'` and `'path'` have variable-length arrays while
186
197
  * `'line'` and `'box'` are always exactly two points.
187
198
  */
188
- type Drawing = LineDrawing | BoxDrawing | PencilDrawing;
199
+ type Drawing = LineDrawing | BoxDrawing | PencilDrawing | PathDrawing;
189
200
  /**
190
201
  * Storage adapter for **managed** drawing persistence. Provide it via the
191
202
  * `drawingStore` prop and the chart owns the drawings array itself — loading and
@@ -783,4 +794,35 @@ declare global {
783
794
  */
784
795
  declare function VroomChart(props: VroomChartProps): React.JSX.Element;
785
796
 
786
- export { type BollingerBandsConfig, type Candle, type ChartType, type CrosshairEvent, type MACDConfig, type MAKind, type MASource, type MovingAverageOverlay, type PriceLine, type PriceLinesStyle, type RSIConfig, type TransitionEasing, type VWAPConfig, type VisibleRange, type VolumeConfig, VroomChart, type VroomChartProps, type VroomColor, type VroomTheme };
797
+ /**
798
+ * How a new `candles` array relates to the one the chart already holds:
799
+ * `'initial'` is the first data, `'stream'` a live update to the same series,
800
+ * `'timeframe'` the same asset re-bucketed into a different interval, and
801
+ * `'reset'` a different series entirely.
802
+ */
803
+ type DataTransition = 'initial' | 'stream' | 'timeframe' | 'reset';
804
+ /**
805
+ * The candle period in ms, inferred as the median of the first few intervals
806
+ * (robust to a single gap). Null when there are fewer than two candles.
807
+ */
808
+ declare function inferStepMs(candles: Candle[]): number | null;
809
+ /**
810
+ * Classify a candles-prop change. `prev` is the previously rendered array
811
+ * (null on first render); `seriesKeyChanged` forces `reset` regardless of the
812
+ * data (the explicit escape hatch).
813
+ *
814
+ * Constraint: detection compares two immutable snapshots. An array mutated in
815
+ * place (same reference) never reaches this code — React props must change
816
+ * identity to re-render.
817
+ */
818
+ declare function classifyTransition(prev: Candle[] | null, next: Candle[], seriesKeyChanged: boolean): DataTransition;
819
+ /**
820
+ * The visible window to apply after a timeframe switch so each candle keeps
821
+ * the exact pixel width it had before: the visible slot count is preserved and
822
+ * the right edge re-anchors on the newest candle (any future-gap overshoot is
823
+ * carried over in slots, clamped to the core's 3/4-window cap). The new start
824
+ * may precede the first candle — that gap is intentional, width wins.
825
+ */
826
+ declare function timeframeWindow(oldWindow: VisibleRange, oldStepMs: number, oldLastMs: number, newStepMs: number, newLastMs: number): VisibleRange;
827
+
828
+ export { type BollingerBandsConfig, type Candle, type ChartType, type CrosshairEvent, type DataTransition, type MACDConfig, type MAKind, type MASource, type MovingAverageOverlay, type PriceLine, type PriceLinesStyle, type RSIConfig, type TransitionEasing, type VWAPConfig, type VisibleRange, type VolumeConfig, VroomChart, type VroomChartProps, type VroomColor, type VroomTheme, classifyTransition, inferStepMs, timeframeWindow };
package/lib/index.js CHANGED
@@ -30,7 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- VroomChart: () => VroomChart
33
+ VroomChart: () => VroomChart,
34
+ classifyTransition: () => classifyTransition,
35
+ inferStepMs: () => inferStepMs,
36
+ timeframeWindow: () => timeframeWindow
34
37
  });
35
38
  module.exports = __toCommonJS(index_exports);
36
39
 
@@ -48,6 +51,86 @@ var import_react = require("react");
48
51
  var import_react_native = require("react-native");
49
52
  var NativeVroomChart_default = import_react_native.TurboModuleRegistry.getEnforcing("VroomChartModule");
50
53
 
54
+ // src/dataTransitions.ts
55
+ var STEP_TOLERANCE = 0.01;
56
+ var MAX_SAME_ASSET_CLOSE_RATIO = 1.25;
57
+ var MAX_END_DRIFT_STEPS = 3;
58
+ var MAX_STREAM_ADVANCE_STEPS = 5;
59
+ function inferStepMs(candles) {
60
+ if (candles.length < 2) return null;
61
+ const k = Math.min(candles.length - 1, 8);
62
+ const diffs = [];
63
+ for (let i = 0; i < k; i++) diffs.push(candles[i + 1].timeMs - candles[i].timeMs);
64
+ diffs.sort((a, b) => a - b);
65
+ const median = diffs[Math.floor(diffs.length / 2)];
66
+ return median > 0 ? median : null;
67
+ }
68
+ function indexByTime(candles, t) {
69
+ let lo = 0;
70
+ let hi = candles.length - 1;
71
+ while (lo <= hi) {
72
+ const mid = lo + hi >>> 1;
73
+ const v = candles[mid].timeMs;
74
+ if (v === t) return mid;
75
+ if (v < t) lo = mid + 1;
76
+ else hi = mid - 1;
77
+ }
78
+ return -1;
79
+ }
80
+ function classifyTransition(prev, next, seriesKeyChanged) {
81
+ if (!prev || prev.length === 0) return "initial";
82
+ if (next.length === 0) return "stream";
83
+ if (seriesKeyChanged) return "reset";
84
+ const prevStep = inferStepMs(prev);
85
+ const nextStep = inferStepMs(next);
86
+ if (prevStep == null || nextStep == null) return "reset";
87
+ const prevLast = prev[prev.length - 1];
88
+ const nextLast = next[next.length - 1];
89
+ if (Math.abs(nextStep - prevStep) <= prevStep * STEP_TOLERANCE) {
90
+ const idx = indexByTime(next, prevLast.timeMs);
91
+ const aligned = idx >= 0;
92
+ const sharedBarRatio = aligned && next[idx].close > 0 && prevLast.close > 0 ? Math.max(next[idx].close / prevLast.close, prevLast.close / next[idx].close) : Infinity;
93
+ const advanced = nextLast.timeMs >= prevLast.timeMs && nextLast.timeMs - prevLast.timeMs <= MAX_STREAM_ADVANCE_STEPS * nextStep;
94
+ return sharedBarRatio <= MAX_SAME_ASSET_CLOSE_RATIO && advanced ? "stream" : "reset";
95
+ }
96
+ const closeRatio = prevLast.close > 0 && nextLast.close > 0 ? Math.max(nextLast.close / prevLast.close, prevLast.close / nextLast.close) : Infinity;
97
+ const prevEnd = prevLast.timeMs + prevStep;
98
+ const nextEnd = nextLast.timeMs + nextStep;
99
+ const endsTogether = Math.abs(nextEnd - prevEnd) <= MAX_END_DRIFT_STEPS * Math.max(prevStep, nextStep);
100
+ return closeRatio <= MAX_SAME_ASSET_CLOSE_RATIO && endsTogether ? "timeframe" : "reset";
101
+ }
102
+ function timeframeWindow(oldWindow, oldStepMs, oldLastMs, newStepMs, newLastMs) {
103
+ const slots = (oldWindow.endMs - oldWindow.startMs) / oldStepMs;
104
+ const offsetRaw = (oldWindow.endMs - oldLastMs) / oldStepMs;
105
+ const offsetSlots = Math.min(Math.max(offsetRaw, 0), slots * 0.75);
106
+ const endMs = Math.round(newLastMs + offsetSlots * newStepMs);
107
+ return { startMs: Math.round(endMs - slots * newStepMs), endMs };
108
+ }
109
+
110
+ // src/easing.ts
111
+ function ease(kind, p) {
112
+ switch (kind) {
113
+ case "linear":
114
+ return p;
115
+ case "ease-in":
116
+ return p * p;
117
+ case "ease-out":
118
+ return p * (2 - p);
119
+ default:
120
+ return p * p * (3 - 2 * p);
121
+ }
122
+ }
123
+ var EASINGS = [
124
+ "linear",
125
+ "ease-in",
126
+ "ease-out",
127
+ "ease-in-out"
128
+ ];
129
+ function easingIndex(kind) {
130
+ const i = kind ? EASINGS.indexOf(kind) : -1;
131
+ return i < 0 ? EASINGS.indexOf("ease-in-out") : i;
132
+ }
133
+
51
134
  // src/packCandles.ts
52
135
  var BYTES_PER_CANDLE = 48;
53
136
  function packCandles(candles) {
@@ -282,15 +365,53 @@ function ensureInstalled() {
282
365
  }
283
366
  installed = true;
284
367
  }
285
- function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, volume, priceLines) {
368
+ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, volume, priceLines, transition) {
286
369
  const handleRef = (0, import_react.useRef)(null);
287
370
  const defaultWidthAppliedRef = (0, import_react.useRef)(false);
288
371
  const volumeCollapseRef = (0, import_react.useRef)(null);
372
+ const prevDataRef = (0, import_react.useRef)(null);
373
+ const intervalMorphRaf = (0, import_react.useRef)(null);
289
374
  const [picture, setPicture] = (0, import_react.useState)(null);
290
375
  if (!handleRef.current && size.width > 0 && size.height > 0) {
291
376
  ensureInstalled();
292
377
  handleRef.current = globalThis.VroomChartJSI.create();
293
378
  }
379
+ const animRef = (0, import_react.useRef)({ ms: 300, easing: void 0, reduceMotion: false });
380
+ animRef.current = {
381
+ ms: Math.max(0, transition?.transitionMs ?? 300),
382
+ easing: transition?.transitionEasing,
383
+ reduceMotion: transition?.reduceMotion ?? false
384
+ };
385
+ const onFrameRef = (0, import_react.useRef)(transition?.onFrame);
386
+ onFrameRef.current = transition?.onFrame;
387
+ const seriesKey = transition?.seriesKey;
388
+ const endIntervalMorph = (0, import_react.useCallback)(() => {
389
+ if (intervalMorphRaf.current != null) {
390
+ cancelAnimationFrame(intervalMorphRaf.current);
391
+ intervalMorphRaf.current = null;
392
+ }
393
+ handleRef.current?.setIntervalMorph(1);
394
+ }, []);
395
+ const startIntervalMorph = (0, import_react.useCallback)((h) => {
396
+ const { ms, easing } = animRef.current;
397
+ const start = performance.now();
398
+ const step = (now) => {
399
+ const p = Math.min(1, (now - start) / ms);
400
+ h.setIntervalMorph(p < 1 ? ease(easing, p) : 1);
401
+ const pic = h.render();
402
+ if (pic) onFrameRef.current?.(pic);
403
+ intervalMorphRaf.current = p < 1 ? requestAnimationFrame(step) : null;
404
+ };
405
+ intervalMorphRaf.current = requestAnimationFrame(step);
406
+ }, []);
407
+ (0, import_react.useEffect)(() => {
408
+ return () => {
409
+ if (intervalMorphRaf.current != null) {
410
+ cancelAnimationFrame(intervalMorphRaf.current);
411
+ intervalMorphRaf.current = null;
412
+ }
413
+ };
414
+ }, []);
294
415
  const explicit = visibleRange != null;
295
416
  const startMs = visibleRange?.startMs ?? 0;
296
417
  const endMs = visibleRange?.endMs ?? 0;
@@ -310,8 +431,54 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
310
431
  h.setDefaultCandleWidth(defaultCandleWidth);
311
432
  defaultWidthAppliedRef.current = true;
312
433
  }
434
+ let morphing = false;
313
435
  if (candles.length > 0) {
314
- h.setCandles(packCandles(candles));
436
+ const prev = prevDataRef.current;
437
+ const freshHandle = prev == null || prev.handle !== h;
438
+ if (freshHandle || prev.candles !== candles || prev.seriesKey !== seriesKey) {
439
+ const transitionKind = freshHandle ? "initial" : explicit ? "stream" : classifyTransition(prev.candles, candles, seriesKey !== prev.seriesKey);
440
+ let tfArgs = null;
441
+ let prevEnvelope = null;
442
+ if (transitionKind === "timeframe" && prev != null) {
443
+ const oldWindow = h.getVisibleRange();
444
+ const oldStepMs = inferStepMs(prev.candles);
445
+ if (oldWindow.endMs > oldWindow.startMs && oldStepMs != null) {
446
+ tfArgs = {
447
+ oldWindow,
448
+ oldStepMs,
449
+ oldLastMs: prev.candles[prev.candles.length - 1].timeMs
450
+ };
451
+ }
452
+ prevEnvelope = h.getVisiblePriceEnvelope();
453
+ morphing = animRef.current.ms > 0 && !animRef.current.reduceMotion && onFrameRef.current != null;
454
+ if (morphing) {
455
+ endIntervalMorph();
456
+ h.beginIntervalMorph();
457
+ }
458
+ } else if (transitionKind === "initial" || transitionKind === "reset") {
459
+ endIntervalMorph();
460
+ }
461
+ h.setCandles(packCandles(candles));
462
+ if (transitionKind === "timeframe") {
463
+ const newStepMs = inferStepMs(candles);
464
+ if (tfArgs && newStepMs != null) {
465
+ const w = timeframeWindow(
466
+ tfArgs.oldWindow,
467
+ tfArgs.oldStepMs,
468
+ tfArgs.oldLastMs,
469
+ newStepMs,
470
+ candles[candles.length - 1].timeMs
471
+ );
472
+ h.setVisibleRange(w.startMs, w.endMs);
473
+ }
474
+ if (prevEnvelope) h.preservePriceEnvelope(prevEnvelope.low, prevEnvelope.high);
475
+ else h.resetPriceScale();
476
+ if (morphing) startIntervalMorph(h);
477
+ } else if (transitionKind === "reset") {
478
+ h.resetView();
479
+ }
480
+ prevDataRef.current = { handle: h, candles, seriesKey };
481
+ }
315
482
  }
316
483
  if (explicit) {
317
484
  h.setVisibleRange(startMs, endMs);
@@ -330,39 +497,16 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
330
497
  h.setPriceLines(
331
498
  priceLines?.lines.length ? priceLinesToSpec(priceLines) : EMPTY_PRICE_LINES
332
499
  );
333
- setPicture(h.render());
334
- }, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, volumeKey, priceLinesKey]);
500
+ if (!morphing) setPicture(h.render());
501
+ }, [candles, seriesKey, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, volumeKey, priceLinesKey, startIntervalMorph, endIntervalMorph]);
335
502
  return { handle: handleRef.current, picture, volumeCollapseRef };
336
503
  }
337
504
 
338
- // src/easing.ts
339
- function ease(kind, p) {
340
- switch (kind) {
341
- case "linear":
342
- return p;
343
- case "ease-in":
344
- return p * p;
345
- case "ease-out":
346
- return p * (2 - p);
347
- default:
348
- return p * p * (3 - 2 * p);
349
- }
350
- }
351
- var EASINGS = [
352
- "linear",
353
- "ease-in",
354
- "ease-out",
355
- "ease-in-out"
356
- ];
357
- function easingIndex(kind) {
358
- const i = kind ? EASINGS.indexOf(kind) : -1;
359
- return i < 0 ? EASINGS.indexOf("ease-in-out") : i;
360
- }
361
-
362
505
  // src/VroomChart.tsx
363
506
  function VroomChart(props) {
364
507
  const {
365
508
  candles,
509
+ seriesKey,
366
510
  width: widthProp,
367
511
  height: heightProp,
368
512
  style,
@@ -405,6 +549,19 @@ function VroomChart(props) {
405
549
  } : void 0,
406
550
  [priceLines, priceLinesStyle, onPriceLineClose]
407
551
  );
552
+ const emptyPicture = (0, import_react2.useMemo)(() => {
553
+ const rec = import_react_native_skia.Skia.PictureRecorder();
554
+ rec.beginRecording(import_react_native_skia.Skia.XYWHRect(0, 0, 1, 1));
555
+ return rec.finishRecordingAsPicture();
556
+ }, []);
557
+ const pictureSV = (0, import_react_native_reanimated.useSharedValue)(emptyPicture);
558
+ const reduceMotion = (0, import_react_native_reanimated.useReducedMotion)();
559
+ const onFrame = (0, import_react2.useCallback)(
560
+ (p) => {
561
+ pictureSV.value = p;
562
+ },
563
+ [pictureSV]
564
+ );
408
565
  const { handle, picture, volumeCollapseRef } = useChartCore(
409
566
  candles,
410
567
  { width, height },
@@ -418,14 +575,9 @@ function VroomChart(props) {
418
575
  vwap,
419
576
  bollingerBands,
420
577
  volume,
421
- priceLinesProp
578
+ priceLinesProp,
579
+ { seriesKey, transitionMs, transitionEasing, reduceMotion, onFrame }
422
580
  );
423
- const emptyPicture = (0, import_react2.useMemo)(() => {
424
- const rec = import_react_native_skia.Skia.PictureRecorder();
425
- rec.beginRecording(import_react_native_skia.Skia.XYWHRect(0, 0, 1, 1));
426
- return rec.finishRecordingAsPicture();
427
- }, []);
428
- const pictureSV = (0, import_react_native_reanimated.useSharedValue)(emptyPicture);
429
581
  const crosshairActive = (0, import_react2.useRef)(false);
430
582
  const lastCrosshairTime = (0, import_react2.useRef)(null);
431
583
  (0, import_react2.useEffect)(() => {
@@ -498,7 +650,7 @@ function VroomChart(props) {
498
650
  const prog = Math.min(1, (now - startTs) / dur);
499
651
  const fade = from + (target - from) * ease(easingRef.current, prog);
500
652
  morphFade.current = fade;
501
- handle.setMorph(fade, fade);
653
+ handle.setMorph(reduceMotion ? 0 : fade, fade);
502
654
  const p = handle.render();
503
655
  if (p) pictureSV.value = p;
504
656
  if (prog < 1) {
@@ -518,7 +670,7 @@ function VroomChart(props) {
518
670
  morphRaf.current = null;
519
671
  }
520
672
  };
521
- }, [handle, chartType, transitionMs, pictureSV]);
673
+ }, [handle, chartType, transitionMs, reduceMotion, pictureSV]);
522
674
  const volumeRaf = (0, import_react2.useRef)(null);
523
675
  const volumeHandle = (0, import_react2.useRef)(null);
524
676
  (0, import_react2.useEffect)(() => {
@@ -536,7 +688,7 @@ function VroomChart(props) {
536
688
  volumeRaf.current = null;
537
689
  }
538
690
  const dur = Math.max(0, transitionMs ?? 300);
539
- if (dur === 0) {
691
+ if (dur === 0 || reduceMotion) {
540
692
  volumeCollapseRef.current = { t: target, easing };
541
693
  handle.setVolumeCollapse(target, easing);
542
694
  const p = handle.render();
@@ -563,7 +715,7 @@ function VroomChart(props) {
563
715
  volumeRaf.current = null;
564
716
  }
565
717
  };
566
- }, [handle, volume?.enabled, transitionMs, pictureSV, volumeCollapseRef]);
718
+ }, [handle, volume?.enabled, transitionMs, reduceMotion, pictureSV, volumeCollapseRef]);
567
719
  const hitAxis = (0, import_react2.useCallback)(
568
720
  (x, y) => {
569
721
  if (!handle) return "chart";
@@ -775,6 +927,9 @@ function VroomChart(props) {
775
927
  }
776
928
  // Annotate the CommonJS export names for ESM import in node:
777
929
  0 && (module.exports = {
778
- VroomChart
930
+ VroomChart,
931
+ classifyTransition,
932
+ inferStepMs,
933
+ timeframeWindow
779
934
  });
780
935
  //# sourceMappingURL=index.js.map