react-native-livechart 4.13.0 → 4.13.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"LiveChart.d.ts","sourceRoot":"","sources":["../../src/components/LiveChart.tsx"],"names":[],"mappings":"AA4HA,OAAO,KAAK,EAGV,cAAc,EAEf,MAAM,UAAU,CAAC;AAq9ElB,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,+BAS9C"}
1
+ {"version":3,"file":"LiveChart.d.ts","sourceRoot":"","sources":["../../src/components/LiveChart.tsx"],"names":[],"mappings":"AA2HA,OAAO,KAAK,EAGV,cAAc,EAEf,MAAM,UAAU,CAAC;AA08ElB,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,+BAS9C"}
@@ -0,0 +1,23 @@
1
+ import type { SharedValue } from "react-native-reanimated";
2
+ import type { ResolvedSegment } from "../core/resolveSegment";
3
+ import type { ChartEngineLayout } from "../core/useLiveChartEngine";
4
+ import type { ChartPadding } from "../draw/line";
5
+ interface SegmentLineGradientProps {
6
+ engine: ChartEngineLayout;
7
+ segments: ResolvedSegment[];
8
+ padding: ChartPadding;
9
+ baseColor: string;
10
+ scrubX: SharedValue<number>;
11
+ scrubActive: SharedValue<boolean>;
12
+ }
13
+ /**
14
+ * Keeps the two SharedValues passed to Skia on one stop-count lifecycle.
15
+ *
16
+ * Scrubbing can change which stops are visible without changing `stopCount`, so
17
+ * padding keeps those mapper updates safe. When the segment props themselves
18
+ * change the count, the keyed child remounts both SharedValues together instead
19
+ * of letting one retain the previous length for a frame.
20
+ */
21
+ export declare function SegmentLineGradient(props: SegmentLineGradientProps): import("react").JSX.Element;
22
+ export {};
23
+ //# sourceMappingURL=SegmentLineGradient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentLineGradient.d.ts","sourceRoot":"","sources":["../../src/components/SegmentLineGradient.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAIjD,UAAU,wBAAwB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5B,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,+BAGlE"}
@@ -1 +1 @@
1
- {"version":3,"file":"useSegmentLineGradient.d.ts","sourceRoot":"","sources":["../../src/hooks/useSegmentLineGradient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKjD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,eAAe,EAAE,EAC3B,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAC3B,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;;;;EA8BlC"}
1
+ {"version":3,"file":"useSegmentLineGradient.d.ts","sourceRoot":"","sources":["../../src/hooks/useSegmentLineGradient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AASjD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,eAAe,EAAE,EAC3B,OAAO,EAAE,YAAY,EACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAC3B,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC;;;;EAkClC"}
@@ -43,4 +43,8 @@ export interface SegmentGradient {
43
43
  * The caller then strokes the line with its plain solid color.
44
44
  */
45
45
  export declare function segmentLineGradient(segments: ResolvedSegment[], winStart: number, win: number, canvasWidth: number, plotLeft: number, plotRight: number, baseColor: string, scrubActive: boolean, scrubX: number): SegmentGradient | null;
46
+ /** Stops {@link segmentLineGradient} can emit for `segments` — no per-frame state. */
47
+ export declare function segmentGradientStopCount(segments: ResolvedSegment[]): number;
48
+ /** Resize `stops` to `count` by repeating its last entry. */
49
+ export declare function padGradientStops<T>(stops: T[], count: number): T[];
46
50
  //# sourceMappingURL=segments.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"segments.d.ts","sourceRoot":"","sources":["../../src/math/segments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,YAAY,CAkBd;AAED,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,MAAM,GACb,eAAe,GAAG,IAAI,CAuFxB"}
1
+ {"version":3,"file":"segments.d.ts","sourceRoot":"","sources":["../../src/math/segments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,sEAAsE;AACtE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAID;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,YAAY,CAkBd;AAED,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,MAAM,GACb,eAAe,GAAG,IAAI,CAuFxB;AAED,sFAAsF;AACtF,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,CAa5E;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,CAOlE"}
package/package.json CHANGED
@@ -67,5 +67,5 @@
67
67
  },
68
68
  "sideEffects": false,
69
69
  "types": "./dist/index.d.ts",
70
- "version": "4.13.0"
70
+ "version": "4.13.1"
71
71
  }
@@ -89,7 +89,6 @@ import {
89
89
  import { AXIS_GRAB_MIN_PX, usePanScroll } from "../hooks/usePanScroll";
90
90
  import { usePinchZoom } from "../hooks/usePinchZoom";
91
91
  import { useVisibleRange } from "../hooks/useVisibleRange";
92
- import { useSegmentLineGradient } from "../hooks/useSegmentLineGradient";
93
92
  import { useSingleChartReverseMorphInputs } from "../hooks/useReverseMorphEngineInputs";
94
93
  import {
95
94
  useThreshold,
@@ -162,6 +161,7 @@ import { ReferenceLineGroupOverlay } from "./ReferenceLineGroupOverlay";
162
161
  import { ReferenceLineOverlay } from "./ReferenceLineOverlay";
163
162
  import { ScrubActionOverlay } from "./ScrubActionOverlay";
164
163
  import { SegmentDividerOverlay } from "./SegmentDividerOverlay";
164
+ import { SegmentLineGradient } from "./SegmentLineGradient";
165
165
  import { TradeStreamOverlay } from "./TradeStreamOverlay";
166
166
  import { ValueLineOverlay } from "./ValueLineOverlay";
167
167
  import { XAxisOverlay } from "./XAxisOverlay";
@@ -1200,19 +1200,6 @@ function useLiveChartController({
1200
1200
  effectivePadding,
1201
1201
  );
1202
1202
 
1203
- // Scrub-focus gradient painted onto the line stroke: uniform at rest, and while
1204
- // scrubbing (or with an `active` segment) the focused segment stays full while
1205
- // the others are de-emphasized. Declared after `crosshair` so it can read the
1206
- // live scrub state.
1207
- const segmentGradient = useSegmentLineGradient(
1208
- engine,
1209
- resolvedSegments,
1210
- effectivePadding,
1211
- lineProp?.color ?? palette.line,
1212
- crosshair.scrubX,
1213
- crosshair.scrubActive,
1214
- );
1215
-
1216
1203
  // Hide the live dot while scrubbing when a selection dot is marking the scrub
1217
1204
  // point instead — otherwise both dots show at once. Applies on static charts
1218
1205
  // too, now that they're scrubbable.
@@ -1326,7 +1313,6 @@ function useLiveChartController({
1326
1313
  refGroupFormat,
1327
1314
  resolvedSegments,
1328
1315
  hasRecolorSegments,
1329
- segmentGradient,
1330
1316
  thresholdCfg,
1331
1317
  thresholdGeom,
1332
1318
  thresholdStrokeColors: thresholdStopColors?.stroke ?? null,
@@ -1764,7 +1750,7 @@ function ChartStack({
1764
1750
  dragValues,
1765
1751
  resolvedSegments,
1766
1752
  hasRecolorSegments,
1767
- segmentGradient,
1753
+ crosshair,
1768
1754
  thresholdCfg,
1769
1755
  thresholdGeom,
1770
1756
  thresholdStrokeColors,
@@ -1905,11 +1891,13 @@ function ChartStack({
1905
1891
  positions={thresholdGeom.splitPositions}
1906
1892
  />
1907
1893
  ) : hasRecolorSegments ? (
1908
- <LinearGradient
1909
- start={vec(0, 0)}
1910
- end={segmentGradient.gradientEnd}
1911
- colors={segmentGradient.colors}
1912
- positions={segmentGradient.positions}
1894
+ <SegmentLineGradient
1895
+ engine={engine}
1896
+ segments={resolvedSegments}
1897
+ padding={effectivePadding}
1898
+ baseColor={lineProp?.color ?? palette.line}
1899
+ scrubX={crosshair.scrubX}
1900
+ scrubActive={crosshair.scrubActive}
1913
1901
  />
1914
1902
  ) : lineProp?.colors?.length ? (
1915
1903
  <LinearGradient
@@ -0,0 +1,57 @@
1
+ import { LinearGradient, vec } from "@shopify/react-native-skia";
2
+ import type { SharedValue } from "react-native-reanimated";
3
+
4
+ import type { ResolvedSegment } from "../core/resolveSegment";
5
+ import type { ChartEngineLayout } from "../core/useLiveChartEngine";
6
+ import type { ChartPadding } from "../draw/line";
7
+ import { useSegmentLineGradient } from "../hooks/useSegmentLineGradient";
8
+ import { segmentGradientStopCount } from "../math/segments";
9
+
10
+ interface SegmentLineGradientProps {
11
+ engine: ChartEngineLayout;
12
+ segments: ResolvedSegment[];
13
+ padding: ChartPadding;
14
+ baseColor: string;
15
+ scrubX: SharedValue<number>;
16
+ scrubActive: SharedValue<boolean>;
17
+ }
18
+
19
+ /**
20
+ * Keeps the two SharedValues passed to Skia on one stop-count lifecycle.
21
+ *
22
+ * Scrubbing can change which stops are visible without changing `stopCount`, so
23
+ * padding keeps those mapper updates safe. When the segment props themselves
24
+ * change the count, the keyed child remounts both SharedValues together instead
25
+ * of letting one retain the previous length for a frame.
26
+ */
27
+ export function SegmentLineGradient(props: SegmentLineGradientProps) {
28
+ const stopCount = segmentGradientStopCount(props.segments);
29
+ return <SegmentLineGradientPaint key={stopCount} {...props} />;
30
+ }
31
+
32
+ function SegmentLineGradientPaint({
33
+ engine,
34
+ segments,
35
+ padding,
36
+ baseColor,
37
+ scrubX,
38
+ scrubActive,
39
+ }: SegmentLineGradientProps) {
40
+ const gradient = useSegmentLineGradient(
41
+ engine,
42
+ segments,
43
+ padding,
44
+ baseColor,
45
+ scrubX,
46
+ scrubActive,
47
+ );
48
+
49
+ return (
50
+ <LinearGradient
51
+ start={vec(0, 0)}
52
+ end={gradient.gradientEnd}
53
+ colors={gradient.colors}
54
+ positions={gradient.positions}
55
+ />
56
+ );
57
+ }
@@ -4,7 +4,11 @@ import { vec } from "@shopify/react-native-skia";
4
4
  import type { ChartEngineLayout } from "../core/useLiveChartEngine";
5
5
  import type { ResolvedSegment } from "../core/resolveSegment";
6
6
  import type { ChartPadding } from "../draw/line";
7
- import { segmentLineGradient } from "../math/segments";
7
+ import {
8
+ padGradientStops,
9
+ segmentGradientStopCount,
10
+ segmentLineGradient,
11
+ } from "../math/segments";
8
12
 
9
13
  const FALLBACK_POSITIONS = [0, 1];
10
14
 
@@ -43,11 +47,15 @@ export function useSegmentLineGradient(
43
47
  );
44
48
  });
45
49
 
46
- const colors = useDerivedValue(
47
- () => data.value?.colors ?? [baseColor, baseColor],
50
+ // Fixed stop count: `colors`/`positions` tear independently and Skia treats a
51
+ // length mismatch as a fatal UI-thread throw.
52
+ const stopCount = segmentGradientStopCount(segments);
53
+
54
+ const colors = useDerivedValue(() =>
55
+ padGradientStops(data.value?.colors ?? [baseColor, baseColor], stopCount),
48
56
  );
49
- const positions = useDerivedValue(
50
- () => data.value?.positions ?? FALLBACK_POSITIONS,
57
+ const positions = useDerivedValue(() =>
58
+ padGradientStops(data.value?.positions ?? FALLBACK_POSITIONS, stopCount),
51
59
  );
52
60
  const gradientEnd = useDerivedValue(() =>
53
61
  vec(Math.max(1, engine.canvasWidth.value), 0),
@@ -171,3 +171,29 @@ export function segmentLineGradient(
171
171
 
172
172
  return { colors, positions };
173
173
  }
174
+
175
+ /** Stops {@link segmentLineGradient} can emit for `segments` — no per-frame state. */
176
+ export function segmentGradientStopCount(segments: ResolvedSegment[]): number {
177
+ "worklet";
178
+ let n = 2;
179
+ for (let i = 0; i < segments.length; i++) {
180
+ const seg = segments[i];
181
+ if (!seg.recolorLine) continue;
182
+ const cols =
183
+ seg.mutedColors && seg.mutedColors.length >= 2
184
+ ? seg.mutedColors.length
185
+ : 2;
186
+ n += cols + 2;
187
+ }
188
+ return n;
189
+ }
190
+
191
+ /** Resize `stops` to `count` by repeating its last entry. */
192
+ export function padGradientStops<T>(stops: T[], count: number): T[] {
193
+ "worklet";
194
+ if (stops.length === count || stops.length === 0) return stops;
195
+ const out = stops.slice(0, count);
196
+ const last = stops[stops.length - 1];
197
+ while (out.length < count) out.push(last);
198
+ return out;
199
+ }