@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,7 +1,7 @@
|
|
|
1
|
-
import React, { useEffect, useMemo,
|
|
1
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import { AccessibilityInfo, Animated, Pressable, StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import { motion } from '@/lib/kit';
|
|
4
|
+
import { motion, useKit } from '@/lib/kit';
|
|
5
5
|
|
|
6
6
|
export type FlipDirection = 'horizontal' | 'vertical';
|
|
7
7
|
export type FlipTrigger = 'press' | 'none';
|
|
@@ -32,7 +32,7 @@ export interface FlipCardProps {
|
|
|
32
32
|
progress?: Animated.Value;
|
|
33
33
|
/** Accessibility label; the hint says which side is showing. */
|
|
34
34
|
accessibilityLabel?: string;
|
|
35
|
-
/** Screen-reader hints (
|
|
35
|
+
/** Screen-reader hints (default: the kit's `labels.flipToBack` / `labels.flipToFront`). */
|
|
36
36
|
labels?: { toBack?: string; toFront?: string };
|
|
37
37
|
style?: StyleProp<ViewStyle>;
|
|
38
38
|
}
|
|
@@ -52,7 +52,7 @@ const SQUEEZE = {
|
|
|
52
52
|
*/
|
|
53
53
|
export function useFlipProgress(flipped: boolean) {
|
|
54
54
|
const reduce = useReduceMotion();
|
|
55
|
-
const progress =
|
|
55
|
+
const [progress] = useState(() => new Animated.Value(flipped ? 1 : 0));
|
|
56
56
|
useEffect(() => {
|
|
57
57
|
if (reduce) progress.setValue(flipped ? 1 : 0);
|
|
58
58
|
else Animated.spring(progress, { toValue: flipped ? 1 : 0, ...motion.gentle, useNativeDriver: true }).start();
|
|
@@ -81,6 +81,7 @@ export function FlipCard({
|
|
|
81
81
|
labels,
|
|
82
82
|
style,
|
|
83
83
|
}: FlipCardProps) {
|
|
84
|
+
const kitLabels = useKit().labels;
|
|
84
85
|
const controlled = flippedProp !== undefined;
|
|
85
86
|
const [own, setOwn] = useState(defaultFlipped);
|
|
86
87
|
const flipped = controlled ? flippedProp : own;
|
|
@@ -177,7 +178,7 @@ export function FlipCard({
|
|
|
177
178
|
onPress={toggle}
|
|
178
179
|
accessibilityRole="button"
|
|
179
180
|
accessibilityLabel={accessibilityLabel}
|
|
180
|
-
accessibilityHint={flipped ? (labels?.toFront ??
|
|
181
|
+
accessibilityHint={flipped ? (labels?.toFront ?? kitLabels.flipToFront) : (labels?.toBack ?? kitLabels.flipToBack)}
|
|
181
182
|
accessibilityState={{ expanded: flipped }}
|
|
182
183
|
style={style}
|
|
183
184
|
>
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
Animated,
|
|
5
5
|
Easing,
|
|
6
6
|
Image,
|
|
7
|
-
PanResponder,
|
|
8
7
|
StyleSheet,
|
|
9
8
|
View,
|
|
10
9
|
type ImageSourcePropType,
|
|
@@ -14,7 +13,7 @@ import {
|
|
|
14
13
|
} from 'react-native';
|
|
15
14
|
import Svg, { Defs, LinearGradient, RadialGradient, Rect, Stop } from 'react-native-svg';
|
|
16
15
|
|
|
17
|
-
import { motion } from '@/lib/kit';
|
|
16
|
+
import { motion, usePanResponder } from '@/lib/kit';
|
|
18
17
|
|
|
19
18
|
/** `holo` adds a rainbow foil sheen that shifts as the card tilts (always faintly visible). */
|
|
20
19
|
export type TiltCardGlare = 'soft' | 'sharp' | 'holo' | 'none';
|
|
@@ -28,58 +27,58 @@ export interface TiltRect {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
export interface TiltCardProps {
|
|
31
|
-
children?: React.ReactNode;
|
|
30
|
+
children?: React.ReactNode | undefined;
|
|
32
31
|
/** Photo that fills the card behind the content (`require()` or `{ uri }`). */
|
|
33
|
-
image?: ImageSourcePropType;
|
|
32
|
+
image?: ImageSourcePropType | undefined;
|
|
34
33
|
/** Darkens the bottom of `image` so white text on it stays readable: 0 off … 1 strong (default 0.6). */
|
|
35
|
-
shade?: number;
|
|
34
|
+
shade?: number | undefined;
|
|
36
35
|
/** Maximum tilt in degrees at the card's edge (default 12). */
|
|
37
|
-
maxTilt?: number;
|
|
36
|
+
maxTilt?: number | undefined;
|
|
38
37
|
/** Scale while touched (default 1.03). */
|
|
39
|
-
pressScale?: number;
|
|
38
|
+
pressScale?: number | undefined;
|
|
40
39
|
/** Light reflection that slides across the card as it tilts. */
|
|
41
|
-
glare?: TiltCardGlare;
|
|
40
|
+
glare?: TiltCardGlare | undefined;
|
|
42
41
|
/**
|
|
43
42
|
* Where the reflection may fall, in card points — for cards with cut-outs (ticket notches,
|
|
44
43
|
* perforated edges), so light never shows over a hole. Default: the whole card.
|
|
45
44
|
*/
|
|
46
|
-
glareClip?: TiltRect[];
|
|
45
|
+
glareClip?: TiltRect[] | undefined;
|
|
47
46
|
/** Depth of the 3D effect — smaller is more dramatic (default 800). */
|
|
48
|
-
perspective?: number;
|
|
47
|
+
perspective?: number | undefined;
|
|
49
48
|
/** Slowly sway on its own while untouched, so the card reads as 3D at rest. */
|
|
50
|
-
idle?: boolean;
|
|
49
|
+
idle?: boolean | undefined;
|
|
51
50
|
/** Corner radius (default 20). */
|
|
52
|
-
radius?: number;
|
|
51
|
+
radius?: number | undefined;
|
|
53
52
|
/** Soft shadow under the card that shifts as it tilts (default true). */
|
|
54
|
-
shadow?: boolean;
|
|
53
|
+
shadow?: boolean | undefined;
|
|
55
54
|
/**
|
|
56
55
|
* The part of the card that casts the shadow, in card points — e.g. leave out a ticket stub that's
|
|
57
56
|
* being torn off, so the plate never shows where it was. Default: the whole card.
|
|
58
57
|
*/
|
|
59
|
-
shadowRect?: TiltRect;
|
|
58
|
+
shadowRect?: TiltRect | undefined;
|
|
60
59
|
/**
|
|
61
60
|
* Narrows the shadow sideways (1 = full width, 0 = none) — for content that turns edge-on inside
|
|
62
61
|
* the card, like a FlipCard mid-flip, so the shadow plate never shows past it.
|
|
63
62
|
*/
|
|
64
|
-
shadowScaleX?: Animated.Value | Animated.AnimatedInterpolation<number
|
|
63
|
+
shadowScaleX?: Animated.Value | Animated.AnimatedInterpolation<number> | undefined;
|
|
65
64
|
/** Turn touch tilting off (the card still renders, e.g. while a parent list scrolls). */
|
|
66
|
-
disabled?: boolean;
|
|
65
|
+
disabled?: boolean | undefined;
|
|
67
66
|
/** Called with a light tap (not after a drag). */
|
|
68
|
-
onPress?: () => void;
|
|
69
|
-
accessibilityLabel?: string;
|
|
67
|
+
onPress?: (() => void) | undefined;
|
|
68
|
+
accessibilityLabel?: string | undefined;
|
|
70
69
|
/** Width, height, margins — applied to the card's outer box. */
|
|
71
|
-
style?: StyleProp<ViewStyle
|
|
70
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
export interface TiltLayerProps {
|
|
75
|
-
children?: React.ReactNode;
|
|
74
|
+
children?: React.ReactNode | undefined;
|
|
76
75
|
/**
|
|
77
76
|
* How far above the card this layer floats: 0 sits on the card, 1 floats well above it
|
|
78
77
|
* and slides furthest as the card tilts (default 0.5). Negative sinks below the surface.
|
|
79
78
|
*/
|
|
80
|
-
depth?: number;
|
|
79
|
+
depth?: number | undefined;
|
|
81
80
|
/** Layers fill the card by default; position content inside, or override here. */
|
|
82
|
-
style?: StyleProp<ViewStyle
|
|
81
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
export interface TiltState {
|
|
@@ -109,7 +108,8 @@ const PAINT = 96;
|
|
|
109
108
|
// pinks, violets and cyans stay clean when blended over dark cards (yellow and green turn olive).
|
|
110
109
|
const SMOOTH = Easing.bezier(0.32, 0.72, 0, 1);
|
|
111
110
|
|
|
112
|
-
const
|
|
111
|
+
const HOLO_CYCLE = ['#ff6bd6', '#b38cff', '#6fb6ff', '#5ff0ff', '#a7ffe0', '#ffc2ef'];
|
|
112
|
+
const HOLO = Array.from({ length: 37 }, (_, i) => HOLO_CYCLE[i % HOLO_CYCLE.length] ?? '#ff6bd6');
|
|
113
113
|
|
|
114
114
|
function GlarePaint({ variant }: { variant: 'soft' | 'sharp' }) {
|
|
115
115
|
const sharp = variant === 'sharp';
|
|
@@ -262,21 +262,15 @@ export function TiltCard({
|
|
|
262
262
|
}: TiltCardProps) {
|
|
263
263
|
const reduce = useReduceMotion();
|
|
264
264
|
const [size, setSize] = useState({ w: 0, h: 0 });
|
|
265
|
-
const sizeRef = useRef(size);
|
|
266
|
-
sizeRef.current = size;
|
|
267
265
|
|
|
268
266
|
// -1 … 1 across the card; the card leans toward the finger.
|
|
269
|
-
const tx =
|
|
270
|
-
const ty =
|
|
271
|
-
const press =
|
|
267
|
+
const [tx] = useState(() => new Animated.Value(0));
|
|
268
|
+
const [ty] = useState(() => new Animated.Value(0));
|
|
269
|
+
const [press] = useState(() => new Animated.Value(0));
|
|
272
270
|
const touching = useRef(false);
|
|
273
271
|
const origin = useRef({ x: 0, y: 0 });
|
|
274
272
|
const moved = useRef(false);
|
|
275
273
|
const viewRef = useRef<ComponentRef<typeof View>>(null);
|
|
276
|
-
const disabledRef = useRef(disabled);
|
|
277
|
-
disabledRef.current = disabled;
|
|
278
|
-
const reduceRef = useRef(reduce);
|
|
279
|
-
reduceRef.current = reduce;
|
|
280
274
|
|
|
281
275
|
// Idle sway: a slow figure-eight while nobody is touching.
|
|
282
276
|
const idleLoop = useRef<Animated.CompositeAnimation | null>(null);
|
|
@@ -310,7 +304,7 @@ export function TiltCard({
|
|
|
310
304
|
}, [idle, reduce]);
|
|
311
305
|
|
|
312
306
|
const aim = (pageX: number, pageY: number) => {
|
|
313
|
-
const { w, h } =
|
|
307
|
+
const { w, h } = size;
|
|
314
308
|
if (!w || !h) return;
|
|
315
309
|
tx.setValue(Math.max(-1, Math.min(1, ((pageX - origin.current.x) / w) * 2 - 1)));
|
|
316
310
|
ty.setValue(Math.max(-1, Math.min(1, ((pageY - origin.current.y) / h) * 2 - 1)));
|
|
@@ -318,7 +312,7 @@ export function TiltCard({
|
|
|
318
312
|
|
|
319
313
|
const release = (tapped: boolean) => {
|
|
320
314
|
touching.current = false;
|
|
321
|
-
if (tapped && !moved.current)
|
|
315
|
+
if (tapped && !moved.current) onPress?.();
|
|
322
316
|
if (reduce) {
|
|
323
317
|
// The card never leaves flat, so only the light has to settle: a short ease, no spring.
|
|
324
318
|
const settle = (v: Animated.Value) => Animated.timing(v, { toValue: 0, duration: 150, easing: SMOOTH, useNativeDriver: true });
|
|
@@ -345,57 +339,48 @@ export function TiltCard({
|
|
|
345
339
|
if (finished && !touching.current) startIdle();
|
|
346
340
|
});
|
|
347
341
|
};
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
onPanResponderRelease: () => releaseRef.current(true),
|
|
391
|
-
onPanResponderTerminate: () => releaseRef.current(false),
|
|
392
|
-
// React Native grants before asking the current responder to let go; when a child keeps its
|
|
393
|
-
// gesture (e.g. a ticket stub being torn), the grant is rejected and no release follows.
|
|
394
|
-
onPanResponderReject: () => releaseRef.current(false),
|
|
395
|
-
}),
|
|
396
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
397
|
-
[]
|
|
398
|
-
);
|
|
342
|
+
// usePanResponder always calls the latest callbacks, so they read props and state directly and
|
|
343
|
+
// the responder is never rebuilt mid-gesture.
|
|
344
|
+
const pan = usePanResponder({
|
|
345
|
+
onStartShouldSetPanResponder: () => !disabled,
|
|
346
|
+
// Only a real drag takes the touch from a button inside the card — a tap's tiny jitter must not.
|
|
347
|
+
onMoveShouldSetPanResponder: (_e, g) => !disabled && Math.abs(g.dx) + Math.abs(g.dy) > 6,
|
|
348
|
+
// Let a parent ScrollView take over scrolls that start on the card (on Android the native
|
|
349
|
+
// scroll view can only do that when the card doesn't block it).
|
|
350
|
+
onPanResponderTerminationRequest: () => true,
|
|
351
|
+
onShouldBlockNativeResponder: () => false,
|
|
352
|
+
onPanResponderGrant: (e) => {
|
|
353
|
+
touching.current = true;
|
|
354
|
+
moved.current = false;
|
|
355
|
+
idleLoop.current?.stop();
|
|
356
|
+
const { pageX, pageY, locationX, locationY } = e.nativeEvent;
|
|
357
|
+
// locationX is relative to the touched child, so measure the card itself and correct
|
|
358
|
+
// once the measurement arrives.
|
|
359
|
+
origin.current = { x: pageX - locationX, y: pageY - locationY };
|
|
360
|
+
viewRef.current?.measure((_x, _y, _w, _h, px, py) => {
|
|
361
|
+
if (typeof px === 'number' && typeof py === 'number') origin.current = { x: px, y: py };
|
|
362
|
+
});
|
|
363
|
+
aim(pageX, pageY);
|
|
364
|
+
if (reduce) {
|
|
365
|
+
Animated.timing(press, { toValue: 1, duration: 150, easing: SMOOTH, useNativeDriver: true }).start();
|
|
366
|
+
} else {
|
|
367
|
+
Animated.spring(press, {
|
|
368
|
+
toValue: 1,
|
|
369
|
+
...motion.snappy,
|
|
370
|
+
useNativeDriver: true,
|
|
371
|
+
}).start();
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
onPanResponderMove: (e, g) => {
|
|
375
|
+
if (Math.abs(g.dx) + Math.abs(g.dy) > 6) moved.current = true;
|
|
376
|
+
aim(e.nativeEvent.pageX, e.nativeEvent.pageY);
|
|
377
|
+
},
|
|
378
|
+
onPanResponderRelease: () => release(true),
|
|
379
|
+
onPanResponderTerminate: () => release(false),
|
|
380
|
+
// React Native grants before asking the current responder to let go; when a child keeps its
|
|
381
|
+
// gesture (e.g. a ticket stub being torn), the grant is rejected and no release follows.
|
|
382
|
+
onPanResponderReject: () => release(false),
|
|
383
|
+
});
|
|
399
384
|
|
|
400
385
|
const onLayout = (e: LayoutChangeEvent) => {
|
|
401
386
|
const { width, height } = e.nativeEvent.layout;
|
|
@@ -473,14 +458,14 @@ export function TiltCard({
|
|
|
473
458
|
<View collapsable={false}>
|
|
474
459
|
<Animated.View
|
|
475
460
|
ref={viewRef}
|
|
476
|
-
{...
|
|
461
|
+
{...pan}
|
|
477
462
|
accessible={!!onPress || !!accessibilityLabel}
|
|
478
463
|
accessibilityRole={onPress ? 'button' : undefined}
|
|
479
464
|
accessibilityLabel={accessibilityLabel}
|
|
480
465
|
// Screen readers activate the card through an action, not synthesized touches.
|
|
481
466
|
accessibilityActions={onPress ? [{ name: 'activate' }] : undefined}
|
|
482
467
|
onAccessibilityAction={(e) => {
|
|
483
|
-
if (e.nativeEvent.actionName === 'activate')
|
|
468
|
+
if (e.nativeEvent.actionName === 'activate') onPress?.();
|
|
484
469
|
}}
|
|
485
470
|
style={{
|
|
486
471
|
borderRadius: radius,
|
|
@@ -575,12 +560,12 @@ export function TiltLayer({ children, depth = 0.5, style }: TiltLayerProps) {
|
|
|
575
560
|
}
|
|
576
561
|
|
|
577
562
|
export interface TiltFoilProps {
|
|
578
|
-
children?: React.ReactNode;
|
|
563
|
+
children?: React.ReactNode | undefined;
|
|
579
564
|
/** Corner radius (default 8). */
|
|
580
|
-
radius?: number;
|
|
565
|
+
radius?: number | undefined;
|
|
581
566
|
/** Base metal under the rainbow (default silver). */
|
|
582
|
-
base?: string;
|
|
583
|
-
style?: StyleProp<ViewStyle
|
|
567
|
+
base?: string | undefined;
|
|
568
|
+
style?: StyleProp<ViewStyle> | undefined;
|
|
584
569
|
}
|
|
585
570
|
|
|
586
571
|
/**
|