@ledgerhq/lumen-ui-rnative-visualization 0.1.24 → 0.1.26

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.
@@ -4,7 +4,7 @@ import { triggerHapticFeedback } from '@ledgerhq/lumen-ui-rnative';
4
4
  import { useCallback, useMemo, useRef, useState } from 'react';
5
5
  import { StyleSheet, View } from 'react-native';
6
6
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
7
- import Animated, { useSharedValue } from 'react-native-reanimated';
7
+ import Animated from 'react-native-reanimated';
8
8
  import { scheduleOnRN } from 'react-native-worklets';
9
9
  import { clamp } from "../../utils/numbers.js";
10
10
  import { useCartesianChartContext } from "../CartesianChart/context/index.js";
@@ -12,7 +12,11 @@ import { useMagneticSnapshot } from "../Point/pointContext/index.js";
12
12
  import { ScrubberContextProvider } from "./context/index.js";
13
13
  import { applyMagnetisation, getDataIndexFromPosition, resolvePixelX, buildSortedMagnets } from "./utils.js";
14
14
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
- const LONG_PRESS_MIN_DURATION_MS = 50;
15
+ const LONG_PRESS_MIN_DURATION_MS = 100;
16
+
17
+ // Travel (px) past which a horizontal drag scrubs and a vertical drag fails
18
+ // the pan (yielding to an ancestor scroll view). Also bounds the long press.
19
+ const PAN_AXIS_THRESHOLD_PX = 10;
16
20
 
17
21
  /**
18
22
  * Provides scrubbing interaction for a chart.
@@ -22,10 +26,9 @@ const LONG_PRESS_MIN_DURATION_MS = 50;
22
26
  * gesture-capture `View` overlay). `CartesianChart` handles this positioning
23
27
  * automatically when `enableScrubbing` is true.
24
28
  *
25
- * Activation requires a 50 ms long press before panning begins. This prevents
26
- * accidental scrubbing when the user is scrolling a parent `ScrollView` or
27
- * `FlatList`. The `isScrubbing` shared value gates the pan via manual activation
28
- * so scroll and scrub gestures never compete.
29
+ * Scrubbing engages on horizontal panning (`activeOffsetX`) or a press-and-hold
30
+ * (`LongPress`); vertical movement fails the pan (`failOffsetY`) so an ancestor
31
+ * vertical scroll view keeps scrolling.
29
32
  */
30
33
  export function ScrubberProvider({
31
34
  children,
@@ -47,11 +50,9 @@ export function ScrubberProvider({
47
50
  version
48
51
  } = useMagneticSnapshot();
49
52
 
50
- // All values touched by the gesture's JS-thread callback live in a single
51
- // ref. Reading via `latest.current` keeps the callbacks reference-stable
52
- // across data, scale, and prop updates, which in turn keeps `composed` and
53
- // the gesture surface JSX stable so re-rendering the provider on each
54
- // index change never tears down the GestureDetector or the View tree.
53
+ // Gesture callbacks read everything through this ref so they stay
54
+ // reference-stable, keeping `composed` and the surface JSX from re-creating
55
+ // (which would tear down the GestureDetector) on each index change.
55
56
  const sortedMagnets = useMemo(() => {
56
57
  const magneticIndices = getMagneticPoints();
57
58
  return buildSortedMagnets({
@@ -109,36 +110,27 @@ export function ScrubberProvider({
109
110
  }
110
111
  setScrubberPositionAndNotify(index);
111
112
  }, [setScrubberPositionAndNotify]);
112
- const isScrubbing = useSharedValue(false);
113
113
  const resetScrubber = useCallback(() => {
114
114
  'worklet';
115
115
 
116
- isScrubbing.value = false;
117
116
  scheduleOnRN(handlePositionChange, null);
118
- }, [isScrubbing, handlePositionChange]);
117
+ }, [handlePositionChange]);
119
118
  const composed = useMemo(() => {
120
- const longPress = Gesture.LongPress().minDuration(LONG_PRESS_MIN_DURATION_MS).onStart(e => {
119
+ const longPress = Gesture.LongPress().minDuration(LONG_PRESS_MIN_DURATION_MS).maxDistance(PAN_AXIS_THRESHOLD_PX).onStart(e => {
121
120
  'worklet';
122
121
 
123
- isScrubbing.value = true;
124
122
  scheduleOnRN(handlePositionChange, e.x);
125
- });
126
- const pan = Gesture.Pan().manualActivation(true).onTouchesMove((_, manager) => {
127
- 'worklet';
128
-
129
- if (isScrubbing.value) manager.activate();
130
- }).onUpdate(e => {
123
+ }).onEnd(resetScrubber);
124
+ const pan = Gesture.Pan().activeOffsetX([-PAN_AXIS_THRESHOLD_PX, PAN_AXIS_THRESHOLD_PX]).failOffsetY([-PAN_AXIS_THRESHOLD_PX, PAN_AXIS_THRESHOLD_PX]).onUpdate(e => {
131
125
  'worklet';
132
126
 
133
127
  scheduleOnRN(handlePositionChange, e.x);
134
- }).onEnd(resetScrubber).onFinalize(resetScrubber);
128
+ }).onFinalize(resetScrubber);
135
129
  return Gesture.Simultaneous(longPress, pan);
136
- }, [isScrubbing, handlePositionChange, resetScrubber]);
130
+ }, [handlePositionChange, resetScrubber]);
137
131
 
138
- // Memoizing the surface lets React's element-identity bailout skip
139
- // reconciling the View / GestureDetector / chart `children` subtree when
140
- // only `scrubberPosition` changes. The Scrubber consumer still updates via
141
- // context as expected.
132
+ // Memoized so a `scrubberPosition` change doesn't re-render the chart
133
+ // subtree; the Scrubber still updates through context.
142
134
  const surface = useMemo(() => /*#__PURE__*/_jsxs(View, {
143
135
  style: [{
144
136
  width,
@@ -1 +1 @@
1
- {"version":3,"names":["triggerHapticFeedback","useCallback","useMemo","useRef","useState","StyleSheet","View","Gesture","GestureDetector","Animated","useSharedValue","scheduleOnRN","clamp","useCartesianChartContext","useMagneticSnapshot","ScrubberContextProvider","applyMagnetisation","getDataIndexFromPosition","resolvePixelX","buildSortedMagnets","jsx","_jsx","jsxs","_jsxs","LONG_PRESS_MIN_DURATION_MS","ScrubberProvider","children","width","height","enableScrubbing","onScrubberPositionChange","magnetRadius","style","scrubberPosition","setScrubberPosition","getXScale","getXAxisConfig","dataLength","getMagneticPoints","version","sortedMagnets","magneticIndices","getPixelForIndex","index","latest","onChange","lastIndex","undefined","current","handleHapticFeedback","ref","clamped","setScrubberPositionAndNotify","handlePositionChange","pixelX","scale","xAxisConfig","resolvedIndex","isScrubbing","resetScrubber","value","composed","longPress","LongPress","minDuration","onStart","e","x","pan","Pan","manualActivation","onTouchesMove","_","manager","activate","onUpdate","onEnd","onFinalize","Simultaneous","surface","gesture","testID","absoluteFill","contextValue"],"sourceRoot":"../../../../../src","sources":["lib/Components/Scrubber/ScrubberProvider.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["triggerHapticFeedback","useCallback","useMemo","useRef","useState","StyleSheet","View","Gesture","GestureDetector","Animated","scheduleOnRN","clamp","useCartesianChartContext","useMagneticSnapshot","ScrubberContextProvider","applyMagnetisation","getDataIndexFromPosition","resolvePixelX","buildSortedMagnets","jsx","_jsx","jsxs","_jsxs","LONG_PRESS_MIN_DURATION_MS","PAN_AXIS_THRESHOLD_PX","ScrubberProvider","children","width","height","enableScrubbing","onScrubberPositionChange","magnetRadius","style","scrubberPosition","setScrubberPosition","getXScale","getXAxisConfig","dataLength","getMagneticPoints","version","sortedMagnets","magneticIndices","getPixelForIndex","index","latest","onChange","lastIndex","undefined","current","handleHapticFeedback","ref","clamped","setScrubberPositionAndNotify","handlePositionChange","pixelX","scale","xAxisConfig","resolvedIndex","resetScrubber","composed","longPress","LongPress","minDuration","maxDistance","onStart","e","x","onEnd","pan","Pan","activeOffsetX","failOffsetY","onUpdate","onFinalize","Simultaneous","surface","gesture","testID","absoluteFill","contextValue","value"],"sourceRoot":"../../../../../src","sources":["lib/Components/Scrubber/ScrubberProvider.tsx"],"mappings":"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","ignoreList":[]}
@@ -7,10 +7,9 @@ import type { ScrubberProviderProps } from './types';
7
7
  * gesture-capture `View` overlay). `CartesianChart` handles this positioning
8
8
  * automatically when `enableScrubbing` is true.
9
9
  *
10
- * Activation requires a 50 ms long press before panning begins. This prevents
11
- * accidental scrubbing when the user is scrolling a parent `ScrollView` or
12
- * `FlatList`. The `isScrubbing` shared value gates the pan via manual activation
13
- * so scroll and scrub gestures never compete.
10
+ * Scrubbing engages on horizontal panning (`activeOffsetX`) or a press-and-hold
11
+ * (`LongPress`); vertical movement fails the pan (`failOffsetY`) so an ancestor
12
+ * vertical scroll view keeps scrolling.
14
13
  */
15
14
  export declare function ScrubberProvider({ children, width, height, enableScrubbing, onScrubberPositionChange, magnetRadius, style, }: Readonly<ScrubberProviderProps>): import("react/jsx-runtime").JSX.Element;
16
15
  //# sourceMappingURL=ScrubberProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ScrubberProvider.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/Components/Scrubber/ScrubberProvider.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAUrD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,KAAK,EACL,MAAM,EACN,eAAe,EACf,wBAAwB,EACxB,YAAgB,EAChB,KAAK,GACN,EAAE,QAAQ,CAAC,qBAAqB,CAAC,2CAwKjC"}
1
+ {"version":3,"file":"ScrubberProvider.d.ts","sourceRoot":"","sources":["../../../../../../src/lib/Components/Scrubber/ScrubberProvider.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAcrD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,KAAK,EACL,MAAM,EACN,eAAe,EACf,wBAAwB,EACxB,YAAgB,EAChB,KAAK,GACN,EAAE,QAAQ,CAAC,qBAAqB,CAAC,2CA8JjC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/lumen-ui-rnative-visualization",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "keywords": [
@@ -31,7 +31,7 @@
31
31
  "!**/*.tsbuildinfo"
32
32
  ],
33
33
  "dependencies": {
34
- "@ledgerhq/lumen-utils-shared": "0.1.6",
34
+ "@ledgerhq/lumen-utils-shared": "0.1.8",
35
35
  "d3-array": "^3.2.4",
36
36
  "d3-scale": "^4.0.2",
37
37
  "d3-shape": "^3.2.0"
@@ -44,8 +44,8 @@
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@types/react": "^19.0.0",
47
- "@ledgerhq/lumen-design-core": "0.1.18",
48
- "@ledgerhq/lumen-ui-rnative": "0.1.47",
47
+ "@ledgerhq/lumen-design-core": "0.1.20",
48
+ "@ledgerhq/lumen-ui-rnative": "0.1.49",
49
49
  "react": "^19.0.0",
50
50
  "react-native": "~0.81.6",
51
51
  "react-native-svg": "^15.0.0",
@@ -2,7 +2,7 @@ import { triggerHapticFeedback } from '@ledgerhq/lumen-ui-rnative';
2
2
  import { useCallback, useMemo, useRef, useState } from 'react';
3
3
  import { StyleSheet, View } from 'react-native';
4
4
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
5
- import Animated, { useSharedValue } from 'react-native-reanimated';
5
+ import Animated from 'react-native-reanimated';
6
6
  import { scheduleOnRN } from 'react-native-worklets';
7
7
 
8
8
  import { clamp } from '../../utils/numbers';
@@ -17,7 +17,11 @@ import {
17
17
  buildSortedMagnets,
18
18
  } from './utils';
19
19
 
20
- const LONG_PRESS_MIN_DURATION_MS = 50;
20
+ const LONG_PRESS_MIN_DURATION_MS = 100;
21
+
22
+ // Travel (px) past which a horizontal drag scrubs and a vertical drag fails
23
+ // the pan (yielding to an ancestor scroll view). Also bounds the long press.
24
+ const PAN_AXIS_THRESHOLD_PX = 10;
21
25
 
22
26
  /**
23
27
  * Provides scrubbing interaction for a chart.
@@ -27,10 +31,9 @@ const LONG_PRESS_MIN_DURATION_MS = 50;
27
31
  * gesture-capture `View` overlay). `CartesianChart` handles this positioning
28
32
  * automatically when `enableScrubbing` is true.
29
33
  *
30
- * Activation requires a 50 ms long press before panning begins. This prevents
31
- * accidental scrubbing when the user is scrolling a parent `ScrollView` or
32
- * `FlatList`. The `isScrubbing` shared value gates the pan via manual activation
33
- * so scroll and scrub gestures never compete.
34
+ * Scrubbing engages on horizontal panning (`activeOffsetX`) or a press-and-hold
35
+ * (`LongPress`); vertical movement fails the pan (`failOffsetY`) so an ancestor
36
+ * vertical scroll view keeps scrolling.
34
37
  */
35
38
  export function ScrubberProvider({
36
39
  children,
@@ -48,11 +51,9 @@ export function ScrubberProvider({
48
51
  const { getXScale, getXAxisConfig, dataLength } = useCartesianChartContext();
49
52
  const { getMagneticPoints, version } = useMagneticSnapshot();
50
53
 
51
- // All values touched by the gesture's JS-thread callback live in a single
52
- // ref. Reading via `latest.current` keeps the callbacks reference-stable
53
- // across data, scale, and prop updates, which in turn keeps `composed` and
54
- // the gesture surface JSX stable so re-rendering the provider on each
55
- // index change never tears down the GestureDetector or the View tree.
54
+ // Gesture callbacks read everything through this ref so they stay
55
+ // reference-stable, keeping `composed` and the surface JSX from re-creating
56
+ // (which would tear down the GestureDetector) on each index change.
56
57
  const sortedMagnets = useMemo(() => {
57
58
  const magneticIndices = getMagneticPoints();
58
59
  return buildSortedMagnets({
@@ -140,43 +141,35 @@ export function ScrubberProvider({
140
141
  [setScrubberPositionAndNotify],
141
142
  );
142
143
 
143
- const isScrubbing = useSharedValue(false);
144
-
145
144
  const resetScrubber = useCallback((): void => {
146
145
  'worklet';
147
- isScrubbing.value = false;
148
146
  scheduleOnRN(handlePositionChange, null);
149
- }, [isScrubbing, handlePositionChange]);
147
+ }, [handlePositionChange]);
150
148
 
151
149
  const composed = useMemo(() => {
152
150
  const longPress = Gesture.LongPress()
153
151
  .minDuration(LONG_PRESS_MIN_DURATION_MS)
152
+ .maxDistance(PAN_AXIS_THRESHOLD_PX)
154
153
  .onStart((e) => {
155
154
  'worklet';
156
- isScrubbing.value = true;
157
155
  scheduleOnRN(handlePositionChange, e.x);
158
- });
156
+ })
157
+ .onEnd(resetScrubber);
159
158
 
160
159
  const pan = Gesture.Pan()
161
- .manualActivation(true)
162
- .onTouchesMove((_, manager) => {
163
- 'worklet';
164
- if (isScrubbing.value) manager.activate();
165
- })
160
+ .activeOffsetX([-PAN_AXIS_THRESHOLD_PX, PAN_AXIS_THRESHOLD_PX])
161
+ .failOffsetY([-PAN_AXIS_THRESHOLD_PX, PAN_AXIS_THRESHOLD_PX])
166
162
  .onUpdate((e) => {
167
163
  'worklet';
168
164
  scheduleOnRN(handlePositionChange, e.x);
169
165
  })
170
- .onEnd(resetScrubber)
171
166
  .onFinalize(resetScrubber);
172
167
 
173
168
  return Gesture.Simultaneous(longPress, pan);
174
- }, [isScrubbing, handlePositionChange, resetScrubber]);
169
+ }, [handlePositionChange, resetScrubber]);
175
170
 
176
- // Memoizing the surface lets React's element-identity bailout skip
177
- // reconciling the View / GestureDetector / chart `children` subtree when
178
- // only `scrubberPosition` changes. The Scrubber consumer still updates via
179
- // context as expected.
171
+ // Memoized so a `scrubberPosition` change doesn't re-render the chart
172
+ // subtree; the Scrubber still updates through context.
180
173
  const surface = useMemo(
181
174
  () => (
182
175
  <View style={[{ width, height }, style]}>