@expokit/cli 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +32 -2
- package/bin/expo-kit.js +1204 -0
- package/bin/lib.mjs +343 -0
- package/bin/mcp.mjs +338 -0
- package/package.json +44 -4
- package/registry/_docs/accordion.json +99 -0
- package/registry/_docs/action-sheet.json +110 -0
- package/registry/_docs/alert.json +127 -0
- package/registry/_docs/avatar.json +203 -0
- package/registry/_docs/badge.json +117 -0
- package/registry/_docs/bottom-nav.json +119 -0
- package/registry/_docs/bottom-sheet.json +158 -0
- package/registry/_docs/bullet.json +24 -0
- package/registry/_docs/button-3d.json +122 -0
- package/registry/_docs/button.json +115 -0
- package/registry/_docs/calendar.json +182 -0
- package/registry/_docs/card-stack.json +108 -0
- package/registry/_docs/card.json +111 -0
- package/registry/_docs/carousel.json +102 -0
- package/registry/_docs/checkbox.json +93 -0
- package/registry/_docs/checkout.json +102 -0
- package/registry/_docs/chip-group.json +116 -0
- package/registry/_docs/color-swatch.json +66 -0
- package/registry/_docs/confetti.json +82 -0
- package/registry/_docs/coupon.json +176 -0
- package/registry/_docs/cube-pager.json +84 -0
- package/registry/_docs/dashboard.json +120 -0
- package/registry/_docs/date-picker.json +249 -0
- package/registry/_docs/dialog.json +162 -0
- package/registry/_docs/drawer.json +171 -0
- package/registry/_docs/fab.json +120 -0
- package/registry/_docs/flip-card.json +111 -0
- package/registry/_docs/floating-input.json +191 -0
- package/registry/_docs/gift-card.json +108 -0
- package/registry/_docs/glass-button.json +118 -0
- package/registry/_docs/glass-nav-bar.json +78 -0
- package/registry/_docs/glass-search-bar.json +90 -0
- package/registry/_docs/glass-segmented.json +66 -0
- package/registry/_docs/glass-sheet.json +108 -0
- package/registry/_docs/glass-tab-bar.json +76 -0
- package/registry/_docs/glass.json +78 -0
- package/registry/_docs/inbox.json +72 -0
- package/registry/_docs/isometric-bar.json +72 -0
- package/registry/_docs/kit.json +11 -0
- package/registry/_docs/kpi-card.json +11 -0
- package/registry/_docs/like-button.json +72 -0
- package/registry/_docs/liquidglass-tab.json +27 -0
- package/registry/_docs/list-item.json +200 -0
- package/registry/_docs/loyalty-card.json +108 -0
- package/registry/_docs/morph-button.json +108 -0
- package/registry/_docs/number-ticker.json +96 -0
- package/registry/_docs/offers.json +78 -0
- package/registry/_docs/onboarding.json +66 -0
- package/registry/_docs/otp-input.json +134 -0
- package/registry/_docs/pagination-dots.json +88 -0
- package/registry/_docs/parallax-layers.json +84 -0
- package/registry/_docs/parallax-scroll.json +186 -0
- package/registry/_docs/password-input.json +92 -0
- package/registry/_docs/payment-card.json +153 -0
- package/registry/_docs/pixel-bar.json +66 -0
- package/registry/_docs/polar-area.json +78 -0
- package/registry/_docs/profile.json +84 -0
- package/registry/_docs/progress-steps.json +92 -0
- package/registry/_docs/progress.json +132 -0
- package/registry/_docs/radio-group.json +92 -0
- package/registry/_docs/rating.json +90 -0
- package/registry/_docs/ring-carousel.json +102 -0
- package/registry/_docs/scratch-card.json +90 -0
- package/registry/_docs/search-bar.json +140 -0
- package/registry/_docs/search-results.json +120 -0
- package/registry/_docs/segmented-control.json +103 -0
- package/registry/_docs/select.json +252 -0
- package/registry/_docs/settings.json +72 -0
- package/registry/_docs/shimmer-button.json +78 -0
- package/registry/_docs/sign-in.json +198 -0
- package/registry/_docs/skeleton.json +142 -0
- package/registry/_docs/slide-to-confirm.json +84 -0
- package/registry/_docs/slider.json +157 -0
- package/registry/_docs/spin-wheel.json +114 -0
- package/registry/_docs/spinner.json +91 -0
- package/registry/_docs/stepper.json +168 -0
- package/registry/_docs/swipe-deck.json +102 -0
- package/registry/_docs/swipeable-row.json +72 -0
- package/registry/_docs/switch.json +104 -0
- package/registry/_docs/tabs.json +105 -0
- package/registry/_docs/tag-input.json +128 -0
- package/registry/_docs/textarea.json +175 -0
- package/registry/_docs/ticket-card.json +174 -0
- package/registry/_docs/ticket-shape.json +11 -0
- package/registry/_docs/tilt-card.json +141 -0
- package/registry/_docs/time-picker.json +253 -0
- package/registry/_docs/timeline-chart.json +30 -0
- package/registry/_docs/timeline.json +156 -0
- package/registry/_docs/toast.json +161 -0
- package/registry/_docs/treemap.json +30 -0
- package/registry/_docs/waterfall.json +36 -0
- package/registry/_docs/wheel-list.json +102 -0
- package/registry/accordion/files/src/components/ui/accordion.tsx +233 -0
- package/registry/accordion/files/src/lib/kit.tsx +219 -0
- package/registry/accordion.json +17 -0
- package/registry/action-sheet/files/src/components/ui/action-sheet.tsx +580 -0
- package/registry/action-sheet/files/src/lib/kit.tsx +219 -0
- package/registry/action-sheet.json +18 -0
- package/registry/alert/files/src/components/ui/alert.tsx +654 -0
- package/registry/alert/files/src/components/ui/button.tsx +274 -0
- package/registry/alert/files/src/lib/kit.tsx +219 -0
- package/registry/alert.json +20 -0
- package/registry/avatar/files/src/components/ui/avatar.tsx +790 -0
- package/registry/avatar/files/src/lib/kit.tsx +219 -0
- package/registry/avatar.json +18 -0
- package/registry/badge/files/src/components/ui/badge.tsx +316 -0
- package/registry/badge/files/src/lib/kit.tsx +219 -0
- package/registry/badge.json +17 -0
- package/registry/bottom-nav/files/src/components/ui/bottom-nav.tsx +1050 -0
- package/registry/bottom-nav/files/src/lib/kit.tsx +219 -0
- package/registry/bottom-nav.json +18 -0
- package/registry/bottom-sheet/files/src/components/ui/bottom-sheet.tsx +585 -0
- package/registry/bottom-sheet/files/src/lib/kit.tsx +219 -0
- package/registry/bottom-sheet.json +17 -0
- package/registry/bullet.json +14 -0
- package/registry/button/files/src/components/ui/button.tsx +274 -0
- package/registry/button/files/src/lib/kit.tsx +219 -0
- package/registry/button-3d/files/src/components/ui/button-3d.tsx +212 -0
- package/registry/button-3d/files/src/lib/kit.tsx +219 -0
- package/registry/button-3d.json +18 -0
- package/registry/button.json +18 -0
- package/registry/calendar/files/src/components/ui/calendar.tsx +822 -0
- package/registry/calendar/files/src/lib/kit.tsx +219 -0
- package/registry/calendar.json +17 -0
- package/registry/card/files/src/components/ui/card.tsx +300 -0
- package/registry/card/files/src/lib/kit.tsx +219 -0
- package/registry/card-stack.json +15 -0
- package/registry/card.json +17 -0
- package/registry/carousel.json +15 -0
- package/registry/checkbox/files/src/components/ui/checkbox.tsx +150 -0
- package/registry/checkbox/files/src/lib/kit.tsx +219 -0
- package/registry/checkbox.json +17 -0
- package/registry/checkout.json +26 -0
- package/registry/chip-group/files/src/components/ui/chip-group.tsx +269 -0
- package/registry/chip-group/files/src/lib/kit.tsx +219 -0
- package/registry/chip-group.json +17 -0
- package/registry/color-swatch.json +17 -0
- package/registry/confetti/files/src/components/ui/confetti.tsx +222 -0
- package/registry/confetti/files/src/lib/kit.tsx +219 -0
- package/registry/confetti.json +15 -0
- package/registry/coupon/files/src/components/ui/coupon.tsx +698 -0
- package/registry/coupon/files/src/components/ui/flip-card.tsx +205 -0
- package/registry/coupon/files/src/components/ui/tilt-card.tsx +635 -0
- package/registry/coupon/files/src/lib/kit.tsx +219 -0
- package/registry/coupon/files/src/lib/ticket-shape.tsx +543 -0
- package/registry/coupon.json +23 -0
- package/registry/cube-pager.json +15 -0
- package/registry/dashboard.json +32 -0
- package/registry/date-picker/files/src/components/ui/calendar.tsx +822 -0
- package/registry/date-picker/files/src/components/ui/date-picker.tsx +796 -0
- package/registry/date-picker/files/src/lib/kit.tsx +219 -0
- package/registry/date-picker.json +19 -0
- package/registry/dialog/files/src/components/ui/dialog.tsx +759 -0
- package/registry/dialog/files/src/lib/kit.tsx +219 -0
- package/registry/dialog.json +18 -0
- package/registry/drawer/files/src/components/ui/drawer.tsx +1135 -0
- package/registry/drawer/files/src/lib/kit.tsx +219 -0
- package/registry/drawer.json +18 -0
- package/registry/fab.json +18 -0
- package/registry/flip-card/files/src/components/ui/flip-card.tsx +205 -0
- package/registry/flip-card/files/src/lib/kit.tsx +219 -0
- package/registry/flip-card.json +15 -0
- package/registry/floating-input/files/src/components/ui/floating-input.tsx +528 -0
- package/registry/floating-input/files/src/lib/kit.tsx +219 -0
- package/registry/floating-input.json +17 -0
- package/registry/gift-card.json +21 -0
- package/registry/glass-button.json +22 -0
- package/registry/glass-nav-bar.json +21 -0
- package/registry/glass-search-bar.json +21 -0
- package/registry/glass-segmented.json +22 -0
- package/registry/glass-sheet.json +22 -0
- package/registry/glass-tab-bar.json +22 -0
- package/registry/glass.json +19 -0
- package/registry/inbox.json +30 -0
- package/registry/isometric-bar.json +14 -0
- package/registry/kit/files/src/lib/kit.tsx +219 -0
- package/registry/kit.json +11 -0
- package/registry/kpi-card/files/src/components/charts/kpi-card.tsx +45 -0
- package/registry/kpi-card.json +14 -0
- package/registry/like-button.json +18 -0
- package/registry/liquidglass-tab/files/src/app/(tabs)/_layout.tsx +97 -0
- package/registry/liquidglass-tab/files/src/app/(tabs)/alerts.tsx +5 -0
- package/registry/liquidglass-tab/files/src/app/(tabs)/explore.tsx +5 -0
- package/registry/liquidglass-tab/files/src/app/(tabs)/index.tsx +5 -0
- package/registry/liquidglass-tab/files/src/app/(tabs)/profile.tsx +5 -0
- package/registry/liquidglass-tab/files/src/app/_layout.tsx +33 -0
- package/registry/liquidglass-tab/files/src/components/GlassTabBar.tsx +259 -0
- package/registry/liquidglass-tab/files/src/components/TabScreen.tsx +122 -0
- package/registry/liquidglass-tab/files/src/lib/tab-bar.ts +61 -0
- package/registry/liquidglass-tab/files/src/lib/tab-icons.ts +130 -0
- package/registry/liquidglass-tab/files/src/lib/tabs.ts +108 -0
- package/registry/liquidglass-tab.json +23 -0
- package/registry/list-item/files/src/components/ui/list-item.tsx +508 -0
- package/registry/list-item/files/src/lib/kit.tsx +219 -0
- package/registry/list-item.json +17 -0
- package/registry/loyalty-card.json +23 -0
- package/registry/morph-button.json +18 -0
- package/registry/number-ticker.json +15 -0
- package/registry/offers.json +24 -0
- package/registry/onboarding.json +17 -0
- package/registry/otp-input/files/src/components/ui/otp-input.tsx +380 -0
- package/registry/otp-input/files/src/lib/kit.tsx +219 -0
- package/registry/otp-input.json +17 -0
- package/registry/pagination-dots/files/src/components/ui/pagination-dots.tsx +262 -0
- package/registry/pagination-dots/files/src/lib/kit.tsx +219 -0
- package/registry/pagination-dots.json +15 -0
- package/registry/parallax-layers.json +15 -0
- package/registry/parallax-scroll.json +17 -0
- package/registry/password-input/files/src/components/ui/floating-input.tsx +528 -0
- package/registry/password-input/files/src/components/ui/password-input.tsx +271 -0
- package/registry/password-input/files/src/lib/kit.tsx +219 -0
- package/registry/password-input.json +19 -0
- package/registry/payment-card/files/src/components/ui/flip-card.tsx +205 -0
- package/registry/payment-card/files/src/components/ui/payment-card.tsx +385 -0
- package/registry/payment-card/files/src/components/ui/tilt-card.tsx +635 -0
- package/registry/payment-card/files/src/lib/kit.tsx +219 -0
- package/registry/payment-card.json +21 -0
- package/registry/pixel-bar.json +14 -0
- package/registry/polar-area.json +14 -0
- package/registry/profile.json +17 -0
- package/registry/progress/files/src/components/ui/progress.tsx +883 -0
- package/registry/progress/files/src/lib/kit.tsx +219 -0
- package/registry/progress-steps/files/src/components/ui/progress-steps.tsx +559 -0
- package/registry/progress-steps/files/src/lib/kit.tsx +219 -0
- package/registry/progress-steps.json +18 -0
- package/registry/progress.json +17 -0
- package/registry/radio-group/files/src/components/ui/radio-group.tsx +327 -0
- package/registry/radio-group/files/src/lib/kit.tsx +219 -0
- package/registry/radio-group.json +18 -0
- package/registry/rating.json +18 -0
- package/registry/ring-carousel.json +15 -0
- package/registry/scratch-card.json +18 -0
- package/registry/search-bar/files/src/components/ui/search-bar.tsx +530 -0
- package/registry/search-bar/files/src/lib/kit.tsx +219 -0
- package/registry/search-bar.json +17 -0
- package/registry/search-results.json +30 -0
- package/registry/segmented-control/files/src/components/ui/segmented-control.tsx +341 -0
- package/registry/segmented-control/files/src/lib/kit.tsx +219 -0
- package/registry/segmented-control.json +18 -0
- package/registry/select/files/src/components/ui/select.tsx +1398 -0
- package/registry/select/files/src/lib/kit.tsx +219 -0
- package/registry/select.json +17 -0
- package/registry/settings.json +26 -0
- package/registry/shimmer-button.json +17 -0
- package/registry/sign-in.json +26 -0
- package/registry/skeleton/files/src/components/ui/skeleton.tsx +799 -0
- package/registry/skeleton/files/src/lib/kit.tsx +219 -0
- package/registry/skeleton.json +17 -0
- package/registry/slide-to-confirm.json +18 -0
- package/registry/slider/files/src/components/ui/slider.tsx +716 -0
- package/registry/slider/files/src/lib/kit.tsx +219 -0
- package/registry/slider.json +17 -0
- package/registry/spin-wheel.json +18 -0
- package/registry/spinner/files/src/components/ui/spinner.tsx +335 -0
- package/registry/spinner/files/src/lib/kit.tsx +219 -0
- package/registry/spinner.json +17 -0
- package/registry/stepper/files/src/components/ui/stepper.tsx +646 -0
- package/registry/stepper/files/src/lib/kit.tsx +219 -0
- package/registry/stepper.json +17 -0
- package/registry/swipe-deck.json +15 -0
- package/registry/swipeable-row.json +15 -0
- package/registry/switch/files/src/components/ui/switch.tsx +344 -0
- package/registry/switch/files/src/lib/kit.tsx +219 -0
- package/registry/switch.json +18 -0
- package/registry/tabs/files/src/components/ui/tabs.tsx +539 -0
- package/registry/tabs/files/src/lib/kit.tsx +219 -0
- package/registry/tabs.json +17 -0
- package/registry/tag-input/files/src/components/ui/tag-input.tsx +720 -0
- package/registry/tag-input/files/src/lib/kit.tsx +219 -0
- package/registry/tag-input.json +17 -0
- package/registry/textarea/files/src/components/ui/textarea.tsx +553 -0
- package/registry/textarea/files/src/lib/kit.tsx +219 -0
- package/registry/textarea.json +17 -0
- package/registry/ticket-card.json +24 -0
- package/registry/ticket-shape/files/src/lib/kit.tsx +219 -0
- package/registry/ticket-shape/files/src/lib/ticket-shape.tsx +543 -0
- package/registry/ticket-shape.json +17 -0
- package/registry/tilt-card/files/src/components/ui/tilt-card.tsx +635 -0
- package/registry/tilt-card/files/src/lib/kit.tsx +219 -0
- package/registry/tilt-card.json +17 -0
- package/registry/time-picker/files/src/components/ui/time-picker.tsx +1159 -0
- package/registry/time-picker/files/src/lib/kit.tsx +219 -0
- package/registry/time-picker.json +17 -0
- package/registry/timeline/files/src/components/ui/avatar.tsx +790 -0
- package/registry/timeline/files/src/components/ui/timeline.tsx +1059 -0
- package/registry/timeline/files/src/lib/kit.tsx +219 -0
- package/registry/timeline-chart.json +14 -0
- package/registry/timeline.json +20 -0
- package/registry/toast/files/src/components/ui/button.tsx +274 -0
- package/registry/toast/files/src/components/ui/toast.tsx +1284 -0
- package/registry/toast/files/src/lib/kit.tsx +219 -0
- package/registry/toast.json +20 -0
- package/registry/treemap.json +14 -0
- package/registry/waterfall.json +14 -0
- package/registry/wheel-list.json +17 -0
- package/schema/components.schema.json +13 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { Animated, Pressable, StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { motion } from '@/lib/kit';
|
|
5
|
+
|
|
6
|
+
export type FlipDirection = 'horizontal' | 'vertical';
|
|
7
|
+
export type FlipTrigger = 'press' | 'none';
|
|
8
|
+
|
|
9
|
+
export interface FlipCardProps {
|
|
10
|
+
/** Shown first. Sets the card's size — the back fills the same box. */
|
|
11
|
+
front: React.ReactNode;
|
|
12
|
+
back: React.ReactNode;
|
|
13
|
+
/** Controlled side: `true` shows the back. */
|
|
14
|
+
flipped?: boolean;
|
|
15
|
+
/** Uncontrolled initial side (default false). */
|
|
16
|
+
defaultFlipped?: boolean;
|
|
17
|
+
onFlip?: (flipped: boolean) => void;
|
|
18
|
+
/** Spin around the vertical axis (left/right) or the horizontal one (top/bottom). */
|
|
19
|
+
direction?: FlipDirection;
|
|
20
|
+
/** `press` flips on tap; `none` leaves it to `flipped` (e.g. a button elsewhere). */
|
|
21
|
+
trigger?: FlipTrigger;
|
|
22
|
+
/** Depth of the 3D effect — smaller is more dramatic (default 1000). */
|
|
23
|
+
perspective?: number;
|
|
24
|
+
/** Corner radius of both faces (default 20). */
|
|
25
|
+
radius?: number;
|
|
26
|
+
/** Soft shadow that narrows as the card turns edge-on (default true). */
|
|
27
|
+
shadow?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Drive the turn from outside (0 = front, 1 = back) — from `useFlipProgress`, when something else
|
|
30
|
+
* must follow the flip, like a TiltCard's shadow. `flipped` still sets the side for accessibility.
|
|
31
|
+
*/
|
|
32
|
+
progress?: Animated.Value;
|
|
33
|
+
/** Accessibility label; the hint says which side is showing. */
|
|
34
|
+
accessibilityLabel?: string;
|
|
35
|
+
/** Screen-reader hints (defaults in English). */
|
|
36
|
+
labels?: { toBack?: string; toFront?: string };
|
|
37
|
+
style?: StyleProp<ViewStyle>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// How wide the shadow under a flipping card is through the turn: roughly cos θ, always a little
|
|
41
|
+
// narrower than the card so a flat shadow plate never shows past it, and none at all edge-on.
|
|
42
|
+
const SQUEEZE = {
|
|
43
|
+
inputRange: [0, 0.25, 0.45, 0.5, 0.55, 0.75, 1],
|
|
44
|
+
outputRange: [1, 0.6, 0.12, 0, 0.12, 0.6, 1],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The flip as an animated 0 → 1 value, springing like FlipCard's own, plus `shadowScaleX` — pass
|
|
49
|
+
* `progress` to the FlipCard and `shadowScaleX` to a TiltCard wrapped round it, so the tilt
|
|
50
|
+
* shadow narrows as the card turns edge-on instead of showing as a dark box behind it.
|
|
51
|
+
*/
|
|
52
|
+
export function useFlipProgress(flipped: boolean) {
|
|
53
|
+
const progress = useRef(new Animated.Value(flipped ? 1 : 0)).current;
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
Animated.spring(progress, { toValue: flipped ? 1 : 0, ...motion.gentle, useNativeDriver: true }).start();
|
|
56
|
+
}, [flipped, progress]);
|
|
57
|
+
const shadowScaleX = useMemo(() => progress.interpolate(SQUEEZE), [progress]);
|
|
58
|
+
return { progress, shadowScaleX };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A card with two faces that flips in 3D on tap — it lifts toward you half-way through and its
|
|
63
|
+
* shadow narrows as it turns edge-on, like a real card turning over. Controlled or uncontrolled.
|
|
64
|
+
*/
|
|
65
|
+
export function FlipCard({
|
|
66
|
+
front,
|
|
67
|
+
back,
|
|
68
|
+
flipped: flippedProp,
|
|
69
|
+
defaultFlipped = false,
|
|
70
|
+
onFlip,
|
|
71
|
+
direction = 'horizontal',
|
|
72
|
+
trigger = 'press',
|
|
73
|
+
perspective = 1000,
|
|
74
|
+
radius = 20,
|
|
75
|
+
shadow = true,
|
|
76
|
+
progress,
|
|
77
|
+
accessibilityLabel,
|
|
78
|
+
labels,
|
|
79
|
+
style,
|
|
80
|
+
}: FlipCardProps) {
|
|
81
|
+
const controlled = flippedProp !== undefined;
|
|
82
|
+
const [own, setOwn] = useState(defaultFlipped);
|
|
83
|
+
const flipped = controlled ? flippedProp : own;
|
|
84
|
+
|
|
85
|
+
const turn = useFlipProgress(flipped).progress;
|
|
86
|
+
const p = progress ?? turn;
|
|
87
|
+
|
|
88
|
+
const toggle = () => {
|
|
89
|
+
const next = !flipped;
|
|
90
|
+
if (!controlled) setOwn(next);
|
|
91
|
+
onFlip?.(next);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const horizontal = direction === 'horizontal';
|
|
95
|
+
const axis = horizontal ? 'rotateY' : 'rotateX';
|
|
96
|
+
const frontTurn = p.interpolate({
|
|
97
|
+
inputRange: [0, 1],
|
|
98
|
+
outputRange: ['0deg', '180deg'],
|
|
99
|
+
});
|
|
100
|
+
const backTurn = p.interpolate({
|
|
101
|
+
inputRange: [0, 1],
|
|
102
|
+
outputRange: ['180deg', '360deg'],
|
|
103
|
+
});
|
|
104
|
+
// Lift toward the viewer half-way through the turn.
|
|
105
|
+
const lift = p.interpolate({
|
|
106
|
+
inputRange: [0, 0.5, 1],
|
|
107
|
+
outputRange: [1, 1.05, 1],
|
|
108
|
+
});
|
|
109
|
+
// Swap faces exactly at 90° — backfaceVisibility alone flickers on some Android versions.
|
|
110
|
+
const frontOpacity = p.interpolate({
|
|
111
|
+
inputRange: [0, 0.499, 0.5, 1],
|
|
112
|
+
outputRange: [1, 1, 0, 0],
|
|
113
|
+
});
|
|
114
|
+
const backOpacity = p.interpolate({
|
|
115
|
+
inputRange: [0, 0.499, 0.5, 1],
|
|
116
|
+
outputRange: [0, 0, 1, 1],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const face = (turn: Animated.AnimatedInterpolation<string>, opacity: Animated.AnimatedInterpolation<number>) =>
|
|
120
|
+
({
|
|
121
|
+
borderRadius: radius,
|
|
122
|
+
opacity,
|
|
123
|
+
transform: [{ perspective }, { [axis]: turn } as never, { scale: lift }],
|
|
124
|
+
}) as Animated.WithAnimatedObject<ViewStyle>;
|
|
125
|
+
|
|
126
|
+
// The shadow squeezes along the turning axis as the card goes edge-on (see SQUEEZE) and fades a little.
|
|
127
|
+
const squeeze = p.interpolate(SQUEEZE);
|
|
128
|
+
|
|
129
|
+
const body = (
|
|
130
|
+
<View>
|
|
131
|
+
{shadow ? (
|
|
132
|
+
<Animated.View
|
|
133
|
+
pointerEvents="none"
|
|
134
|
+
style={[
|
|
135
|
+
styles.plate,
|
|
136
|
+
{
|
|
137
|
+
borderRadius: radius,
|
|
138
|
+
opacity: p.interpolate({
|
|
139
|
+
inputRange: [0, 0.5, 1],
|
|
140
|
+
outputRange: [1, 0.4, 1],
|
|
141
|
+
}),
|
|
142
|
+
transform: [{ scale: 0.9 }, horizontal ? { scaleX: squeeze } : { scaleY: squeeze }],
|
|
143
|
+
},
|
|
144
|
+
]}
|
|
145
|
+
/>
|
|
146
|
+
) : null}
|
|
147
|
+
{/* Faces live in their own (non-collapsing) layer: iOS intersects sibling layers in 3D, so a
|
|
148
|
+
turning face next to the flat shadow plate would be sliced by it. */}
|
|
149
|
+
{/* On Android the wrapper carries the elevation that keeps the faces above the plate; the faces
|
|
150
|
+
get none, since a face turned in 3D would cast a warped shadow wedge below the card. */}
|
|
151
|
+
<View collapsable={false} style={{ elevation: shadow ? 23 : 0 }}>
|
|
152
|
+
{/* The hidden face stays mounted (for the turn) but is hidden from screen readers. */}
|
|
153
|
+
<Animated.View
|
|
154
|
+
style={[styles.face, face(frontTurn, frontOpacity)]}
|
|
155
|
+
pointerEvents={flipped ? 'none' : 'auto'}
|
|
156
|
+
accessibilityElementsHidden={flipped}
|
|
157
|
+
importantForAccessibility={flipped ? 'no-hide-descendants' : 'auto'}
|
|
158
|
+
>
|
|
159
|
+
{front}
|
|
160
|
+
</Animated.View>
|
|
161
|
+
<Animated.View
|
|
162
|
+
style={[styles.face, styles.back, face(backTurn, backOpacity)]}
|
|
163
|
+
pointerEvents={flipped ? 'auto' : 'none'}
|
|
164
|
+
accessibilityElementsHidden={!flipped}
|
|
165
|
+
importantForAccessibility={flipped ? 'auto' : 'no-hide-descendants'}
|
|
166
|
+
>
|
|
167
|
+
{back}
|
|
168
|
+
</Animated.View>
|
|
169
|
+
</View>
|
|
170
|
+
</View>
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
if (trigger === 'none') return <View style={style}>{body}</View>;
|
|
174
|
+
return (
|
|
175
|
+
<Pressable
|
|
176
|
+
onPress={toggle}
|
|
177
|
+
accessibilityRole="button"
|
|
178
|
+
accessibilityLabel={accessibilityLabel}
|
|
179
|
+
accessibilityHint={flipped ? (labels?.toFront ?? 'Showing the back. Tap to flip to the front.') : (labels?.toBack ?? 'Tap to flip to the back.')}
|
|
180
|
+
accessibilityState={{ expanded: flipped }}
|
|
181
|
+
style={style}
|
|
182
|
+
>
|
|
183
|
+
{body}
|
|
184
|
+
</Pressable>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const styles = StyleSheet.create({
|
|
189
|
+
face: { overflow: 'hidden', backfaceVisibility: 'hidden' },
|
|
190
|
+
back: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 },
|
|
191
|
+
plate: {
|
|
192
|
+
position: 'absolute',
|
|
193
|
+
top: 0,
|
|
194
|
+
left: 0,
|
|
195
|
+
right: 0,
|
|
196
|
+
bottom: 0,
|
|
197
|
+
backgroundColor: '#000',
|
|
198
|
+
shadowColor: '#000',
|
|
199
|
+
shadowOpacity: 0.4,
|
|
200
|
+
shadowRadius: 20,
|
|
201
|
+
shadowOffset: { width: 0, height: 14 },
|
|
202
|
+
// High enough that Android's shadow spreads past the inset plate (iOS uses the shadow* props).
|
|
203
|
+
elevation: 22,
|
|
204
|
+
},
|
|
205
|
+
});
|