@expokit/cli 0.4.4 → 0.5.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/README.md +30 -3
- package/bin/expo-kit.js +749 -288
- package/bin/lib.mjs +310 -3
- package/package.json +1 -1
- package/registry/_docs/action-sheet.json +1 -1
- package/registry/_docs/alert.json +6 -0
- package/registry/_docs/bottom-sheet.json +6 -0
- package/registry/_docs/bullet.json +6 -0
- package/registry/_docs/dialog.json +1 -1
- package/registry/_docs/drawer.json +3 -3
- package/registry/_docs/glass-search-bar.json +1 -1
- package/registry/_docs/grain.json +6 -1
- package/registry/_docs/isometric-bar.json +6 -0
- package/registry/_docs/liquidglass-tab.json +1 -1
- package/registry/_docs/password-input.json +1 -1
- package/registry/_docs/pixel-bar.json +6 -0
- package/registry/_docs/polar-area.json +6 -0
- package/registry/_docs/qr-code-button.json +9 -3
- package/registry/_docs/scratch-card.json +7 -1
- package/registry/_docs/search-bar.json +1 -1
- package/registry/_docs/select.json +2 -2
- package/registry/_docs/slide-to-confirm.json +2 -2
- package/registry/_docs/spinner.json +1 -1
- package/registry/_docs/stateful-button.json +2 -2
- package/registry/_docs/swipe-deck.json +1 -1
- package/registry/_docs/time-picker.json +2 -2
- package/registry/_docs/timeline-chart.json +6 -0
- package/registry/_docs/toast.json +15 -3
- package/registry/_docs/treemap.json +6 -0
- package/registry/_docs/waterfall.json +6 -0
- package/registry/accordion/files/src/components/ui/accordion.tsx +6 -4
- package/registry/accordion/files/src/lib/kit.tsx +363 -11
- package/registry/accordion.json +1 -0
- package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +43 -48
- package/registry/action-sheet/files/src/lib/kit.tsx +363 -11
- package/registry/action-sheet.json +1 -0
- package/registry/alert/files/src/components/ui/alert.tsx +19 -12
- package/registry/alert/files/src/lib/kit.tsx +363 -11
- package/registry/alert.json +3 -4
- package/registry/assistant-app.json +1 -0
- package/registry/avatar/files/src/components/ui/avatar.tsx +84 -66
- package/registry/avatar/files/src/lib/kit.tsx +363 -11
- package/registry/avatar.json +1 -0
- package/registry/badge/files/src/components/ui/badge.tsx +34 -34
- package/registry/badge/files/src/lib/kit.tsx +363 -11
- package/registry/badge.json +1 -0
- package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +28 -27
- package/registry/bottom-nav/files/src/lib/kit.tsx +363 -11
- package/registry/bottom-nav.json +5 -0
- package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +353 -289
- package/registry/bottom-sheet/files/src/lib/kit.tsx +363 -11
- package/registry/bottom-sheet.json +5 -1
- package/registry/bullet.json +1 -0
- package/registry/button/files/src/components/ui/button.tsx +18 -16
- package/registry/button/files/src/lib/kit.tsx +363 -11
- package/registry/button-3d/files/src/components/ui/button-3d.tsx +2 -2
- package/registry/button-3d/files/src/lib/kit.tsx +363 -11
- package/registry/button-3d.json +1 -0
- package/registry/button.json +1 -0
- package/registry/calendar/files/src/components/ui/calendar.tsx +74 -76
- package/registry/calendar/files/src/lib/kit.tsx +363 -11
- package/registry/calendar.json +1 -0
- package/registry/card/files/src/components/ui/card.tsx +3 -3
- package/registry/card/files/src/lib/kit.tsx +363 -11
- package/registry/card-stack.json +1 -0
- package/registry/card.json +1 -0
- package/registry/carousel.json +1 -0
- package/registry/chat.json +7 -0
- package/registry/checkbox/files/src/components/ui/checkbox.tsx +4 -4
- package/registry/checkbox/files/src/lib/kit.tsx +363 -11
- package/registry/checkbox.json +1 -0
- package/registry/checkout.json +1 -0
- package/registry/chip-group/files/src/components/ui/chip-group.tsx +22 -22
- package/registry/chip-group/files/src/lib/kit.tsx +363 -11
- package/registry/chip-group.json +1 -0
- package/registry/confetti/files/src/components/ui/confetti.tsx +15 -14
- package/registry/confetti.json +3 -6
- package/registry/coupon/files/src/components/ui/coupon.tsx +42 -42
- package/registry/coupon/files/src/components/ui/flip-card.tsx +6 -5
- package/registry/coupon/files/src/components/ui/tilt-card.tsx +76 -91
- package/registry/coupon/files/src/lib/kit.tsx +363 -11
- package/registry/coupon/files/src/lib/ticket-shape.tsx +54 -44
- package/registry/coupon.json +1 -0
- package/registry/cube-pager.json +1 -0
- package/registry/dashboard.json +1 -0
- package/registry/date-picker/files/src/components/ui/calendar.tsx +74 -76
- package/registry/date-picker/files/src/components/ui/date-picker.tsx +55 -56
- package/registry/date-picker/files/src/lib/kit.tsx +363 -11
- package/registry/date-picker.json +1 -0
- package/registry/dialog/files/src/components/ui/dialog.tsx +60 -56
- package/registry/dialog/files/src/lib/kit.tsx +363 -11
- package/registry/dialog.json +1 -0
- package/registry/donut-shop.json +1 -0
- package/registry/drawer/files/src/components/ui/drawer.tsx +73 -69
- package/registry/drawer/files/src/lib/kit.tsx +363 -11
- package/registry/drawer.json +1 -0
- package/registry/fab.json +1 -0
- package/registry/fintech-app.json +1 -0
- package/registry/flip-calendar/files/src/components/ui/flip-calendar.tsx +92 -86
- package/registry/flip-calendar/files/src/lib/kit.tsx +363 -11
- package/registry/flip-calendar.json +7 -0
- package/registry/flip-card/files/src/components/ui/flip-card.tsx +6 -5
- package/registry/flip-card/files/src/lib/kit.tsx +363 -11
- package/registry/flip-card.json +1 -0
- package/registry/floating-input/files/src/components/ui/floating-input.tsx +33 -33
- package/registry/floating-input/files/src/lib/kit.tsx +363 -11
- package/registry/floating-input.json +1 -0
- package/registry/food-app.json +1 -0
- package/registry/gift-card.json +1 -0
- package/registry/glass-button.json +5 -0
- package/registry/glass-nav-bar.json +1 -0
- package/registry/glass-search-bar.json +1 -0
- package/registry/glass-segmented.json +1 -0
- package/registry/glass-sheet.json +1 -0
- package/registry/glass-tab-bar.json +5 -0
- package/registry/glass.json +1 -0
- package/registry/grain/files/src/components/ui/grain.tsx +16 -14
- package/registry/grain.json +8 -6
- package/registry/inbox.json +1 -0
- package/registry/isometric-bar.json +1 -0
- package/registry/kit/files/src/lib/kit.tsx +363 -11
- package/registry/kit.json +1 -0
- package/registry/liquidglass-tab/files/src/app/_layout.tsx +0 -1
- package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +23 -9
- package/registry/liquidglass-tab/files/src/components/TabScreen.tsx +2 -2
- package/registry/liquidglass-tab/files/src/lib/tab-icons.ts +1 -1
- package/registry/liquidglass-tab.json +1 -0
- package/registry/list-item/files/src/components/ui/list-item.tsx +42 -42
- package/registry/list-item/files/src/lib/kit.tsx +363 -11
- package/registry/list-item.json +1 -0
- package/registry/loyalty-card.json +1 -0
- package/registry/morphing-button-group.json +1 -0
- package/registry/number-ticker.json +1 -0
- package/registry/offers.json +1 -0
- package/registry/onboarding.json +1 -0
- package/registry/orb-reveal.json +1 -0
- package/registry/otp-input/files/src/components/ui/otp-input.tsx +48 -29
- package/registry/otp-input/files/src/lib/kit.tsx +363 -11
- package/registry/otp-input.json +1 -0
- package/registry/parallax-layers.json +1 -0
- package/registry/parallax-scroll.json +1 -0
- package/registry/password-input/files/src/components/ui/floating-input.tsx +33 -33
- package/registry/password-input/files/src/components/ui/password-input.tsx +29 -25
- package/registry/password-input/files/src/lib/kit.tsx +363 -11
- package/registry/password-input.json +1 -0
- package/registry/payment-card/files/src/components/ui/flip-card.tsx +6 -5
- package/registry/payment-card/files/src/components/ui/payment-card.tsx +17 -17
- package/registry/payment-card/files/src/components/ui/tilt-card.tsx +76 -91
- package/registry/payment-card/files/src/lib/kit.tsx +363 -11
- package/registry/payment-card.json +1 -0
- package/registry/paywall.json +1 -0
- package/registry/pixel-bar.json +1 -0
- package/registry/polar-area.json +1 -0
- package/registry/profile.json +1 -0
- package/registry/progress/files/src/components/ui/progress.tsx +29 -29
- package/registry/progress/files/src/lib/kit.tsx +363 -11
- package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +20 -20
- package/registry/progress-steps/files/src/lib/kit.tsx +363 -11
- package/registry/progress-steps.json +1 -0
- package/registry/progress.json +1 -0
- package/registry/qr-code-button.json +1 -0
- package/registry/radio-group/files/src/components/ui/radio-group.tsx +19 -19
- package/registry/radio-group/files/src/lib/kit.tsx +363 -11
- package/registry/radio-group.json +1 -0
- package/registry/rating.json +1 -0
- package/registry/ring-carousel.json +1 -0
- package/registry/ruler-time-picker/files/src/components/ui/ruler-time-picker.tsx +98 -82
- package/registry/ruler-time-picker/files/src/lib/kit.tsx +363 -11
- package/registry/ruler-time-picker.json +7 -0
- package/registry/scratch-card.json +1 -0
- package/registry/search-bar/files/src/components/ui/search-bar.tsx +25 -21
- package/registry/search-bar/files/src/lib/kit.tsx +363 -11
- package/registry/search-bar.json +1 -0
- package/registry/search-results.json +4 -0
- package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +8 -7
- package/registry/segmented-control/files/src/lib/kit.tsx +363 -11
- package/registry/segmented-control.json +1 -0
- package/registry/select/files/src/components/ui/select.tsx +93 -88
- package/registry/select/files/src/lib/kit.tsx +363 -11
- package/registry/select.json +6 -0
- package/registry/settings.json +1 -0
- package/registry/sign-in.json +1 -0
- package/registry/skeleton/files/src/components/ui/skeleton.tsx +149 -80
- package/registry/skeleton/files/src/lib/kit.tsx +363 -11
- package/registry/skeleton.json +1 -0
- package/registry/slide-to-confirm.json +1 -0
- package/registry/slider/files/src/components/ui/slider.tsx +103 -96
- package/registry/slider/files/src/lib/kit.tsx +363 -11
- package/registry/slider.json +5 -0
- package/registry/spin-wheel.json +1 -0
- package/registry/spinner/files/src/components/ui/spinner.tsx +39 -29
- package/registry/spinner/files/src/lib/kit.tsx +363 -11
- package/registry/spinner.json +6 -0
- package/registry/stateful-button/files/src/components/ui/stateful-button.tsx +39 -32
- package/registry/stateful-button/files/src/lib/kit.tsx +363 -11
- package/registry/stateful-button.json +5 -0
- package/registry/stepper/files/src/components/ui/stepper.tsx +38 -36
- package/registry/stepper/files/src/lib/kit.tsx +363 -11
- package/registry/stepper.json +1 -0
- package/registry/swipe-deck.json +1 -0
- package/registry/swipeable-row.json +4 -0
- package/registry/switch/files/src/components/ui/switch.tsx +39 -42
- package/registry/switch/files/src/lib/kit.tsx +363 -11
- package/registry/switch.json +1 -0
- package/registry/tabs/files/src/components/ui/tabs.tsx +59 -62
- package/registry/tabs/files/src/lib/kit.tsx +363 -11
- package/registry/tabs.json +1 -0
- package/registry/text-animation/files/src/components/ui/text-animation.tsx +55 -42
- package/registry/text-animation/files/src/lib/kit.tsx +363 -11
- package/registry/text-animation.json +7 -0
- package/registry/textarea/files/src/components/ui/textarea.tsx +10 -10
- package/registry/textarea/files/src/lib/kit.tsx +363 -11
- package/registry/textarea.json +1 -0
- package/registry/ticket-card.json +1 -0
- package/registry/ticket-shape/files/src/lib/kit.tsx +363 -11
- package/registry/ticket-shape/files/src/lib/ticket-shape.tsx +54 -44
- package/registry/ticket-shape.json +1 -0
- package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +76 -91
- package/registry/tilt-card/files/src/lib/kit.tsx +363 -11
- package/registry/tilt-card.json +1 -0
- package/registry/time-picker/files/src/components/ui/time-picker.tsx +122 -119
- package/registry/time-picker/files/src/lib/kit.tsx +363 -11
- package/registry/time-picker.json +1 -0
- package/registry/timeline/files/src/components/ui/avatar.tsx +84 -66
- package/registry/timeline/files/src/components/ui/timeline.tsx +44 -41
- package/registry/timeline/files/src/lib/kit.tsx +363 -11
- package/registry/timeline-chart.json +1 -0
- package/registry/timeline.json +1 -0
- package/registry/toast/files/src/components/ui/toast.tsx +541 -463
- package/registry/toast/files/src/lib/kit.tsx +363 -11
- package/registry/toast.json +7 -5
- package/registry/treemap.json +1 -0
- package/registry/waterfall.json +1 -0
- package/registry/wheel-list.json +1 -0
- package/schema/components.schema.json +1 -0
- package/registry/alert/files/src/components/ui/button.tsx +0 -290
- package/registry/confetti/files/src/lib/kit.tsx +0 -320
- package/registry/grain/files/src/lib/kit.tsx +0 -320
- package/registry/toast/files/src/components/ui/button.tsx +0 -290
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
AccessibilityInfo,
|
|
4
4
|
Animated,
|
|
5
5
|
Easing,
|
|
6
|
-
PanResponder,
|
|
7
6
|
Pressable,
|
|
8
7
|
StyleSheet,
|
|
9
8
|
Text,
|
|
@@ -17,7 +16,7 @@ import {
|
|
|
17
16
|
} from 'react-native';
|
|
18
17
|
import Svg, { Circle, Path } from 'react-native-svg';
|
|
19
18
|
|
|
20
|
-
import { alpha, motion, readableOn, useKit } from '@/lib/kit';
|
|
19
|
+
import { alpha, motion, readableOn, useKit, usePanResponder } from '@/lib/kit';
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
22
|
* - `default` — thin track with a round thumb (iOS / Material).
|
|
@@ -130,6 +129,10 @@ const glide = (v: Animated.Value, toValue: number, reduce: boolean) =>
|
|
|
130
129
|
? Animated.timing(v, { toValue, duration: 150, easing: SMOOTH, useNativeDriver: true })
|
|
131
130
|
: Animated.spring(v, { toValue, useNativeDriver: true, ...motion.snappy });
|
|
132
131
|
const decimals = (n: number) => (String(n).split('.')[1] ?? '').length;
|
|
132
|
+
/** Value `i` of a slider's values: index 1 of a single slider (or a short array) falls back to the first. */
|
|
133
|
+
const nth = (arr: readonly number[], i: number) => arr[i] ?? arr[0] ?? 0;
|
|
134
|
+
/** The animated value of thumb `i` (always 0 or 1). */
|
|
135
|
+
const pick = <T,>(pair: readonly [T, T], i: number): T => (i === 1 ? pair[1] : pair[0]);
|
|
133
136
|
|
|
134
137
|
/**
|
|
135
138
|
* A slider that feels native: the thumb and fill move on the native driver (no re-render per
|
|
@@ -173,7 +176,7 @@ export function Slider(props: SliderProps) {
|
|
|
173
176
|
const onSlidingStart = props.onSlidingStart as Callback;
|
|
174
177
|
const onSlidingComplete = props.onSlidingComplete as Callback;
|
|
175
178
|
|
|
176
|
-
const { colors, radius, dark, font, shadow } = useKit();
|
|
179
|
+
const { colors, radius, dark, font, shadow, labels } = useKit();
|
|
177
180
|
const ff = font.family ? { fontFamily: font.family } : null;
|
|
178
181
|
const reduce = useReduceMotion();
|
|
179
182
|
const tint = accent ?? colors.accent;
|
|
@@ -203,7 +206,7 @@ export function Slider(props: SliderProps) {
|
|
|
203
206
|
const controlled = props.value !== undefined;
|
|
204
207
|
const [inner, setInner] = useState<number[]>(() => toArr(props.defaultValue));
|
|
205
208
|
const vals = (controlled ? toArr(props.value) : inner).map((v) => clamp(v, min, max));
|
|
206
|
-
if (range && vals
|
|
209
|
+
if (range && nth(vals, 0) > nth(vals, 1)) vals.reverse();
|
|
207
210
|
|
|
208
211
|
const span = max - min || 1;
|
|
209
212
|
const ratioOf = (v: number) => clamp((v - min) / span, 0, 1);
|
|
@@ -213,28 +216,33 @@ export function Slider(props: SliderProps) {
|
|
|
213
216
|
return clamp(Number(n.toFixed(decimals(step))), min, max);
|
|
214
217
|
};
|
|
215
218
|
const fmt = (v: number) => (formatValue ? formatValue(v) : step ? v.toFixed(decimals(step)) : String(Math.round(v)));
|
|
216
|
-
const out = (arr: number[]): SliderValue => (range ? [arr
|
|
219
|
+
const out = (arr: number[]): SliderValue => (range ? [nth(arr, 0), nth(arr, 1)] : nth(arr, 0));
|
|
217
220
|
|
|
218
221
|
const [w, setW] = useState(0);
|
|
219
222
|
const [active, setActive] = useState<number | null>(null);
|
|
220
223
|
|
|
221
224
|
// ---- animated values ------------------------------------------------------------------------
|
|
222
225
|
// All native-driven: they only ever feed transform / opacity.
|
|
223
|
-
const ratios =
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
226
|
+
const [ratios] = useState((): readonly [Animated.Value, Animated.Value] => [
|
|
227
|
+
new Animated.Value(ratioOf(nth(vals, 0))),
|
|
228
|
+
new Animated.Value(ratioOf(nth(vals, 1))),
|
|
229
|
+
]);
|
|
230
|
+
const [press] = useState(() => [new Animated.Value(0), new Animated.Value(0)]);
|
|
231
|
+
const [bubble] = useState(() => [new Animated.Value(bubbleShown ? 1 : 0), new Animated.Value(bubbleShown ? 1 : 0)]);
|
|
232
|
+
const [held] = useState(() => new Animated.Value(0));
|
|
227
233
|
|
|
228
234
|
// Everything the (once-created) PanResponder reads, kept fresh every render.
|
|
229
235
|
const live = useRef({ vals, w, inset, step, span, min, range, isBar, T, disabled, controlled, reduce, snap, ratioOf, fmt, out, onValueChange, onSlidingStart, onSlidingComplete });
|
|
230
|
-
|
|
236
|
+
useLayoutEffect(() => {
|
|
237
|
+
live.current = { vals, w, inset, step, span, min, range, isBar, T, disabled, controlled, reduce, snap, ratioOf, fmt, out, onValueChange, onSlidingStart, onSlidingComplete };
|
|
238
|
+
});
|
|
231
239
|
const drag = useRef({ dragging: false, thumb: 0, startX: 0, origin: 0, relative: false, moved: false, cur: [] as number[], target: [-1, -1] });
|
|
232
240
|
|
|
233
241
|
// Follow value changes from outside (controlled updates, a11y, icon taps) when nobody is dragging.
|
|
234
242
|
const key = vals.join(',');
|
|
235
243
|
useEffect(() => {
|
|
236
244
|
if (drag.current.dragging) return;
|
|
237
|
-
vals.forEach((v, i) => glide(ratios
|
|
245
|
+
vals.forEach((v, i) => glide(pick(ratios, i), ratioOf(v), reduce).start());
|
|
238
246
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
239
247
|
}, [key, min, max]);
|
|
240
248
|
|
|
@@ -245,91 +253,90 @@ export function Slider(props: SliderProps) {
|
|
|
245
253
|
glide(held, active !== null ? 1 : 0, reduce).start();
|
|
246
254
|
}, [active, bubbleShown, showValue, press, bubble, held, reduce]);
|
|
247
255
|
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
256
|
+
const usableOf = () => Math.max(1, live.current.w - 2 * live.current.inset);
|
|
257
|
+
const ratioAt = (x: number) => clamp((x - live.current.inset) / usableOf(), 0, 1);
|
|
258
|
+
|
|
259
|
+
const moveTo = (x: number, animate: boolean) => {
|
|
260
|
+
const L = live.current;
|
|
261
|
+
const d = drag.current;
|
|
262
|
+
const i = d.thumb;
|
|
263
|
+
let v = L.min + ratioAt(x) * L.span;
|
|
264
|
+
if (L.range) v = i === 0 ? Math.min(v, nth(d.cur, 1)) : Math.max(v, nth(d.cur, 0));
|
|
265
|
+
const snapped = L.snap(v);
|
|
266
|
+
const coarse = !!L.step && (L.step / L.span) * usableOf() >= SNAP_PX;
|
|
267
|
+
const target = coarse ? L.ratioOf(snapped) : L.ratioOf(v);
|
|
268
|
+
if (animate || coarse) {
|
|
269
|
+
if (target !== d.target[i]) glide(pick(ratios, i), target, L.reduce).start();
|
|
270
|
+
} else {
|
|
271
|
+
pick(ratios, i).setValue(target);
|
|
272
|
+
}
|
|
273
|
+
d.target[i] = target;
|
|
274
|
+
if (snapped === d.cur[i]) return;
|
|
275
|
+
const prev = nth(d.cur, i);
|
|
276
|
+
const next = [...d.cur];
|
|
277
|
+
next[i] = snapped;
|
|
278
|
+
d.cur = next;
|
|
279
|
+
// Uncontrolled continuous sliders only re-render when the shown text changes.
|
|
280
|
+
if (!L.controlled && (L.step || L.fmt(prev) !== L.fmt(snapped))) setInner(next);
|
|
281
|
+
L.onValueChange?.(L.out(next));
|
|
282
|
+
};
|
|
251
283
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
ratios[i].setValue(target);
|
|
265
|
-
}
|
|
266
|
-
d.target[i] = target;
|
|
267
|
-
if (snapped === d.cur[i]) return;
|
|
268
|
-
const prev = d.cur[i];
|
|
269
|
-
const next = [...d.cur];
|
|
270
|
-
next[i] = snapped;
|
|
271
|
-
d.cur = next;
|
|
272
|
-
// Uncontrolled continuous sliders only re-render when the shown text changes.
|
|
273
|
-
if (!L.controlled && (L.step || L.fmt(prev) !== L.fmt(snapped))) setInner(next);
|
|
274
|
-
L.onValueChange?.(L.out(next));
|
|
275
|
-
};
|
|
284
|
+
const finish = (seek: boolean) => {
|
|
285
|
+
const L = live.current;
|
|
286
|
+
const d = drag.current;
|
|
287
|
+
if (!d.dragging) return;
|
|
288
|
+
if (seek) moveTo(d.startX, true);
|
|
289
|
+
glide(pick(ratios, d.thumb), L.ratioOf(nth(d.cur, d.thumb)), L.reduce).start();
|
|
290
|
+
d.dragging = false;
|
|
291
|
+
d.target = [-1, -1];
|
|
292
|
+
if (!L.controlled) setInner(d.cur);
|
|
293
|
+
setActive(null);
|
|
294
|
+
L.onSlidingComplete?.(L.out(d.cur));
|
|
295
|
+
};
|
|
276
296
|
|
|
277
|
-
|
|
297
|
+
const pan = usePanResponder({
|
|
298
|
+
onStartShouldSetPanResponder: () => !live.current.disabled,
|
|
299
|
+
onMoveShouldSetPanResponder: () => !live.current.disabled,
|
|
300
|
+
onPanResponderTerminationRequest: () => false,
|
|
301
|
+
onShouldBlockNativeResponder: () => true,
|
|
302
|
+
onPanResponderGrant: (e: GestureResponderEvent) => {
|
|
278
303
|
const L = live.current;
|
|
304
|
+
const x = e.nativeEvent.locationX;
|
|
305
|
+
const cur = [...L.vals];
|
|
306
|
+
const xs = cur.map((v) => L.inset + L.ratioOf(v) * usableOf());
|
|
307
|
+
let thumb = 0;
|
|
308
|
+
if (L.range) {
|
|
309
|
+
const d0 = Math.abs(x - nth(xs, 0));
|
|
310
|
+
const d1 = Math.abs(x - nth(xs, 1));
|
|
311
|
+
thumb = d0 === d1 ? (x > nth(xs, 1) ? 1 : 0) : d1 < d0 ? 1 : 0;
|
|
312
|
+
}
|
|
313
|
+
// Grabbing the thumb (or anywhere on a bar) drags relative to it; elsewhere seeks first.
|
|
314
|
+
const onThumb = !L.isBar && Math.abs(x - nth(xs, thumb)) <= Math.max(L.T / 2 + 8, 22);
|
|
315
|
+
const relative = L.isBar || onThumb;
|
|
316
|
+
drag.current = { dragging: true, thumb, startX: x, origin: relative ? nth(xs, thumb) : x, relative, moved: false, cur, target: [-1, -1] };
|
|
317
|
+
setActive(thumb);
|
|
318
|
+
L.onSlidingStart?.(L.out(cur));
|
|
319
|
+
if (!relative) moveTo(x, true);
|
|
320
|
+
},
|
|
321
|
+
onPanResponderMove: (_, g) => {
|
|
279
322
|
const d = drag.current;
|
|
280
|
-
if (
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
return PanResponder.create({
|
|
291
|
-
onStartShouldSetPanResponder: () => !live.current.disabled,
|
|
292
|
-
onMoveShouldSetPanResponder: () => !live.current.disabled,
|
|
293
|
-
onPanResponderTerminationRequest: () => false,
|
|
294
|
-
onShouldBlockNativeResponder: () => true,
|
|
295
|
-
onPanResponderGrant: (e: GestureResponderEvent) => {
|
|
296
|
-
const L = live.current;
|
|
297
|
-
const x = e.nativeEvent.locationX;
|
|
298
|
-
const cur = [...L.vals];
|
|
299
|
-
const xs = cur.map((v) => L.inset + L.ratioOf(v) * usableOf());
|
|
300
|
-
let thumb = 0;
|
|
301
|
-
if (L.range) {
|
|
302
|
-
const d0 = Math.abs(x - xs[0]);
|
|
303
|
-
const d1 = Math.abs(x - xs[1]);
|
|
304
|
-
thumb = d0 === d1 ? (x > xs[1] ? 1 : 0) : d1 < d0 ? 1 : 0;
|
|
305
|
-
}
|
|
306
|
-
// Grabbing the thumb (or anywhere on a bar) drags relative to it; elsewhere seeks first.
|
|
307
|
-
const onThumb = !L.isBar && Math.abs(x - xs[thumb]) <= Math.max(L.T / 2 + 8, 22);
|
|
308
|
-
const relative = L.isBar || onThumb;
|
|
309
|
-
drag.current = { dragging: true, thumb, startX: x, origin: relative ? xs[thumb] : x, relative, moved: false, cur, target: [-1, -1] };
|
|
310
|
-
setActive(thumb);
|
|
311
|
-
L.onSlidingStart?.(L.out(cur));
|
|
312
|
-
if (!relative) moveTo(x, true);
|
|
313
|
-
},
|
|
314
|
-
onPanResponderMove: (_, g) => {
|
|
315
|
-
const d = drag.current;
|
|
316
|
-
if (Math.abs(g.dx) >= 3) d.moved = true;
|
|
317
|
-
if (!d.moved && live.current.isBar) return; // keep a tap on a bar a tap
|
|
318
|
-
moveTo(d.origin + g.dx, false);
|
|
319
|
-
},
|
|
320
|
-
// A tap on a bar (no drag) still seeks.
|
|
321
|
-
onPanResponderRelease: () => finish(drag.current.relative && live.current.isBar && !drag.current.moved),
|
|
322
|
-
onPanResponderTerminate: () => finish(false),
|
|
323
|
-
});
|
|
324
|
-
}, [ratios]);
|
|
323
|
+
if (Math.abs(g.dx) >= 3) d.moved = true;
|
|
324
|
+
if (!d.moved && live.current.isBar) return; // keep a tap on a bar a tap
|
|
325
|
+
moveTo(d.origin + g.dx, false);
|
|
326
|
+
},
|
|
327
|
+
// A tap on a bar (no drag) still seeks.
|
|
328
|
+
onPanResponderRelease: () => finish(drag.current.relative && live.current.isBar && !drag.current.moved),
|
|
329
|
+
onPanResponderTerminate: () => finish(false),
|
|
330
|
+
});
|
|
325
331
|
|
|
326
332
|
const stepBy = (i: number, dir: 1 | -1, amount?: number) => {
|
|
327
333
|
if (disabled) return;
|
|
328
334
|
const inc = amount ?? (step || span / 100);
|
|
329
335
|
const next = [...vals];
|
|
330
|
-
|
|
331
|
-
if (range)
|
|
332
|
-
|
|
336
|
+
let moved = snap(nth(next, i) + dir * inc);
|
|
337
|
+
if (range) moved = i === 0 ? Math.min(moved, nth(vals, 1)) : Math.max(moved, nth(vals, 0));
|
|
338
|
+
next[i] = moved;
|
|
339
|
+
if (moved === vals[i]) return;
|
|
333
340
|
if (!controlled) setInner(next);
|
|
334
341
|
onValueChange?.(out(next));
|
|
335
342
|
onSlidingComplete?.(out(next));
|
|
@@ -341,9 +348,9 @@ export function Slider(props: SliderProps) {
|
|
|
341
348
|
const usable = Math.max(1, w - 2 * inset);
|
|
342
349
|
const geo = useMemo(() => {
|
|
343
350
|
if (!w) return null;
|
|
344
|
-
const
|
|
345
|
-
r.interpolate({ inputRange: [0, 1], outputRange: [inset, inset + usable], extrapolate: 'clamp' })
|
|
346
|
-
);
|
|
351
|
+
const toPx = (r: Animated.Value) =>
|
|
352
|
+
r.interpolate({ inputRange: [0, 1], outputRange: [inset, inset + usable], extrapolate: 'clamp' });
|
|
353
|
+
const px = [toPx(ratios[0]), toPx(ratios[1])] as const;
|
|
347
354
|
// Single: a full-width fill slid left so its edge sits at the thumb. Range: a full-width fill
|
|
348
355
|
// scaled about its centre to span the two thumbs. Both are clipped by a rounded container.
|
|
349
356
|
const shift = Animated.add(px[0], -w);
|
|
@@ -386,7 +393,7 @@ export function Slider(props: SliderProps) {
|
|
|
386
393
|
}, [marks, stepped, step, span, min]);
|
|
387
394
|
const hasMarkLabels = markList.some((m) => m.label);
|
|
388
395
|
const minMax = showMinMax || minLabel !== undefined || maxLabel !== undefined;
|
|
389
|
-
const inFill = (v: number) => (range ? v >= vals
|
|
396
|
+
const inFill = (v: number) => (range ? v >= nth(vals, 0) && v <= nth(vals, 1) : v <= nth(vals, 0));
|
|
390
397
|
const dot = Math.max(2, Math.round(trackH * (isBar ? 0.12 : 0.4)));
|
|
391
398
|
|
|
392
399
|
// ---- colours --------------------------------------------------------------------------------
|
|
@@ -425,7 +432,7 @@ export function Slider(props: SliderProps) {
|
|
|
425
432
|
<View>{icon !== undefined ? drawIcon(icon, iconColor) : null}</View>
|
|
426
433
|
{showValue === 'always' ? (
|
|
427
434
|
<Text numberOfLines={1} selectable={false} maxFontSizeMultiplier={FONT_CAP} style={[styles.barValue, ff, { color: textColor, fontSize: sz.font + 1 }, labelStyle]}>
|
|
428
|
-
{range ? `${fmt(vals
|
|
435
|
+
{range ? `${fmt(nth(vals, 0))} – ${fmt(nth(vals, 1))}` : fmt(nth(vals, 0))}
|
|
429
436
|
</Text>
|
|
430
437
|
) : null}
|
|
431
438
|
</View>
|
|
@@ -450,7 +457,7 @@ export function Slider(props: SliderProps) {
|
|
|
450
457
|
accessibilityRole={!range ? 'adjustable' : undefined}
|
|
451
458
|
accessibilityLabel={accessibilityLabel}
|
|
452
459
|
accessibilityState={{ disabled: !!disabled }}
|
|
453
|
-
accessibilityValue={!range ? { min, max, now: vals
|
|
460
|
+
accessibilityValue={!range ? { min, max, now: nth(vals, 0), text: fmt(nth(vals, 0)) } : undefined}
|
|
454
461
|
accessibilityActions={!range ? [{ name: 'increment' }, { name: 'decrement' }] : undefined}
|
|
455
462
|
onAccessibilityAction={(e: AccessibilityActionEvent) => stepBy(0, e.nativeEvent.actionName === 'increment' ? 1 : -1)}
|
|
456
463
|
>
|
|
@@ -481,7 +488,7 @@ export function Slider(props: SliderProps) {
|
|
|
481
488
|
) : null}
|
|
482
489
|
|
|
483
490
|
<View
|
|
484
|
-
{...pan
|
|
491
|
+
{...pan}
|
|
485
492
|
onLayout={(e) => setW(e.nativeEvent.layout.width)}
|
|
486
493
|
style={[styles.surface, { height: surfaceH }, !disabled && styles.pointer]}
|
|
487
494
|
>
|
|
@@ -535,7 +542,7 @@ export function Slider(props: SliderProps) {
|
|
|
535
542
|
key={i}
|
|
536
543
|
accessible={range}
|
|
537
544
|
accessibilityRole={range ? 'adjustable' : undefined}
|
|
538
|
-
accessibilityLabel={range ?
|
|
545
|
+
accessibilityLabel={range ? (i === 0 ? labels.rangeMinimum : labels.rangeMaximum)(accessibilityLabel ?? labels.range) : undefined}
|
|
539
546
|
accessibilityValue={range ? { min, max, now: v, text: fmt(v) } : undefined}
|
|
540
547
|
accessibilityActions={range ? [{ name: 'increment' }, { name: 'decrement' }] : undefined}
|
|
541
548
|
onAccessibilityAction={(e: AccessibilityActionEvent) => stepBy(i, e.nativeEvent.actionName === 'increment' ? 1 : -1)}
|