@ledgerhq/lumen-ui-rnative-visualization 0.1.24 → 0.1.25
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/dist/module/lib/Components/Scrubber/ScrubberProvider.js +20 -28
- package/dist/module/lib/Components/Scrubber/ScrubberProvider.js.map +1 -1
- package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts +3 -4
- package/dist/typescript/src/lib/Components/Scrubber/ScrubberProvider.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/lib/Components/Scrubber/ScrubberProvider.tsx +21 -28
|
@@ -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
|
|
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 =
|
|
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
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
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
|
-
}, [
|
|
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().
|
|
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
|
-
}).
|
|
128
|
+
}).onFinalize(resetScrubber);
|
|
135
129
|
return Gesture.Simultaneous(longPress, pan);
|
|
136
|
-
}, [
|
|
130
|
+
}, [handlePositionChange, resetScrubber]);
|
|
137
131
|
|
|
138
|
-
//
|
|
139
|
-
//
|
|
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","
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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;
|
|
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.
|
|
3
|
+
"version": "0.1.25",
|
|
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.
|
|
34
|
+
"@ledgerhq/lumen-utils-shared": "0.1.7",
|
|
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.
|
|
48
|
-
"@ledgerhq/lumen-ui-rnative": "0.1.
|
|
47
|
+
"@ledgerhq/lumen-design-core": "0.1.19",
|
|
48
|
+
"@ledgerhq/lumen-ui-rnative": "0.1.48",
|
|
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
|
|
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 =
|
|
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
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
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
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
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
|
-
}, [
|
|
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
|
-
.
|
|
162
|
-
.
|
|
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
|
-
}, [
|
|
169
|
+
}, [handlePositionChange, resetScrubber]);
|
|
175
170
|
|
|
176
|
-
//
|
|
177
|
-
//
|
|
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]}>
|