@gryt/ui-native 0.6.0 → 0.7.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/dist/components/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.js +147 -111
- package/dist/components/ScrollArea/ScrollArea.d.ts +10 -5
- package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.js +11 -19
- package/dist/components/Slider/Slider.d.ts +17 -6
- package/dist/components/Slider/Slider.d.ts.map +1 -1
- package/dist/components/Slider/Slider.js +100 -101
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/package.json +1 -1
- package/dist/components/internal/dragLock.d.ts +0 -43
- package/dist/components/internal/dragLock.d.ts.map +0 -1
- package/dist/components/internal/dragLock.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../../src/components/Drawer/Drawer.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../../src/components/Drawer/Drawer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,OAAO,CAAC;AACf,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAYtB,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG/E,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;AAgBrD,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,iBAAS,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAE,EAAE,eAAe,+BAKxD;AAED,iBAAS,OAAO,CAAC,EACf,QAAQ,EACR,KAAK,EACN,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,+BAWA;AAED,iBAAS,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,+BAErD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAgBD,iBAAS,KAAK,CAAC,EACb,QAAQ,EACR,IAAa,EACb,IAAU,EACV,WAAkB,EAClB,KAAK,EACN,EAAE,gBAAgB,+BA0UlB;AAED,iBAAS,KAAK,CAAC,EACb,QAAQ,EACR,KAAK,EACN,EAAE;IACD,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,+BAWA;AAED,eAAO,MAAM,MAAM;;;;;;CAA0C,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useContext, useEffect,
|
|
3
|
-
import { Dimensions,
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { Dimensions, Modal, Pressable } from "react-native";
|
|
4
|
+
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
4
5
|
import Animated, { runOnJS, useAnimatedStyle, useSharedValue } from "react-native-reanimated";
|
|
5
6
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
6
7
|
import { useReducedMotion } from "../../hooks/useReducedMotion.js";
|
|
@@ -79,7 +80,11 @@ function Popup({ children, side = "left", size = 0.8, dismissible = true, style
|
|
|
79
80
|
const panelExtent = extent + bleed;
|
|
80
81
|
// Measured against the bleed panel, so the panel's *visible* edge lands
|
|
81
82
|
// exactly off-screen rather than the overhang doing it.
|
|
82
|
-
const hidden = side === "right"
|
|
83
|
+
const hidden = side === "right"
|
|
84
|
+
? panelExtent
|
|
85
|
+
: side === "left"
|
|
86
|
+
? -panelExtent
|
|
87
|
+
: panelExtent;
|
|
83
88
|
/**
|
|
84
89
|
* 700ms on the *tight* curve, and this changed on both platforms at once.
|
|
85
90
|
*
|
|
@@ -150,141 +155,172 @@ function Popup({ children, side = "left", size = 0.8, dismissible = true, style
|
|
|
150
155
|
};
|
|
151
156
|
});
|
|
152
157
|
/**
|
|
153
|
-
* The scrim
|
|
158
|
+
* The scrim fades with the panel, and thins further as it is dragged away.
|
|
154
159
|
*
|
|
155
|
-
*
|
|
156
|
-
* distinction from a dialog, and a scrim that fades up alongside the panel
|
|
157
|
-
* puts a second, slower animation on top of the one that matters. It is up
|
|
158
|
-
* when the drawer is up.
|
|
160
|
+
* Two separate rules, both the web's:
|
|
159
161
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
162
|
+
* ```
|
|
163
|
+
* "[opacity:calc(1-var(--drawer-swipe-progress,0))]",
|
|
164
|
+
* "transition-opacity duration-(--gryt-dur-spring-soft) ease-spring-tight",
|
|
165
|
+
* "data-starting-style:opacity-0 data-ending-style:opacity-0",
|
|
166
|
+
* ```
|
|
163
167
|
*
|
|
164
|
-
* The
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* the
|
|
168
|
+
* The first is the drag term. The other two are the fade: the backdrop
|
|
169
|
+
* starts and ends at zero, over the same duration and easing as the panel's
|
|
170
|
+
* slide. `progress` already runs on `travel`, which is `easeSpringTight` at
|
|
171
|
+
* `springSoft` — so multiplying by it is the same curve, not a new one.
|
|
172
|
+
*
|
|
173
|
+
* GRYT-408 took the fade out, on the grounds that "the web's Popup declares
|
|
174
|
+
* `transition-transform` and nothing else". That is true, and it is about
|
|
175
|
+
* `Drawer.Popup` — the panel, which still only translates. The backdrop is a
|
|
176
|
+
* different element and says the opposite. Without the fade the scrim was at
|
|
177
|
+
* full strength before the panel was on screen and stayed there while it slid
|
|
178
|
+
* away, then blinked off with the Modal.
|
|
170
179
|
*/
|
|
171
180
|
const scrimStyle = useAnimatedStyle(() => {
|
|
172
181
|
const dragged = extent > 0 ? Math.min(1, Math.abs(drag.value) / extent) : 0;
|
|
173
|
-
return { opacity: 1 - dragged };
|
|
182
|
+
return { opacity: progress.value * (1 - dragged) };
|
|
174
183
|
});
|
|
175
184
|
/**
|
|
176
185
|
* Swipe to dismiss, which the web has had from Base UI's drawer primitive
|
|
177
186
|
* and this did not have at all (GRYT-395). A drawer you cannot push back is
|
|
178
187
|
* the thing a drawer is for.
|
|
179
188
|
*
|
|
180
|
-
* `
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
189
|
+
* `react-native-gesture-handler` rather than `PanResponder`. That was the
|
|
190
|
+
* other way round because gesture callbacks from this package's prebuilt
|
|
191
|
+
* output were measured doing nothing (GRYT-393) — the babel plugin was not
|
|
192
|
+
* reaching `node_modules`, so nothing became a worklet. Measured again on
|
|
193
|
+
* 2026-08-21 with a probe built inside this package: both worklet and
|
|
194
|
+
* `runOnJS` callbacks report correctly. Whatever it was, it is fixed, and
|
|
195
|
+
* `PanResponder` was only ever the fallback.
|
|
196
|
+
*
|
|
197
|
+
* The reason to move is what the axis constraints below buy. `PanResponder`
|
|
198
|
+
* cannot negotiate with a native scroll recogniser, so the old version kept
|
|
199
|
+
* the drag with `onPanResponderTerminationRequest: () => false` — which
|
|
200
|
+
* works by never handing the gesture back, and stops a `ScrollView` inside
|
|
201
|
+
* the drawer scrolling at all. Here the pan simply fails on a cross-axis
|
|
202
|
+
* drag and the scrollable gets it, which is the same rule the web relies on
|
|
203
|
+
* the browser for.
|
|
204
|
+
*
|
|
205
|
+
* The callbacks stay worklets. Running them on the JS thread would be
|
|
206
|
+
* simpler and would give up the whole point: the panel tracks the finger on
|
|
207
|
+
* the UI thread, with nothing to be blocked by a busy bridge.
|
|
184
208
|
*/
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
gesture
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
},
|
|
205
|
-
// Once it is ours it stays ours, for the same reason the Slider needs
|
|
206
|
-
// this: the default is to grant, and a ScrollView inside the drawer
|
|
207
|
-
// would take the drag back mid-swipe.
|
|
208
|
-
onPanResponderTerminationRequest: () => false,
|
|
209
|
-
onPanResponderMove: (_e, g) => {
|
|
210
|
-
const { vertical: v, side: sd } = gesture.current;
|
|
211
|
-
const raw = v ? g.dy : g.dx;
|
|
209
|
+
const pan = useMemo(() => {
|
|
210
|
+
const closingSign = side === "left" ? -1 : 1;
|
|
211
|
+
const gesture = Gesture.Pan().enabled(dismissible);
|
|
212
|
+
/* Claim only a drag heading the way the panel closes, and only once it is
|
|
213
|
+
* clearly a drag rather than a slow press — 8pt, the same threshold the
|
|
214
|
+
* old responder used. `failOffset` on the other axis is the half that
|
|
215
|
+
* `PanResponder` had no answer for: a finger moving across the panel is
|
|
216
|
+
* somebody scrolling its contents, and this hands that over rather than
|
|
217
|
+
* swallowing it. */
|
|
218
|
+
if (vertical) {
|
|
219
|
+
gesture.activeOffsetY(8).failOffsetX([-12, 12]);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
gesture.activeOffsetX(closingSign * 8).failOffsetY([-12, 12]);
|
|
223
|
+
}
|
|
224
|
+
return gesture
|
|
225
|
+
.onUpdate((event) => {
|
|
226
|
+
"worklet";
|
|
227
|
+
const raw = vertical ? event.translationY : event.translationX;
|
|
212
228
|
// Clamped to the closing direction. Dragging a left drawer rightwards
|
|
213
229
|
// should do nothing, not tear it off its edge.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
drag.value = closingSign < 0 ? Math.min(0, raw) : Math.max(0, raw);
|
|
231
|
+
})
|
|
232
|
+
.onEnd((event) => {
|
|
233
|
+
"worklet";
|
|
234
|
+
const moved = Math.abs(vertical ? event.translationY : event.translationX);
|
|
235
|
+
const speed = Math.abs(vertical ? event.velocityY : event.velocityX);
|
|
236
|
+
/* Half the panel, or a flick. The velocity term is what makes a short
|
|
237
|
+
* sharp swipe work — without it you have to drag the whole way, which
|
|
238
|
+
* is the difference between a drawer and a slow puzzle.
|
|
239
|
+
*
|
|
240
|
+
* Gesture-handler reports velocity in points per second where
|
|
241
|
+
* `PanResponder` reported points per millisecond, so the old `0.5`
|
|
242
|
+
* became 500. Same gesture, different unit — worth stating, because
|
|
243
|
+
* carrying the number across unchanged would have made a flick need to
|
|
244
|
+
* be a thousand times faster and looked like the velocity term simply
|
|
245
|
+
* not working.
|
|
246
|
+
*/
|
|
247
|
+
if (moved > extent / 2 || speed > 500) {
|
|
248
|
+
// Left where it is: the close animation runs from here, and snapping
|
|
249
|
+
// it back first would show the panel returning before it left.
|
|
250
|
+
runOnJS(setOpen)(false);
|
|
230
251
|
return;
|
|
231
252
|
}
|
|
232
|
-
// eslint-disable-next-line react-hooks/immutability
|
|
233
253
|
drag.value = travelTo(0, { duration: durations.springSoft });
|
|
234
|
-
}
|
|
235
|
-
|
|
254
|
+
})
|
|
255
|
+
.onFinalize((_event, success) => {
|
|
256
|
+
"worklet";
|
|
257
|
+
// A gesture cancelled by the system — an incoming call, a parent
|
|
258
|
+
// taking over — leaves the panel wherever the finger was.
|
|
259
|
+
if (!success)
|
|
260
|
+
drag.value = travelTo(0, { duration: durations.springSoft });
|
|
261
|
+
});
|
|
262
|
+
}, [dismissible, drag, extent, setOpen, side, vertical]);
|
|
263
|
+
/**
|
|
264
|
+
* Any leftover drag goes back as the panel opens, and is cleared once it is
|
|
265
|
+
* gone.
|
|
266
|
+
*
|
|
267
|
+
* Two moments, deliberately. Clearing on `open` going false was wrong: that
|
|
268
|
+
* happens the instant a swipe dismisses, so the panel jumped back to fully
|
|
269
|
+
* open and then slid out — exactly what the release handler above says must
|
|
270
|
+
* not happen (GRYT-429). `mounted` is the moment the panel is actually off
|
|
271
|
+
* screen, where a hard reset costs nothing to look at.
|
|
272
|
+
*/
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
if (open) {
|
|
236
275
|
// eslint-disable-next-line react-hooks/immutability
|
|
237
276
|
drag.value = travelTo(0, { duration: durations.springSoft });
|
|
238
277
|
}
|
|
239
|
-
})
|
|
240
|
-
/* eslint-enable react-hooks/refs */
|
|
241
|
-
// Cleared once the panel is closed, so the next open does not start from
|
|
242
|
-
// wherever the last swipe left it.
|
|
278
|
+
}, [open, drag]);
|
|
243
279
|
useEffect(() => {
|
|
244
|
-
if (!
|
|
280
|
+
if (!mounted) {
|
|
245
281
|
// eslint-disable-next-line react-hooks/immutability
|
|
246
282
|
drag.value = 0;
|
|
247
283
|
}
|
|
248
|
-
}, [
|
|
249
|
-
return (_jsx(Modal, { visible: mounted, transparent: true, animationType: "none", onRequestClose: dismissible ? () => setOpen(false) : undefined, children: _jsx(AnimatedPressable, { onPress: dismissible ? () => setOpen(false) : undefined, style: [{ flex: 1, backgroundColor: "rgba(0,0,0,0.6)" }, scrimStyle], children: _jsx(Animated.View, { accessibilityViewIsModal: true,
|
|
250
|
-
{
|
|
251
|
-
position: "absolute",
|
|
252
|
-
// The overhang hangs *off* the edge the panel comes from, which
|
|
253
|
-
// is the only direction that helps. It used to be added to the
|
|
254
|
-
// width instead, so the panel grew inwards — 64pt more of the
|
|
255
|
-
// screen covered, and the seam it was meant to hide still there,
|
|
256
|
-
// because the gap opens on the entering edge and that is the edge
|
|
257
|
-
// the extra material was not on.
|
|
258
|
-
top: side === "bottom" ? undefined : 0,
|
|
259
|
-
bottom: vertical ? -bleed : 0,
|
|
260
|
-
left: side === "right" ? undefined : side === "left" ? -bleed : 0,
|
|
261
|
-
right: side === "left" ? undefined : side === "right" ? -bleed : 0,
|
|
262
|
-
width: vertical ? "100%" : panelExtent,
|
|
263
|
-
height: vertical ? panelExtent : "100%",
|
|
264
|
-
// Puts the content back where it would have been without the
|
|
265
|
-
// overhang, so `size` still means what it says.
|
|
266
|
-
paddingLeft: side === "left" ? bleed : 0,
|
|
267
|
-
paddingRight: side === "right" ? bleed : 0,
|
|
268
|
-
paddingBottom: vertical ? bleed : 0,
|
|
269
|
-
backgroundColor: theme.color.surface,
|
|
270
|
-
borderColor: theme.color.border,
|
|
271
|
-
borderRightWidth: side === "left" ? 1 : 0,
|
|
272
|
-
borderLeftWidth: side === "right" ? 1 : 0,
|
|
273
|
-
borderTopWidth: vertical ? 1 : 0,
|
|
274
|
-
borderTopLeftRadius: vertical ? theme.radius.lg : 0,
|
|
275
|
-
borderTopRightRadius: vertical ? theme.radius.lg : 0
|
|
276
|
-
},
|
|
277
|
-
panelStyle
|
|
278
|
-
], children: _jsx(Pressable, { onPress: () => { }, style: [
|
|
284
|
+
}, [mounted, drag]);
|
|
285
|
+
return (_jsx(Modal, { visible: mounted, transparent: true, animationType: "none", onRequestClose: dismissible ? () => setOpen(false) : undefined, children: _jsx(AnimatedPressable, { onPress: dismissible ? () => setOpen(false) : undefined, style: [{ flex: 1, backgroundColor: "rgba(0,0,0,0.6)" }, scrimStyle], children: _jsx(GestureDetector, { gesture: pan, children: _jsx(Animated.View, { accessibilityViewIsModal: true, style: [
|
|
279
286
|
{
|
|
280
|
-
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
|
|
287
|
+
position: "absolute",
|
|
288
|
+
// The overhang hangs *off* the edge the panel comes from, which
|
|
289
|
+
// is the only direction that helps. It used to be added to the
|
|
290
|
+
// width instead, so the panel grew inwards — 64pt more of the
|
|
291
|
+
// screen covered, and the seam it was meant to hide still there,
|
|
292
|
+
// because the gap opens on the entering edge and that is the edge
|
|
293
|
+
// the extra material was not on.
|
|
294
|
+
top: side === "bottom" ? undefined : 0,
|
|
295
|
+
bottom: vertical ? -bleed : 0,
|
|
296
|
+
left: side === "right" ? undefined : side === "left" ? -bleed : 0,
|
|
297
|
+
right: side === "left" ? undefined : side === "right" ? -bleed : 0,
|
|
298
|
+
width: vertical ? "100%" : panelExtent,
|
|
299
|
+
height: vertical ? panelExtent : "100%",
|
|
300
|
+
// Puts the content back where it would have been without the
|
|
301
|
+
// overhang, so `size` still means what it says.
|
|
302
|
+
paddingLeft: side === "left" ? bleed : 0,
|
|
303
|
+
paddingRight: side === "right" ? bleed : 0,
|
|
304
|
+
paddingBottom: vertical ? bleed : 0,
|
|
305
|
+
backgroundColor: theme.color.surface,
|
|
306
|
+
borderColor: theme.color.border,
|
|
307
|
+
borderRightWidth: side === "left" ? 1 : 0,
|
|
308
|
+
borderLeftWidth: side === "right" ? 1 : 0,
|
|
309
|
+
borderTopWidth: vertical ? 1 : 0,
|
|
310
|
+
borderTopLeftRadius: vertical ? theme.radius.lg : 0,
|
|
311
|
+
borderTopRightRadius: vertical ? theme.radius.lg : 0
|
|
285
312
|
},
|
|
286
|
-
|
|
287
|
-
], children:
|
|
313
|
+
panelStyle
|
|
314
|
+
], children: _jsx(Pressable, { onPress: () => { }, style: [
|
|
315
|
+
{
|
|
316
|
+
flex: 1,
|
|
317
|
+
// Before the caller's style, so a drawer that wants to run
|
|
318
|
+
// under the island — a full-bleed image, say — still can.
|
|
319
|
+
paddingTop: vertical ? 0 : insets.top,
|
|
320
|
+
paddingBottom: insets.bottom
|
|
321
|
+
},
|
|
322
|
+
style
|
|
323
|
+
], children: children }) }) }) }) }));
|
|
288
324
|
}
|
|
289
325
|
function Close({ children, style }) {
|
|
290
326
|
const { setOpen } = useDrawer("Close");
|
|
@@ -15,10 +15,15 @@ export interface ScrollAreaProps extends Omit<ScrollViewProps, "style"> {
|
|
|
15
15
|
* device. So the component stays for call-site parity and does almost nothing,
|
|
16
16
|
* which is the honest version.
|
|
17
17
|
*
|
|
18
|
-
* Its one job
|
|
19
|
-
* native scrollbar too.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Its one job is defaulting the indicator off, since the web version hides the
|
|
19
|
+
* native scrollbar too.
|
|
20
|
+
*
|
|
21
|
+
* It used to have a second: publishing a drag lock that a Slider could claim to
|
|
22
|
+
* switch this list off for the duration of a drag. That existed because
|
|
23
|
+
* `PanResponder` could not tell the native scroll recogniser anything, so the
|
|
24
|
+
* only way to stop the list moving under a slider was to disable it. The Slider
|
|
25
|
+
* declares `activeOffsetX` now and the two gestures settle it between them, so
|
|
26
|
+
* there is nothing to hold still and nothing to leak if a drag is interrupted.
|
|
22
27
|
*/
|
|
23
|
-
export declare function ScrollArea({ children, horizontal, style, contentStyle, showsVerticalScrollIndicator, showsHorizontalScrollIndicator,
|
|
28
|
+
export declare function ScrollArea({ children, horizontal, style, contentStyle, showsVerticalScrollIndicator, showsHorizontalScrollIndicator, ...rest }: ScrollAreaProps): import("react").JSX.Element;
|
|
24
29
|
//# sourceMappingURL=ScrollArea.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollArea.d.ts","sourceRoot":"","sources":["../../../src/components/ScrollArea/ScrollArea.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ScrollArea.d.ts","sourceRoot":"","sources":["../../../src/components/ScrollArea/ScrollArea.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAc,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEhG,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,UAAkB,EAClB,KAAK,EACL,YAAY,EACZ,4BAAoC,EACpC,8BAAsC,EACtC,GAAG,IAAI,EACR,EAAE,eAAe,+BAajB"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useMemo, useState } from "react";
|
|
3
2
|
import { ScrollView } from "react-native";
|
|
4
|
-
import { DragLockContext } from "../internal/dragLock.js";
|
|
5
3
|
/**
|
|
6
4
|
* A thin pass over ScrollView.
|
|
7
5
|
*
|
|
@@ -11,22 +9,16 @@ import { DragLockContext } from "../internal/dragLock.js";
|
|
|
11
9
|
* device. So the component stays for call-site parity and does almost nothing,
|
|
12
10
|
* which is the honest version.
|
|
13
11
|
*
|
|
14
|
-
* Its one job
|
|
15
|
-
* native scrollbar too.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
12
|
+
* Its one job is defaulting the indicator off, since the web version hides the
|
|
13
|
+
* native scrollbar too.
|
|
14
|
+
*
|
|
15
|
+
* It used to have a second: publishing a drag lock that a Slider could claim to
|
|
16
|
+
* switch this list off for the duration of a drag. That existed because
|
|
17
|
+
* `PanResponder` could not tell the native scroll recogniser anything, so the
|
|
18
|
+
* only way to stop the list moving under a slider was to disable it. The Slider
|
|
19
|
+
* declares `activeOffsetX` now and the two gestures settle it between them, so
|
|
20
|
+
* there is nothing to hold still and nothing to leak if a drag is interrupted.
|
|
18
21
|
*/
|
|
19
|
-
export function ScrollArea({ children, horizontal = false, style, contentStyle, showsVerticalScrollIndicator = false, showsHorizontalScrollIndicator = false,
|
|
20
|
-
|
|
21
|
-
// Counted rather than a boolean. Two controls can overlap in principle — a
|
|
22
|
-
// drag interrupted by a second one starting — and the first to finish would
|
|
23
|
-
// otherwise unlock the list while the second is still going.
|
|
24
|
-
const lock = useCallback(() => setLocks((n) => n + 1), []);
|
|
25
|
-
const unlock = useCallback(() => setLocks((n) => Math.max(0, n - 1)), []);
|
|
26
|
-
const dragLock = useMemo(() => ({ locked: locks > 0, lock, unlock }), [locks, lock, unlock]);
|
|
27
|
-
return (_jsx(DragLockContext.Provider, { value: dragLock, children: _jsx(ScrollView, { horizontal: horizontal, style: style, contentContainerStyle: contentStyle, showsVerticalScrollIndicator: showsVerticalScrollIndicator, showsHorizontalScrollIndicator: showsHorizontalScrollIndicator,
|
|
28
|
-
// Only overridden while something is actually dragging, so a caller
|
|
29
|
-
// that passes `scrollEnabled={false}` still gets a list that never
|
|
30
|
-
// scrolls.
|
|
31
|
-
scrollEnabled: scrollEnabled === false ? false : locks === 0, ...rest, children: children }) }));
|
|
22
|
+
export function ScrollArea({ children, horizontal = false, style, contentStyle, showsVerticalScrollIndicator = false, showsHorizontalScrollIndicator = false, ...rest }) {
|
|
23
|
+
return (_jsx(ScrollView, { horizontal: horizontal, style: style, contentContainerStyle: contentStyle, showsVerticalScrollIndicator: showsVerticalScrollIndicator, showsHorizontalScrollIndicator: showsHorizontalScrollIndicator, ...rest, children: children }));
|
|
32
24
|
}
|
|
@@ -18,12 +18,23 @@ export interface SliderProps {
|
|
|
18
18
|
/**
|
|
19
19
|
* Dragging, on a surface where a drag might belong to something else.
|
|
20
20
|
*
|
|
21
|
-
* The web gets pointer capture: once the thumb is grabbed, every move belongs
|
|
22
|
-
* the slider until release. React Native has no equivalent,
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* The web gets pointer capture: once the thumb is grabbed, every move belongs
|
|
22
|
+
* to the slider until release. React Native has no equivalent, and volume
|
|
23
|
+
* sliders live in settings lists, so a horizontal drag has to be told apart
|
|
24
|
+
* from the scroll it is sitting in.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
26
|
+
* `activeOffsetX` is that distinction, declared rather than fought over. The
|
|
27
|
+
* pan claims the gesture once the finger has clearly gone sideways, and a
|
|
28
|
+
* vertical drag never activates it at all, so the scroll view keeps it. That
|
|
29
|
+
* replaces `onPanResponderTerminationRequest: () => false` plus the `DragLock`
|
|
30
|
+
* that had to switch the scroll view off, because refusing to hand back a JS
|
|
31
|
+
* responder says nothing to the native recogniser that actually does the
|
|
32
|
+
* scrolling on iOS.
|
|
33
|
+
*
|
|
34
|
+
* Both gestures run on the JS thread. The Drawer's stay worklets because they
|
|
35
|
+
* only move a shared value; every callback here has to reach React state and
|
|
36
|
+
* the consumer's `onValueChange`, so the hop is happening either way and
|
|
37
|
+
* pretending otherwise would only add a way to get it wrong.
|
|
27
38
|
*/
|
|
28
|
-
export declare function Slider({ value: controlled, defaultValue, onValueChange, onValueCommit, min, max, step, disabled, tone, style, accessibilityLabel
|
|
39
|
+
export declare function Slider({ value: controlled, defaultValue, onValueChange, onValueCommit, min, max, step, disabled, tone, style, accessibilityLabel }: SliderProps): import("react").JSX.Element;
|
|
29
40
|
//# sourceMappingURL=Slider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/components/Slider/Slider.tsx"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/components/Slider/Slider.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAUtB,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGrE,MAAM,MAAM,UAAU,GAAG,OAAO,CAC9B,aAAa,EACb,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAC/C,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,+DAA+D;IAC/D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAKD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EAAE,UAAU,EACjB,YAAgB,EAChB,aAAa,EACb,aAAa,EACb,GAAO,EACP,GAAS,EACT,IAAQ,EACR,QAAQ,EACR,IAAgB,EAChB,KAAK,EACL,kBAAkB,EACnB,EAAE,WAAW,+BA4Jb"}
|
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import {
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
4
5
|
import Animated, { useAnimatedStyle, useSharedValue } from "react-native-reanimated";
|
|
5
6
|
import { grytScaleSteps } from "@gryt/theme";
|
|
6
7
|
import { springy } from "../../motion/index.js";
|
|
7
8
|
import { toneRamp, useTheme } from "../../theme/index.js";
|
|
8
|
-
import { useDragLock } from "../internal/dragLock.js";
|
|
9
9
|
import { valueAt } from "./sliderValue.js";
|
|
10
10
|
const TRACK_HEIGHT = 4;
|
|
11
11
|
const THUMB = 20;
|
|
12
12
|
/**
|
|
13
13
|
* Dragging, on a surface where a drag might belong to something else.
|
|
14
14
|
*
|
|
15
|
-
* The web gets pointer capture: once the thumb is grabbed, every move belongs
|
|
16
|
-
* the slider until release. React Native has no equivalent,
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* The web gets pointer capture: once the thumb is grabbed, every move belongs
|
|
16
|
+
* to the slider until release. React Native has no equivalent, and volume
|
|
17
|
+
* sliders live in settings lists, so a horizontal drag has to be told apart
|
|
18
|
+
* from the scroll it is sitting in.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* `activeOffsetX` is that distinction, declared rather than fought over. The
|
|
21
|
+
* pan claims the gesture once the finger has clearly gone sideways, and a
|
|
22
|
+
* vertical drag never activates it at all, so the scroll view keeps it. That
|
|
23
|
+
* replaces `onPanResponderTerminationRequest: () => false` plus the `DragLock`
|
|
24
|
+
* that had to switch the scroll view off, because refusing to hand back a JS
|
|
25
|
+
* responder says nothing to the native recogniser that actually does the
|
|
26
|
+
* scrolling on iOS.
|
|
27
|
+
*
|
|
28
|
+
* Both gestures run on the JS thread. The Drawer's stay worklets because they
|
|
29
|
+
* only move a shared value; every callback here has to reach React state and
|
|
30
|
+
* the consumer's `onValueChange`, so the hop is happening either way and
|
|
31
|
+
* pretending otherwise would only add a way to get it wrong.
|
|
21
32
|
*/
|
|
22
|
-
export function Slider({ value: controlled, defaultValue = 0, onValueChange, onValueCommit, min = 0, max = 100, step = 1, disabled, tone = "primary", style, accessibilityLabel
|
|
33
|
+
export function Slider({ value: controlled, defaultValue = 0, onValueChange, onValueCommit, min = 0, max = 100, step = 1, disabled, tone = "primary", style, accessibilityLabel }) {
|
|
23
34
|
const theme = useTheme();
|
|
24
|
-
// Held for the duration of a drag, so the list this is sitting in stays put.
|
|
25
|
-
// A no-op outside a ScrollView from this package — see useDragLock.
|
|
26
|
-
const dragLock = useDragLock();
|
|
27
35
|
const [uncontrolled, setUncontrolled] = useState(defaultValue);
|
|
28
36
|
const value = controlled ?? uncontrolled;
|
|
29
37
|
const [width, setWidth] = useState(0);
|
|
@@ -35,11 +43,6 @@ export function Slider({ value: controlled, defaultValue = 0, onValueChange, onV
|
|
|
35
43
|
// fire from touch events, which is always after an effect has run.
|
|
36
44
|
const state = useRef({ width, value, min, max, step, disabled });
|
|
37
45
|
const emit = useRef({ onValueChange, onValueCommit, controlled });
|
|
38
|
-
// Same reason as the others: the responder callbacks are created once, and
|
|
39
|
-
// the lock's identity changes whenever the count does.
|
|
40
|
-
const lockRef = useRef(dragLock);
|
|
41
|
-
/** Where the current gesture started, in track coordinates. */
|
|
42
|
-
const origin = useRef(0);
|
|
43
46
|
/**
|
|
44
47
|
* `active:scale-[0.94]` on the web. `hover:scale-[1.12]` has no touch
|
|
45
48
|
* equivalent, so only the press half ports.
|
|
@@ -54,9 +57,6 @@ export function Slider({ value: controlled, defaultValue = 0, onValueChange, onV
|
|
|
54
57
|
useEffect(() => {
|
|
55
58
|
emit.current = { onValueChange, onValueCommit, controlled };
|
|
56
59
|
}, [onValueChange, onValueCommit, controlled]);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
lockRef.current = dragLock;
|
|
59
|
-
}, [dragLock]);
|
|
60
60
|
const valueFromX = (x) => {
|
|
61
61
|
const s = state.current;
|
|
62
62
|
// Before layout there is no position to read, so hold what we have rather
|
|
@@ -70,90 +70,89 @@ export function Slider({ value: controlled, defaultValue = 0, onValueChange, onV
|
|
|
70
70
|
setUncontrolled(next);
|
|
71
71
|
emit.current.onValueChange?.(next);
|
|
72
72
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
//
|
|
91
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Tap to seek, drag to scrub, and nothing at all if the finger goes down the
|
|
75
|
+
* page.
|
|
76
|
+
*
|
|
77
|
+
* Two gestures rather than one because they want opposite thresholds. A tap
|
|
78
|
+
* has to work with no movement; a drag must not claim anything until it is
|
|
79
|
+
* clearly sideways, or every attempt to scroll past a slider moves it. `Race`
|
|
80
|
+
* lets whichever qualifies win, and only one ever does.
|
|
81
|
+
*/
|
|
82
|
+
const gesture = useMemo(() => {
|
|
83
|
+
const seek = (x) => {
|
|
84
|
+
const s = state.current;
|
|
85
|
+
if (s.disabled)
|
|
86
|
+
return;
|
|
87
|
+
// Absolute position in the track, not accumulated translation.
|
|
88
|
+
//
|
|
89
|
+
// The old version anchored on where the gesture started and added
|
|
90
|
+
// `gesture.dx`, which is the distance from the *start* rather than from
|
|
91
|
+
// the last event — so offsetting the live value by it added the whole
|
|
92
|
+
// travel again every move and the thumb accelerated away from the
|
|
93
|
+
// finger. Reading the position directly cannot express that bug.
|
|
94
|
+
apply(valueFromX(x));
|
|
95
|
+
};
|
|
96
|
+
const pan = Gesture.Pan()
|
|
97
|
+
.runOnJS(true)
|
|
98
|
+
.enabled(!disabled)
|
|
99
|
+
// Sideways, and clearly so. Below this the scroll view keeps the gesture,
|
|
100
|
+
// which is the whole reason the lock is gone.
|
|
101
|
+
.activeOffsetX([-4, 4])
|
|
102
|
+
.onBegin(() => {
|
|
103
|
+
// On touch down rather than on activation: the press feedback should
|
|
104
|
+
// answer the finger, not wait to find out where it is going.
|
|
92
105
|
thumbScale.value = springy(grytScaleSteps.sliderThumb.press);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// the finger — 200px wide, 0-100, dragging to x=50 then 60 then 70 gave
|
|
99
|
-
// 25, then 55, then 90. Tapping was always fine, because grant uses
|
|
100
|
-
// locationX directly, which is what made it look like a rendering
|
|
101
|
-
// problem rather than an arithmetic one.
|
|
102
|
-
//
|
|
103
|
-
// Anchoring on the grant position is also what makes the drag continue
|
|
104
|
-
// from the finger: grant has already seeked the thumb there.
|
|
105
|
-
onPanResponderMove: (_e, gesture) => {
|
|
106
|
-
apply(valueFromX(origin.current + gesture.dx));
|
|
107
|
-
},
|
|
108
|
-
// The fix for GRYT-390's "the slider still lets me scroll the page".
|
|
109
|
-
//
|
|
110
|
-
// The comment above says this "claims the gesture and holds it". It did
|
|
111
|
-
// not: `onPanResponderTerminationRequest` defaults to *granting*, so the
|
|
112
|
-
// enclosing ScrollView asked for the responder as soon as the finger
|
|
113
|
-
// moved and got it. Every drag inside a scrolling screen scrolled the
|
|
114
|
-
// screen, which is every drag — volume sliders live in settings lists.
|
|
115
|
-
//
|
|
116
|
-
// Saying no is the whole fix. `onShouldBlockNativeResponder` stops the
|
|
117
|
-
// native scroll view taking over underneath on Android, where the JS
|
|
118
|
-
// answer alone is not enough.
|
|
119
|
-
onPanResponderTerminationRequest: () => false,
|
|
120
|
-
// A refused termination can still happen — the system can take the
|
|
121
|
-
// responder away regardless, on a call or a notification. Without this
|
|
122
|
-
// the lock leaks and the screen never scrolls again, which is a far
|
|
123
|
-
// worse bug than the one being fixed.
|
|
124
|
-
onPanResponderTerminate: () => {
|
|
125
|
-
lockRef.current.unlock();
|
|
126
|
-
thumbScale.value = springy(1);
|
|
127
|
-
},
|
|
128
|
-
onShouldBlockNativeResponder: () => true,
|
|
129
|
-
onPanResponderRelease: () => {
|
|
130
|
-
lockRef.current.unlock();
|
|
106
|
+
})
|
|
107
|
+
.onStart((event) => seek(event.x))
|
|
108
|
+
.onUpdate((event) => seek(event.x))
|
|
109
|
+
.onEnd(() => emit.current.onValueCommit?.(state.current.value))
|
|
110
|
+
.onFinalize(() => {
|
|
131
111
|
thumbScale.value = springy(1);
|
|
112
|
+
});
|
|
113
|
+
const tap = Gesture.Tap()
|
|
114
|
+
.runOnJS(true)
|
|
115
|
+
.enabled(!disabled)
|
|
116
|
+
.onEnd((event, success) => {
|
|
117
|
+
if (!success)
|
|
118
|
+
return;
|
|
119
|
+
seek(event.x);
|
|
132
120
|
emit.current.onValueCommit?.(state.current.value);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
121
|
+
});
|
|
122
|
+
return Gesture.Race(pan, tap);
|
|
123
|
+
// `apply` and `valueFromX` read refs that are written in effects, so they
|
|
124
|
+
// do not need to be dependencies — and listing them would rebuild the
|
|
125
|
+
// gesture on every render.
|
|
126
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
127
|
+
}, [disabled, thumbScale]);
|
|
136
128
|
const ratio = (value - min) / (max - min || 1);
|
|
137
|
-
return (_jsxs(View, { accessibilityRole: "adjustable", accessibilityLabel: accessibilityLabel, accessibilityValue: { min, max, now: value }, onLayout: (e) => setWidth(e.nativeEvent.layout.width), style: [
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
return (_jsx(GestureDetector, { gesture: gesture, children: _jsxs(View, { accessibilityRole: "adjustable", accessibilityLabel: accessibilityLabel, accessibilityValue: { min, max, now: value }, onLayout: (e) => setWidth(e.nativeEvent.layout.width), style: [
|
|
130
|
+
{
|
|
131
|
+
height: THUMB,
|
|
132
|
+
justifyContent: "center",
|
|
133
|
+
opacity: disabled ? 0.5 : 1
|
|
134
|
+
},
|
|
135
|
+
style
|
|
136
|
+
], children: [_jsx(View, { style: {
|
|
137
|
+
height: TRACK_HEIGHT,
|
|
144
138
|
borderRadius: TRACK_HEIGHT / 2,
|
|
145
|
-
backgroundColor:
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
139
|
+
backgroundColor: theme.scales.neutral[4]
|
|
140
|
+
}, children: _jsx(View, { style: {
|
|
141
|
+
width: `${ratio * 100}%`,
|
|
142
|
+
height: "100%",
|
|
143
|
+
borderRadius: TRACK_HEIGHT / 2,
|
|
144
|
+
backgroundColor: ramp[8]
|
|
145
|
+
} }) }), _jsx(Animated.View, { pointerEvents: "none", style: [
|
|
146
|
+
{
|
|
147
|
+
position: "absolute",
|
|
148
|
+
left: Math.max(0, ratio * width - THUMB / 2),
|
|
149
|
+
width: THUMB,
|
|
150
|
+
height: THUMB,
|
|
151
|
+
borderRadius: THUMB / 2,
|
|
152
|
+
backgroundColor: ramp[8],
|
|
153
|
+
borderWidth: 2,
|
|
154
|
+
borderColor: theme.color.bg
|
|
155
|
+
},
|
|
156
|
+
thumbStyle
|
|
157
|
+
] })] }) }));
|
|
159
158
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,6 @@ export { NumberField, type NumberFieldProps } from "./components/NumberField/Num
|
|
|
31
31
|
export { OtpField, type OtpFieldProps } from "./components/OtpField/OtpField.js";
|
|
32
32
|
export { ScrollArea, type ScrollAreaProps } from "./components/ScrollArea/ScrollArea.js";
|
|
33
33
|
export { Sheet, type SheetCloseProps, type SheetContentProps, type SheetProps, SheetProvider, type SheetProviderProps, type SheetTitleProps, type SheetTriggerProps, } from "./components/Sheet/Sheet.js";
|
|
34
|
-
export { useDragLock, type DragLock } from "./components/internal/dragLock.js";
|
|
35
34
|
export { ToastProvider, useToast, type ToastOptions, type ToastSeverity, } from "./components/Toast/Toast.js";
|
|
36
35
|
export { Toolbar, ToolbarSeparator, type ToolbarProps, type ToolbarSeparatorProps, } from "./components/Toolbar/Toolbar.js";
|
|
37
36
|
export { AnchoredPopup, type AnchoredPopupProps } from "./overlay/AnchoredPopup.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,IAAI,EACT,QAAQ,EACR,KAAK,aAAa,GACnB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,WAAW,EACX,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACvF,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxG,OAAO,EACL,IAAI,EACJ,WAAW,EACX,WAAW,EACX,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC/F,OAAO,EACL,MAAM,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,kBAAkB,GACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,WAAW,EACX,KAAK,oBAAoB,GAC1B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC3G,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACtG,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACpH,OAAO,EACL,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,MAAM,EACN,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACvF,OAAO,EACL,GAAG,EACH,IAAI,EACJ,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACtG,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxG,OAAO,EACL,OAAO,EACP,eAAe,EACf,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,MAAM,EACN,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,UAAU,GAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACtF,OAAO,EACL,KAAK,EACL,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,6 @@ export { NumberField } from "./components/NumberField/NumberField.js";
|
|
|
31
31
|
export { OtpField } from "./components/OtpField/OtpField.js";
|
|
32
32
|
export { ScrollArea } from "./components/ScrollArea/ScrollArea.js";
|
|
33
33
|
export { Sheet, SheetProvider, } from "./components/Sheet/Sheet.js";
|
|
34
|
-
export { useDragLock } from "./components/internal/dragLock.js";
|
|
35
34
|
export { ToastProvider, useToast, } from "./components/Toast/Toast.js";
|
|
36
35
|
export { Toolbar, ToolbarSeparator, } from "./components/Toolbar/Toolbar.js";
|
|
37
36
|
export { AnchoredPopup } from "./overlay/AnchoredPopup.js";
|
package/package.json
CHANGED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A control holding a scrolling ancestor still while it is being dragged.
|
|
3
|
-
*
|
|
4
|
-
* This exists because of one bug, and the obvious fixes all fail in ways that
|
|
5
|
-
* look like they worked, so it is worth writing down.
|
|
6
|
-
*
|
|
7
|
-
* Dragging a `Slider` inside a scrolling screen scrolled the screen. The first
|
|
8
|
-
* fix — `onPanResponderTerminationRequest: () => false` — was necessary and not
|
|
9
|
-
* sufficient: it stops the ScrollView taking the responder away, so the thumb
|
|
10
|
-
* follows your finger now, and the page still scrolls underneath. On iOS the
|
|
11
|
-
* scroll is driven by a native `UIPanGestureRecognizer` that is not part of
|
|
12
|
-
* React Native's JS responder system, so refusing to hand over the responder
|
|
13
|
-
* answers a question the native recogniser never asked.
|
|
14
|
-
* `onShouldBlockNativeResponder` is the knob for that, and it is Android-only.
|
|
15
|
-
*
|
|
16
|
-
* What works is `scrollEnabled` — and the control cannot reach the scroll view
|
|
17
|
-
* to set it, since they are separated by however much app markup. So the scroll
|
|
18
|
-
* view publishes a lock, the control claims it, and neither has to know where
|
|
19
|
-
* the other is.
|
|
20
|
-
*
|
|
21
|
-
* `react-native-gesture-handler` solves this properly, by negotiating with the
|
|
22
|
-
* native recogniser rather than switching it off. That is the better fix and it
|
|
23
|
-
* is blocked on GRYT-393: this package ships prebuilt JavaScript, Reanimated's
|
|
24
|
-
* babel plugin does not run over `node_modules`, and gesture callbacks are
|
|
25
|
-
* therefore never worklets. Measured on a device, not assumed. When that is
|
|
26
|
-
* solved, this should probably go.
|
|
27
|
-
*/
|
|
28
|
-
export interface DragLock {
|
|
29
|
-
locked: boolean;
|
|
30
|
-
lock: () => void;
|
|
31
|
-
unlock: () => void;
|
|
32
|
-
}
|
|
33
|
-
export declare const DragLockContext: import("react").Context<DragLock | null>;
|
|
34
|
-
/**
|
|
35
|
-
* Claimed by a control for the duration of a drag.
|
|
36
|
-
*
|
|
37
|
-
* No-ops outside a `ScrollArea`, which is the normal case for a control that is
|
|
38
|
-
* not in a scrolling screen. A control must not require the provider: a slider
|
|
39
|
-
* in a fixed panel has nothing to lock, and throwing there would be inventing a
|
|
40
|
-
* dependency on a component it does not need.
|
|
41
|
-
*/
|
|
42
|
-
export declare function useDragLock(): DragLock;
|
|
43
|
-
//# sourceMappingURL=dragLock.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dragLock.d.ts","sourceRoot":"","sources":["../../../src/components/internal/dragLock.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,eAAO,MAAM,eAAe,0CAAuC,CAAC;AAQpE;;;;;;;GAOG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAEtC"}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from "react";
|
|
2
|
-
export const DragLockContext = createContext(null);
|
|
3
|
-
const NO_LOCK = {
|
|
4
|
-
locked: false,
|
|
5
|
-
lock: () => { },
|
|
6
|
-
unlock: () => { },
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Claimed by a control for the duration of a drag.
|
|
10
|
-
*
|
|
11
|
-
* No-ops outside a `ScrollArea`, which is the normal case for a control that is
|
|
12
|
-
* not in a scrolling screen. A control must not require the provider: a slider
|
|
13
|
-
* in a fixed panel has nothing to lock, and throwing there would be inventing a
|
|
14
|
-
* dependency on a component it does not need.
|
|
15
|
-
*/
|
|
16
|
-
export function useDragLock() {
|
|
17
|
-
return useContext(DragLockContext) ?? NO_LOCK;
|
|
18
|
-
}
|