@retray-dev/ui-kit 6.2.0 → 9.0.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/COMPONENTS.md +997 -20
- package/EXAMPLES.md +250 -2
- package/README.md +21 -14
- package/dist/Accordion.d.mts +28 -0
- package/dist/Accordion.d.ts +28 -0
- package/dist/Accordion.js +392 -0
- package/dist/Accordion.mjs +7 -0
- package/dist/AlertBanner.d.mts +16 -0
- package/dist/AlertBanner.d.ts +16 -0
- package/dist/AlertBanner.js +250 -0
- package/dist/AlertBanner.mjs +6 -0
- package/dist/AppHeader.d.mts +40 -0
- package/dist/AppHeader.d.ts +40 -0
- package/dist/AppHeader.js +515 -0
- package/dist/AppHeader.mjs +10 -0
- package/dist/Avatar.d.mts +20 -0
- package/dist/Avatar.d.ts +20 -0
- package/dist/Avatar.js +244 -0
- package/dist/Avatar.mjs +4 -0
- package/dist/Badge.d.mts +26 -0
- package/dist/Badge.d.ts +26 -0
- package/dist/Badge.js +257 -0
- package/dist/Badge.mjs +5 -0
- package/dist/Button.d.mts +30 -0
- package/dist/Button.d.ts +30 -0
- package/dist/Button.js +432 -0
- package/dist/Button.mjs +9 -0
- package/dist/ButtonGroup.d.mts +26 -0
- package/dist/ButtonGroup.d.ts +26 -0
- package/dist/ButtonGroup.js +52 -0
- package/dist/ButtonGroup.mjs +3 -0
- package/dist/Card.d.mts +39 -0
- package/dist/Card.d.ts +39 -0
- package/dist/Card.js +349 -0
- package/dist/Card.mjs +8 -0
- package/dist/CategoryStrip.d.mts +26 -0
- package/dist/CategoryStrip.d.ts +26 -0
- package/dist/CategoryStrip.js +453 -0
- package/dist/CategoryStrip.mjs +9 -0
- package/dist/Checkbox.d.mts +14 -0
- package/dist/Checkbox.d.ts +14 -0
- package/dist/Checkbox.js +336 -0
- package/dist/Checkbox.mjs +7 -0
- package/dist/Chip.d.mts +31 -0
- package/dist/Chip.d.ts +31 -0
- package/dist/Chip.js +403 -0
- package/dist/Chip.mjs +8 -0
- package/dist/ConfirmDialog.d.mts +15 -0
- package/dist/ConfirmDialog.d.ts +15 -0
- package/dist/ConfirmDialog.js +560 -0
- package/dist/ConfirmDialog.mjs +10 -0
- package/dist/CurrencyDisplay.d.mts +24 -0
- package/dist/CurrencyDisplay.d.ts +24 -0
- package/dist/CurrencyDisplay.js +189 -0
- package/dist/CurrencyDisplay.mjs +4 -0
- package/dist/CurrencyInput.d.mts +26 -0
- package/dist/CurrencyInput.d.ts +26 -0
- package/dist/CurrencyInput.js +408 -0
- package/dist/CurrencyInput.mjs +8 -0
- package/dist/DetailRow.d.mts +32 -0
- package/dist/DetailRow.d.ts +32 -0
- package/dist/DetailRow.js +275 -0
- package/dist/DetailRow.mjs +5 -0
- package/dist/EmptyState.d.mts +27 -0
- package/dist/EmptyState.d.ts +27 -0
- package/dist/EmptyState.js +523 -0
- package/dist/EmptyState.mjs +10 -0
- package/dist/ErrorBoundary.d.mts +42 -0
- package/dist/ErrorBoundary.d.ts +42 -0
- package/dist/ErrorBoundary.js +351 -0
- package/dist/ErrorBoundary.mjs +7 -0
- package/dist/Form.d.mts +52 -0
- package/dist/Form.d.ts +52 -0
- package/dist/Form.js +204 -0
- package/dist/Form.mjs +4 -0
- package/dist/HolographicCard.d.mts +55 -0
- package/dist/HolographicCard.d.ts +55 -0
- package/dist/HolographicCard.js +316 -0
- package/dist/HolographicCard.mjs +191 -0
- package/dist/IconButton.d.mts +27 -0
- package/dist/IconButton.d.ts +27 -0
- package/dist/IconButton.js +400 -0
- package/dist/IconButton.mjs +8 -0
- package/dist/ImageViewer.d.mts +23 -0
- package/dist/ImageViewer.d.ts +23 -0
- package/dist/ImageViewer.js +582 -0
- package/dist/ImageViewer.mjs +8 -0
- package/dist/Input.d.mts +23 -0
- package/dist/Input.d.ts +23 -0
- package/dist/Input.js +351 -0
- package/dist/Input.mjs +7 -0
- package/dist/LabelValue.d.mts +16 -0
- package/dist/LabelValue.d.ts +16 -0
- package/dist/LabelValue.js +225 -0
- package/dist/LabelValue.mjs +5 -0
- package/dist/ListGroup.d.mts +34 -0
- package/dist/ListGroup.d.ts +34 -0
- package/dist/ListGroup.js +217 -0
- package/dist/ListGroup.mjs +5 -0
- package/dist/ListItem.d.mts +64 -0
- package/dist/ListItem.d.ts +64 -0
- package/dist/ListItem.js +444 -0
- package/dist/ListItem.mjs +9 -0
- package/dist/MediaCard.d.mts +39 -0
- package/dist/MediaCard.d.ts +39 -0
- package/dist/MediaCard.js +475 -0
- package/dist/MediaCard.mjs +9 -0
- package/dist/MenuGroup.d.mts +34 -0
- package/dist/MenuGroup.d.ts +34 -0
- package/dist/MenuGroup.js +217 -0
- package/dist/MenuGroup.mjs +5 -0
- package/dist/MenuItem.d.mts +48 -0
- package/dist/MenuItem.d.ts +48 -0
- package/dist/MenuItem.js +415 -0
- package/dist/MenuItem.mjs +9 -0
- package/dist/MonthPicker.d.mts +28 -0
- package/dist/MonthPicker.d.ts +28 -0
- package/dist/MonthPicker.js +297 -0
- package/dist/MonthPicker.mjs +5 -0
- package/dist/PagerDots.d.mts +35 -0
- package/dist/PagerDots.d.ts +35 -0
- package/dist/PagerDots.js +392 -0
- package/dist/PagerDots.mjs +7 -0
- package/dist/Pressable.d.mts +34 -0
- package/dist/Pressable.d.ts +34 -0
- package/dist/Pressable.js +143 -0
- package/dist/Pressable.mjs +5 -0
- package/dist/PricingCard.d.mts +50 -0
- package/dist/PricingCard.d.ts +50 -0
- package/dist/PricingCard.js +636 -0
- package/dist/PricingCard.mjs +11 -0
- package/dist/Progress.d.mts +14 -0
- package/dist/Progress.d.ts +14 -0
- package/dist/Progress.js +191 -0
- package/dist/Progress.mjs +5 -0
- package/dist/RadioGroup.d.mts +19 -0
- package/dist/RadioGroup.d.ts +19 -0
- package/dist/RadioGroup.js +392 -0
- package/dist/RadioGroup.mjs +7 -0
- package/dist/RetrayProvider.d.mts +2 -0
- package/dist/RetrayProvider.d.ts +2 -0
- package/dist/RetrayProvider.js +214 -0
- package/dist/RetrayProvider.mjs +5 -0
- package/dist/Select.d.mts +22 -0
- package/dist/Select.d.ts +22 -0
- package/dist/Select.js +488 -0
- package/dist/Select.mjs +7 -0
- package/dist/SelectableGrid.d.mts +44 -0
- package/dist/SelectableGrid.d.ts +44 -0
- package/dist/SelectableGrid.js +448 -0
- package/dist/SelectableGrid.mjs +9 -0
- package/dist/Separator.d.mts +10 -0
- package/dist/Separator.d.ts +10 -0
- package/dist/Separator.js +156 -0
- package/dist/Separator.mjs +3 -0
- package/dist/Sheet.d.mts +93 -0
- package/dist/Sheet.d.ts +93 -0
- package/dist/Sheet.js +450 -0
- package/dist/Sheet.mjs +6 -0
- package/dist/Skeleton.d.mts +67 -0
- package/dist/Skeleton.d.ts +67 -0
- package/dist/Skeleton.js +266 -0
- package/dist/Skeleton.mjs +6 -0
- package/dist/Slider.d.mts +20 -0
- package/dist/Slider.d.ts +20 -0
- package/dist/Slider.js +279 -0
- package/dist/Slider.mjs +5 -0
- package/dist/Spinner.d.mts +12 -0
- package/dist/Spinner.d.ts +12 -0
- package/dist/Spinner.js +193 -0
- package/dist/Spinner.mjs +4 -0
- package/dist/Switch.d.mts +13 -0
- package/dist/Switch.d.ts +13 -0
- package/dist/Switch.js +311 -0
- package/dist/Switch.mjs +6 -0
- package/dist/TabBar.d.mts +42 -0
- package/dist/TabBar.d.ts +42 -0
- package/dist/TabBar.js +361 -0
- package/dist/TabBar.mjs +6 -0
- package/dist/Tabs.d.mts +27 -0
- package/dist/Tabs.d.ts +27 -0
- package/dist/Tabs.js +419 -0
- package/dist/Tabs.mjs +7 -0
- package/dist/Text.d.mts +12 -0
- package/dist/Text.d.ts +12 -0
- package/dist/Text.js +327 -0
- package/dist/Text.mjs +5 -0
- package/dist/Textarea.d.mts +16 -0
- package/dist/Textarea.d.ts +16 -0
- package/dist/Textarea.js +333 -0
- package/dist/Textarea.mjs +7 -0
- package/dist/Toast.d.mts +47 -0
- package/dist/Toast.d.ts +47 -0
- package/dist/Toast.js +185 -0
- package/dist/Toast.mjs +4 -0
- package/dist/Toggle.d.mts +36 -0
- package/dist/Toggle.d.ts +36 -0
- package/dist/Toggle.js +412 -0
- package/dist/Toggle.mjs +8 -0
- package/dist/VirtualList.d.mts +19 -0
- package/dist/VirtualList.d.ts +19 -0
- package/dist/VirtualList.js +38 -0
- package/dist/VirtualList.mjs +2 -0
- package/dist/chunk-26BCI223.mjs +14 -0
- package/dist/chunk-2CE3TQVY.mjs +11 -0
- package/dist/chunk-2TFTAWVJ.mjs +131 -0
- package/dist/chunk-2UYENBLV.mjs +49 -0
- package/dist/chunk-3BBOZ3OQ.mjs +41 -0
- package/dist/chunk-3DKJ2GIC.mjs +30 -0
- package/dist/chunk-3U4SSNWP.mjs +120 -0
- package/dist/chunk-4I7D47FH.mjs +139 -0
- package/dist/chunk-4K625MVM.mjs +142 -0
- package/dist/chunk-6OAZJ577.mjs +98 -0
- package/dist/chunk-6Q64UFIA.mjs +71 -0
- package/dist/chunk-756RAKE4.mjs +145 -0
- package/dist/chunk-7QHVVCB3.mjs +115 -0
- package/dist/chunk-A3A6KNQN.mjs +245 -0
- package/dist/chunk-A4MDAP7G.mjs +42 -0
- package/dist/chunk-AJ7ZDNBT.mjs +120 -0
- package/dist/chunk-AV4EMIRH.mjs +94 -0
- package/dist/chunk-AZJF2BLK.mjs +115 -0
- package/dist/chunk-BNP626TY.mjs +159 -0
- package/dist/chunk-BRKYVJVV.mjs +60 -0
- package/dist/chunk-DVK4G2GT.mjs +59 -0
- package/dist/chunk-EH745HE5.mjs +127 -0
- package/dist/chunk-EJ7ZPXOH.mjs +163 -0
- package/dist/chunk-GD6KXMG5.mjs +106 -0
- package/dist/chunk-GQYFLP3D.mjs +187 -0
- package/dist/chunk-ID72TK46.mjs +111 -0
- package/dist/chunk-IRRY3CRZ.mjs +82 -0
- package/dist/chunk-JB67UOB5.mjs +92 -0
- package/dist/chunk-JMOZEC77.mjs +90 -0
- package/dist/chunk-JT7HKXRB.mjs +114 -0
- package/dist/chunk-KIHCWCWL.mjs +124 -0
- package/dist/chunk-LXJIIOYQ.mjs +104 -0
- package/dist/chunk-M6ZXVBTK.mjs +64 -0
- package/dist/chunk-MAC465BB.mjs +61 -0
- package/dist/chunk-MBMXYJJV.mjs +36 -0
- package/dist/chunk-MLF3EZFW.mjs +119 -0
- package/dist/chunk-MX6HRKMI.mjs +29 -0
- package/dist/chunk-NA7PARID.mjs +147 -0
- package/dist/chunk-NC5ZTR2Y.mjs +32 -0
- package/dist/chunk-O3HA6TYM.mjs +139 -0
- package/dist/chunk-OB4JUQ3O.mjs +51 -0
- package/dist/chunk-PFZTM6D5.mjs +238 -0
- package/dist/chunk-QKH5ZOD5.mjs +97 -0
- package/dist/chunk-QY3X2UYR.mjs +191 -0
- package/dist/chunk-SOA2Z4RB.mjs +82 -0
- package/dist/chunk-SOYNZDVY.mjs +151 -0
- package/dist/chunk-T7XZ7H7Y.mjs +57 -0
- package/dist/chunk-TERDKCLE.mjs +74 -0
- package/dist/chunk-UREA2GYY.mjs +113 -0
- package/dist/chunk-VGTDN7SW.mjs +164 -0
- package/dist/chunk-VQ57HWPL.mjs +144 -0
- package/dist/chunk-WBOOUHSS.mjs +62 -0
- package/dist/chunk-WJLKJMKR.mjs +78 -0
- package/dist/chunk-X4G6APW6.mjs +134 -0
- package/dist/chunk-Y6FXYEAI.mjs +8 -0
- package/dist/chunk-YFZ3ELX5.mjs +16 -0
- package/dist/chunk-YNROWHQJ.mjs +46 -0
- package/dist/chunk-Z4BVUWW6.mjs +196 -0
- package/dist/chunk-ZJKGQMYH.mjs +131 -0
- package/dist/index-wt-orHUi.d.mts +85 -0
- package/dist/index-wt-orHUi.d.ts +85 -0
- package/dist/index.d.mts +149 -920
- package/dist/index.d.ts +149 -920
- package/dist/index.js +2560 -970
- package/dist/index.mjs +60 -3895
- package/package.json +55 -16
- package/src/assets/fonts/Sohne-Bold.otf +0 -0
- package/src/assets/fonts/Sohne-BoldItalic.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraBold.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraBoldItalic.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraLight.otf +0 -0
- package/src/assets/fonts/Sohne-ExtraLightItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Italic.otf +0 -0
- package/src/assets/fonts/Sohne-Light.otf +0 -0
- package/src/assets/fonts/Sohne-LightItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Medium.otf +0 -0
- package/src/assets/fonts/Sohne-MediumItalic.otf +0 -0
- package/src/assets/fonts/Sohne-Regular.otf +0 -0
- package/src/assets/fonts/Sohne-SemiBold.otf +0 -0
- package/src/assets/fonts/Sohne-SemiBoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Bold.otf +0 -0
- package/src/assets/fonts/SohneMono-BoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraBold.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraBoldItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraLight.otf +0 -0
- package/src/assets/fonts/SohneMono-ExtraLightItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Italic.otf +0 -0
- package/src/assets/fonts/SohneMono-Light.otf +0 -0
- package/src/assets/fonts/SohneMono-LightItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Medium.otf +0 -0
- package/src/assets/fonts/SohneMono-MediumItalic.otf +0 -0
- package/src/assets/fonts/SohneMono-Regular.otf +0 -0
- package/src/assets/fonts/SohneMono-SemiBold.otf +0 -0
- package/src/assets/fonts/SohneMono-SemiBoldItalic.otf +0 -0
- package/src/components/Accordion/Accordion.tsx +15 -4
- package/src/components/AlertBanner/AlertBanner.tsx +38 -12
- package/src/components/AppHeader/AppHeader.tsx +172 -0
- package/src/components/AppHeader/index.ts +1 -0
- package/src/components/Avatar/Avatar.tsx +14 -4
- package/src/components/Badge/Badge.tsx +12 -3
- package/src/components/Button/Button.tsx +30 -38
- package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
- package/src/components/Card/Card.tsx +29 -57
- package/src/components/CategoryStrip/CategoryStrip.tsx +41 -42
- package/src/components/Checkbox/Checkbox.tsx +36 -45
- package/src/components/Chip/Chip.tsx +41 -48
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
- package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
- package/src/components/CurrencyInput/CurrencyInput.tsx +12 -10
- package/src/components/DetailRow/DetailRow.tsx +9 -7
- package/src/components/EmptyState/EmptyState.tsx +4 -3
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +153 -0
- package/src/components/ErrorBoundary/index.ts +1 -0
- package/src/components/Form/Form.tsx +149 -0
- package/src/components/Form/index.ts +1 -0
- package/src/components/HolographicCard/HolographicCard.tsx +315 -0
- package/src/components/HolographicCard/index.ts +1 -0
- package/src/components/IconButton/IconButton.tsx +23 -29
- package/src/components/ImageViewer/ImageViewer.tsx +290 -0
- package/src/components/ImageViewer/index.ts +1 -0
- package/src/components/Input/Input.tsx +27 -31
- package/src/components/LabelValue/LabelValue.tsx +6 -4
- package/src/components/ListGroup/ListGroup.tsx +145 -0
- package/src/components/ListGroup/index.ts +1 -0
- package/src/components/ListItem/ListItem.tsx +78 -76
- package/src/components/MediaCard/MediaCard.tsx +15 -7
- package/src/components/MenuGroup/MenuGroup.tsx +145 -0
- package/src/components/MenuGroup/index.ts +1 -0
- package/src/components/MenuItem/MenuItem.tsx +16 -33
- package/src/components/MonthPicker/MonthPicker.tsx +41 -15
- package/src/components/MonthPicker/index.ts +1 -1
- package/src/components/PagerDots/PagerDots.tsx +200 -0
- package/src/components/PagerDots/index.ts +1 -0
- package/src/components/Pressable/Pressable.tsx +19 -35
- package/src/components/PricingCard/PricingCard.tsx +220 -0
- package/src/components/PricingCard/index.ts +1 -0
- package/src/components/RadioGroup/RadioGroup.tsx +23 -39
- package/src/components/RetrayProvider/RetrayProvider.tsx +59 -0
- package/src/components/RetrayProvider/index.ts +1 -0
- package/src/components/Select/Select.tsx +6 -6
- package/src/components/SelectableGrid/SelectableGrid.tsx +205 -0
- package/src/components/SelectableGrid/index.ts +1 -0
- package/src/components/Separator/Separator.tsx +1 -3
- package/src/components/Sheet/Sheet.tsx +146 -18
- package/src/components/Skeleton/Skeleton.tsx +143 -2
- package/src/components/Slider/Slider.tsx +2 -2
- package/src/components/Spinner/Spinner.tsx +18 -3
- package/src/components/Switch/Switch.tsx +44 -49
- package/src/components/TabBar/TabBar.tsx +169 -0
- package/src/components/TabBar/index.ts +1 -0
- package/src/components/Tabs/Tabs.tsx +45 -44
- package/src/components/Text/Text.tsx +5 -1
- package/src/components/Textarea/Textarea.tsx +18 -14
- package/src/components/Toast/Toast.tsx +6 -6
- package/src/components/Toggle/Toggle.tsx +80 -72
- package/src/components/VirtualList/VirtualList.tsx +60 -0
- package/src/components/VirtualList/index.ts +1 -0
- package/src/fonts.ts +41 -20
- package/src/index.ts +28 -3
- package/src/theme/colors.ts +53 -39
- package/src/theme/types.ts +3 -0
- package/src/tokens.ts +49 -39
- package/src/utils/animations.ts +29 -1
- package/src/utils/fontGuard.ts +34 -0
- package/src/utils/haptics.ts +211 -9
- package/src/utils/icons.ts +47 -20
- package/src/utils/pressable.ts +66 -0
- package/src/utils/usePressScale.ts +2 -0
- package/src/assets/fonts/Poppins-Black.ttf +0 -0
- package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Bold.ttf +0 -0
- package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Italic.ttf +0 -0
- package/src/assets/fonts/Poppins-Light.ttf +0 -0
- package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Medium.ttf +0 -0
- package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Regular.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Thin.ttf +0 -0
- package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
|
+
import { useImage } from '@shopify/react-native-skia';
|
|
4
|
+
|
|
5
|
+
/** Available foil color preset names */
|
|
6
|
+
type FoilPreset = 'rainbow' | 'gold' | 'silver' | 'cosmic' | 'emerald' | 'rose' | 'ocean' | 'fire' | 'aurora' | 'neon';
|
|
7
|
+
/** Foil color presets — each is an array of RGBA colors for the gradient */
|
|
8
|
+
declare const FOIL_PRESETS: Record<FoilPreset, string[]>;
|
|
9
|
+
interface HolographicCardProps {
|
|
10
|
+
/** Card art — `require()` asset or `{ uri }`. Omitted = gradient-only foil surface. */
|
|
11
|
+
source?: Parameters<typeof useImage>[0];
|
|
12
|
+
/** Card width (dp). Defaults to 300. */
|
|
13
|
+
width?: number;
|
|
14
|
+
/** Card height (dp). Defaults to `width * 1.4` (trading-card ratio). */
|
|
15
|
+
height?: number;
|
|
16
|
+
/** Corner radius (dp). Defaults to `RADIUS.md`. */
|
|
17
|
+
borderRadius?: number;
|
|
18
|
+
/** React to device motion (gyroscope) for parallax tilt + sheen. Defaults to true. */
|
|
19
|
+
enableTilt?: boolean;
|
|
20
|
+
/** Strength of the foil sheen, 0–1. Defaults to 1. */
|
|
21
|
+
intensity?: number;
|
|
22
|
+
/** Called when the card is pressed. */
|
|
23
|
+
onPress?: () => void;
|
|
24
|
+
style?: ViewStyle;
|
|
25
|
+
/** Foil color preset. Defaults to 'rainbow'. Ignored if `foilColors` is provided. */
|
|
26
|
+
foilPreset?: FoilPreset;
|
|
27
|
+
/** Custom foil gradient colors (array of RGBA strings). Overrides `foilPreset`. */
|
|
28
|
+
foilColors?: string[];
|
|
29
|
+
/** Maximum tilt angle in degrees (0–45). Defaults to 10. */
|
|
30
|
+
maxTiltDegrees?: number;
|
|
31
|
+
/** Sensitivity of tilt to device motion (0.1–2). Higher = more responsive. Defaults to 1. */
|
|
32
|
+
tiltSensitivity?: number;
|
|
33
|
+
/** How far the sheen moves relative to tilt (0–1). Defaults to 0.6. */
|
|
34
|
+
sheenSpread?: number;
|
|
35
|
+
/** Animation duration for tilt smoothing in ms. Defaults to 80. */
|
|
36
|
+
tiltAnimationDuration?: number;
|
|
37
|
+
/** Perspective depth for 3D effect (200–2000). Defaults to 800. */
|
|
38
|
+
perspective?: number;
|
|
39
|
+
/** Blend mode for the foil overlay. Defaults to 'plus'. */
|
|
40
|
+
blendMode?: 'plus' | 'screen' | 'overlay' | 'softLight' | 'hardLight';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Holographic / foil trading-card surface (Pokémon-TCG style). Renders the art
|
|
44
|
+
* on a Skia canvas with an animated rainbow sheen, and tilts in 3D toward device
|
|
45
|
+
* motion. The sheen position tracks the tilt so the foil "catches the light".
|
|
46
|
+
*
|
|
47
|
+
* Deep-import only — keeps Skia out of the main bundle:
|
|
48
|
+
* `import { HolographicCard } from '@retray-dev/ui-kit/HolographicCard'`
|
|
49
|
+
*
|
|
50
|
+
* Requires the optional peers `@shopify/react-native-skia` and (for tilt)
|
|
51
|
+
* `expo-sensors`. Without `expo-sensors` the card renders with a static sheen.
|
|
52
|
+
*/
|
|
53
|
+
declare function HolographicCard({ source, width, height, borderRadius, enableTilt, intensity, onPress, style, foilPreset, foilColors, maxTiltDegrees, tiltSensitivity, sheenSpread, tiltAnimationDuration, perspective, blendMode, }: HolographicCardProps): React.JSX.Element;
|
|
54
|
+
|
|
55
|
+
export { FOIL_PRESETS, type FoilPreset, HolographicCard, type HolographicCardProps };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
|
+
import { useImage } from '@shopify/react-native-skia';
|
|
4
|
+
|
|
5
|
+
/** Available foil color preset names */
|
|
6
|
+
type FoilPreset = 'rainbow' | 'gold' | 'silver' | 'cosmic' | 'emerald' | 'rose' | 'ocean' | 'fire' | 'aurora' | 'neon';
|
|
7
|
+
/** Foil color presets — each is an array of RGBA colors for the gradient */
|
|
8
|
+
declare const FOIL_PRESETS: Record<FoilPreset, string[]>;
|
|
9
|
+
interface HolographicCardProps {
|
|
10
|
+
/** Card art — `require()` asset or `{ uri }`. Omitted = gradient-only foil surface. */
|
|
11
|
+
source?: Parameters<typeof useImage>[0];
|
|
12
|
+
/** Card width (dp). Defaults to 300. */
|
|
13
|
+
width?: number;
|
|
14
|
+
/** Card height (dp). Defaults to `width * 1.4` (trading-card ratio). */
|
|
15
|
+
height?: number;
|
|
16
|
+
/** Corner radius (dp). Defaults to `RADIUS.md`. */
|
|
17
|
+
borderRadius?: number;
|
|
18
|
+
/** React to device motion (gyroscope) for parallax tilt + sheen. Defaults to true. */
|
|
19
|
+
enableTilt?: boolean;
|
|
20
|
+
/** Strength of the foil sheen, 0–1. Defaults to 1. */
|
|
21
|
+
intensity?: number;
|
|
22
|
+
/** Called when the card is pressed. */
|
|
23
|
+
onPress?: () => void;
|
|
24
|
+
style?: ViewStyle;
|
|
25
|
+
/** Foil color preset. Defaults to 'rainbow'. Ignored if `foilColors` is provided. */
|
|
26
|
+
foilPreset?: FoilPreset;
|
|
27
|
+
/** Custom foil gradient colors (array of RGBA strings). Overrides `foilPreset`. */
|
|
28
|
+
foilColors?: string[];
|
|
29
|
+
/** Maximum tilt angle in degrees (0–45). Defaults to 10. */
|
|
30
|
+
maxTiltDegrees?: number;
|
|
31
|
+
/** Sensitivity of tilt to device motion (0.1–2). Higher = more responsive. Defaults to 1. */
|
|
32
|
+
tiltSensitivity?: number;
|
|
33
|
+
/** How far the sheen moves relative to tilt (0–1). Defaults to 0.6. */
|
|
34
|
+
sheenSpread?: number;
|
|
35
|
+
/** Animation duration for tilt smoothing in ms. Defaults to 80. */
|
|
36
|
+
tiltAnimationDuration?: number;
|
|
37
|
+
/** Perspective depth for 3D effect (200–2000). Defaults to 800. */
|
|
38
|
+
perspective?: number;
|
|
39
|
+
/** Blend mode for the foil overlay. Defaults to 'plus'. */
|
|
40
|
+
blendMode?: 'plus' | 'screen' | 'overlay' | 'softLight' | 'hardLight';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Holographic / foil trading-card surface (Pokémon-TCG style). Renders the art
|
|
44
|
+
* on a Skia canvas with an animated rainbow sheen, and tilts in 3D toward device
|
|
45
|
+
* motion. The sheen position tracks the tilt so the foil "catches the light".
|
|
46
|
+
*
|
|
47
|
+
* Deep-import only — keeps Skia out of the main bundle:
|
|
48
|
+
* `import { HolographicCard } from '@retray-dev/ui-kit/HolographicCard'`
|
|
49
|
+
*
|
|
50
|
+
* Requires the optional peers `@shopify/react-native-skia` and (for tilt)
|
|
51
|
+
* `expo-sensors`. Without `expo-sensors` the card renders with a static sheen.
|
|
52
|
+
*/
|
|
53
|
+
declare function HolographicCard({ source, width, height, borderRadius, enableTilt, intensity, onPress, style, foilPreset, foilColors, maxTiltDegrees, tiltSensitivity, sheenSpread, tiltAnimationDuration, perspective, blendMode, }: HolographicCardProps): React.JSX.Element;
|
|
54
|
+
|
|
55
|
+
export { FOIL_PRESETS, type FoilPreset, HolographicCard, type HolographicCardProps };
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactNative = require('react-native');
|
|
5
|
+
var reactNativeSkia = require('@shopify/react-native-skia');
|
|
6
|
+
var Animated = require('react-native-reanimated');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
11
|
+
var Animated__default = /*#__PURE__*/_interopDefault(Animated);
|
|
12
|
+
|
|
13
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
14
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
15
|
+
}) : x)(function(x) {
|
|
16
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
17
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
18
|
+
});
|
|
19
|
+
var SPRINGS = {
|
|
20
|
+
/** Tight, premium press feel — Buttons, Toggle, Tabs triggers. */
|
|
21
|
+
pressIn: { stiffness: 600, damping: 35, mass: 0.8 },
|
|
22
|
+
pressOut: { stiffness: 280, damping: 22, mass: 0.8 }};
|
|
23
|
+
({
|
|
24
|
+
/** Material-style ease-out — natural deceleration for state changes. */
|
|
25
|
+
standard: Animated.Easing.bezier(0.2, 0, 0, 1),
|
|
26
|
+
/** Strong ease-out for expanding surfaces (Accordion open). */
|
|
27
|
+
expand: Animated.Easing.bezier(0.23, 1, 0.32, 1),
|
|
28
|
+
/** Quick ease-in for collapsing. */
|
|
29
|
+
collapse: Animated.Easing.in(Animated.Easing.ease)
|
|
30
|
+
});
|
|
31
|
+
var PRESS_SCALE = {
|
|
32
|
+
button: 0.95,
|
|
33
|
+
card: 0.98};
|
|
34
|
+
function useHover() {
|
|
35
|
+
const [hovered, setHovered] = React.useState(false);
|
|
36
|
+
const onMouseEnter = React.useCallback(() => setHovered(true), []);
|
|
37
|
+
const onMouseLeave = React.useCallback(() => setHovered(false), []);
|
|
38
|
+
if (reactNative.Platform.OS !== "web") {
|
|
39
|
+
return { hovered: false, hoverHandlers: {} };
|
|
40
|
+
}
|
|
41
|
+
return { hovered, hoverHandlers: { onMouseEnter, onMouseLeave } };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/utils/usePressScale.ts
|
|
45
|
+
function usePressScale({
|
|
46
|
+
pressScale = PRESS_SCALE.button,
|
|
47
|
+
hoverScale = 1.02,
|
|
48
|
+
pressInSpring = SPRINGS.pressIn,
|
|
49
|
+
pressOutSpring = SPRINGS.pressOut,
|
|
50
|
+
disabled = false
|
|
51
|
+
} = {}) {
|
|
52
|
+
const scale = Animated.useSharedValue(1);
|
|
53
|
+
const { hovered, hoverHandlers } = useHover();
|
|
54
|
+
const onPressIn = React.useCallback(() => {
|
|
55
|
+
if (disabled) return;
|
|
56
|
+
scale.value = Animated.withSpring(pressScale, pressInSpring);
|
|
57
|
+
}, [disabled, pressScale, pressInSpring, scale]);
|
|
58
|
+
const onPressOut = React.useCallback(() => {
|
|
59
|
+
if (disabled) return;
|
|
60
|
+
scale.value = Animated.withSpring(1, pressOutSpring);
|
|
61
|
+
}, [disabled, pressOutSpring, scale]);
|
|
62
|
+
const hoverActive = reactNative.Platform.OS === "web" && hovered && hoverScale !== 1 && !disabled;
|
|
63
|
+
const animatedStyle = Animated.useAnimatedStyle(() => ({
|
|
64
|
+
transform: [
|
|
65
|
+
{ scale: scale.value * (hoverActive ? hoverScale : 1) }
|
|
66
|
+
]
|
|
67
|
+
}));
|
|
68
|
+
return {
|
|
69
|
+
animatedStyle,
|
|
70
|
+
onPressIn,
|
|
71
|
+
onPressOut,
|
|
72
|
+
hoverHandlers
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
var _haptics = null;
|
|
76
|
+
var _hapticsLoaded = false;
|
|
77
|
+
async function getHaptics() {
|
|
78
|
+
if (reactNative.Platform.OS === "web") return null;
|
|
79
|
+
if (!_hapticsLoaded) {
|
|
80
|
+
_hapticsLoaded = true;
|
|
81
|
+
try {
|
|
82
|
+
_haptics = await import('expo-haptics');
|
|
83
|
+
} catch {
|
|
84
|
+
_haptics = null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return _haptics;
|
|
88
|
+
}
|
|
89
|
+
var _pulsar = null;
|
|
90
|
+
var _pulsarChecked = false;
|
|
91
|
+
var _pulsarAvailable = false;
|
|
92
|
+
function isPulsarNativeRegistered() {
|
|
93
|
+
try {
|
|
94
|
+
const g = globalThis;
|
|
95
|
+
if (typeof g.__turboModuleProxy === "function") {
|
|
96
|
+
return g.__turboModuleProxy("RNPulsar") != null;
|
|
97
|
+
}
|
|
98
|
+
return reactNative.NativeModules?.RNPulsar != null;
|
|
99
|
+
} catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function getPulsar() {
|
|
104
|
+
if (reactNative.Platform.OS === "web") return null;
|
|
105
|
+
if (!_pulsarChecked) {
|
|
106
|
+
_pulsarChecked = true;
|
|
107
|
+
try {
|
|
108
|
+
if (isPulsarNativeRegistered()) {
|
|
109
|
+
_pulsar = __require("react-native-pulsar");
|
|
110
|
+
_pulsarAvailable = true;
|
|
111
|
+
}
|
|
112
|
+
} catch {
|
|
113
|
+
_pulsar = null;
|
|
114
|
+
_pulsarAvailable = false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return _pulsarAvailable ? _pulsar : null;
|
|
118
|
+
}
|
|
119
|
+
function impactLight() {
|
|
120
|
+
if (reactNative.Platform.OS === "web") return;
|
|
121
|
+
getHaptics().then((h) => {
|
|
122
|
+
if (h) {
|
|
123
|
+
h.impactAsync(h.ImpactFeedbackStyle.Light);
|
|
124
|
+
} else {
|
|
125
|
+
getPulsar()?.Presets.System.impactLight();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/tokens.ts
|
|
131
|
+
var RADIUS = {
|
|
132
|
+
md: 14};
|
|
133
|
+
|
|
134
|
+
// src/components/HolographicCard/HolographicCard.tsx
|
|
135
|
+
var FOIL_PRESETS = {
|
|
136
|
+
// Classic holographic rainbow
|
|
137
|
+
rainbow: [
|
|
138
|
+
"rgba(255, 0, 128, 0.45)",
|
|
139
|
+
"rgba(255, 200, 0, 0.40)",
|
|
140
|
+
"rgba(0, 255, 170, 0.40)",
|
|
141
|
+
"rgba(0, 170, 255, 0.45)",
|
|
142
|
+
"rgba(180, 0, 255, 0.45)"
|
|
143
|
+
],
|
|
144
|
+
// Premium gold foil
|
|
145
|
+
gold: [
|
|
146
|
+
"rgba(255, 215, 0, 0.50)",
|
|
147
|
+
"rgba(255, 180, 0, 0.45)",
|
|
148
|
+
"rgba(218, 165, 32, 0.40)",
|
|
149
|
+
"rgba(255, 223, 128, 0.50)",
|
|
150
|
+
"rgba(184, 134, 11, 0.45)"
|
|
151
|
+
],
|
|
152
|
+
// Chrome silver foil
|
|
153
|
+
silver: [
|
|
154
|
+
"rgba(192, 192, 192, 0.50)",
|
|
155
|
+
"rgba(220, 220, 220, 0.45)",
|
|
156
|
+
"rgba(169, 169, 169, 0.40)",
|
|
157
|
+
"rgba(240, 240, 240, 0.50)",
|
|
158
|
+
"rgba(128, 128, 128, 0.45)"
|
|
159
|
+
],
|
|
160
|
+
// Deep space cosmic
|
|
161
|
+
cosmic: [
|
|
162
|
+
"rgba(75, 0, 130, 0.50)",
|
|
163
|
+
"rgba(138, 43, 226, 0.45)",
|
|
164
|
+
"rgba(255, 20, 147, 0.40)",
|
|
165
|
+
"rgba(0, 191, 255, 0.45)",
|
|
166
|
+
"rgba(148, 0, 211, 0.50)"
|
|
167
|
+
],
|
|
168
|
+
// Emerald green luxury
|
|
169
|
+
emerald: [
|
|
170
|
+
"rgba(0, 201, 87, 0.50)",
|
|
171
|
+
"rgba(46, 139, 87, 0.45)",
|
|
172
|
+
"rgba(0, 255, 127, 0.40)",
|
|
173
|
+
"rgba(60, 179, 113, 0.45)",
|
|
174
|
+
"rgba(0, 128, 0, 0.50)"
|
|
175
|
+
],
|
|
176
|
+
// Rose gold / pink
|
|
177
|
+
rose: [
|
|
178
|
+
"rgba(255, 105, 180, 0.50)",
|
|
179
|
+
"rgba(255, 182, 193, 0.45)",
|
|
180
|
+
"rgba(219, 112, 147, 0.40)",
|
|
181
|
+
"rgba(255, 20, 147, 0.45)",
|
|
182
|
+
"rgba(199, 21, 133, 0.50)"
|
|
183
|
+
],
|
|
184
|
+
// Deep ocean blue
|
|
185
|
+
ocean: [
|
|
186
|
+
"rgba(0, 119, 190, 0.50)",
|
|
187
|
+
"rgba(0, 180, 216, 0.45)",
|
|
188
|
+
"rgba(72, 202, 228, 0.40)",
|
|
189
|
+
"rgba(144, 224, 239, 0.45)",
|
|
190
|
+
"rgba(0, 150, 199, 0.50)"
|
|
191
|
+
],
|
|
192
|
+
// Hot fire gradient
|
|
193
|
+
fire: [
|
|
194
|
+
"rgba(255, 69, 0, 0.50)",
|
|
195
|
+
"rgba(255, 140, 0, 0.45)",
|
|
196
|
+
"rgba(255, 215, 0, 0.40)",
|
|
197
|
+
"rgba(255, 99, 71, 0.45)",
|
|
198
|
+
"rgba(220, 20, 60, 0.50)"
|
|
199
|
+
],
|
|
200
|
+
// Aurora borealis
|
|
201
|
+
aurora: [
|
|
202
|
+
"rgba(0, 255, 127, 0.45)",
|
|
203
|
+
"rgba(127, 255, 212, 0.40)",
|
|
204
|
+
"rgba(0, 206, 209, 0.45)",
|
|
205
|
+
"rgba(138, 43, 226, 0.40)",
|
|
206
|
+
"rgba(255, 20, 147, 0.45)"
|
|
207
|
+
],
|
|
208
|
+
// Neon cyberpunk
|
|
209
|
+
neon: [
|
|
210
|
+
"rgba(255, 0, 255, 0.55)",
|
|
211
|
+
"rgba(0, 255, 255, 0.50)",
|
|
212
|
+
"rgba(255, 255, 0, 0.45)",
|
|
213
|
+
"rgba(0, 255, 0, 0.50)",
|
|
214
|
+
"rgba(255, 0, 128, 0.55)"
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
var DEFAULT_FOIL_COLORS = FOIL_PRESETS.rainbow;
|
|
218
|
+
var DEFAULT_TILT_DEG = 10;
|
|
219
|
+
var DEFAULT_NORM_FACTOR = Math.PI / 6;
|
|
220
|
+
function HolographicCard({
|
|
221
|
+
source,
|
|
222
|
+
width = 300,
|
|
223
|
+
height,
|
|
224
|
+
borderRadius = RADIUS.md,
|
|
225
|
+
enableTilt = true,
|
|
226
|
+
intensity = 1,
|
|
227
|
+
onPress,
|
|
228
|
+
style,
|
|
229
|
+
// New customization props
|
|
230
|
+
foilPreset = "rainbow",
|
|
231
|
+
foilColors,
|
|
232
|
+
maxTiltDegrees = DEFAULT_TILT_DEG,
|
|
233
|
+
tiltSensitivity = 1,
|
|
234
|
+
sheenSpread = 0.6,
|
|
235
|
+
tiltAnimationDuration = 80,
|
|
236
|
+
perspective = 800,
|
|
237
|
+
blendMode = "plus"
|
|
238
|
+
}) {
|
|
239
|
+
const h = height ?? width * 1.4;
|
|
240
|
+
const image = reactNativeSkia.useImage(source ?? null);
|
|
241
|
+
const clampedTilt = Math.max(0, Math.min(45, maxTiltDegrees));
|
|
242
|
+
const clampedSensitivity = Math.max(0.1, Math.min(2, tiltSensitivity));
|
|
243
|
+
const clampedSpread = Math.max(0, Math.min(1, sheenSpread));
|
|
244
|
+
const clampedPerspective = Math.max(200, Math.min(2e3, perspective));
|
|
245
|
+
const resolvedFoilColors = React.useMemo(() => {
|
|
246
|
+
if (foilColors && foilColors.length >= 2) return foilColors;
|
|
247
|
+
return FOIL_PRESETS[foilPreset] ?? DEFAULT_FOIL_COLORS;
|
|
248
|
+
}, [foilColors, foilPreset]);
|
|
249
|
+
const normFactor = DEFAULT_NORM_FACTOR / clampedSensitivity;
|
|
250
|
+
const tiltX = Animated.useSharedValue(0);
|
|
251
|
+
const tiltY = Animated.useSharedValue(0);
|
|
252
|
+
React.useEffect(() => {
|
|
253
|
+
if (!enableTilt || reactNative.Platform.OS === "web") return;
|
|
254
|
+
let remove;
|
|
255
|
+
let cancelled = false;
|
|
256
|
+
import('expo-sensors').then(({ DeviceMotion }) => {
|
|
257
|
+
if (cancelled) return;
|
|
258
|
+
DeviceMotion.setUpdateInterval(16);
|
|
259
|
+
const sub = DeviceMotion.addListener(({ rotation }) => {
|
|
260
|
+
if (!rotation) return;
|
|
261
|
+
const nx = Math.max(-1, Math.min(rotation.gamma / normFactor, 1));
|
|
262
|
+
const ny = Math.max(-1, Math.min(rotation.beta / normFactor, 1));
|
|
263
|
+
tiltX.value = Animated.withTiming(nx, { duration: tiltAnimationDuration });
|
|
264
|
+
tiltY.value = Animated.withTiming(ny, { duration: tiltAnimationDuration });
|
|
265
|
+
});
|
|
266
|
+
remove = () => sub.remove();
|
|
267
|
+
}).catch(() => {
|
|
268
|
+
});
|
|
269
|
+
return () => {
|
|
270
|
+
cancelled = true;
|
|
271
|
+
remove?.();
|
|
272
|
+
};
|
|
273
|
+
}, [enableTilt, tiltX, tiltY, normFactor, tiltAnimationDuration]);
|
|
274
|
+
const { animatedStyle: pressStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
275
|
+
pressScale: PRESS_SCALE.card,
|
|
276
|
+
disabled: !onPress
|
|
277
|
+
});
|
|
278
|
+
const tiltStyle = Animated.useAnimatedStyle(() => ({
|
|
279
|
+
transform: [
|
|
280
|
+
{ perspective: clampedPerspective },
|
|
281
|
+
{ rotateX: `${-tiltY.value * clampedTilt}deg` },
|
|
282
|
+
{ rotateY: `${tiltX.value * clampedTilt}deg` }
|
|
283
|
+
]
|
|
284
|
+
}));
|
|
285
|
+
const start = Animated.useDerivedValue(() => reactNativeSkia.vec(width * (0.5 - tiltX.value * clampedSpread), h * (0.5 - tiltY.value * clampedSpread)));
|
|
286
|
+
const end = Animated.useDerivedValue(() => reactNativeSkia.vec(width * (0.5 + tiltX.value * clampedSpread), h * (0.5 + tiltY.value * clampedSpread)));
|
|
287
|
+
const rrct = { x: 0, y: 0, width, height: h };
|
|
288
|
+
const canvas = /* @__PURE__ */ React__default.default.createElement(reactNativeSkia.Canvas, { style: { width, height: h } }, image ? /* @__PURE__ */ React__default.default.createElement(reactNativeSkia.Group, { clip: { rect: rrct, rx: borderRadius, ry: borderRadius } }, /* @__PURE__ */ React__default.default.createElement(reactNativeSkia.Image, { image, x: 0, y: 0, width, height: h, fit: "cover" })) : null, /* @__PURE__ */ React__default.default.createElement(reactNativeSkia.RoundedRect, { x: 0, y: 0, width, height: h, r: borderRadius, opacity: intensity, blendMode }, /* @__PURE__ */ React__default.default.createElement(reactNativeSkia.LinearGradient, { start, end, colors: resolvedFoilColors })));
|
|
289
|
+
const card = /* @__PURE__ */ React__default.default.createElement(Animated__default.default.View, { style: [{ width, height: h }, tiltStyle, style] }, canvas);
|
|
290
|
+
if (!onPress) return card;
|
|
291
|
+
return /* @__PURE__ */ React__default.default.createElement(Animated__default.default.View, { style: pressStyle }, /* @__PURE__ */ React__default.default.createElement(
|
|
292
|
+
reactNative.TouchableOpacity,
|
|
293
|
+
{
|
|
294
|
+
onPress: () => {
|
|
295
|
+
impactLight();
|
|
296
|
+
onPress();
|
|
297
|
+
},
|
|
298
|
+
onPressIn,
|
|
299
|
+
onPressOut,
|
|
300
|
+
activeOpacity: 1,
|
|
301
|
+
touchSoundDisabled: true,
|
|
302
|
+
accessibilityRole: "imagebutton",
|
|
303
|
+
...hoverHandlers,
|
|
304
|
+
style: styles.touch
|
|
305
|
+
},
|
|
306
|
+
card
|
|
307
|
+
));
|
|
308
|
+
}
|
|
309
|
+
var styles = reactNative.StyleSheet.create({
|
|
310
|
+
touch: {
|
|
311
|
+
alignSelf: "flex-start"
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
exports.FOIL_PRESETS = FOIL_PRESETS;
|
|
316
|
+
exports.HolographicCard = HolographicCard;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { usePressScale } from './chunk-YNROWHQJ.mjs';
|
|
2
|
+
import { impactLight } from './chunk-EJ7ZPXOH.mjs';
|
|
3
|
+
import { PRESS_SCALE } from './chunk-DVK4G2GT.mjs';
|
|
4
|
+
import { RADIUS } from './chunk-QY3X2UYR.mjs';
|
|
5
|
+
import './chunk-Y6FXYEAI.mjs';
|
|
6
|
+
import React, { useMemo, useEffect } from 'react';
|
|
7
|
+
import { StyleSheet, Platform, TouchableOpacity } from 'react-native';
|
|
8
|
+
import { useImage, vec, Canvas, Group, Image, RoundedRect, LinearGradient } from '@shopify/react-native-skia';
|
|
9
|
+
import Animated, { useSharedValue, withTiming, useAnimatedStyle, useDerivedValue } from 'react-native-reanimated';
|
|
10
|
+
|
|
11
|
+
var FOIL_PRESETS = {
|
|
12
|
+
// Classic holographic rainbow
|
|
13
|
+
rainbow: [
|
|
14
|
+
"rgba(255, 0, 128, 0.45)",
|
|
15
|
+
"rgba(255, 200, 0, 0.40)",
|
|
16
|
+
"rgba(0, 255, 170, 0.40)",
|
|
17
|
+
"rgba(0, 170, 255, 0.45)",
|
|
18
|
+
"rgba(180, 0, 255, 0.45)"
|
|
19
|
+
],
|
|
20
|
+
// Premium gold foil
|
|
21
|
+
gold: [
|
|
22
|
+
"rgba(255, 215, 0, 0.50)",
|
|
23
|
+
"rgba(255, 180, 0, 0.45)",
|
|
24
|
+
"rgba(218, 165, 32, 0.40)",
|
|
25
|
+
"rgba(255, 223, 128, 0.50)",
|
|
26
|
+
"rgba(184, 134, 11, 0.45)"
|
|
27
|
+
],
|
|
28
|
+
// Chrome silver foil
|
|
29
|
+
silver: [
|
|
30
|
+
"rgba(192, 192, 192, 0.50)",
|
|
31
|
+
"rgba(220, 220, 220, 0.45)",
|
|
32
|
+
"rgba(169, 169, 169, 0.40)",
|
|
33
|
+
"rgba(240, 240, 240, 0.50)",
|
|
34
|
+
"rgba(128, 128, 128, 0.45)"
|
|
35
|
+
],
|
|
36
|
+
// Deep space cosmic
|
|
37
|
+
cosmic: [
|
|
38
|
+
"rgba(75, 0, 130, 0.50)",
|
|
39
|
+
"rgba(138, 43, 226, 0.45)",
|
|
40
|
+
"rgba(255, 20, 147, 0.40)",
|
|
41
|
+
"rgba(0, 191, 255, 0.45)",
|
|
42
|
+
"rgba(148, 0, 211, 0.50)"
|
|
43
|
+
],
|
|
44
|
+
// Emerald green luxury
|
|
45
|
+
emerald: [
|
|
46
|
+
"rgba(0, 201, 87, 0.50)",
|
|
47
|
+
"rgba(46, 139, 87, 0.45)",
|
|
48
|
+
"rgba(0, 255, 127, 0.40)",
|
|
49
|
+
"rgba(60, 179, 113, 0.45)",
|
|
50
|
+
"rgba(0, 128, 0, 0.50)"
|
|
51
|
+
],
|
|
52
|
+
// Rose gold / pink
|
|
53
|
+
rose: [
|
|
54
|
+
"rgba(255, 105, 180, 0.50)",
|
|
55
|
+
"rgba(255, 182, 193, 0.45)",
|
|
56
|
+
"rgba(219, 112, 147, 0.40)",
|
|
57
|
+
"rgba(255, 20, 147, 0.45)",
|
|
58
|
+
"rgba(199, 21, 133, 0.50)"
|
|
59
|
+
],
|
|
60
|
+
// Deep ocean blue
|
|
61
|
+
ocean: [
|
|
62
|
+
"rgba(0, 119, 190, 0.50)",
|
|
63
|
+
"rgba(0, 180, 216, 0.45)",
|
|
64
|
+
"rgba(72, 202, 228, 0.40)",
|
|
65
|
+
"rgba(144, 224, 239, 0.45)",
|
|
66
|
+
"rgba(0, 150, 199, 0.50)"
|
|
67
|
+
],
|
|
68
|
+
// Hot fire gradient
|
|
69
|
+
fire: [
|
|
70
|
+
"rgba(255, 69, 0, 0.50)",
|
|
71
|
+
"rgba(255, 140, 0, 0.45)",
|
|
72
|
+
"rgba(255, 215, 0, 0.40)",
|
|
73
|
+
"rgba(255, 99, 71, 0.45)",
|
|
74
|
+
"rgba(220, 20, 60, 0.50)"
|
|
75
|
+
],
|
|
76
|
+
// Aurora borealis
|
|
77
|
+
aurora: [
|
|
78
|
+
"rgba(0, 255, 127, 0.45)",
|
|
79
|
+
"rgba(127, 255, 212, 0.40)",
|
|
80
|
+
"rgba(0, 206, 209, 0.45)",
|
|
81
|
+
"rgba(138, 43, 226, 0.40)",
|
|
82
|
+
"rgba(255, 20, 147, 0.45)"
|
|
83
|
+
],
|
|
84
|
+
// Neon cyberpunk
|
|
85
|
+
neon: [
|
|
86
|
+
"rgba(255, 0, 255, 0.55)",
|
|
87
|
+
"rgba(0, 255, 255, 0.50)",
|
|
88
|
+
"rgba(255, 255, 0, 0.45)",
|
|
89
|
+
"rgba(0, 255, 0, 0.50)",
|
|
90
|
+
"rgba(255, 0, 128, 0.55)"
|
|
91
|
+
]
|
|
92
|
+
};
|
|
93
|
+
var DEFAULT_FOIL_COLORS = FOIL_PRESETS.rainbow;
|
|
94
|
+
var DEFAULT_TILT_DEG = 10;
|
|
95
|
+
var DEFAULT_NORM_FACTOR = Math.PI / 6;
|
|
96
|
+
function HolographicCard({
|
|
97
|
+
source,
|
|
98
|
+
width = 300,
|
|
99
|
+
height,
|
|
100
|
+
borderRadius = RADIUS.md,
|
|
101
|
+
enableTilt = true,
|
|
102
|
+
intensity = 1,
|
|
103
|
+
onPress,
|
|
104
|
+
style,
|
|
105
|
+
// New customization props
|
|
106
|
+
foilPreset = "rainbow",
|
|
107
|
+
foilColors,
|
|
108
|
+
maxTiltDegrees = DEFAULT_TILT_DEG,
|
|
109
|
+
tiltSensitivity = 1,
|
|
110
|
+
sheenSpread = 0.6,
|
|
111
|
+
tiltAnimationDuration = 80,
|
|
112
|
+
perspective = 800,
|
|
113
|
+
blendMode = "plus"
|
|
114
|
+
}) {
|
|
115
|
+
const h = height ?? width * 1.4;
|
|
116
|
+
const image = useImage(source ?? null);
|
|
117
|
+
const clampedTilt = Math.max(0, Math.min(45, maxTiltDegrees));
|
|
118
|
+
const clampedSensitivity = Math.max(0.1, Math.min(2, tiltSensitivity));
|
|
119
|
+
const clampedSpread = Math.max(0, Math.min(1, sheenSpread));
|
|
120
|
+
const clampedPerspective = Math.max(200, Math.min(2e3, perspective));
|
|
121
|
+
const resolvedFoilColors = useMemo(() => {
|
|
122
|
+
if (foilColors && foilColors.length >= 2) return foilColors;
|
|
123
|
+
return FOIL_PRESETS[foilPreset] ?? DEFAULT_FOIL_COLORS;
|
|
124
|
+
}, [foilColors, foilPreset]);
|
|
125
|
+
const normFactor = DEFAULT_NORM_FACTOR / clampedSensitivity;
|
|
126
|
+
const tiltX = useSharedValue(0);
|
|
127
|
+
const tiltY = useSharedValue(0);
|
|
128
|
+
useEffect(() => {
|
|
129
|
+
if (!enableTilt || Platform.OS === "web") return;
|
|
130
|
+
let remove;
|
|
131
|
+
let cancelled = false;
|
|
132
|
+
import('expo-sensors').then(({ DeviceMotion }) => {
|
|
133
|
+
if (cancelled) return;
|
|
134
|
+
DeviceMotion.setUpdateInterval(16);
|
|
135
|
+
const sub = DeviceMotion.addListener(({ rotation }) => {
|
|
136
|
+
if (!rotation) return;
|
|
137
|
+
const nx = Math.max(-1, Math.min(rotation.gamma / normFactor, 1));
|
|
138
|
+
const ny = Math.max(-1, Math.min(rotation.beta / normFactor, 1));
|
|
139
|
+
tiltX.value = withTiming(nx, { duration: tiltAnimationDuration });
|
|
140
|
+
tiltY.value = withTiming(ny, { duration: tiltAnimationDuration });
|
|
141
|
+
});
|
|
142
|
+
remove = () => sub.remove();
|
|
143
|
+
}).catch(() => {
|
|
144
|
+
});
|
|
145
|
+
return () => {
|
|
146
|
+
cancelled = true;
|
|
147
|
+
remove?.();
|
|
148
|
+
};
|
|
149
|
+
}, [enableTilt, tiltX, tiltY, normFactor, tiltAnimationDuration]);
|
|
150
|
+
const { animatedStyle: pressStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
151
|
+
pressScale: PRESS_SCALE.card,
|
|
152
|
+
disabled: !onPress
|
|
153
|
+
});
|
|
154
|
+
const tiltStyle = useAnimatedStyle(() => ({
|
|
155
|
+
transform: [
|
|
156
|
+
{ perspective: clampedPerspective },
|
|
157
|
+
{ rotateX: `${-tiltY.value * clampedTilt}deg` },
|
|
158
|
+
{ rotateY: `${tiltX.value * clampedTilt}deg` }
|
|
159
|
+
]
|
|
160
|
+
}));
|
|
161
|
+
const start = useDerivedValue(() => vec(width * (0.5 - tiltX.value * clampedSpread), h * (0.5 - tiltY.value * clampedSpread)));
|
|
162
|
+
const end = useDerivedValue(() => vec(width * (0.5 + tiltX.value * clampedSpread), h * (0.5 + tiltY.value * clampedSpread)));
|
|
163
|
+
const rrct = { x: 0, y: 0, width, height: h };
|
|
164
|
+
const canvas = /* @__PURE__ */ React.createElement(Canvas, { style: { width, height: h } }, image ? /* @__PURE__ */ React.createElement(Group, { clip: { rect: rrct, rx: borderRadius, ry: borderRadius } }, /* @__PURE__ */ React.createElement(Image, { image, x: 0, y: 0, width, height: h, fit: "cover" })) : null, /* @__PURE__ */ React.createElement(RoundedRect, { x: 0, y: 0, width, height: h, r: borderRadius, opacity: intensity, blendMode }, /* @__PURE__ */ React.createElement(LinearGradient, { start, end, colors: resolvedFoilColors })));
|
|
165
|
+
const card = /* @__PURE__ */ React.createElement(Animated.View, { style: [{ width, height: h }, tiltStyle, style] }, canvas);
|
|
166
|
+
if (!onPress) return card;
|
|
167
|
+
return /* @__PURE__ */ React.createElement(Animated.View, { style: pressStyle }, /* @__PURE__ */ React.createElement(
|
|
168
|
+
TouchableOpacity,
|
|
169
|
+
{
|
|
170
|
+
onPress: () => {
|
|
171
|
+
impactLight();
|
|
172
|
+
onPress();
|
|
173
|
+
},
|
|
174
|
+
onPressIn,
|
|
175
|
+
onPressOut,
|
|
176
|
+
activeOpacity: 1,
|
|
177
|
+
touchSoundDisabled: true,
|
|
178
|
+
accessibilityRole: "imagebutton",
|
|
179
|
+
...hoverHandlers,
|
|
180
|
+
style: styles.touch
|
|
181
|
+
},
|
|
182
|
+
card
|
|
183
|
+
));
|
|
184
|
+
}
|
|
185
|
+
var styles = StyleSheet.create({
|
|
186
|
+
touch: {
|
|
187
|
+
alignSelf: "flex-start"
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
export { FOIL_PRESETS, HolographicCard };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type IconButtonVariant = 'primary' | 'secondary' | 'outline' | 'text' | 'destructive';
|
|
5
|
+
type IconButtonSize = 'sm' | 'md' | 'lg';
|
|
6
|
+
interface IconButtonProps {
|
|
7
|
+
iconName?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
iconColor?: string;
|
|
10
|
+
variant?: IconButtonVariant;
|
|
11
|
+
size?: IconButtonSize;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Badge overlay. `true` shows a dot. A number shows a count (capped at 99).
|
|
15
|
+
* The dot/count appears top-right of the button.
|
|
16
|
+
*/
|
|
17
|
+
badge?: boolean | number;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
style?: ViewStyle;
|
|
20
|
+
onPress?: () => void;
|
|
21
|
+
accessibilityLabel?: string;
|
|
22
|
+
accessibilityHint?: string;
|
|
23
|
+
}
|
|
24
|
+
declare function IconButtonBase({ iconName, icon, iconColor, variant, size, loading, badge, disabled, style, onPress, accessibilityLabel, accessibilityHint, }: IconButtonProps): React.JSX.Element;
|
|
25
|
+
declare const IconButton: React.MemoExoticComponent<typeof IconButtonBase>;
|
|
26
|
+
|
|
27
|
+
export { IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type IconButtonVariant = 'primary' | 'secondary' | 'outline' | 'text' | 'destructive';
|
|
5
|
+
type IconButtonSize = 'sm' | 'md' | 'lg';
|
|
6
|
+
interface IconButtonProps {
|
|
7
|
+
iconName?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
iconColor?: string;
|
|
10
|
+
variant?: IconButtonVariant;
|
|
11
|
+
size?: IconButtonSize;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Badge overlay. `true` shows a dot. A number shows a count (capped at 99).
|
|
15
|
+
* The dot/count appears top-right of the button.
|
|
16
|
+
*/
|
|
17
|
+
badge?: boolean | number;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
style?: ViewStyle;
|
|
20
|
+
onPress?: () => void;
|
|
21
|
+
accessibilityLabel?: string;
|
|
22
|
+
accessibilityHint?: string;
|
|
23
|
+
}
|
|
24
|
+
declare function IconButtonBase({ iconName, icon, iconColor, variant, size, loading, badge, disabled, style, onPress, accessibilityLabel, accessibilityHint, }: IconButtonProps): React.JSX.Element;
|
|
25
|
+
declare const IconButton: React.MemoExoticComponent<typeof IconButtonBase>;
|
|
26
|
+
|
|
27
|
+
export { IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant };
|