react-native-vroom-chart 0.5.0 → 0.6.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.ts CHANGED
@@ -352,6 +352,78 @@ type LiquidityConfig = {
352
352
  * `widthPx` and `widthFrac * paneWidth` is used. */
353
353
  widthFrac?: number;
354
354
  };
355
+ /**
356
+ * A consumer-supplied horizontal status line at a fixed price — the primitive
357
+ * behind resting limit orders, take-profits, stop-losses and liquidation levels.
358
+ *
359
+ * Renders as a line across the price pane ending in a label group (a `text` pill
360
+ * plus an optional solid-filled `quantity` pill and an optional close button),
361
+ * with a price badge in the y-axis strip.
362
+ *
363
+ * Interaction is opt-in and callback-gated, mirroring TradingView: the line is
364
+ * only draggable when `draggable` is set, and the close button only renders when
365
+ * you pass `onPriceLineClose`. Dragging is a *preview* — the chart never mutates
366
+ * the price you gave it, so a move your backend rejects reverts on its own
367
+ * simply by leaving your `priceLines` state unchanged.
368
+ */
369
+ type PriceLine = {
370
+ /** Stable unique id, echoed back by every callback. */
371
+ id: string;
372
+ /** Where the line sits on the price scale. */
373
+ price: number;
374
+ /** Body label — render whatever you like (e.g. `'Limit Buy @ 13.79'`). */
375
+ text?: string;
376
+ /**
377
+ * Trailing segment, drawn as a solid-filled pill with white text so size reads
378
+ * at a glance (e.g. `'x 5.206'`). Omit to hide it.
379
+ */
380
+ quantity?: string;
381
+ /** Line, border, body text and close-icon color. Defaults to a soft red. */
382
+ color?: VroomColor;
383
+ /** Stroke width in px. Default 1. */
384
+ width?: number;
385
+ /** Line style. Default `'dotted'`, matching the current-price indicator. */
386
+ lineStyle?: 'solid' | 'dotted' | 'dashed';
387
+ /**
388
+ * Let the user drag this line vertically to a new price. Default false.
389
+ * Pair with `onPriceLineDragEnd` to commit the move.
390
+ */
391
+ draggable?: boolean;
392
+ /**
393
+ * Show the close button on this line. Defaults to true, but the button only
394
+ * ever renders if you also pass `onPriceLineClose` — set this to false to opt a
395
+ * single line out (e.g. a liquidation level the user can't dismiss).
396
+ */
397
+ closable?: boolean;
398
+ /** Extend the line to the pane's left edge. Default true. */
399
+ extendLeft?: boolean;
400
+ /** Show the price badge in the y-axis strip. Default true. */
401
+ axisLabel?: boolean;
402
+ };
403
+ /** Shared layout/style for every price line, passed via `priceLinesStyle`. */
404
+ type PriceLinesStyle = {
405
+ /**
406
+ * Translucent fill behind the body and close-button pills, so the label reads
407
+ * over candles without hiding them. Defaults to a dark translucent grey.
408
+ */
409
+ bodyBackground?: VroomColor;
410
+ /** Label font size in px. Defaults to the axis font size. */
411
+ fontSize?: number;
412
+ /**
413
+ * How far in from the price axis the label group sits, as a fraction of pane
414
+ * width (0 = flush against the axis, 0.5 = at the pane's midpoint). Only
415
+ * applies when `align` is `'right'`. Default 0.
416
+ */
417
+ inset?: number;
418
+ /** Where the label group sits horizontally. Default `'right'`. */
419
+ align?: 'left' | 'center' | 'right';
420
+ /**
421
+ * How much the hovered line or close button brightens, as a channel
422
+ * multiplier. 1 disables the highlight. Default 1.25. Web only — touch
423
+ * platforms have no hover state.
424
+ */
425
+ hoverBoost?: number;
426
+ };
355
427
  /** MACD indicator config. Rendered in its own pane below the candles. */
356
428
  type MACDConfig = {
357
429
  enabled?: boolean;
@@ -420,6 +492,37 @@ type VroomChartCoreProps = {
420
492
  bollingerBands?: BollingerBandsConfig;
421
493
  /** Resting-order / order-book liquidity bands drawn behind the candles. */
422
494
  liquidity?: LiquidityConfig;
495
+ /**
496
+ * Horizontal status lines at consumer-supplied prices (resting orders, TP/SL,
497
+ * liquidation levels), each with a text label and an optional close button.
498
+ *
499
+ * This is a controlled prop: the chart renders exactly what you pass and never
500
+ * mutates it. A drag paints a live preview and reports the new price through
501
+ * `onPriceLineDragEnd`; the line only actually moves once you update this
502
+ * array, so a rejected move needs no explicit rollback.
503
+ */
504
+ priceLines?: PriceLine[];
505
+ /** Shared layout/style for every entry in `priceLines`. */
506
+ priceLinesStyle?: PriceLinesStyle;
507
+ /**
508
+ * Fired continuously while a draggable price line is being dragged, with the
509
+ * price under the pointer. Use it for a live readout (e.g. an order ticket);
510
+ * wait for `onPriceLineDragEnd` to commit.
511
+ */
512
+ onPriceLineDrag?: (id: string, price: number) => void;
513
+ /**
514
+ * Fired once when the user drops a dragged price line. Submit the new price to
515
+ * your backend here, then update `priceLines` on success — the line snaps back
516
+ * on its own if you don't. Dragging is cancelled (and this never fires) if the
517
+ * user presses Escape.
518
+ */
519
+ onPriceLineDragEnd?: (id: string, price: number) => void;
520
+ /**
521
+ * Fired when the user activates a price line's close button. Passing this
522
+ * handler is what makes the button render at all; individual lines opt out with
523
+ * `closable: false`.
524
+ */
525
+ onPriceLineClose?: (id: string) => void;
423
526
  /**
424
527
  * Pixels the crosshair dot / horizontal line sit *above* the touch point so
425
528
  * they aren't hidden under the thumb. The vertical line stays centered on the
@@ -547,4 +650,4 @@ declare global {
547
650
  */
548
651
  declare function VroomChart(props: VroomChartProps): React.JSX.Element;
549
652
 
550
- export { type BollingerBandsConfig, type Candle, type ChartType, type CrosshairEvent, type MACDConfig, type MASource, type MovingAverageOverlay, type RSIConfig, type VWAPConfig, type VisibleRange, VroomChart, type VroomChartProps, type VroomColor, type VroomTheme };
653
+ export { type BollingerBandsConfig, type Candle, type ChartType, type CrosshairEvent, type MACDConfig, type MASource, type MovingAverageOverlay, type PriceLine, type PriceLinesStyle, type RSIConfig, type VWAPConfig, type VisibleRange, VroomChart, type VroomChartProps, type VroomColor, type VroomTheme };
package/lib/index.js CHANGED
@@ -181,6 +181,33 @@ function bollingerToSpec(cfg) {
181
181
  fillOpacity: cfg?.fillOpacity ?? 0.1
182
182
  };
183
183
  }
184
+ var DEFAULT_PRICE_LINE_COLOR = 4293874512;
185
+ var DEFAULT_PRICE_LINE_BODY_BG = 3642499368;
186
+ var DEFAULT_PRICE_LINE_HOVER_BOOST = 1.25;
187
+ var LINE_STYLES = { solid: 0, dotted: 1, dashed: 2 };
188
+ var PRICE_LINE_DRAGGABLE = 1 << 0;
189
+ var PRICE_LINE_CLOSABLE = 1 << 1;
190
+ var PRICE_LINE_AXIS_LABEL = 1 << 2;
191
+ var PRICE_LINE_EXTEND_LEFT = 1 << 3;
192
+ function priceLinesToSpec(cfg) {
193
+ return {
194
+ lines: cfg.lines.map((l) => ({
195
+ price: l.price,
196
+ color: (l.color != null ? parseColor(l.color) : null) ?? DEFAULT_PRICE_LINE_COLOR,
197
+ width: l.width ?? 1,
198
+ lineStyle: LINE_STYLES[l.lineStyle ?? "dotted"],
199
+ text: l.text ?? "",
200
+ quantity: l.quantity ?? "",
201
+ flags: (l.draggable ? PRICE_LINE_DRAGGABLE : 0) | (cfg.hasCloseHandler && l.closable !== false ? PRICE_LINE_CLOSABLE : 0) | (l.axisLabel !== false ? PRICE_LINE_AXIS_LABEL : 0) | (l.extendLeft !== false ? PRICE_LINE_EXTEND_LEFT : 0)
202
+ })),
203
+ bodyBg: (cfg.style?.bodyBackground != null ? parseColor(cfg.style.bodyBackground) : null) ?? DEFAULT_PRICE_LINE_BODY_BG,
204
+ fontSizePx: cfg.style?.fontSize ?? 0,
205
+ lineLengthFrac: cfg.style?.inset ?? 0,
206
+ align: cfg.style?.align === "left" ? 0 : cfg.style?.align === "center" ? 1 : 2,
207
+ hoverBoost: cfg.style?.hoverBoost ?? DEFAULT_PRICE_LINE_HOVER_BOOST
208
+ };
209
+ }
210
+ var EMPTY_PRICE_LINES = priceLinesToSpec({ lines: [], hasCloseHandler: false });
184
211
  var installed = false;
185
212
  function ensureInstalled() {
186
213
  if (installed) return;
@@ -191,7 +218,7 @@ function ensureInstalled() {
191
218
  }
192
219
  installed = true;
193
220
  }
194
- function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands) {
221
+ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType, theme, rsi, macd, movingAverages, vwap, bollingerBands, priceLines) {
195
222
  const handleRef = (0, import_react.useRef)(null);
196
223
  const defaultWidthAppliedRef = (0, import_react.useRef)(false);
197
224
  const [picture, setPicture] = (0, import_react.useState)(null);
@@ -208,6 +235,7 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
208
235
  const maKey = movingAverages ? JSON.stringify(movingAverages) : "";
209
236
  const vwapKey = vwap ? JSON.stringify(vwap) : "";
210
237
  const bollingerKey = bollingerBands ? JSON.stringify(bollingerBands) : "";
238
+ const priceLinesKey = priceLines ? JSON.stringify(priceLines) : "";
211
239
  (0, import_react.useEffect)(() => {
212
240
  const h = handleRef.current;
213
241
  if (!h) return;
@@ -247,8 +275,11 @@ function useChartCore(candles, size, visibleRange, defaultCandleWidth, chartType
247
275
  vwap?.width ?? 1.5
248
276
  );
249
277
  h.setBollinger(bollingerToSpec(bollingerBands));
278
+ h.setPriceLines(
279
+ priceLines?.lines.length ? priceLinesToSpec(priceLines) : EMPTY_PRICE_LINES
280
+ );
250
281
  setPicture(h.render());
251
- }, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey]);
282
+ }, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, priceLinesKey]);
252
283
  return { handle: handleRef.current, picture };
253
284
  }
254
285
 
@@ -271,7 +302,12 @@ function VroomChart(props) {
271
302
  bollingerBands,
272
303
  crosshairOffset = 40,
273
304
  onCrosshair,
274
- onViewportChange
305
+ onViewportChange,
306
+ priceLines,
307
+ priceLinesStyle,
308
+ onPriceLineDrag,
309
+ onPriceLineDragEnd,
310
+ onPriceLineClose
275
311
  } = props;
276
312
  const [measured, setMeasured] = (0, import_react2.useState)({ width: 0, height: 0 });
277
313
  const width = widthProp ?? measured.width;
@@ -283,6 +319,14 @@ function VroomChart(props) {
283
319
  (prev) => prev.width === w && prev.height === h ? prev : { width: w, height: h }
284
320
  );
285
321
  }, []);
322
+ const priceLinesProp = (0, import_react2.useMemo)(
323
+ () => priceLines ? {
324
+ lines: priceLines,
325
+ style: priceLinesStyle,
326
+ hasCloseHandler: onPriceLineClose != null
327
+ } : void 0,
328
+ [priceLines, priceLinesStyle, onPriceLineClose]
329
+ );
286
330
  const { handle, picture } = useChartCore(
287
331
  candles,
288
332
  { width, height },
@@ -294,7 +338,8 @@ function VroomChart(props) {
294
338
  macd,
295
339
  movingAverages,
296
340
  vwap,
297
- bollingerBands
341
+ bollingerBands,
342
+ priceLinesProp
298
343
  );
299
344
  const emptyPicture = (0, import_react2.useMemo)(() => {
300
345
  const rec = import_react_native_skia.Skia.PictureRecorder();
@@ -407,12 +452,33 @@ function VroomChart(props) {
407
452
  },
408
453
  [handle, width, height]
409
454
  );
410
- const panMode = (0, import_react2.useRef)(
411
- "chart"
455
+ const hitPriceLine = (0, import_react2.useCallback)(
456
+ (x, y) => {
457
+ if (!handle || !priceLines?.length) return null;
458
+ const hit = handle.hitTestPriceLine(x, y);
459
+ const line = hit ? priceLines[hit.index] : void 0;
460
+ return hit && line ? { index: hit.index, part: hit.part, line } : null;
461
+ },
462
+ [handle, priceLines]
463
+ );
464
+ const priceDrag = (0, import_react2.useRef)(
465
+ null
412
466
  );
467
+ const panMode = (0, import_react2.useRef)("chart");
413
468
  const pan = import_react_native_gesture_handler.Gesture.Pan().runOnJS(true).maxPointers(1).onStart((e) => {
414
469
  cancelDecay();
415
470
  panMode.current = hitAxis(e.x, e.y);
471
+ priceDrag.current = null;
472
+ if (handle && panMode.current === "chart" && !crosshairActive.current) {
473
+ const pl = hitPriceLine(e.x, e.y);
474
+ if (pl && pl.part === 0) {
475
+ panMode.current = "price-line";
476
+ priceDrag.current = { index: pl.index, id: pl.line.id, price: pl.line.price };
477
+ handle.setPriceLineDrag(pl.index, pl.line.price);
478
+ const p = handle.render();
479
+ if (p) pictureSV.value = p;
480
+ }
481
+ }
416
482
  }).onChange((e) => {
417
483
  if (!handle) return;
418
484
  let next = null;
@@ -422,6 +488,15 @@ function VroomChart(props) {
422
488
  next = handle.scaleTimeAxis(e.changeX);
423
489
  } else if (panMode.current === "indicator") {
424
490
  next = handle.pan(e.changeX, 0);
491
+ } else if (panMode.current === "price-line") {
492
+ const g = priceDrag.current;
493
+ if (!g) return;
494
+ const c = handle.coordAt(e.x, e.y);
495
+ if (!c) return;
496
+ g.price = c.price;
497
+ handle.setPriceLineDrag(g.index, c.price);
498
+ onPriceLineDrag?.(g.id, c.price);
499
+ next = handle.render();
425
500
  } else if (crosshairActive.current) {
426
501
  const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
427
502
  if (ch) pictureSV.value = ch;
@@ -439,6 +514,15 @@ function VroomChart(props) {
439
514
  maybeStartAnim();
440
515
  }).onEnd((e) => {
441
516
  if (!handle) return;
517
+ if (panMode.current === "price-line") {
518
+ const g = priceDrag.current;
519
+ priceDrag.current = null;
520
+ handle.setPriceLineDrag(-1, 0);
521
+ const p = handle.render();
522
+ if (p) pictureSV.value = p;
523
+ if (g) onPriceLineDragEnd?.(g.id, g.price);
524
+ return;
525
+ }
442
526
  if (panMode.current === "chart" && crosshairActive.current) return;
443
527
  onViewportChange?.(0, 0);
444
528
  if (panMode.current !== "chart" && panMode.current !== "indicator") return;
@@ -515,6 +599,7 @@ function VroomChart(props) {
515
599
  const longPress = import_react_native_gesture_handler.Gesture.LongPress().runOnJS(true).onStart((e) => {
516
600
  if (!handle) return;
517
601
  if (hitAxis(e.x, e.y) !== "chart") return;
602
+ if (hitPriceLine(e.x, e.y)) return;
518
603
  cancelDecay();
519
604
  crosshairActive.current = true;
520
605
  const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);
@@ -531,7 +616,13 @@ function VroomChart(props) {
531
616
  });
532
617
  });
533
618
  const tap = import_react_native_gesture_handler.Gesture.Tap().runOnJS(true).onStart((e) => {
534
- if (!handle || !crosshairActive.current) return;
619
+ if (!handle) return;
620
+ const pl = hitPriceLine(e.x, e.y);
621
+ if (pl && pl.part === 1) {
622
+ onPriceLineClose?.(pl.line.id);
623
+ return;
624
+ }
625
+ if (!crosshairActive.current) return;
535
626
  if (hitAxis(e.x, e.y) !== "chart") return;
536
627
  crosshairActive.current = false;
537
628
  const ch = handle.clearCrosshair();
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/VroomChart.tsx","../src/useChartCore.ts","../src/NativeVroomChart.ts","../src/packCandles.ts","../src/theme.ts"],"sourcesContent":["export { VroomChart } from './VroomChart';\nexport type {\n VroomChartProps,\n Candle,\n CrosshairEvent,\n VroomTheme,\n VroomColor,\n VisibleRange,\n RSIConfig,\n MACDConfig,\n MASource,\n MovingAverageOverlay,\n VWAPConfig,\n BollingerBandsConfig,\n ChartType,\n} from './types';\n","// VroomChart — Phase 3.\n//\n// Owns a SharedValue<SkPicture> driven by:\n// - useChartCore's \"initial\" picture (when data/size/range change), AND\n// - Pan gesture callbacks that call handle.pan(dx, dy) → fresh picture.\n//\n// Reanimated 4 + RN-Skia 2 propagate SharedValue<SkPicture> changes to\n// <Picture> without a React re-render, so gesture-driven redraws are cheap.\n//\n// Gestures run on the JS thread for now (`runOnJS(true)`) — installing the\n// JSI bindings on the worklet runtime is a later perf optimization.\n\nimport React, { useEffect, useRef, useCallback, useState, useMemo } from 'react';\nimport { View, type LayoutChangeEvent } from 'react-native';\nimport { Canvas, Picture, Skia, type SkPicture } from '@shopify/react-native-skia';\nimport {\n Gesture,\n GestureDetector,\n GestureHandlerRootView,\n} from 'react-native-gesture-handler';\nimport { useSharedValue } from 'react-native-reanimated';\n\nimport { useChartCore } from './useChartCore';\nimport type { VroomChartProps } from './types';\nimport './jsi.d';\n\n/**\n * Skia-rendered candlestick chart. Pass OHLCV `candles` and size it via `style`\n * (it fills its parent by default). Pan to scroll, pinch to zoom, drag the\n * price/time axes to rescale, and long-press for the crosshair. Optional\n * indicators (`rsi`, `macd`, `movingAverages`, `vwap`), colors (`theme`), and\n * events (`onCrosshair`, `onViewportChange`) are configured through props.\n *\n * @see {@link VroomChartProps} for the full prop reference.\n */\nexport function VroomChart(props: VroomChartProps) {\n const {\n candles,\n width: widthProp,\n height: heightProp,\n style,\n visibleRange,\n defaultCandleWidth,\n chartType,\n transitionMs,\n theme,\n rsi,\n macd,\n movingAverages,\n vwap,\n bollingerBands,\n crosshairOffset = 40,\n onCrosshair,\n onViewportChange,\n } = props;\n\n // Fill the parent by default: measure via onLayout. Explicit width/height\n // props (if given) win per-axis. Until the first layout, dims are 0 and we\n // render nothing (one frame).\n const [measured, setMeasured] = useState({ width: 0, height: 0 });\n const width = widthProp ?? measured.width;\n const height = heightProp ?? measured.height;\n\n const onLayout = useCallback((e: LayoutChangeEvent) => {\n const w = Math.round(e.nativeEvent.layout.width);\n const h = Math.round(e.nativeEvent.layout.height);\n setMeasured((prev) =>\n prev.width === w && prev.height === h ? prev : { width: w, height: h },\n );\n }, []);\n\n const { handle, picture } = useChartCore(\n candles,\n { width, height },\n visibleRange,\n defaultCandleWidth,\n chartType,\n theme,\n rsi,\n macd,\n movingAverages,\n vwap,\n bollingerBands,\n );\n\n // RN-Skia's recorder reads this SharedValue on the UI/render runtime, a beat\n // behind JS-thread writes. If it ever reads null it throws (\"Invalid prop\n // value for SkTextBlob received\" — RN-Skia's mislabeled SkPicture error), so\n // we seed it with an empty picture and *never* assign null into it.\n const emptyPicture = useMemo(() => {\n const rec = Skia.PictureRecorder();\n rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1));\n return rec.finishRecordingAsPicture();\n }, []);\n const pictureSV = useSharedValue<SkPicture>(emptyPicture);\n\n // When the crosshair is showing, pan moves it (instead of scrolling) and\n // pinch is disabled. A ref (not state) so gesture callbacks read it\n // synchronously without re-subscribing. Tap dismisses it.\n const crosshairActive = useRef(false);\n\n // timeMs of the candle last reported through onCrosshair, so a drag fires a\n // 'move' event only when it crosses into a *different* candle (one per\n // candle, not per frame). Null while the crosshair is hidden.\n const lastCrosshairTime = useRef<number | null>(null);\n\n // Sync the initial picture from useChartCore into the SV whenever it\n // refreshes (data load, size change, externally-controlled range change).\n // Only ever assign a non-null picture (see emptyPicture note above).\n useEffect(() => {\n if (picture) pictureSV.value = picture;\n }, [picture, pictureSV]);\n\n // Momentum scroll. After Pan ends with non-trivial velocity, we run a RAF\n // loop that calls handle.pan(dx, 0) each frame with an exponentially\n // decaying velocity. A new pan (or unmount) cancels the loop.\n const decayRaf = useRef<number | null>(null);\n const cancelDecay = useCallback(() => {\n if (decayRaf.current != null) {\n cancelAnimationFrame(decayRaf.current);\n decayRaf.current = null;\n }\n }, []);\n useEffect(() => cancelDecay, [cancelDecay]);\n\n // Axis-label fade animation loop. When a gesture changes which labels are\n // active, the C++ side starts ramping their opacities. We keep calling\n // render() on every frame until handle.isAnimating() returns false. The\n // loop is started by gesture callbacks (and the momentum tick) after they\n // update the picture, and self-stops when fades settle.\n const animRaf = useRef<number | null>(null);\n const animTick = useCallback(() => {\n animRaf.current = null;\n if (!handle) return;\n const next = handle.render();\n if (next) pictureSV.value = next;\n if (handle.isAnimating()) {\n animRaf.current = requestAnimationFrame(animTick);\n }\n }, [handle, pictureSV]);\n const maybeStartAnim = useCallback(() => {\n if (animRaf.current != null) return;\n if (!handle?.isAnimating()) return;\n animRaf.current = requestAnimationFrame(animTick);\n }, [handle, animTick]);\n useEffect(() => {\n return () => {\n if (animRaf.current != null) {\n cancelAnimationFrame(animRaf.current);\n animRaf.current = null;\n }\n };\n }, []);\n\n // Candle↔line morph. When `chartType` changes we drive the core per-frame with\n // a (collapse, fade) blend and push a fresh picture into the SV each frame — the\n // JS side owns the eased clock (see plan). A fresh handle snaps to the target;\n // transitionMs=0 snaps. Mirrors the web driver in react/src/useChartCore.ts.\n const morphRaf = useRef<number | null>(null);\n const morphFade = useRef<number | null>(null);\n const morphHandle = useRef<typeof handle>(null);\n useEffect(() => {\n if (!handle) return undefined;\n const target = chartType === 'line' ? 1 : 0;\n\n // Fresh handle (first load / recreate): snap, don't animate.\n if (morphHandle.current !== handle || morphFade.current == null) {\n morphHandle.current = handle;\n morphFade.current = target;\n handle.setChartType(target);\n const p = handle.render();\n if (p) pictureSV.value = p;\n return undefined;\n }\n if (morphFade.current === target) return undefined;\n\n if (morphRaf.current != null) {\n cancelAnimationFrame(morphRaf.current);\n morphRaf.current = null;\n }\n const dur = Math.max(0, transitionMs ?? 300);\n if (dur === 0) {\n morphFade.current = target;\n handle.setChartType(target);\n const p = handle.render();\n if (p) pictureSV.value = p;\n return undefined;\n }\n\n const from = morphFade.current;\n let startTs: number | null = null;\n const step = (now: number) => {\n if (startTs == null) startTs = now;\n const prog = Math.min(1, (now - startTs) / dur);\n const e = prog * prog * (3 - 2 * prog); // smoothstep ease-in-out\n const fade = from + (target - from) * e;\n morphFade.current = fade;\n handle.setMorph(fade, fade);\n const p = handle.render();\n if (p) pictureSV.value = p;\n if (prog < 1) {\n morphRaf.current = requestAnimationFrame(step);\n } else {\n morphRaf.current = null;\n morphFade.current = target;\n handle.setChartType(target); // lock the exact endpoint\n const q = handle.render();\n if (q) pictureSV.value = q;\n }\n };\n morphRaf.current = requestAnimationFrame(step);\n\n return () => {\n if (morphRaf.current != null) {\n cancelAnimationFrame(morphRaf.current);\n morphRaf.current = null;\n }\n };\n }, [handle, chartType, transitionMs, pictureSV]);\n\n // Classifies a touch point into the candle area vs. an axis strip. Axis\n // strips always own their gesture (scale price/time) and take priority over\n // the crosshair: an axis touch never opens, moves, or dismisses it.\n const hitAxis = useCallback(\n (x: number, y: number): 'chart' | 'price-axis' | 'time-axis' | 'indicator' => {\n if (!handle) return 'chart';\n const { yAxisWidth, xAxisHeight, indicatorHeight } =\n handle.getAxisMetrics();\n if (x > width - yAxisWidth) return 'price-axis';\n if (y > height - xAxisHeight) return 'time-axis';\n // The indicator pane sits just above the time-axis strip. A drag here\n // scrolls the candles horizontally (no vertical price change).\n if (indicatorHeight > 0 && y > height - xAxisHeight - indicatorHeight) {\n return 'indicator';\n }\n return 'chart';\n },\n [handle, width, height],\n );\n\n // Pan routes to different C++ mutators depending on where it started: the\n // candle area (chart scroll / crosshair move), the y-axis strip (price\n // scale), the x-axis strip (time scale), or the indicator pane (horizontal\n // scroll only). We classify on onStart.\n const panMode = useRef<'chart' | 'price-axis' | 'time-axis' | 'indicator'>(\n 'chart',\n );\n\n const pan = Gesture.Pan()\n .runOnJS(true)\n .maxPointers(1) // don't fight Pinch's two-finger gesture\n .onStart((e) => {\n cancelDecay();\n // Always classify — an axis drag controls the axis even while the\n // crosshair is up. Only a chart-area drag interacts with the crosshair.\n panMode.current = hitAxis(e.x, e.y);\n })\n .onChange((e) => {\n if (!handle) return;\n let next: ReturnType<typeof handle.pan> = null;\n if (panMode.current === 'price-axis') {\n next = handle.scalePriceAxis(e.changeY);\n } else if (panMode.current === 'time-axis') {\n next = handle.scaleTimeAxis(e.changeX);\n } else if (panMode.current === 'indicator') {\n // Drag in an indicator pane scrolls the candles horizontally only —\n // no vertical price slide (the pane's scale is fixed).\n next = handle.pan(e.changeX, 0);\n } else if (crosshairActive.current) {\n // Chart area + crosshair up → the drag moves the crosshair instead of\n // scrolling. Vertical line tracks the finger x; the dot/horizontal line\n // stay lifted `crosshairOffset` px above the fingertip.\n const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);\n if (ch) pictureSV.value = ch;\n // The line follows the finger every frame (above), but only notify the\n // host when the snapped slot actually changes. The slot has a timeMs\n // even in the empty space ahead of the last candle, where candle=null.\n const info = handle.getCrosshairInfo();\n const t = info?.timeMs ?? null;\n if (t !== lastCrosshairTime.current) {\n lastCrosshairTime.current = t;\n // price is web-only for now (see @vroomchart/react); RN reports null.\n onCrosshair?.({ active: true, candle: info?.candle ?? null, timeMs: t, price: null, reason: 'move' });\n }\n return;\n } else {\n // Chart area: 1-finger drag translates both axes. Horizontal\n // component scrolls time, vertical component slides price bounds\n // (axes follow). Diagonal works naturally.\n next = handle.translate(e.changeX, e.changeY);\n }\n if (next) pictureSV.value = next;\n maybeStartAnim();\n })\n .onEnd((e) => {\n if (!handle) return;\n // A chart-area drag with the crosshair up just moved the crosshair —\n // nothing about the viewport changed, and no momentum.\n if (panMode.current === 'chart' && crosshairActive.current) return;\n onViewportChange?.(0, 0);\n\n // Axis drags don't get momentum — they're a precise size adjustment.\n // Chart and indicator-pane drags both get horizontal fling momentum.\n if (panMode.current !== 'chart' && panMode.current !== 'indicator') return;\n\n let velocity = e.velocityX; // px/s\n const MIN_LAUNCH = 80; // ignore tiny flicks\n const MIN_STOP = 8; // px/s — stop threshold\n const HALF_LIFE_S = 0.35; // velocity halves every 0.35s\n if (Math.abs(velocity) < MIN_LAUNCH) return;\n\n let lastTime = performance.now();\n const tick = () => {\n const now = performance.now();\n const dt = (now - lastTime) / 1000;\n lastTime = now;\n\n // Frame-time-independent exponential decay.\n velocity *= Math.pow(0.5, dt / HALF_LIFE_S);\n const dx = velocity * dt;\n const next = handle.pan(dx, 0);\n if (next) pictureSV.value = next;\n maybeStartAnim();\n\n if (Math.abs(velocity) > MIN_STOP) {\n decayRaf.current = requestAnimationFrame(tick);\n } else {\n decayRaf.current = null;\n }\n };\n decayRaf.current = requestAnimationFrame(tick);\n });\n\n // Directional pinch. A single Pinch scale is uniform, so we read the two\n // touch points and track their horizontal/vertical spans independently: a\n // vertical pinch scales price (y), a horizontal pinch scales the time window\n // (x), and a diagonal pinch does both. An axis whose initial span is tiny\n // (fingers ~collinear on that axis) is left alone.\n // Lock the scalable axes at gesture start by orientation: an axis only\n // scales if its initial span is meaningful AND at least AXIS_RATIO of the\n // other axis. This keeps a vertical pinch from ever touching x (and vice\n // versa) — critical because during a vertical pinch the fingers' x-coords\n // drift and cross, sending spanX through ~0 and otherwise exploding frameX.\n const MIN_SPAN = 24; // px — minimum span for an axis to scale at all\n const AXIS_RATIO = 0.5; // axis scales only if its span ≥ this × the other's\n const pinchStart = useRef({\n spanX: 1,\n spanY: 1,\n ratioX: 1,\n ratioY: 1,\n enableX: false,\n enableY: false,\n });\n const pinch = Gesture.Pinch()\n .runOnJS(true)\n .onTouchesDown((e) => {\n if (e.numberOfTouches < 2) return;\n const [a, b] = e.allTouches;\n const spanX = Math.abs(a.x - b.x);\n const spanY = Math.abs(a.y - b.y);\n pinchStart.current = {\n spanX,\n spanY,\n ratioX: 1,\n ratioY: 1,\n enableX: spanX >= MIN_SPAN && spanX >= spanY * AXIS_RATIO,\n enableY: spanY >= MIN_SPAN && spanY >= spanX * AXIS_RATIO,\n };\n })\n .onTouchesMove((e) => {\n if (!handle || crosshairActive.current) return;\n if (e.numberOfTouches < 2) return;\n const [a, b] = e.allTouches;\n const start = pinchStart.current;\n const focalX = (a.x + b.x) * 0.5;\n const focalY = (a.y + b.y) * 0.5;\n\n // Per-frame factor = current cumulative ratio / previous. Floor the\n // current span at MIN_SPAN so a near-zero span (fingers crossing on that\n // axis) can't blow the ratio up.\n let frameX = 1;\n if (start.enableX) {\n const ratioX = Math.max(Math.abs(a.x - b.x), MIN_SPAN) / start.spanX;\n frameX = ratioX / start.ratioX;\n start.ratioX = ratioX;\n }\n let frameY = 1;\n if (start.enableY) {\n const ratioY = Math.max(Math.abs(a.y - b.y), MIN_SPAN) / start.spanY;\n frameY = ratioY / start.ratioY;\n start.ratioY = ratioY;\n }\n if (frameX === 1 && frameY === 1) return;\n\n const next = handle.zoom(frameX, frameY, focalX, focalY);\n if (next) pictureSV.value = next;\n maybeStartAnim();\n });\n\n // Long press shows the crosshair at the press point. A stationary hold never\n // activates `pan` (it needs movement first), so the chart won't scroll under\n // the hold. The dot/horizontal line are lifted above the fingertip.\n const longPress = Gesture.LongPress()\n .runOnJS(true)\n .onStart((e) => {\n if (!handle) return;\n // A long press on an axis strip controls the axis, never the crosshair.\n if (hitAxis(e.x, e.y) !== 'chart') return;\n cancelDecay();\n crosshairActive.current = true;\n const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);\n if (ch) pictureSV.value = ch;\n const info = handle.getCrosshairInfo();\n lastCrosshairTime.current = info?.timeMs ?? null;\n onCrosshair?.({\n active: true,\n candle: info?.candle ?? null,\n timeMs: info?.timeMs ?? null,\n price: null, // web-only for now (see @vroomchart/react)\n reason: 'show',\n });\n });\n\n // A tap dismisses the crosshair while it's up; otherwise it's a no-op (so it\n // never interferes with normal pan/pinch).\n const tap = Gesture.Tap()\n .runOnJS(true)\n .onStart((e) => {\n if (!handle || !crosshairActive.current) return;\n // A tap on an axis strip controls the axis, never dismisses the crosshair.\n if (hitAxis(e.x, e.y) !== 'chart') return;\n crosshairActive.current = false;\n const ch = handle.clearCrosshair();\n if (ch) pictureSV.value = ch;\n lastCrosshairTime.current = null;\n onCrosshair?.({ active: false, candle: null, timeMs: null, price: null, reason: 'hide' });\n });\n\n const gesture = Gesture.Simultaneous(pan, pinch, longPress, tap);\n\n return (\n <GestureHandlerRootView\n onLayout={onLayout}\n style={[\n { width: widthProp, height: heightProp },\n widthProp == null && heightProp == null ? { flex: 1 } : null,\n style,\n ]}\n >\n <GestureDetector gesture={gesture}>\n <View style={{ flex: 1 }}>\n <Canvas style={{ flex: 1 }}>\n {width > 0 && height > 0 ? (\n // pictureSV is always a valid picture (seeded empty, never null),\n // so RN-Skia's UI-thread reader never sees null.\n <Picture picture={pictureSV} />\n ) : null}\n </Canvas>\n </View>\n </GestureDetector>\n </GestureHandlerRootView>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { SkPicture } from '@shopify/react-native-skia';\n\nimport NativeVroomChart from './NativeVroomChart';\nimport type { ChartHandle } from './jsi.d';\nimport { packCandles } from './packCandles';\nimport { applyTheme, parseColor } from './theme';\nimport type {\n BollingerBandsConfig,\n Candle,\n ChartType,\n MACDConfig,\n MovingAverageOverlay,\n RSIConfig,\n VisibleRange,\n VroomTheme,\n VWAPConfig,\n} from './types';\n\n// Mirrors vroom::ma::Source order in packages/core/src/ma.h.\nconst MA_SOURCES = [\n 'close',\n 'open',\n 'high',\n 'low',\n 'hl2',\n 'hlc3',\n 'ohlc4',\n] as const;\n\nfunction overlayToNumeric(o: MovingAverageOverlay) {\n const srcIdx = o.source ? MA_SOURCES.indexOf(o.source) : 0;\n return {\n kind: o.kind === 'ema' ? 1 : 0,\n period: o.length,\n source: srcIdx < 0 ? 0 : srcIdx,\n color: (o.color != null ? parseColor(o.color) : null) ?? 0xff2962ff,\n width: o.width ?? 1.5,\n };\n}\n\n// Bollinger defaults: blue bands / orange basis, matching the repo palette.\nconst DEFAULT_BB_BAND_COLOR = 0xff2962ff;\nconst DEFAULT_BB_BASIS_COLOR = 0xffff6d00;\n\nfunction bollingerToSpec(cfg: BollingerBandsConfig | undefined) {\n const srcIdx = cfg?.source ? MA_SOURCES.indexOf(cfg.source) : 0;\n return {\n enabled: cfg?.enabled ?? false,\n period: cfg?.period ?? 20,\n mult: cfg?.stdDev ?? 2,\n source: srcIdx < 0 ? 0 : srcIdx,\n basisKind: cfg?.basis === 'ema' ? 1 : 0,\n upperColor:\n (cfg?.upperColor != null ? parseColor(cfg.upperColor) : null) ??\n DEFAULT_BB_BAND_COLOR,\n upperWidth: cfg?.upperWidth ?? 1,\n middleColor:\n (cfg?.middleColor != null ? parseColor(cfg.middleColor) : null) ??\n DEFAULT_BB_BASIS_COLOR,\n middleWidth: cfg?.middleWidth ?? 1,\n lowerColor:\n (cfg?.lowerColor != null ? parseColor(cfg.lowerColor) : null) ??\n DEFAULT_BB_BAND_COLOR,\n lowerWidth: cfg?.lowerWidth ?? 1,\n fillEnabled: cfg?.fill ?? true,\n fillOpacity: cfg?.fillOpacity ?? 0.1,\n };\n}\n\nlet installed = false;\nfunction ensureInstalled(): void {\n if (installed) return;\n const ok = NativeVroomChart.install();\n if (!ok) throw new Error('VroomChartModule.install() returned false');\n if (typeof globalThis.VroomChartJSI === 'undefined') {\n throw new Error('global.VroomChartJSI undefined after install()');\n }\n installed = true;\n}\n\nexport type ChartCoreState = {\n handle: ChartHandle | null;\n /** Picture freshly rendered after the latest data/size/range push. */\n picture: SkPicture | null;\n};\n\n// Owns a ChartHandle and produces an \"initial\" picture whenever data, size,\n// or the externally-controlled visible range changes. Gesture-driven updates\n// happen outside this hook by calling handle.pan(...) directly and assigning\n// the result into a SharedValue.\nexport function useChartCore(\n candles: Candle[],\n size: { width: number; height: number; pxRatio?: number },\n visibleRange?: VisibleRange,\n defaultCandleWidth?: number,\n chartType?: ChartType,\n theme?: VroomTheme,\n rsi?: RSIConfig,\n macd?: MACDConfig,\n movingAverages?: MovingAverageOverlay[],\n vwap?: VWAPConfig,\n bollingerBands?: BollingerBandsConfig,\n): ChartCoreState {\n const handleRef = useRef<ChartHandle | null>(null);\n // Push setDefaultCandleWidth only once (first load): setCandles re-runs on\n // every data change, and the core setter re-frames when candles are present,\n // so re-pushing would snap the view away from the user's pan/zoom.\n const defaultWidthAppliedRef = useRef(false);\n const [picture, setPicture] = useState<SkPicture | null>(null);\n\n if (!handleRef.current && size.width > 0 && size.height > 0) {\n ensureInstalled();\n handleRef.current = globalThis.VroomChartJSI!.create();\n }\n\n // When no visibleRange is provided, leave the range entirely to the C++\n // side (which defaults to a sensible recent window on first setCandles).\n // Only push setVisibleRange when the caller is actively controlling it,\n // so it doesn't clobber the default or fight gesture-driven pans.\n const explicit = visibleRange != null;\n const startMs = visibleRange?.startMs ?? 0;\n const endMs = visibleRange?.endMs ?? 0;\n\n // Stable deps so inline `theme={{...}}` / `rsi={{...}}` literals don't re-run\n // the effect every render — only when the actual values change.\n const themeKey = theme ? JSON.stringify(theme) : '';\n const rsiKey = rsi ? JSON.stringify(rsi) : '';\n const macdKey = macd ? JSON.stringify(macd) : '';\n const maKey = movingAverages ? JSON.stringify(movingAverages) : '';\n const vwapKey = vwap ? JSON.stringify(vwap) : '';\n const bollingerKey = bollingerBands ? JSON.stringify(bollingerBands) : '';\n\n useEffect(() => {\n const h = handleRef.current;\n if (!h) return;\n h.setSize(size.width, size.height, size.pxRatio ?? 1);\n // Drive the initial zoom from a target candle width. Pushed once, before the\n // first setCandles (while the core window is still 0/0), and only when the\n // caller isn't explicitly controlling the range.\n if (\n !defaultWidthAppliedRef.current &&\n !explicit &&\n defaultCandleWidth != null &&\n defaultCandleWidth > 0\n ) {\n h.setDefaultCandleWidth(defaultCandleWidth);\n defaultWidthAppliedRef.current = true;\n }\n if (candles.length > 0) {\n h.setCandles(packCandles(candles));\n }\n if (explicit) {\n h.setVisibleRange(startMs, endMs);\n }\n // chartType / the candle↔line morph is driven separately (VroomChart owns the\n // per-frame animation loop so it can update the picture SharedValue directly).\n if (theme) {\n applyTheme(h, theme);\n }\n h.setRSI(\n rsi?.enabled ?? false,\n rsi?.period ?? 14,\n rsi?.upperBand ?? 70,\n rsi?.lowerBand ?? 30,\n rsi?.maEnabled ?? true,\n rsi?.maPeriod ?? 14,\n );\n h.setMACD(\n macd?.enabled ?? false,\n macd?.fast ?? 12,\n macd?.slow ?? 26,\n macd?.signal ?? 9,\n );\n h.setOverlays((movingAverages ?? []).map(overlayToNumeric));\n h.setVWAP(\n vwap?.enabled ?? false,\n vwap?.resetMinutes ?? 0,\n (vwap?.color != null ? parseColor(vwap.color) : null) ?? 0xff00bcd4,\n vwap?.width ?? 1.5,\n );\n h.setBollinger(bollingerToSpec(bollingerBands));\n // TODO(rn-parity): mirror the web `liquidity` overlay here (setLiquidity +\n // the VroomBand structs in the JSI handle) — web-only for now.\n setPicture(h.render());\n // theme/rsi/macd/movingAverages/vwap/bollingerBands are represented by\n // their *Key deps.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey]);\n\n return { handle: handleRef.current, picture };\n}\n","import type { TurboModule } from 'react-native';\nimport { TurboModuleRegistry } from 'react-native';\n\n// TurboModule spec consumed by codegen. The only method is `install`, which\n// the native side uses to install the `global.VroomChartJSI` host object the\n// first time it's called from JS. All real chart operations go through that\n// host object, not through the TurboModule itself.\nexport interface Spec extends TurboModule {\n install(): boolean;\n}\n\nexport default TurboModuleRegistry.getEnforcing<Spec>('VroomChartModule');\n","import type { Candle } from './types';\n\n// Wire format must match `VroomCandle` in packages/core/include/vroom/vroom_chart.h:\n// int64_t time_ms; double open, high, low, close, volume;\n// = 48 bytes per candle, 8-byte aligned, little-endian on iOS/Android.\nexport const BYTES_PER_CANDLE = 48;\n\n// Serializes candles into the packed little-endian buffer the C++ core expects.\n// Pure (no native/Skia deps) so it can be unit-tested in isolation.\nexport function packCandles(candles: Candle[]): ArrayBuffer {\n const buf = new ArrayBuffer(candles.length * BYTES_PER_CANDLE);\n const view = new DataView(buf);\n for (let i = 0; i < candles.length; i++) {\n const c = candles[i]!;\n const off = i * BYTES_PER_CANDLE;\n view.setBigInt64(off, BigInt(c.timeMs), true);\n view.setFloat64(off + 8, c.open, true);\n view.setFloat64(off + 16, c.high, true);\n view.setFloat64(off + 24, c.low, true);\n view.setFloat64(off + 32, c.close, true);\n view.setFloat64(off + 40, c.volume, true);\n }\n return buf;\n}\n","import type { ChartHandle } from './jsi.d';\nimport type { VroomColor, VroomTheme } from './types';\n\n// Maps each color VroomTheme field to its VroomColorKey index in the C++ enum\n// (packages/core/include/vroom/vroom_chart.h). Keep in sync with that enum;\n// new keys are appended there so existing indices never shift.\nexport const COLOR_KEYS: Partial<Record<keyof VroomTheme, number>> = {\n background: 0, // VROOM_COLOR_BACKGROUND\n bull: 1, // VROOM_COLOR_BULL\n bear: 2, // VROOM_COLOR_BEAR\n grid: 4, // VROOM_COLOR_GRID\n axisText: 5, // VROOM_COLOR_AXIS_TEXT\n crosshair: 6, // VROOM_COLOR_CROSSHAIR\n crosshairTarget: 9, // VROOM_COLOR_CROSSHAIR_TARGET\n borderBull: 10, // VROOM_COLOR_BORDER_BULL\n borderBear: 11, // VROOM_COLOR_BORDER_BEAR\n wickBull: 12, // VROOM_COLOR_WICK_BULL\n wickBear: 13, // VROOM_COLOR_WICK_BEAR\n accentBull: 14, // VROOM_COLOR_ACCENT_BULL\n accentBear: 15, // VROOM_COLOR_ACCENT_BEAR\n lineColor: 16, // VROOM_COLOR_LINE\n};\n\n// Maps each numeric VroomTheme field to its VroomFloatKey index.\nexport const FLOAT_KEYS: Partial<Record<keyof VroomTheme, number>> = {\n wickWidth: 1, // VROOM_FLOAT_WICK_WIDTH_PX\n candleRadius: 8, // VROOM_FLOAT_CANDLE_RADIUS_PX\n volumeRadius: 10, // VROOM_FLOAT_VOLUME_RADIUS_PX\n lineWidth: 11, // VROOM_FLOAT_LINE_WIDTH_PX\n};\n\n// Maps each boolean VroomTheme field to its VroomFloatKey index (pushed as 0/1).\nexport const BOOL_KEYS: Partial<Record<keyof VroomTheme, number>> = {\n wickRoundCap: 9, // VROOM_FLOAT_WICK_ROUND_CAP\n};\n\n// Parses a color into a packed 0xAARRGGBB integer (Skia's ARGB order).\n// - number → taken as already-packed ARGB\n// - '#rgb'-style 6-digit hex → opaque (alpha forced to ff)\n// - 8-digit hex → interpreted as AARRGGBB\n// Returns null for anything malformed so the caller can skip it.\nexport function parseColor(value: VroomColor): number | null {\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value >>> 0 : null;\n }\n let s = value.trim();\n if (s.startsWith('#')) s = s.slice(1);\n if (s.length === 6) s = `ff${s}`; // assume opaque\n if (s.length !== 8 || !/^[0-9a-fA-F]{8}$/.test(s)) return null;\n return parseInt(s, 16) >>> 0;\n}\n\n// Pushes every provided theme color + numeric float into the chart core via\n// handle.setColor / handle.setFloat. Unspecified or unparseable values are\n// skipped (they keep their default).\nexport function applyTheme(handle: ChartHandle, theme: VroomTheme): void {\n (Object.keys(COLOR_KEYS) as (keyof VroomTheme)[]).forEach((field) => {\n const value = theme[field];\n if (typeof value !== 'string' && typeof value !== 'number') return;\n const argb = parseColor(value);\n if (argb == null) return;\n handle.setColor(COLOR_KEYS[field]!, argb);\n });\n (Object.keys(FLOAT_KEYS) as (keyof VroomTheme)[]).forEach((field) => {\n const value = theme[field];\n if (typeof value !== 'number' || !Number.isFinite(value)) return;\n handle.setFloat(FLOAT_KEYS[field]!, value);\n });\n (Object.keys(BOOL_KEYS) as (keyof VroomTheme)[]).forEach((field) => {\n const value = theme[field];\n if (typeof value !== 'boolean') return;\n handle.setFloat(BOOL_KEYS[field]!, value ? 1 : 0);\n });\n}\n"],"mappings":"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","names":["import_react","import_react_native","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/VroomChart.tsx","../src/useChartCore.ts","../src/NativeVroomChart.ts","../src/packCandles.ts","../src/theme.ts"],"sourcesContent":["export { VroomChart } from './VroomChart';\nexport type {\n VroomChartProps,\n Candle,\n CrosshairEvent,\n VroomTheme,\n VroomColor,\n VisibleRange,\n RSIConfig,\n MACDConfig,\n MASource,\n MovingAverageOverlay,\n VWAPConfig,\n BollingerBandsConfig,\n ChartType,\n PriceLine,\n PriceLinesStyle,\n} from './types';\n","// VroomChart — Phase 3.\n//\n// Owns a SharedValue<SkPicture> driven by:\n// - useChartCore's \"initial\" picture (when data/size/range change), AND\n// - Pan gesture callbacks that call handle.pan(dx, dy) → fresh picture.\n//\n// Reanimated 4 + RN-Skia 2 propagate SharedValue<SkPicture> changes to\n// <Picture> without a React re-render, so gesture-driven redraws are cheap.\n//\n// Gestures run on the JS thread for now (`runOnJS(true)`) — installing the\n// JSI bindings on the worklet runtime is a later perf optimization.\n\nimport React, { useEffect, useRef, useCallback, useState, useMemo } from 'react';\nimport { View, type LayoutChangeEvent } from 'react-native';\nimport { Canvas, Picture, Skia, type SkPicture } from '@shopify/react-native-skia';\nimport {\n Gesture,\n GestureDetector,\n GestureHandlerRootView,\n} from 'react-native-gesture-handler';\nimport { useSharedValue } from 'react-native-reanimated';\n\nimport { useChartCore } from './useChartCore';\nimport type { VroomChartProps } from './types';\nimport './jsi.d';\n\n/**\n * Skia-rendered candlestick chart. Pass OHLCV `candles` and size it via `style`\n * (it fills its parent by default). Pan to scroll, pinch to zoom, drag the\n * price/time axes to rescale, and long-press for the crosshair. Optional\n * indicators (`rsi`, `macd`, `movingAverages`, `vwap`), colors (`theme`), and\n * events (`onCrosshair`, `onViewportChange`) are configured through props.\n *\n * @see {@link VroomChartProps} for the full prop reference.\n */\nexport function VroomChart(props: VroomChartProps) {\n const {\n candles,\n width: widthProp,\n height: heightProp,\n style,\n visibleRange,\n defaultCandleWidth,\n chartType,\n transitionMs,\n theme,\n rsi,\n macd,\n movingAverages,\n vwap,\n bollingerBands,\n crosshairOffset = 40,\n onCrosshair,\n onViewportChange,\n priceLines,\n priceLinesStyle,\n onPriceLineDrag,\n onPriceLineDragEnd,\n onPriceLineClose,\n } = props;\n\n // Fill the parent by default: measure via onLayout. Explicit width/height\n // props (if given) win per-axis. Until the first layout, dims are 0 and we\n // render nothing (one frame).\n const [measured, setMeasured] = useState({ width: 0, height: 0 });\n const width = widthProp ?? measured.width;\n const height = heightProp ?? measured.height;\n\n const onLayout = useCallback((e: LayoutChangeEvent) => {\n const w = Math.round(e.nativeEvent.layout.width);\n const h = Math.round(e.nativeEvent.layout.height);\n setMeasured((prev) =>\n prev.width === w && prev.height === h ? prev : { width: w, height: h },\n );\n }, []);\n\n // The close button is callback-gated, so whether a handler exists is part of\n // what gets rendered.\n const priceLinesProp = useMemo(\n () =>\n priceLines\n ? {\n lines: priceLines,\n style: priceLinesStyle,\n hasCloseHandler: onPriceLineClose != null,\n }\n : undefined,\n [priceLines, priceLinesStyle, onPriceLineClose],\n );\n\n const { handle, picture } = useChartCore(\n candles,\n { width, height },\n visibleRange,\n defaultCandleWidth,\n chartType,\n theme,\n rsi,\n macd,\n movingAverages,\n vwap,\n bollingerBands,\n priceLinesProp,\n );\n\n // RN-Skia's recorder reads this SharedValue on the UI/render runtime, a beat\n // behind JS-thread writes. If it ever reads null it throws (\"Invalid prop\n // value for SkTextBlob received\" — RN-Skia's mislabeled SkPicture error), so\n // we seed it with an empty picture and *never* assign null into it.\n const emptyPicture = useMemo(() => {\n const rec = Skia.PictureRecorder();\n rec.beginRecording(Skia.XYWHRect(0, 0, 1, 1));\n return rec.finishRecordingAsPicture();\n }, []);\n const pictureSV = useSharedValue<SkPicture>(emptyPicture);\n\n // When the crosshair is showing, pan moves it (instead of scrolling) and\n // pinch is disabled. A ref (not state) so gesture callbacks read it\n // synchronously without re-subscribing. Tap dismisses it.\n const crosshairActive = useRef(false);\n\n // timeMs of the candle last reported through onCrosshair, so a drag fires a\n // 'move' event only when it crosses into a *different* candle (one per\n // candle, not per frame). Null while the crosshair is hidden.\n const lastCrosshairTime = useRef<number | null>(null);\n\n // Sync the initial picture from useChartCore into the SV whenever it\n // refreshes (data load, size change, externally-controlled range change).\n // Only ever assign a non-null picture (see emptyPicture note above).\n useEffect(() => {\n if (picture) pictureSV.value = picture;\n }, [picture, pictureSV]);\n\n // Momentum scroll. After Pan ends with non-trivial velocity, we run a RAF\n // loop that calls handle.pan(dx, 0) each frame with an exponentially\n // decaying velocity. A new pan (or unmount) cancels the loop.\n const decayRaf = useRef<number | null>(null);\n const cancelDecay = useCallback(() => {\n if (decayRaf.current != null) {\n cancelAnimationFrame(decayRaf.current);\n decayRaf.current = null;\n }\n }, []);\n useEffect(() => cancelDecay, [cancelDecay]);\n\n // Axis-label fade animation loop. When a gesture changes which labels are\n // active, the C++ side starts ramping their opacities. We keep calling\n // render() on every frame until handle.isAnimating() returns false. The\n // loop is started by gesture callbacks (and the momentum tick) after they\n // update the picture, and self-stops when fades settle.\n const animRaf = useRef<number | null>(null);\n const animTick = useCallback(() => {\n animRaf.current = null;\n if (!handle) return;\n const next = handle.render();\n if (next) pictureSV.value = next;\n if (handle.isAnimating()) {\n animRaf.current = requestAnimationFrame(animTick);\n }\n }, [handle, pictureSV]);\n const maybeStartAnim = useCallback(() => {\n if (animRaf.current != null) return;\n if (!handle?.isAnimating()) return;\n animRaf.current = requestAnimationFrame(animTick);\n }, [handle, animTick]);\n useEffect(() => {\n return () => {\n if (animRaf.current != null) {\n cancelAnimationFrame(animRaf.current);\n animRaf.current = null;\n }\n };\n }, []);\n\n // Candle↔line morph. When `chartType` changes we drive the core per-frame with\n // a (collapse, fade) blend and push a fresh picture into the SV each frame — the\n // JS side owns the eased clock (see plan). A fresh handle snaps to the target;\n // transitionMs=0 snaps. Mirrors the web driver in react/src/useChartCore.ts.\n const morphRaf = useRef<number | null>(null);\n const morphFade = useRef<number | null>(null);\n const morphHandle = useRef<typeof handle>(null);\n useEffect(() => {\n if (!handle) return undefined;\n const target = chartType === 'line' ? 1 : 0;\n\n // Fresh handle (first load / recreate): snap, don't animate.\n if (morphHandle.current !== handle || morphFade.current == null) {\n morphHandle.current = handle;\n morphFade.current = target;\n handle.setChartType(target);\n const p = handle.render();\n if (p) pictureSV.value = p;\n return undefined;\n }\n if (morphFade.current === target) return undefined;\n\n if (morphRaf.current != null) {\n cancelAnimationFrame(morphRaf.current);\n morphRaf.current = null;\n }\n const dur = Math.max(0, transitionMs ?? 300);\n if (dur === 0) {\n morphFade.current = target;\n handle.setChartType(target);\n const p = handle.render();\n if (p) pictureSV.value = p;\n return undefined;\n }\n\n const from = morphFade.current;\n let startTs: number | null = null;\n const step = (now: number) => {\n if (startTs == null) startTs = now;\n const prog = Math.min(1, (now - startTs) / dur);\n const e = prog * prog * (3 - 2 * prog); // smoothstep ease-in-out\n const fade = from + (target - from) * e;\n morphFade.current = fade;\n handle.setMorph(fade, fade);\n const p = handle.render();\n if (p) pictureSV.value = p;\n if (prog < 1) {\n morphRaf.current = requestAnimationFrame(step);\n } else {\n morphRaf.current = null;\n morphFade.current = target;\n handle.setChartType(target); // lock the exact endpoint\n const q = handle.render();\n if (q) pictureSV.value = q;\n }\n };\n morphRaf.current = requestAnimationFrame(step);\n\n return () => {\n if (morphRaf.current != null) {\n cancelAnimationFrame(morphRaf.current);\n morphRaf.current = null;\n }\n };\n }, [handle, chartType, transitionMs, pictureSV]);\n\n // Classifies a touch point into the candle area vs. an axis strip. Axis\n // strips always own their gesture (scale price/time) and take priority over\n // the crosshair: an axis touch never opens, moves, or dismisses it.\n const hitAxis = useCallback(\n (x: number, y: number): 'chart' | 'price-axis' | 'time-axis' | 'indicator' => {\n if (!handle) return 'chart';\n const { yAxisWidth, xAxisHeight, indicatorHeight } =\n handle.getAxisMetrics();\n if (x > width - yAxisWidth) return 'price-axis';\n if (y > height - xAxisHeight) return 'time-axis';\n // The indicator pane sits just above the time-axis strip. A drag here\n // scrolls the candles horizontally (no vertical price change).\n if (indicatorHeight > 0 && y > height - xAxisHeight - indicatorHeight) {\n return 'indicator';\n }\n return 'chart';\n },\n [handle, width, height],\n );\n\n // Hit-tests the price lines at a touch point, resolving the core's index back\n // to the line it belongs to. Null when nothing was hit.\n const hitPriceLine = useCallback(\n (x: number, y: number) => {\n if (!handle || !priceLines?.length) return null;\n const hit = handle.hitTestPriceLine(x, y);\n const line = hit ? priceLines[hit.index] : undefined;\n return hit && line ? { index: hit.index, part: hit.part, line } : null;\n },\n [handle, priceLines],\n );\n\n // A price line being dragged vertically: its core index, its id, and the last\n // previewed price (the payload for the drop).\n const priceDrag = useRef<{ index: number; id: string; price: number } | null>(\n null,\n );\n\n // Pan routes to different C++ mutators depending on where it started: the\n // candle area (chart scroll / crosshair move), the y-axis strip (price\n // scale), the x-axis strip (time scale), the indicator pane (horizontal\n // scroll only), or a draggable price line. We classify on onStart.\n const panMode = useRef<\n 'chart' | 'price-axis' | 'time-axis' | 'indicator' | 'price-line'\n >('chart');\n\n const pan = Gesture.Pan()\n .runOnJS(true)\n .maxPointers(1) // don't fight Pinch's two-finger gesture\n .onStart((e) => {\n cancelDecay();\n // Always classify — an axis drag controls the axis even while the\n // crosshair is up. Only a chart-area drag interacts with the crosshair.\n panMode.current = hitAxis(e.x, e.y);\n // A draggable price line takes the drag over from the chart. Seeding the\n // preview at the committed price puts the label in drag styling before the\n // first move, so the grab registers immediately.\n priceDrag.current = null;\n if (handle && panMode.current === 'chart' && !crosshairActive.current) {\n const pl = hitPriceLine(e.x, e.y);\n if (pl && pl.part === 0) {\n panMode.current = 'price-line';\n priceDrag.current = { index: pl.index, id: pl.line.id, price: pl.line.price };\n handle.setPriceLineDrag(pl.index, pl.line.price);\n const p = handle.render();\n if (p) pictureSV.value = p;\n }\n }\n })\n .onChange((e) => {\n if (!handle) return;\n let next: ReturnType<typeof handle.pan> = null;\n if (panMode.current === 'price-axis') {\n next = handle.scalePriceAxis(e.changeY);\n } else if (panMode.current === 'time-axis') {\n next = handle.scaleTimeAxis(e.changeX);\n } else if (panMode.current === 'indicator') {\n // Drag in an indicator pane scrolls the candles horizontally only —\n // no vertical price slide (the pane's scale is fixed).\n next = handle.pan(e.changeX, 0);\n } else if (panMode.current === 'price-line') {\n // Preview the price under the finger; nothing is committed until the drop.\n const g = priceDrag.current;\n if (!g) return;\n const c = handle.coordAt(e.x, e.y);\n if (!c) return;\n g.price = c.price;\n handle.setPriceLineDrag(g.index, c.price);\n onPriceLineDrag?.(g.id, c.price);\n next = handle.render();\n } else if (crosshairActive.current) {\n // Chart area + crosshair up → the drag moves the crosshair instead of\n // scrolling. Vertical line tracks the finger x; the dot/horizontal line\n // stay lifted `crosshairOffset` px above the fingertip.\n const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);\n if (ch) pictureSV.value = ch;\n // The line follows the finger every frame (above), but only notify the\n // host when the snapped slot actually changes. The slot has a timeMs\n // even in the empty space ahead of the last candle, where candle=null.\n const info = handle.getCrosshairInfo();\n const t = info?.timeMs ?? null;\n if (t !== lastCrosshairTime.current) {\n lastCrosshairTime.current = t;\n // price is web-only for now (see @vroomchart/react); RN reports null.\n onCrosshair?.({ active: true, candle: info?.candle ?? null, timeMs: t, price: null, reason: 'move' });\n }\n return;\n } else {\n // Chart area: 1-finger drag translates both axes. Horizontal\n // component scrolls time, vertical component slides price bounds\n // (axes follow). Diagonal works naturally.\n next = handle.translate(e.changeX, e.changeY);\n }\n if (next) pictureSV.value = next;\n maybeStartAnim();\n })\n .onEnd((e) => {\n if (!handle) return;\n // Price-line drop. The preview always clears here: the line is a controlled\n // prop, so it only really moves once the host restates it — which means a\n // rejected (or ignored) move reverts on its own.\n if (panMode.current === 'price-line') {\n const g = priceDrag.current;\n priceDrag.current = null;\n handle.setPriceLineDrag(-1, 0);\n const p = handle.render();\n if (p) pictureSV.value = p;\n if (g) onPriceLineDragEnd?.(g.id, g.price);\n return;\n }\n // A chart-area drag with the crosshair up just moved the crosshair —\n // nothing about the viewport changed, and no momentum.\n if (panMode.current === 'chart' && crosshairActive.current) return;\n onViewportChange?.(0, 0);\n\n // Axis drags don't get momentum — they're a precise size adjustment.\n // Chart and indicator-pane drags both get horizontal fling momentum.\n if (panMode.current !== 'chart' && panMode.current !== 'indicator') return;\n\n let velocity = e.velocityX; // px/s\n const MIN_LAUNCH = 80; // ignore tiny flicks\n const MIN_STOP = 8; // px/s — stop threshold\n const HALF_LIFE_S = 0.35; // velocity halves every 0.35s\n if (Math.abs(velocity) < MIN_LAUNCH) return;\n\n let lastTime = performance.now();\n const tick = () => {\n const now = performance.now();\n const dt = (now - lastTime) / 1000;\n lastTime = now;\n\n // Frame-time-independent exponential decay.\n velocity *= Math.pow(0.5, dt / HALF_LIFE_S);\n const dx = velocity * dt;\n const next = handle.pan(dx, 0);\n if (next) pictureSV.value = next;\n maybeStartAnim();\n\n if (Math.abs(velocity) > MIN_STOP) {\n decayRaf.current = requestAnimationFrame(tick);\n } else {\n decayRaf.current = null;\n }\n };\n decayRaf.current = requestAnimationFrame(tick);\n });\n\n // Directional pinch. A single Pinch scale is uniform, so we read the two\n // touch points and track their horizontal/vertical spans independently: a\n // vertical pinch scales price (y), a horizontal pinch scales the time window\n // (x), and a diagonal pinch does both. An axis whose initial span is tiny\n // (fingers ~collinear on that axis) is left alone.\n // Lock the scalable axes at gesture start by orientation: an axis only\n // scales if its initial span is meaningful AND at least AXIS_RATIO of the\n // other axis. This keeps a vertical pinch from ever touching x (and vice\n // versa) — critical because during a vertical pinch the fingers' x-coords\n // drift and cross, sending spanX through ~0 and otherwise exploding frameX.\n const MIN_SPAN = 24; // px — minimum span for an axis to scale at all\n const AXIS_RATIO = 0.5; // axis scales only if its span ≥ this × the other's\n const pinchStart = useRef({\n spanX: 1,\n spanY: 1,\n ratioX: 1,\n ratioY: 1,\n enableX: false,\n enableY: false,\n });\n const pinch = Gesture.Pinch()\n .runOnJS(true)\n .onTouchesDown((e) => {\n if (e.numberOfTouches < 2) return;\n const [a, b] = e.allTouches;\n const spanX = Math.abs(a.x - b.x);\n const spanY = Math.abs(a.y - b.y);\n pinchStart.current = {\n spanX,\n spanY,\n ratioX: 1,\n ratioY: 1,\n enableX: spanX >= MIN_SPAN && spanX >= spanY * AXIS_RATIO,\n enableY: spanY >= MIN_SPAN && spanY >= spanX * AXIS_RATIO,\n };\n })\n .onTouchesMove((e) => {\n if (!handle || crosshairActive.current) return;\n if (e.numberOfTouches < 2) return;\n const [a, b] = e.allTouches;\n const start = pinchStart.current;\n const focalX = (a.x + b.x) * 0.5;\n const focalY = (a.y + b.y) * 0.5;\n\n // Per-frame factor = current cumulative ratio / previous. Floor the\n // current span at MIN_SPAN so a near-zero span (fingers crossing on that\n // axis) can't blow the ratio up.\n let frameX = 1;\n if (start.enableX) {\n const ratioX = Math.max(Math.abs(a.x - b.x), MIN_SPAN) / start.spanX;\n frameX = ratioX / start.ratioX;\n start.ratioX = ratioX;\n }\n let frameY = 1;\n if (start.enableY) {\n const ratioY = Math.max(Math.abs(a.y - b.y), MIN_SPAN) / start.spanY;\n frameY = ratioY / start.ratioY;\n start.ratioY = ratioY;\n }\n if (frameX === 1 && frameY === 1) return;\n\n const next = handle.zoom(frameX, frameY, focalX, focalY);\n if (next) pictureSV.value = next;\n maybeStartAnim();\n });\n\n // Long press shows the crosshair at the press point. A stationary hold never\n // activates `pan` (it needs movement first), so the chart won't scroll under\n // the hold. The dot/horizontal line are lifted above the fingertip.\n const longPress = Gesture.LongPress()\n .runOnJS(true)\n .onStart((e) => {\n if (!handle) return;\n // A long press on an axis strip controls the axis, never the crosshair.\n if (hitAxis(e.x, e.y) !== 'chart') return;\n // A press on a price line belongs to that line — dragging it or tapping its\n // close button — so it must not raise the crosshair over the top.\n if (hitPriceLine(e.x, e.y)) return;\n cancelDecay();\n crosshairActive.current = true;\n const ch = handle.setCrosshair(e.x, e.y - crosshairOffset);\n if (ch) pictureSV.value = ch;\n const info = handle.getCrosshairInfo();\n lastCrosshairTime.current = info?.timeMs ?? null;\n onCrosshair?.({\n active: true,\n candle: info?.candle ?? null,\n timeMs: info?.timeMs ?? null,\n price: null, // web-only for now (see @vroomchart/react)\n reason: 'show',\n });\n });\n\n // A tap activates a price line's close button, and otherwise dismisses the\n // crosshair while it's up. Any other tap is a no-op, so it never interferes\n // with normal pan/pinch.\n const tap = Gesture.Tap()\n .runOnJS(true)\n .onStart((e) => {\n if (!handle) return;\n // The close button is a tap target whether or not the crosshair is up.\n const pl = hitPriceLine(e.x, e.y);\n if (pl && pl.part === 1) {\n onPriceLineClose?.(pl.line.id);\n return;\n }\n if (!crosshairActive.current) return;\n // A tap on an axis strip controls the axis, never dismisses the crosshair.\n if (hitAxis(e.x, e.y) !== 'chart') return;\n crosshairActive.current = false;\n const ch = handle.clearCrosshair();\n if (ch) pictureSV.value = ch;\n lastCrosshairTime.current = null;\n onCrosshair?.({ active: false, candle: null, timeMs: null, price: null, reason: 'hide' });\n });\n\n const gesture = Gesture.Simultaneous(pan, pinch, longPress, tap);\n\n return (\n <GestureHandlerRootView\n onLayout={onLayout}\n style={[\n { width: widthProp, height: heightProp },\n widthProp == null && heightProp == null ? { flex: 1 } : null,\n style,\n ]}\n >\n <GestureDetector gesture={gesture}>\n <View style={{ flex: 1 }}>\n <Canvas style={{ flex: 1 }}>\n {width > 0 && height > 0 ? (\n // pictureSV is always a valid picture (seeded empty, never null),\n // so RN-Skia's UI-thread reader never sees null.\n <Picture picture={pictureSV} />\n ) : null}\n </Canvas>\n </View>\n </GestureDetector>\n </GestureHandlerRootView>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { SkPicture } from '@shopify/react-native-skia';\n\nimport NativeVroomChart from './NativeVroomChart';\nimport type { ChartHandle } from './jsi.d';\nimport { packCandles } from './packCandles';\nimport { applyTheme, parseColor } from './theme';\nimport type {\n BollingerBandsConfig,\n Candle,\n ChartType,\n MACDConfig,\n MovingAverageOverlay,\n PriceLine,\n PriceLinesStyle,\n RSIConfig,\n VisibleRange,\n VroomTheme,\n VWAPConfig,\n} from './types';\n\n// Mirrors vroom::ma::Source order in packages/core/src/ma.h.\nconst MA_SOURCES = [\n 'close',\n 'open',\n 'high',\n 'low',\n 'hl2',\n 'hlc3',\n 'ohlc4',\n] as const;\n\nfunction overlayToNumeric(o: MovingAverageOverlay) {\n const srcIdx = o.source ? MA_SOURCES.indexOf(o.source) : 0;\n return {\n kind: o.kind === 'ema' ? 1 : 0,\n period: o.length,\n source: srcIdx < 0 ? 0 : srcIdx,\n color: (o.color != null ? parseColor(o.color) : null) ?? 0xff2962ff,\n width: o.width ?? 1.5,\n };\n}\n\n// Bollinger defaults: blue bands / orange basis, matching the repo palette.\nconst DEFAULT_BB_BAND_COLOR = 0xff2962ff;\nconst DEFAULT_BB_BASIS_COLOR = 0xffff6d00;\n\nfunction bollingerToSpec(cfg: BollingerBandsConfig | undefined) {\n const srcIdx = cfg?.source ? MA_SOURCES.indexOf(cfg.source) : 0;\n return {\n enabled: cfg?.enabled ?? false,\n period: cfg?.period ?? 20,\n mult: cfg?.stdDev ?? 2,\n source: srcIdx < 0 ? 0 : srcIdx,\n basisKind: cfg?.basis === 'ema' ? 1 : 0,\n upperColor:\n (cfg?.upperColor != null ? parseColor(cfg.upperColor) : null) ??\n DEFAULT_BB_BAND_COLOR,\n upperWidth: cfg?.upperWidth ?? 1,\n middleColor:\n (cfg?.middleColor != null ? parseColor(cfg.middleColor) : null) ??\n DEFAULT_BB_BASIS_COLOR,\n middleWidth: cfg?.middleWidth ?? 1,\n lowerColor:\n (cfg?.lowerColor != null ? parseColor(cfg.lowerColor) : null) ??\n DEFAULT_BB_BAND_COLOR,\n lowerWidth: cfg?.lowerWidth ?? 1,\n fillEnabled: cfg?.fill ?? true,\n fillOpacity: cfg?.fillOpacity ?? 0.1,\n };\n}\n\n// Price-line defaults: a soft red dotted rule with a dark translucent label,\n// close in weight to the current-price indicator it sits beside.\nconst DEFAULT_PRICE_LINE_COLOR = 0xffef5350;\nconst DEFAULT_PRICE_LINE_BODY_BG = 0xd91c2128;\nconst DEFAULT_PRICE_LINE_HOVER_BOOST = 1.25;\n\nconst LINE_STYLES = { solid: 0, dotted: 1, dashed: 2 } as const;\n\n// Mirrors VroomPriceLineFlags in packages/core/include/vroom/vroom_chart.h.\nconst PRICE_LINE_DRAGGABLE = 1 << 0;\nconst PRICE_LINE_CLOSABLE = 1 << 1;\nconst PRICE_LINE_AXIS_LABEL = 1 << 2;\nconst PRICE_LINE_EXTEND_LEFT = 1 << 3;\n\n/** The price lines + their shared style, as the chart's props express them. */\nexport type PriceLinesProp = {\n lines: PriceLine[];\n style?: PriceLinesStyle;\n /**\n * Whether the host supplied a close handler. The close button is\n * callback-gated, so with nothing for it to do it isn't drawn at all.\n */\n hasCloseHandler: boolean;\n};\n\nfunction priceLinesToSpec(cfg: PriceLinesProp) {\n return {\n lines: cfg.lines.map((l) => ({\n price: l.price,\n color:\n (l.color != null ? parseColor(l.color) : null) ?? DEFAULT_PRICE_LINE_COLOR,\n width: l.width ?? 1,\n lineStyle: LINE_STYLES[l.lineStyle ?? 'dotted'],\n text: l.text ?? '',\n quantity: l.quantity ?? '',\n flags:\n (l.draggable ? PRICE_LINE_DRAGGABLE : 0) |\n (cfg.hasCloseHandler && l.closable !== false ? PRICE_LINE_CLOSABLE : 0) |\n (l.axisLabel !== false ? PRICE_LINE_AXIS_LABEL : 0) |\n (l.extendLeft !== false ? PRICE_LINE_EXTEND_LEFT : 0),\n })),\n bodyBg:\n (cfg.style?.bodyBackground != null ? parseColor(cfg.style.bodyBackground) : null) ??\n DEFAULT_PRICE_LINE_BODY_BG,\n fontSizePx: cfg.style?.fontSize ?? 0,\n lineLengthFrac: cfg.style?.inset ?? 0,\n align: cfg.style?.align === 'left' ? 0 : cfg.style?.align === 'center' ? 1 : 2,\n hoverBoost: cfg.style?.hoverBoost ?? DEFAULT_PRICE_LINE_HOVER_BOOST,\n };\n}\n\n// Cleared overlay: no lines (the style values are irrelevant, but the spec shape\n// requires them).\nconst EMPTY_PRICE_LINES = priceLinesToSpec({ lines: [], hasCloseHandler: false });\n\nlet installed = false;\nfunction ensureInstalled(): void {\n if (installed) return;\n const ok = NativeVroomChart.install();\n if (!ok) throw new Error('VroomChartModule.install() returned false');\n if (typeof globalThis.VroomChartJSI === 'undefined') {\n throw new Error('global.VroomChartJSI undefined after install()');\n }\n installed = true;\n}\n\nexport type ChartCoreState = {\n handle: ChartHandle | null;\n /** Picture freshly rendered after the latest data/size/range push. */\n picture: SkPicture | null;\n};\n\n// Owns a ChartHandle and produces an \"initial\" picture whenever data, size,\n// or the externally-controlled visible range changes. Gesture-driven updates\n// happen outside this hook by calling handle.pan(...) directly and assigning\n// the result into a SharedValue.\nexport function useChartCore(\n candles: Candle[],\n size: { width: number; height: number; pxRatio?: number },\n visibleRange?: VisibleRange,\n defaultCandleWidth?: number,\n chartType?: ChartType,\n theme?: VroomTheme,\n rsi?: RSIConfig,\n macd?: MACDConfig,\n movingAverages?: MovingAverageOverlay[],\n vwap?: VWAPConfig,\n bollingerBands?: BollingerBandsConfig,\n priceLines?: PriceLinesProp,\n): ChartCoreState {\n const handleRef = useRef<ChartHandle | null>(null);\n // Push setDefaultCandleWidth only once (first load): setCandles re-runs on\n // every data change, and the core setter re-frames when candles are present,\n // so re-pushing would snap the view away from the user's pan/zoom.\n const defaultWidthAppliedRef = useRef(false);\n const [picture, setPicture] = useState<SkPicture | null>(null);\n\n if (!handleRef.current && size.width > 0 && size.height > 0) {\n ensureInstalled();\n handleRef.current = globalThis.VroomChartJSI!.create();\n }\n\n // When no visibleRange is provided, leave the range entirely to the C++\n // side (which defaults to a sensible recent window on first setCandles).\n // Only push setVisibleRange when the caller is actively controlling it,\n // so it doesn't clobber the default or fight gesture-driven pans.\n const explicit = visibleRange != null;\n const startMs = visibleRange?.startMs ?? 0;\n const endMs = visibleRange?.endMs ?? 0;\n\n // Stable deps so inline `theme={{...}}` / `rsi={{...}}` literals don't re-run\n // the effect every render — only when the actual values change.\n const themeKey = theme ? JSON.stringify(theme) : '';\n const rsiKey = rsi ? JSON.stringify(rsi) : '';\n const macdKey = macd ? JSON.stringify(macd) : '';\n const maKey = movingAverages ? JSON.stringify(movingAverages) : '';\n const vwapKey = vwap ? JSON.stringify(vwap) : '';\n const bollingerKey = bollingerBands ? JSON.stringify(bollingerBands) : '';\n const priceLinesKey = priceLines ? JSON.stringify(priceLines) : '';\n\n useEffect(() => {\n const h = handleRef.current;\n if (!h) return;\n h.setSize(size.width, size.height, size.pxRatio ?? 1);\n // Drive the initial zoom from a target candle width. Pushed once, before the\n // first setCandles (while the core window is still 0/0), and only when the\n // caller isn't explicitly controlling the range.\n if (\n !defaultWidthAppliedRef.current &&\n !explicit &&\n defaultCandleWidth != null &&\n defaultCandleWidth > 0\n ) {\n h.setDefaultCandleWidth(defaultCandleWidth);\n defaultWidthAppliedRef.current = true;\n }\n if (candles.length > 0) {\n h.setCandles(packCandles(candles));\n }\n if (explicit) {\n h.setVisibleRange(startMs, endMs);\n }\n // chartType / the candle↔line morph is driven separately (VroomChart owns the\n // per-frame animation loop so it can update the picture SharedValue directly).\n if (theme) {\n applyTheme(h, theme);\n }\n h.setRSI(\n rsi?.enabled ?? false,\n rsi?.period ?? 14,\n rsi?.upperBand ?? 70,\n rsi?.lowerBand ?? 30,\n rsi?.maEnabled ?? true,\n rsi?.maPeriod ?? 14,\n );\n h.setMACD(\n macd?.enabled ?? false,\n macd?.fast ?? 12,\n macd?.slow ?? 26,\n macd?.signal ?? 9,\n );\n h.setOverlays((movingAverages ?? []).map(overlayToNumeric));\n h.setVWAP(\n vwap?.enabled ?? false,\n vwap?.resetMinutes ?? 0,\n (vwap?.color != null ? parseColor(vwap.color) : null) ?? 0xff00bcd4,\n vwap?.width ?? 1.5,\n );\n h.setBollinger(bollingerToSpec(bollingerBands));\n h.setPriceLines(\n priceLines?.lines.length ? priceLinesToSpec(priceLines) : EMPTY_PRICE_LINES,\n );\n // TODO(rn-parity): mirror the web `liquidity` overlay here (setLiquidity +\n // the VroomBand structs in the JSI handle) — web-only for now.\n setPicture(h.render());\n // theme/rsi/macd/movingAverages/vwap/bollingerBands/priceLines are\n // represented by their *Key deps.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [candles, size.width, size.height, size.pxRatio, explicit, startMs, endMs, defaultCandleWidth, themeKey, rsiKey, macdKey, maKey, vwapKey, bollingerKey, priceLinesKey]);\n\n return { handle: handleRef.current, picture };\n}\n","import type { TurboModule } from 'react-native';\nimport { TurboModuleRegistry } from 'react-native';\n\n// TurboModule spec consumed by codegen. The only method is `install`, which\n// the native side uses to install the `global.VroomChartJSI` host object the\n// first time it's called from JS. All real chart operations go through that\n// host object, not through the TurboModule itself.\nexport interface Spec extends TurboModule {\n install(): boolean;\n}\n\nexport default TurboModuleRegistry.getEnforcing<Spec>('VroomChartModule');\n","import type { Candle } from './types';\n\n// Wire format must match `VroomCandle` in packages/core/include/vroom/vroom_chart.h:\n// int64_t time_ms; double open, high, low, close, volume;\n// = 48 bytes per candle, 8-byte aligned, little-endian on iOS/Android.\nexport const BYTES_PER_CANDLE = 48;\n\n// Serializes candles into the packed little-endian buffer the C++ core expects.\n// Pure (no native/Skia deps) so it can be unit-tested in isolation.\nexport function packCandles(candles: Candle[]): ArrayBuffer {\n const buf = new ArrayBuffer(candles.length * BYTES_PER_CANDLE);\n const view = new DataView(buf);\n for (let i = 0; i < candles.length; i++) {\n const c = candles[i]!;\n const off = i * BYTES_PER_CANDLE;\n view.setBigInt64(off, BigInt(c.timeMs), true);\n view.setFloat64(off + 8, c.open, true);\n view.setFloat64(off + 16, c.high, true);\n view.setFloat64(off + 24, c.low, true);\n view.setFloat64(off + 32, c.close, true);\n view.setFloat64(off + 40, c.volume, true);\n }\n return buf;\n}\n","import type { ChartHandle } from './jsi.d';\nimport type { VroomColor, VroomTheme } from './types';\n\n// Maps each color VroomTheme field to its VroomColorKey index in the C++ enum\n// (packages/core/include/vroom/vroom_chart.h). Keep in sync with that enum;\n// new keys are appended there so existing indices never shift.\nexport const COLOR_KEYS: Partial<Record<keyof VroomTheme, number>> = {\n background: 0, // VROOM_COLOR_BACKGROUND\n bull: 1, // VROOM_COLOR_BULL\n bear: 2, // VROOM_COLOR_BEAR\n grid: 4, // VROOM_COLOR_GRID\n axisText: 5, // VROOM_COLOR_AXIS_TEXT\n crosshair: 6, // VROOM_COLOR_CROSSHAIR\n crosshairTarget: 9, // VROOM_COLOR_CROSSHAIR_TARGET\n borderBull: 10, // VROOM_COLOR_BORDER_BULL\n borderBear: 11, // VROOM_COLOR_BORDER_BEAR\n wickBull: 12, // VROOM_COLOR_WICK_BULL\n wickBear: 13, // VROOM_COLOR_WICK_BEAR\n accentBull: 14, // VROOM_COLOR_ACCENT_BULL\n accentBear: 15, // VROOM_COLOR_ACCENT_BEAR\n lineColor: 16, // VROOM_COLOR_LINE\n};\n\n// Maps each numeric VroomTheme field to its VroomFloatKey index.\nexport const FLOAT_KEYS: Partial<Record<keyof VroomTheme, number>> = {\n wickWidth: 1, // VROOM_FLOAT_WICK_WIDTH_PX\n candleRadius: 8, // VROOM_FLOAT_CANDLE_RADIUS_PX\n volumeRadius: 10, // VROOM_FLOAT_VOLUME_RADIUS_PX\n lineWidth: 11, // VROOM_FLOAT_LINE_WIDTH_PX\n};\n\n// Maps each boolean VroomTheme field to its VroomFloatKey index (pushed as 0/1).\nexport const BOOL_KEYS: Partial<Record<keyof VroomTheme, number>> = {\n wickRoundCap: 9, // VROOM_FLOAT_WICK_ROUND_CAP\n};\n\n// Parses a color into a packed 0xAARRGGBB integer (Skia's ARGB order).\n// - number → taken as already-packed ARGB\n// - '#rgb'-style 6-digit hex → opaque (alpha forced to ff)\n// - 8-digit hex → interpreted as AARRGGBB\n// Returns null for anything malformed so the caller can skip it.\nexport function parseColor(value: VroomColor): number | null {\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value >>> 0 : null;\n }\n let s = value.trim();\n if (s.startsWith('#')) s = s.slice(1);\n if (s.length === 6) s = `ff${s}`; // assume opaque\n if (s.length !== 8 || !/^[0-9a-fA-F]{8}$/.test(s)) return null;\n return parseInt(s, 16) >>> 0;\n}\n\n// Pushes every provided theme color + numeric float into the chart core via\n// handle.setColor / handle.setFloat. Unspecified or unparseable values are\n// skipped (they keep their default).\nexport function applyTheme(handle: ChartHandle, theme: VroomTheme): void {\n (Object.keys(COLOR_KEYS) as (keyof VroomTheme)[]).forEach((field) => {\n const value = theme[field];\n if (typeof value !== 'string' && typeof value !== 'number') return;\n const argb = parseColor(value);\n if (argb == null) return;\n handle.setColor(COLOR_KEYS[field]!, argb);\n });\n (Object.keys(FLOAT_KEYS) as (keyof VroomTheme)[]).forEach((field) => {\n const value = theme[field];\n if (typeof value !== 'number' || !Number.isFinite(value)) return;\n handle.setFloat(FLOAT_KEYS[field]!, value);\n });\n (Object.keys(BOOL_KEYS) as (keyof VroomTheme)[]).forEach((field) => {\n const value = theme[field];\n if (typeof value !== 'boolean') return;\n handle.setFloat(BOOL_KEYS[field]!, value ? 1 : 0);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYA,IAAAA,gBAAyE;AACzE,IAAAC,uBAA6C;AAC7C,+BAAsD;AACtD,0CAIO;AACP,qCAA+B;;;ACpB/B,mBAA4C;;;ACC5C,0BAAoC;AAUpC,IAAO,2BAAQ,wCAAoB,aAAmB,kBAAkB;;;ACNjE,IAAM,mBAAmB;AAIzB,SAAS,YAAY,SAAgC;AAC1D,QAAM,MAAM,IAAI,YAAY,QAAQ,SAAS,gBAAgB;AAC7D,QAAM,OAAO,IAAI,SAAS,GAAG;AAC7B,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,IAAI,QAAQ,CAAC;AACnB,UAAM,MAAM,IAAI;AAChB,SAAK,YAAY,KAAK,OAAO,EAAE,MAAM,GAAG,IAAI;AAC5C,SAAK,WAAW,MAAM,GAAG,EAAE,MAAM,IAAI;AACrC,SAAK,WAAW,MAAM,IAAI,EAAE,MAAM,IAAI;AACtC,SAAK,WAAW,MAAM,IAAI,EAAE,KAAK,IAAI;AACrC,SAAK,WAAW,MAAM,IAAI,EAAE,OAAO,IAAI;AACvC,SAAK,WAAW,MAAM,IAAI,EAAE,QAAQ,IAAI;AAAA,EAC1C;AACA,SAAO;AACT;;;ACjBO,IAAM,aAAwD;AAAA,EACnE,YAAY;AAAA;AAAA,EACZ,MAAM;AAAA;AAAA,EACN,MAAM;AAAA;AAAA,EACN,MAAM;AAAA;AAAA,EACN,UAAU;AAAA;AAAA,EACV,WAAW;AAAA;AAAA,EACX,iBAAiB;AAAA;AAAA,EACjB,YAAY;AAAA;AAAA,EACZ,YAAY;AAAA;AAAA,EACZ,UAAU;AAAA;AAAA,EACV,UAAU;AAAA;AAAA,EACV,YAAY;AAAA;AAAA,EACZ,YAAY;AAAA;AAAA,EACZ,WAAW;AAAA;AACb;AAGO,IAAM,aAAwD;AAAA,EACnE,WAAW;AAAA;AAAA,EACX,cAAc;AAAA;AAAA,EACd,cAAc;AAAA;AAAA,EACd,WAAW;AAAA;AACb;AAGO,IAAM,YAAuD;AAAA,EAClE,cAAc;AAAA;AAChB;AAOO,SAAS,WAAW,OAAkC;AAC3D,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,OAAO,SAAS,KAAK,IAAI,UAAU,IAAI;AAAA,EAChD;AACA,MAAI,IAAI,MAAM,KAAK;AACnB,MAAI,EAAE,WAAW,GAAG,EAAG,KAAI,EAAE,MAAM,CAAC;AACpC,MAAI,EAAE,WAAW,EAAG,KAAI,KAAK,CAAC;AAC9B,MAAI,EAAE,WAAW,KAAK,CAAC,mBAAmB,KAAK,CAAC,EAAG,QAAO;AAC1D,SAAO,SAAS,GAAG,EAAE,MAAM;AAC7B;AAKO,SAAS,WAAW,QAAqB,OAAyB;AACvE,EAAC,OAAO,KAAK,UAAU,EAA2B,QAAQ,CAAC,UAAU;AACnE,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAAU;AAC5D,UAAM,OAAO,WAAW,KAAK;AAC7B,QAAI,QAAQ,KAAM;AAClB,WAAO,SAAS,WAAW,KAAK,GAAI,IAAI;AAAA,EAC1C,CAAC;AACD,EAAC,OAAO,KAAK,UAAU,EAA2B,QAAQ,CAAC,UAAU;AACnE,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG;AAC1D,WAAO,SAAS,WAAW,KAAK,GAAI,KAAK;AAAA,EAC3C,CAAC;AACD,EAAC,OAAO,KAAK,SAAS,EAA2B,QAAQ,CAAC,UAAU;AAClE,UAAM,QAAQ,MAAM,KAAK;AACzB,QAAI,OAAO,UAAU,UAAW;AAChC,WAAO,SAAS,UAAU,KAAK,GAAI,QAAQ,IAAI,CAAC;AAAA,EAClD,CAAC;AACH;;;AHnDA,IAAM,aAAa;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,iBAAiB,GAAyB;AACjD,QAAM,SAAS,EAAE,SAAS,WAAW,QAAQ,EAAE,MAAM,IAAI;AACzD,SAAO;AAAA,IACL,MAAM,EAAE,SAAS,QAAQ,IAAI;AAAA,IAC7B,QAAQ,EAAE;AAAA,IACV,QAAQ,SAAS,IAAI,IAAI;AAAA,IACzB,QAAQ,EAAE,SAAS,OAAO,WAAW,EAAE,KAAK,IAAI,SAAS;AAAA,IACzD,OAAO,EAAE,SAAS;AAAA,EACpB;AACF;AAGA,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAE/B,SAAS,gBAAgB,KAAuC;AAC9D,QAAM,SAAS,KAAK,SAAS,WAAW,QAAQ,IAAI,MAAM,IAAI;AAC9D,SAAO;AAAA,IACL,SAAS,KAAK,WAAW;AAAA,IACzB,QAAQ,KAAK,UAAU;AAAA,IACvB,MAAM,KAAK,UAAU;AAAA,IACrB,QAAQ,SAAS,IAAI,IAAI;AAAA,IACzB,WAAW,KAAK,UAAU,QAAQ,IAAI;AAAA,IACtC,aACG,KAAK,cAAc,OAAO,WAAW,IAAI,UAAU,IAAI,SACxD;AAAA,IACF,YAAY,KAAK,cAAc;AAAA,IAC/B,cACG,KAAK,eAAe,OAAO,WAAW,IAAI,WAAW,IAAI,SAC1D;AAAA,IACF,aAAa,KAAK,eAAe;AAAA,IACjC,aACG,KAAK,cAAc,OAAO,WAAW,IAAI,UAAU,IAAI,SACxD;AAAA,IACF,YAAY,KAAK,cAAc;AAAA,IAC/B,aAAa,KAAK,QAAQ;AAAA,IAC1B,aAAa,KAAK,eAAe;AAAA,EACnC;AACF;AAIA,IAAM,2BAA2B;AACjC,IAAM,6BAA6B;AACnC,IAAM,iCAAiC;AAEvC,IAAM,cAAc,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,EAAE;AAGrD,IAAM,uBAAuB,KAAK;AAClC,IAAM,sBAAsB,KAAK;AACjC,IAAM,wBAAwB,KAAK;AACnC,IAAM,yBAAyB,KAAK;AAapC,SAAS,iBAAiB,KAAqB;AAC7C,SAAO;AAAA,IACL,OAAO,IAAI,MAAM,IAAI,CAAC,OAAO;AAAA,MAC3B,OAAO,EAAE;AAAA,MACT,QACG,EAAE,SAAS,OAAO,WAAW,EAAE,KAAK,IAAI,SAAS;AAAA,MACpD,OAAO,EAAE,SAAS;AAAA,MAClB,WAAW,YAAY,EAAE,aAAa,QAAQ;AAAA,MAC9C,MAAM,EAAE,QAAQ;AAAA,MAChB,UAAU,EAAE,YAAY;AAAA,MACxB,QACG,EAAE,YAAY,uBAAuB,MACrC,IAAI,mBAAmB,EAAE,aAAa,QAAQ,sBAAsB,MACpE,EAAE,cAAc,QAAQ,wBAAwB,MAChD,EAAE,eAAe,QAAQ,yBAAyB;AAAA,IACvD,EAAE;AAAA,IACF,SACG,IAAI,OAAO,kBAAkB,OAAO,WAAW,IAAI,MAAM,cAAc,IAAI,SAC5E;AAAA,IACF,YAAY,IAAI,OAAO,YAAY;AAAA,IACnC,gBAAgB,IAAI,OAAO,SAAS;AAAA,IACpC,OAAO,IAAI,OAAO,UAAU,SAAS,IAAI,IAAI,OAAO,UAAU,WAAW,IAAI;AAAA,IAC7E,YAAY,IAAI,OAAO,cAAc;AAAA,EACvC;AACF;AAIA,IAAM,oBAAoB,iBAAiB,EAAE,OAAO,CAAC,GAAG,iBAAiB,MAAM,CAAC;AAEhF,IAAI,YAAY;AAChB,SAAS,kBAAwB;AAC/B,MAAI,UAAW;AACf,QAAM,KAAK,yBAAiB,QAAQ;AACpC,MAAI,CAAC,GAAI,OAAM,IAAI,MAAM,2CAA2C;AACpE,MAAI,OAAO,WAAW,kBAAkB,aAAa;AACnD,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,cAAY;AACd;AAYO,SAAS,aACd,SACA,MACA,cACA,oBACA,WACA,OACA,KACA,MACA,gBACA,MACA,gBACA,YACgB;AAChB,QAAM,gBAAY,qBAA2B,IAAI;AAIjD,QAAM,6BAAyB,qBAAO,KAAK;AAC3C,QAAM,CAAC,SAAS,UAAU,QAAI,uBAA2B,IAAI;AAE7D,MAAI,CAAC,UAAU,WAAW,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AAC3D,oBAAgB;AAChB,cAAU,UAAU,WAAW,cAAe,OAAO;AAAA,EACvD;AAMA,QAAM,WAAW,gBAAgB;AACjC,QAAM,UAAU,cAAc,WAAW;AACzC,QAAM,QAAQ,cAAc,SAAS;AAIrC,QAAM,WAAW,QAAQ,KAAK,UAAU,KAAK,IAAI;AACjD,QAAM,SAAS,MAAM,KAAK,UAAU,GAAG,IAAI;AAC3C,QAAM,UAAU,OAAO,KAAK,UAAU,IAAI,IAAI;AAC9C,QAAM,QAAQ,iBAAiB,KAAK,UAAU,cAAc,IAAI;AAChE,QAAM,UAAU,OAAO,KAAK,UAAU,IAAI,IAAI;AAC9C,QAAM,eAAe,iBAAiB,KAAK,UAAU,cAAc,IAAI;AACvE,QAAM,gBAAgB,aAAa,KAAK,UAAU,UAAU,IAAI;AAEhE,8BAAU,MAAM;AACd,UAAM,IAAI,UAAU;AACpB,QAAI,CAAC,EAAG;AACR,MAAE,QAAQ,KAAK,OAAO,KAAK,QAAQ,KAAK,WAAW,CAAC;AAIpD,QACE,CAAC,uBAAuB,WACxB,CAAC,YACD,sBAAsB,QACtB,qBAAqB,GACrB;AACA,QAAE,sBAAsB,kBAAkB;AAC1C,6BAAuB,UAAU;AAAA,IACnC;AACA,QAAI,QAAQ,SAAS,GAAG;AACtB,QAAE,WAAW,YAAY,OAAO,CAAC;AAAA,IACnC;AACA,QAAI,UAAU;AACZ,QAAE,gBAAgB,SAAS,KAAK;AAAA,IAClC;AAGA,QAAI,OAAO;AACT,iBAAW,GAAG,KAAK;AAAA,IACrB;AACA,MAAE;AAAA,MACA,KAAK,WAAW;AAAA,MAChB,KAAK,UAAU;AAAA,MACf,KAAK,aAAa;AAAA,MAClB,KAAK,aAAa;AAAA,MAClB,KAAK,aAAa;AAAA,MAClB,KAAK,YAAY;AAAA,IACnB;AACA,MAAE;AAAA,MACA,MAAM,WAAW;AAAA,MACjB,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,MAAM,UAAU;AAAA,IAClB;AACA,MAAE,aAAa,kBAAkB,CAAC,GAAG,IAAI,gBAAgB,CAAC;AAC1D,MAAE;AAAA,MACA,MAAM,WAAW;AAAA,MACjB,MAAM,gBAAgB;AAAA,OACrB,MAAM,SAAS,OAAO,WAAW,KAAK,KAAK,IAAI,SAAS;AAAA,MACzD,MAAM,SAAS;AAAA,IACjB;AACA,MAAE,aAAa,gBAAgB,cAAc,CAAC;AAC9C,MAAE;AAAA,MACA,YAAY,MAAM,SAAS,iBAAiB,UAAU,IAAI;AAAA,IAC5D;AAGA,eAAW,EAAE,OAAO,CAAC;AAAA,EAIvB,GAAG,CAAC,SAAS,KAAK,OAAO,KAAK,QAAQ,KAAK,SAAS,UAAU,SAAS,OAAO,oBAAoB,UAAU,QAAQ,SAAS,OAAO,SAAS,cAAc,aAAa,CAAC;AAEzK,SAAO,EAAE,QAAQ,UAAU,SAAS,QAAQ;AAC9C;;;AD1NO,SAAS,WAAW,OAAwB;AACjD,QAAM;AAAA,IACJ;AAAA,IACA,OAAO;AAAA,IACP,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAKJ,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;AAChE,QAAM,QAAQ,aAAa,SAAS;AACpC,QAAM,SAAS,cAAc,SAAS;AAEtC,QAAM,eAAW,2BAAY,CAAC,MAAyB;AACrD,UAAM,IAAI,KAAK,MAAM,EAAE,YAAY,OAAO,KAAK;AAC/C,UAAM,IAAI,KAAK,MAAM,EAAE,YAAY,OAAO,MAAM;AAChD;AAAA,MAAY,CAAC,SACX,KAAK,UAAU,KAAK,KAAK,WAAW,IAAI,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,IACvE;AAAA,EACF,GAAG,CAAC,CAAC;AAIL,QAAM,qBAAiB;AAAA,IACrB,MACE,aACI;AAAA,MACE,OAAO;AAAA,MACP,OAAO;AAAA,MACP,iBAAiB,oBAAoB;AAAA,IACvC,IACA;AAAA,IACN,CAAC,YAAY,iBAAiB,gBAAgB;AAAA,EAChD;AAEA,QAAM,EAAE,QAAQ,QAAQ,IAAI;AAAA,IAC1B;AAAA,IACA,EAAE,OAAO,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAMA,QAAM,mBAAe,uBAAQ,MAAM;AACjC,UAAM,MAAM,8BAAK,gBAAgB;AACjC,QAAI,eAAe,8BAAK,SAAS,GAAG,GAAG,GAAG,CAAC,CAAC;AAC5C,WAAO,IAAI,yBAAyB;AAAA,EACtC,GAAG,CAAC,CAAC;AACL,QAAM,gBAAY,+CAA0B,YAAY;AAKxD,QAAM,sBAAkB,sBAAO,KAAK;AAKpC,QAAM,wBAAoB,sBAAsB,IAAI;AAKpD,+BAAU,MAAM;AACd,QAAI,QAAS,WAAU,QAAQ;AAAA,EACjC,GAAG,CAAC,SAAS,SAAS,CAAC;AAKvB,QAAM,eAAW,sBAAsB,IAAI;AAC3C,QAAM,kBAAc,2BAAY,MAAM;AACpC,QAAI,SAAS,WAAW,MAAM;AAC5B,2BAAqB,SAAS,OAAO;AACrC,eAAS,UAAU;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,CAAC;AACL,+BAAU,MAAM,aAAa,CAAC,WAAW,CAAC;AAO1C,QAAM,cAAU,sBAAsB,IAAI;AAC1C,QAAM,eAAW,2BAAY,MAAM;AACjC,YAAQ,UAAU;AAClB,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,OAAO,OAAO;AAC3B,QAAI,KAAM,WAAU,QAAQ;AAC5B,QAAI,OAAO,YAAY,GAAG;AACxB,cAAQ,UAAU,sBAAsB,QAAQ;AAAA,IAClD;AAAA,EACF,GAAG,CAAC,QAAQ,SAAS,CAAC;AACtB,QAAM,qBAAiB,2BAAY,MAAM;AACvC,QAAI,QAAQ,WAAW,KAAM;AAC7B,QAAI,CAAC,QAAQ,YAAY,EAAG;AAC5B,YAAQ,UAAU,sBAAsB,QAAQ;AAAA,EAClD,GAAG,CAAC,QAAQ,QAAQ,CAAC;AACrB,+BAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,QAAQ,WAAW,MAAM;AAC3B,6BAAqB,QAAQ,OAAO;AACpC,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAML,QAAM,eAAW,sBAAsB,IAAI;AAC3C,QAAM,gBAAY,sBAAsB,IAAI;AAC5C,QAAM,kBAAc,sBAAsB,IAAI;AAC9C,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,SAAS,cAAc,SAAS,IAAI;AAG1C,QAAI,YAAY,YAAY,UAAU,UAAU,WAAW,MAAM;AAC/D,kBAAY,UAAU;AACtB,gBAAU,UAAU;AACpB,aAAO,aAAa,MAAM;AAC1B,YAAM,IAAI,OAAO,OAAO;AACxB,UAAI,EAAG,WAAU,QAAQ;AACzB,aAAO;AAAA,IACT;AACA,QAAI,UAAU,YAAY,OAAQ,QAAO;AAEzC,QAAI,SAAS,WAAW,MAAM;AAC5B,2BAAqB,SAAS,OAAO;AACrC,eAAS,UAAU;AAAA,IACrB;AACA,UAAM,MAAM,KAAK,IAAI,GAAG,gBAAgB,GAAG;AAC3C,QAAI,QAAQ,GAAG;AACb,gBAAU,UAAU;AACpB,aAAO,aAAa,MAAM;AAC1B,YAAM,IAAI,OAAO,OAAO;AACxB,UAAI,EAAG,WAAU,QAAQ;AACzB,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,UAAU;AACvB,QAAI,UAAyB;AAC7B,UAAM,OAAO,CAAC,QAAgB;AAC5B,UAAI,WAAW,KAAM,WAAU;AAC/B,YAAM,OAAO,KAAK,IAAI,IAAI,MAAM,WAAW,GAAG;AAC9C,YAAM,IAAI,OAAO,QAAQ,IAAI,IAAI;AACjC,YAAM,OAAO,QAAQ,SAAS,QAAQ;AACtC,gBAAU,UAAU;AACpB,aAAO,SAAS,MAAM,IAAI;AAC1B,YAAM,IAAI,OAAO,OAAO;AACxB,UAAI,EAAG,WAAU,QAAQ;AACzB,UAAI,OAAO,GAAG;AACZ,iBAAS,UAAU,sBAAsB,IAAI;AAAA,MAC/C,OAAO;AACL,iBAAS,UAAU;AACnB,kBAAU,UAAU;AACpB,eAAO,aAAa,MAAM;AAC1B,cAAM,IAAI,OAAO,OAAO;AACxB,YAAI,EAAG,WAAU,QAAQ;AAAA,MAC3B;AAAA,IACF;AACA,aAAS,UAAU,sBAAsB,IAAI;AAE7C,WAAO,MAAM;AACX,UAAI,SAAS,WAAW,MAAM;AAC5B,6BAAqB,SAAS,OAAO;AACrC,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,cAAc,SAAS,CAAC;AAK/C,QAAM,cAAU;AAAA,IACd,CAAC,GAAW,MAAkE;AAC5E,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,EAAE,YAAY,aAAa,gBAAgB,IAC/C,OAAO,eAAe;AACxB,UAAI,IAAI,QAAQ,WAAY,QAAO;AACnC,UAAI,IAAI,SAAS,YAAa,QAAO;AAGrC,UAAI,kBAAkB,KAAK,IAAI,SAAS,cAAc,iBAAiB;AACrE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,QAAQ,OAAO,MAAM;AAAA,EACxB;AAIA,QAAM,mBAAe;AAAA,IACnB,CAAC,GAAW,MAAc;AACxB,UAAI,CAAC,UAAU,CAAC,YAAY,OAAQ,QAAO;AAC3C,YAAM,MAAM,OAAO,iBAAiB,GAAG,CAAC;AACxC,YAAM,OAAO,MAAM,WAAW,IAAI,KAAK,IAAI;AAC3C,aAAO,OAAO,OAAO,EAAE,OAAO,IAAI,OAAO,MAAM,IAAI,MAAM,KAAK,IAAI;AAAA,IACpE;AAAA,IACA,CAAC,QAAQ,UAAU;AAAA,EACrB;AAIA,QAAM,gBAAY;AAAA,IAChB;AAAA,EACF;AAMA,QAAM,cAAU,sBAEd,OAAO;AAET,QAAM,MAAM,4CAAQ,IAAI,EACrB,QAAQ,IAAI,EACZ,YAAY,CAAC,EACb,QAAQ,CAAC,MAAM;AACd,gBAAY;AAGZ,YAAQ,UAAU,QAAQ,EAAE,GAAG,EAAE,CAAC;AAIlC,cAAU,UAAU;AACpB,QAAI,UAAU,QAAQ,YAAY,WAAW,CAAC,gBAAgB,SAAS;AACrE,YAAM,KAAK,aAAa,EAAE,GAAG,EAAE,CAAC;AAChC,UAAI,MAAM,GAAG,SAAS,GAAG;AACvB,gBAAQ,UAAU;AAClB,kBAAU,UAAU,EAAE,OAAO,GAAG,OAAO,IAAI,GAAG,KAAK,IAAI,OAAO,GAAG,KAAK,MAAM;AAC5E,eAAO,iBAAiB,GAAG,OAAO,GAAG,KAAK,KAAK;AAC/C,cAAM,IAAI,OAAO,OAAO;AACxB,YAAI,EAAG,WAAU,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,EACF,CAAC,EACA,SAAS,CAAC,MAAM;AACf,QAAI,CAAC,OAAQ;AACb,QAAI,OAAsC;AAC1C,QAAI,QAAQ,YAAY,cAAc;AACpC,aAAO,OAAO,eAAe,EAAE,OAAO;AAAA,IACxC,WAAW,QAAQ,YAAY,aAAa;AAC1C,aAAO,OAAO,cAAc,EAAE,OAAO;AAAA,IACvC,WAAW,QAAQ,YAAY,aAAa;AAG1C,aAAO,OAAO,IAAI,EAAE,SAAS,CAAC;AAAA,IAChC,WAAW,QAAQ,YAAY,cAAc;AAE3C,YAAM,IAAI,UAAU;AACpB,UAAI,CAAC,EAAG;AACR,YAAM,IAAI,OAAO,QAAQ,EAAE,GAAG,EAAE,CAAC;AACjC,UAAI,CAAC,EAAG;AACR,QAAE,QAAQ,EAAE;AACZ,aAAO,iBAAiB,EAAE,OAAO,EAAE,KAAK;AACxC,wBAAkB,EAAE,IAAI,EAAE,KAAK;AAC/B,aAAO,OAAO,OAAO;AAAA,IACvB,WAAW,gBAAgB,SAAS;AAIlC,YAAM,KAAK,OAAO,aAAa,EAAE,GAAG,EAAE,IAAI,eAAe;AACzD,UAAI,GAAI,WAAU,QAAQ;AAI1B,YAAM,OAAO,OAAO,iBAAiB;AACrC,YAAM,IAAI,MAAM,UAAU;AAC1B,UAAI,MAAM,kBAAkB,SAAS;AACnC,0BAAkB,UAAU;AAE5B,sBAAc,EAAE,QAAQ,MAAM,QAAQ,MAAM,UAAU,MAAM,QAAQ,GAAG,OAAO,MAAM,QAAQ,OAAO,CAAC;AAAA,MACtG;AACA;AAAA,IACF,OAAO;AAIL,aAAO,OAAO,UAAU,EAAE,SAAS,EAAE,OAAO;AAAA,IAC9C;AACA,QAAI,KAAM,WAAU,QAAQ;AAC5B,mBAAe;AAAA,EACjB,CAAC,EACA,MAAM,CAAC,MAAM;AACZ,QAAI,CAAC,OAAQ;AAIb,QAAI,QAAQ,YAAY,cAAc;AACpC,YAAM,IAAI,UAAU;AACpB,gBAAU,UAAU;AACpB,aAAO,iBAAiB,IAAI,CAAC;AAC7B,YAAM,IAAI,OAAO,OAAO;AACxB,UAAI,EAAG,WAAU,QAAQ;AACzB,UAAI,EAAG,sBAAqB,EAAE,IAAI,EAAE,KAAK;AACzC;AAAA,IACF;AAGA,QAAI,QAAQ,YAAY,WAAW,gBAAgB,QAAS;AAC5D,uBAAmB,GAAG,CAAC;AAIvB,QAAI,QAAQ,YAAY,WAAW,QAAQ,YAAY,YAAa;AAEpE,QAAI,WAAW,EAAE;AACjB,UAAM,aAAa;AACnB,UAAM,WAAW;AACjB,UAAM,cAAc;AACpB,QAAI,KAAK,IAAI,QAAQ,IAAI,WAAY;AAErC,QAAI,WAAW,YAAY,IAAI;AAC/B,UAAM,OAAO,MAAM;AACjB,YAAM,MAAM,YAAY,IAAI;AAC5B,YAAM,MAAM,MAAM,YAAY;AAC9B,iBAAW;AAGX,kBAAY,KAAK,IAAI,KAAK,KAAK,WAAW;AAC1C,YAAM,KAAK,WAAW;AACtB,YAAM,OAAO,OAAO,IAAI,IAAI,CAAC;AAC7B,UAAI,KAAM,WAAU,QAAQ;AAC5B,qBAAe;AAEf,UAAI,KAAK,IAAI,QAAQ,IAAI,UAAU;AACjC,iBAAS,UAAU,sBAAsB,IAAI;AAAA,MAC/C,OAAO;AACL,iBAAS,UAAU;AAAA,MACrB;AAAA,IACF;AACA,aAAS,UAAU,sBAAsB,IAAI;AAAA,EAC/C,CAAC;AAYH,QAAM,WAAW;AACjB,QAAM,aAAa;AACnB,QAAM,iBAAa,sBAAO;AAAA,IACxB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AACD,QAAM,QAAQ,4CAAQ,MAAM,EACzB,QAAQ,IAAI,EACZ,cAAc,CAAC,MAAM;AACpB,QAAI,EAAE,kBAAkB,EAAG;AAC3B,UAAM,CAAC,GAAG,CAAC,IAAI,EAAE;AACjB,UAAM,QAAQ,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC;AAChC,UAAM,QAAQ,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC;AAChC,eAAW,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS,SAAS,YAAY,SAAS,QAAQ;AAAA,MAC/C,SAAS,SAAS,YAAY,SAAS,QAAQ;AAAA,IACjD;AAAA,EACF,CAAC,EACA,cAAc,CAAC,MAAM;AACpB,QAAI,CAAC,UAAU,gBAAgB,QAAS;AACxC,QAAI,EAAE,kBAAkB,EAAG;AAC3B,UAAM,CAAC,GAAG,CAAC,IAAI,EAAE;AACjB,UAAM,QAAQ,WAAW;AACzB,UAAM,UAAU,EAAE,IAAI,EAAE,KAAK;AAC7B,UAAM,UAAU,EAAE,IAAI,EAAE,KAAK;AAK7B,QAAI,SAAS;AACb,QAAI,MAAM,SAAS;AACjB,YAAM,SAAS,KAAK,IAAI,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,QAAQ,IAAI,MAAM;AAC/D,eAAS,SAAS,MAAM;AACxB,YAAM,SAAS;AAAA,IACjB;AACA,QAAI,SAAS;AACb,QAAI,MAAM,SAAS;AACjB,YAAM,SAAS,KAAK,IAAI,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,QAAQ,IAAI,MAAM;AAC/D,eAAS,SAAS,MAAM;AACxB,YAAM,SAAS;AAAA,IACjB;AACA,QAAI,WAAW,KAAK,WAAW,EAAG;AAElC,UAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ,QAAQ,MAAM;AACvD,QAAI,KAAM,WAAU,QAAQ;AAC5B,mBAAe;AAAA,EACjB,CAAC;AAKH,QAAM,YAAY,4CAAQ,UAAU,EACjC,QAAQ,IAAI,EACZ,QAAQ,CAAC,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,QAAI,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,QAAS;AAGnC,QAAI,aAAa,EAAE,GAAG,EAAE,CAAC,EAAG;AAC5B,gBAAY;AACZ,oBAAgB,UAAU;AAC1B,UAAM,KAAK,OAAO,aAAa,EAAE,GAAG,EAAE,IAAI,eAAe;AACzD,QAAI,GAAI,WAAU,QAAQ;AAC1B,UAAM,OAAO,OAAO,iBAAiB;AACrC,sBAAkB,UAAU,MAAM,UAAU;AAC5C,kBAAc;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ,MAAM,UAAU;AAAA,MACxB,QAAQ,MAAM,UAAU;AAAA,MACxB,OAAO;AAAA;AAAA,MACP,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AAKH,QAAM,MAAM,4CAAQ,IAAI,EACrB,QAAQ,IAAI,EACZ,QAAQ,CAAC,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,KAAK,aAAa,EAAE,GAAG,EAAE,CAAC;AAChC,QAAI,MAAM,GAAG,SAAS,GAAG;AACvB,yBAAmB,GAAG,KAAK,EAAE;AAC7B;AAAA,IACF;AACA,QAAI,CAAC,gBAAgB,QAAS;AAE9B,QAAI,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,QAAS;AACnC,oBAAgB,UAAU;AAC1B,UAAM,KAAK,OAAO,eAAe;AACjC,QAAI,GAAI,WAAU,QAAQ;AAC1B,sBAAkB,UAAU;AAC5B,kBAAc,EAAE,QAAQ,OAAO,QAAQ,MAAM,QAAQ,MAAM,OAAO,MAAM,QAAQ,OAAO,CAAC;AAAA,EAC1F,CAAC;AAEH,QAAM,UAAU,4CAAQ,aAAa,KAAK,OAAO,WAAW,GAAG;AAE/D,SACE,8BAAAC,QAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,EAAE,OAAO,WAAW,QAAQ,WAAW;AAAA,QACvC,aAAa,QAAQ,cAAc,OAAO,EAAE,MAAM,EAAE,IAAI;AAAA,QACxD;AAAA,MACF;AAAA;AAAA,IAEA,8BAAAA,QAAA,cAAC,uDAAgB,WACf,8BAAAA,QAAA,cAAC,6BAAK,OAAO,EAAE,MAAM,EAAE,KACrB,8BAAAA,QAAA,cAAC,mCAAO,OAAO,EAAE,MAAM,EAAE,KACtB,QAAQ,KAAK,SAAS;AAAA;AAAA;AAAA,MAGrB,8BAAAA,QAAA,cAAC,oCAAQ,SAAS,WAAW;AAAA,QAC3B,IACN,CACF,CACF;AAAA,EACF;AAEJ;","names":["import_react","import_react_native","React"]}