@retray-dev/ui-kit 12.1.0 → 13.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 +183 -147
- package/CONSUMER.md +2 -2
- package/DESIGN.md +2 -2
- package/README.md +13 -8
- package/dist/Accordion.d.mts +6 -0
- package/dist/Accordion.d.ts +6 -0
- package/dist/Accordion.js +62 -208
- package/dist/Accordion.mjs +6 -5
- package/dist/AlertBanner.js +29 -151
- package/dist/AlertBanner.mjs +3 -3
- package/dist/AppHeader.js +37 -233
- package/dist/AppHeader.mjs +6 -7
- package/dist/Avatar.d.mts +17 -1
- package/dist/Avatar.d.ts +17 -1
- package/dist/Avatar.js +80 -113
- package/dist/Avatar.mjs +2 -2
- package/dist/Badge.js +24 -147
- package/dist/Badge.mjs +3 -3
- package/dist/Button.js +86 -274
- package/dist/Button.mjs +6 -6
- package/dist/Card.js +15 -198
- package/dist/Card.mjs +4 -5
- package/dist/CategoryStrip.d.mts +0 -5
- package/dist/CategoryStrip.d.ts +0 -5
- package/dist/CategoryStrip.js +47 -263
- package/dist/CategoryStrip.mjs +6 -6
- package/dist/Checkbox.js +15 -198
- package/dist/Checkbox.mjs +5 -5
- package/dist/Chip.js +44 -234
- package/dist/Chip.mjs +7 -6
- package/dist/ConfirmDialog.js +100 -296
- package/dist/ConfirmDialog.mjs +7 -7
- package/dist/CurrencyDisplay.js +1 -112
- package/dist/CurrencyDisplay.mjs +2 -2
- package/dist/CurrencyInput.js +35 -160
- package/dist/CurrencyInput.mjs +5 -5
- package/dist/DetailRow.js +25 -148
- package/dist/DetailRow.mjs +3 -3
- package/dist/EmptyState.js +87 -275
- package/dist/EmptyState.mjs +7 -7
- package/dist/ErrorBoundary.js +32 -197
- package/dist/ErrorBoundary.mjs +4 -4
- package/dist/Form.js +1 -112
- package/dist/Form.mjs +2 -2
- package/dist/HolographicCard.d.mts +0 -28
- package/dist/HolographicCard.d.ts +0 -28
- package/dist/HolographicCard.js +20 -130
- package/dist/HolographicCard.mjs +9 -32
- package/dist/IconButton.js +36 -232
- package/dist/IconButton.mjs +5 -6
- package/dist/IconPicker.js +222 -927
- package/dist/IconPicker.mjs +5 -5
- package/dist/ImageUpload.d.mts +5 -1
- package/dist/ImageUpload.d.ts +5 -1
- package/dist/ImageUpload.js +32 -215
- package/dist/ImageUpload.mjs +5 -6
- package/dist/ImageViewer.js +75 -264
- package/dist/ImageViewer.mjs +8 -8
- package/dist/Input.d.mts +1 -1
- package/dist/Input.d.ts +1 -1
- package/dist/Input.js +35 -160
- package/dist/Input.mjs +4 -4
- package/dist/LabelValue.js +24 -147
- package/dist/LabelValue.mjs +3 -3
- package/dist/ListGroup.js +1 -112
- package/dist/ListGroup.mjs +2 -2
- package/dist/ListItem.js +38 -233
- package/dist/ListItem.mjs +5 -6
- package/dist/MediaCard.d.mts +0 -14
- package/dist/MediaCard.d.ts +0 -14
- package/dist/MediaCard.js +69 -313
- package/dist/MediaCard.mjs +5 -6
- package/dist/MenuGroup.js +1 -112
- package/dist/MenuGroup.mjs +2 -2
- package/dist/MenuItem.js +36 -232
- package/dist/MenuItem.mjs +5 -6
- package/dist/MonthPicker.js +8 -161
- package/dist/MonthPicker.mjs +3 -3
- package/dist/NumberStepper.js +40 -236
- package/dist/NumberStepper.mjs +5 -6
- package/dist/PagerDots.d.mts +1 -1
- package/dist/PagerDots.d.ts +1 -1
- package/dist/PagerDots.js +69 -222
- package/dist/PagerDots.mjs +6 -5
- package/dist/Pressable.js +14 -85
- package/dist/Pressable.mjs +4 -4
- package/dist/PricingCard.js +94 -279
- package/dist/PricingCard.mjs +8 -8
- package/dist/Progress.js +3 -121
- package/dist/Progress.mjs +3 -3
- package/dist/RadioGroup.js +52 -263
- package/dist/RadioGroup.mjs +5 -5
- package/dist/RetrayProvider.d.mts +1 -1
- package/dist/RetrayProvider.d.ts +1 -1
- package/dist/RetrayProvider.js +5 -6
- package/dist/RetrayProvider.mjs +3 -3
- package/dist/Select.d.mts +2 -1
- package/dist/Select.d.ts +2 -1
- package/dist/Select.js +24 -230
- package/dist/Select.mjs +4 -5
- package/dist/SelectableCard.d.mts +27 -0
- package/dist/SelectableCard.d.ts +27 -0
- package/dist/SelectableCard.js +335 -0
- package/dist/SelectableCard.mjs +8 -0
- package/dist/SelectableGrid.d.mts +0 -21
- package/dist/SelectableGrid.d.ts +0 -21
- package/dist/SelectableGrid.js +49 -269
- package/dist/SelectableGrid.mjs +5 -6
- package/dist/Separator.js +1 -112
- package/dist/Separator.mjs +2 -2
- package/dist/Sheet.js +16 -163
- package/dist/Sheet.mjs +3 -3
- package/dist/SheetSelect.js +39 -234
- package/dist/SheetSelect.mjs +6 -6
- package/dist/Skeleton.d.mts +3 -1
- package/dist/Skeleton.d.ts +3 -1
- package/dist/Skeleton.js +7 -124
- package/dist/Skeleton.mjs +3 -3
- package/dist/Slider.js +6 -159
- package/dist/Slider.mjs +3 -3
- package/dist/Spinner.js +3 -114
- package/dist/Spinner.mjs +2 -2
- package/dist/Stats.d.mts +4 -1
- package/dist/Stats.d.ts +4 -1
- package/dist/Stats.js +60 -234
- package/dist/Stats.mjs +5 -6
- package/dist/Switch.js +24 -173
- package/dist/Switch.mjs +5 -4
- package/dist/TabBar.js +43 -198
- package/dist/TabBar.mjs +5 -4
- package/dist/Tabs.js +15 -197
- package/dist/Tabs.mjs +5 -5
- package/dist/Text.js +9 -128
- package/dist/Text.mjs +2 -2
- package/dist/Textarea.d.mts +2 -1
- package/dist/Textarea.d.ts +2 -1
- package/dist/Textarea.js +71 -217
- package/dist/Textarea.mjs +4 -4
- package/dist/Toast.js +1 -112
- package/dist/Toast.mjs +2 -2
- package/dist/Toggle.js +39 -234
- package/dist/Toggle.mjs +6 -6
- package/dist/{chunk-FFTYLPSB.mjs → chunk-2QOHHBJC.mjs} +13 -7
- package/dist/{chunk-BCWEHE34.mjs → chunk-2VIDP72N.mjs} +3 -3
- package/dist/{chunk-PGERH3P7.mjs → chunk-4NQFTHN3.mjs} +13 -7
- package/dist/{chunk-3N2M3WZL.mjs → chunk-4ZO5PTKF.mjs} +4 -4
- package/dist/{chunk-MYZ2EDYU.mjs → chunk-5MYNAAFE.mjs} +13 -17
- package/dist/{chunk-E7NEHHXV.mjs → chunk-62BBSSUF.mjs} +3 -3
- package/dist/{chunk-ISY26JQJ.mjs → chunk-6CR4S6W2.mjs} +3 -3
- package/dist/{chunk-FUVYSVGR.mjs → chunk-6QLBHUEG.mjs} +8 -7
- package/dist/chunk-ARONDO7M.mjs +40 -0
- package/dist/{chunk-3UYAZ7I4.mjs → chunk-AZV7KNJI.mjs} +3 -3
- package/dist/{chunk-HLMPMUK2.mjs → chunk-BTUW5LSG.mjs} +11 -8
- package/dist/chunk-BULKGOIZ.mjs +235 -0
- package/dist/{chunk-265G6A46.mjs → chunk-CBIZLRYH.mjs} +29 -12
- package/dist/chunk-CM2DG4MR.mjs +142 -0
- package/dist/{chunk-2I2AYECM.mjs → chunk-DBHSUUKU.mjs} +2 -2
- package/dist/{chunk-P64WHW4A.mjs → chunk-DE25XTVQ.mjs} +3 -3
- package/dist/{chunk-DI7CBDL6.mjs → chunk-E4EQSCKR.mjs} +5 -5
- package/dist/{chunk-357YO24D.mjs → chunk-EHGBHFMH.mjs} +9 -17
- package/dist/{chunk-GK4VRMNE.mjs → chunk-EROPDCB5.mjs} +24 -27
- package/dist/{chunk-XBAGGKLW.mjs → chunk-ERWJPVX7.mjs} +2 -2
- package/dist/{chunk-LRM4AVYY.mjs → chunk-ESQDPO5E.mjs} +7 -7
- package/dist/{chunk-EFLFRAHD.mjs → chunk-EW2FIDSM.mjs} +1 -1
- package/dist/{chunk-7HSILTC4.mjs → chunk-FTTI6T5Q.mjs} +4 -4
- package/dist/{chunk-X26S5EVZ.mjs → chunk-HUSSF6TF.mjs} +1 -1
- package/dist/chunk-IFYMBOEN.mjs +14 -0
- package/dist/{chunk-S3KJCPEJ.mjs → chunk-IGU223UM.mjs} +80 -4
- package/dist/chunk-IJCMPVW5.mjs +121 -0
- package/dist/{chunk-I4V5XZPS.mjs → chunk-ITG4JQM3.mjs} +4 -4
- package/dist/{chunk-F4V6XLP4.mjs → chunk-K3QX2M26.mjs} +11 -8
- package/dist/{chunk-V6NFJXKO.mjs → chunk-K7TKID3V.mjs} +8 -7
- package/dist/{chunk-ZHMSAYLT.mjs → chunk-KAGADD2O.mjs} +4 -4
- package/dist/{chunk-3GEYJ7I5.mjs → chunk-KC5QDYGZ.mjs} +4 -4
- package/dist/{chunk-HJ46DTJE.mjs → chunk-KPTY7UYQ.mjs} +1 -1
- package/dist/{chunk-EMUWGDWC.mjs → chunk-KSSVIFYR.mjs} +11 -12
- package/dist/chunk-L3YKPTJQ.mjs +119 -0
- package/dist/chunk-M53LC4Q7.mjs +35 -0
- package/dist/{chunk-NXI4YDZ2.mjs → chunk-MP7GLMIR.mjs} +17 -25
- package/dist/chunk-MZ6WRTD2.mjs +40 -0
- package/dist/chunk-NGEN2EES.mjs +581 -0
- package/dist/{chunk-JULSIZDM.mjs → chunk-OBV72JD4.mjs} +1 -1
- package/dist/{chunk-2A2LEFZG.mjs → chunk-PGQ6FMXS.mjs} +6 -5
- package/dist/{chunk-BQZE3HAW.mjs → chunk-PI6RULJX.mjs} +1 -1
- package/dist/{chunk-FA2KMTH5.mjs → chunk-RA6SAAFE.mjs} +9 -8
- package/dist/{chunk-FVTVCJAH.mjs → chunk-RRKM4MKB.mjs} +7 -7
- package/dist/{chunk-AKM4EPOT.mjs → chunk-S2VGME7X.mjs} +1 -1
- package/dist/{chunk-OULVKTWL.mjs → chunk-S44XWTTC.mjs} +35 -25
- package/dist/{chunk-QSFV2P7O.mjs → chunk-SZEKQAOY.mjs} +1 -1
- package/dist/{chunk-N4ZPVCJH.mjs → chunk-TETMEKZE.mjs} +9 -9
- package/dist/{chunk-2CBQKU7H.mjs → chunk-TMH263OK.mjs} +5 -4
- package/dist/{chunk-D3Y2T42P.mjs → chunk-U6DEBYU5.mjs} +10 -9
- package/dist/{chunk-4WFMPFZB.mjs → chunk-UOKFSFNJ.mjs} +2 -2
- package/dist/{chunk-WOEWGSTU.mjs → chunk-URIH43IJ.mjs} +13 -21
- package/dist/{chunk-JCZQOY4O.mjs → chunk-V2ZB2XNS.mjs} +16 -10
- package/dist/{chunk-P73V2EKS.mjs → chunk-WIPEDNSD.mjs} +7 -7
- package/dist/{chunk-BOVUP27T.mjs → chunk-XCIG6HT2.mjs} +6 -5
- package/dist/chunk-Y6YS33GM.mjs +131 -0
- package/dist/{chunk-5OLNXP3S.mjs → chunk-ZKDKKQCE.mjs} +29 -7
- package/dist/{chunk-DF6DU42P.mjs → chunk-ZTPYUU5C.mjs} +5 -5
- package/dist/{index-wt-orHUi.d.ts → index-CY34hxPN.d.mts} +1 -0
- package/dist/{index-wt-orHUi.d.mts → index-CY34hxPN.d.ts} +1 -0
- package/dist/index.d.mts +15 -74
- package/dist/index.d.ts +15 -74
- package/dist/index.js +1055 -1562
- package/dist/index.mjs +81 -84
- package/package.json +8 -10
- package/src/components/Accordion/Accordion.tsx +32 -9
- package/src/components/AlertBanner/AlertBanner.tsx +7 -6
- package/src/components/AppHeader/AppHeader.tsx +1 -1
- package/src/components/Avatar/Avatar.tsx +92 -1
- package/src/components/Avatar/index.ts +2 -2
- package/src/components/Badge/Badge.tsx +2 -2
- package/src/components/Button/Button.tsx +64 -57
- package/src/components/Card/Card.tsx +1 -0
- package/src/components/CategoryStrip/CategoryStrip.tsx +36 -49
- package/src/components/Chip/Chip.tsx +5 -4
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +13 -6
- package/src/components/DetailRow/DetailRow.tsx +3 -3
- package/src/components/EmptyState/EmptyState.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +6 -6
- package/src/components/HolographicCard/HolographicCard.tsx +14 -95
- package/src/components/IconButton/IconButton.tsx +2 -2
- package/src/components/IconPicker/IconPicker.tsx +13 -12
- package/src/components/ImageUpload/ImageUpload.tsx +24 -28
- package/src/components/ImageViewer/ImageViewer.tsx +3 -3
- package/src/components/Input/Input.tsx +11 -5
- package/src/components/LabelValue/LabelValue.tsx +2 -2
- package/src/components/ListItem/ListItem.tsx +4 -4
- package/src/components/MediaCard/MediaCard.tsx +21 -59
- package/src/components/MenuItem/MenuItem.tsx +2 -2
- package/src/components/MonthPicker/MonthPicker.tsx +2 -2
- package/src/components/NumberStepper/NumberStepper.tsx +6 -6
- package/src/components/PagerDots/PagerDots.tsx +38 -28
- package/src/components/PricingCard/PricingCard.tsx +6 -6
- package/src/components/RadioGroup/RadioGroup.tsx +18 -31
- package/src/components/Select/Select.tsx +32 -39
- package/src/components/SelectableCard/SelectableCard.tsx +302 -0
- package/src/components/SelectableCard/index.ts +1 -0
- package/src/components/SelectableGrid/SelectableGrid.tsx +38 -72
- package/src/components/Sheet/Sheet.tsx +11 -4
- package/src/components/SheetSelect/SheetSelect.tsx +3 -3
- package/src/components/Skeleton/Skeleton.tsx +6 -3
- package/src/components/Spinner/Spinner.tsx +2 -2
- package/src/components/Stats/Stats.tsx +36 -8
- package/src/components/Switch/Switch.tsx +9 -6
- package/src/components/TabBar/TabBar.tsx +9 -8
- package/src/components/Text/Text.tsx +12 -1
- package/src/components/Textarea/Textarea.tsx +18 -32
- package/src/components/Toggle/Toggle.tsx +3 -3
- package/src/hooks/useConfirmDialog.ts +31 -42
- package/src/index.ts +4 -4
- package/src/theme/ThemeProvider.tsx +1 -4
- package/src/theme/colorUtils.ts +1 -72
- package/src/theme/colors.ts +47 -1
- package/src/theme/types.ts +6 -3
- package/src/utils/animations.ts +0 -47
- package/src/utils/curatedIcons.ts +93 -801
- package/src/utils/haptics.ts +13 -208
- package/src/utils/icons.ts +27 -91
- package/src/utils/pressable.ts +10 -61
- package/dist/VirtualList.d.mts +0 -19
- package/dist/VirtualList.d.ts +0 -19
- package/dist/VirtualList.js +0 -38
- package/dist/VirtualList.mjs +0 -2
- package/dist/chunk-3DKJ2GIC.mjs +0 -30
- package/dist/chunk-AQEVCEXV.mjs +0 -164
- package/dist/chunk-DOGIPOF5.mjs +0 -131
- package/dist/chunk-DVK4G2GT.mjs +0 -59
- package/dist/chunk-EJ7ZPXOH.mjs +0 -163
- package/dist/chunk-J6Q2YJEV.mjs +0 -134
- package/dist/chunk-JNVAIDLK.mjs +0 -136
- package/dist/chunk-KA7LTET3.mjs +0 -71
- package/dist/chunk-KHYX4IOM.mjs +0 -1114
- package/dist/chunk-NC5ZTR2Y.mjs +0 -32
- package/dist/chunk-YNROWHQJ.mjs +0 -46
- package/src/components/VirtualList/VirtualList.tsx +0 -60
- package/src/components/VirtualList/index.ts +0 -1
- package/src/utils/fontGuard.ts +0 -35
- package/src/utils/hover.ts +0 -25
- package/src/utils/useColorTransition.ts +0 -40
- package/src/utils/usePressScale.ts +0 -75
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { ViewStyle, Platform } from 'react-native'
|
|
3
3
|
import {
|
|
4
4
|
Canvas,
|
|
5
5
|
Group,
|
|
@@ -15,14 +15,10 @@ import Animated, {
|
|
|
15
15
|
useAnimatedStyle,
|
|
16
16
|
withTiming,
|
|
17
17
|
} from 'react-native-reanimated'
|
|
18
|
-
import {
|
|
19
|
-
import { PRESS_SCALE } from '../../utils/animations'
|
|
18
|
+
import { PressableCard } from '../../utils/pressable'
|
|
20
19
|
import { impactLight } from '../../utils/haptics'
|
|
21
20
|
import { RADIUS } from '../../tokens'
|
|
22
21
|
|
|
23
|
-
// ─── Foil Color Presets ───────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
/** Available foil color preset names */
|
|
26
22
|
export type FoilPreset =
|
|
27
23
|
| 'rainbow'
|
|
28
24
|
| 'gold'
|
|
@@ -35,9 +31,7 @@ export type FoilPreset =
|
|
|
35
31
|
| 'aurora'
|
|
36
32
|
| 'neon'
|
|
37
33
|
|
|
38
|
-
/** Foil color presets — each is an array of RGBA colors for the gradient */
|
|
39
34
|
export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
40
|
-
// Classic holographic rainbow
|
|
41
35
|
rainbow: [
|
|
42
36
|
'rgba(255, 0, 128, 0.45)',
|
|
43
37
|
'rgba(255, 200, 0, 0.40)',
|
|
@@ -45,7 +39,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
45
39
|
'rgba(0, 170, 255, 0.45)',
|
|
46
40
|
'rgba(180, 0, 255, 0.45)',
|
|
47
41
|
],
|
|
48
|
-
// Premium gold foil
|
|
49
42
|
gold: [
|
|
50
43
|
'rgba(255, 215, 0, 0.50)',
|
|
51
44
|
'rgba(255, 180, 0, 0.45)',
|
|
@@ -53,7 +46,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
53
46
|
'rgba(255, 223, 128, 0.50)',
|
|
54
47
|
'rgba(184, 134, 11, 0.45)',
|
|
55
48
|
],
|
|
56
|
-
// Chrome silver foil
|
|
57
49
|
silver: [
|
|
58
50
|
'rgba(192, 192, 192, 0.50)',
|
|
59
51
|
'rgba(220, 220, 220, 0.45)',
|
|
@@ -61,7 +53,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
61
53
|
'rgba(240, 240, 240, 0.50)',
|
|
62
54
|
'rgba(128, 128, 128, 0.45)',
|
|
63
55
|
],
|
|
64
|
-
// Deep space cosmic
|
|
65
56
|
cosmic: [
|
|
66
57
|
'rgba(75, 0, 130, 0.50)',
|
|
67
58
|
'rgba(138, 43, 226, 0.45)',
|
|
@@ -69,7 +60,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
69
60
|
'rgba(0, 191, 255, 0.45)',
|
|
70
61
|
'rgba(148, 0, 211, 0.50)',
|
|
71
62
|
],
|
|
72
|
-
// Emerald green luxury
|
|
73
63
|
emerald: [
|
|
74
64
|
'rgba(0, 201, 87, 0.50)',
|
|
75
65
|
'rgba(46, 139, 87, 0.45)',
|
|
@@ -77,7 +67,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
77
67
|
'rgba(60, 179, 113, 0.45)',
|
|
78
68
|
'rgba(0, 128, 0, 0.50)',
|
|
79
69
|
],
|
|
80
|
-
// Rose gold / pink
|
|
81
70
|
rose: [
|
|
82
71
|
'rgba(255, 105, 180, 0.50)',
|
|
83
72
|
'rgba(255, 182, 193, 0.45)',
|
|
@@ -85,7 +74,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
85
74
|
'rgba(255, 20, 147, 0.45)',
|
|
86
75
|
'rgba(199, 21, 133, 0.50)',
|
|
87
76
|
],
|
|
88
|
-
// Deep ocean blue
|
|
89
77
|
ocean: [
|
|
90
78
|
'rgba(0, 119, 190, 0.50)',
|
|
91
79
|
'rgba(0, 180, 216, 0.45)',
|
|
@@ -93,7 +81,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
93
81
|
'rgba(144, 224, 239, 0.45)',
|
|
94
82
|
'rgba(0, 150, 199, 0.50)',
|
|
95
83
|
],
|
|
96
|
-
// Hot fire gradient
|
|
97
84
|
fire: [
|
|
98
85
|
'rgba(255, 69, 0, 0.50)',
|
|
99
86
|
'rgba(255, 140, 0, 0.45)',
|
|
@@ -101,7 +88,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
101
88
|
'rgba(255, 99, 71, 0.45)',
|
|
102
89
|
'rgba(220, 20, 60, 0.50)',
|
|
103
90
|
],
|
|
104
|
-
// Aurora borealis
|
|
105
91
|
aurora: [
|
|
106
92
|
'rgba(0, 255, 127, 0.45)',
|
|
107
93
|
'rgba(127, 255, 212, 0.40)',
|
|
@@ -109,7 +95,6 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
109
95
|
'rgba(138, 43, 226, 0.40)',
|
|
110
96
|
'rgba(255, 20, 147, 0.45)',
|
|
111
97
|
],
|
|
112
|
-
// Neon cyberpunk
|
|
113
98
|
neon: [
|
|
114
99
|
'rgba(255, 0, 255, 0.55)',
|
|
115
100
|
'rgba(0, 255, 255, 0.50)',
|
|
@@ -119,64 +104,29 @@ export const FOIL_PRESETS: Record<FoilPreset, string[]> = {
|
|
|
119
104
|
],
|
|
120
105
|
}
|
|
121
106
|
|
|
122
|
-
// Default preset
|
|
123
107
|
const DEFAULT_FOIL_COLORS = FOIL_PRESETS.rainbow
|
|
124
|
-
|
|
125
|
-
// ─── Tilt Configuration ───────────────────────────────────────────────────────
|
|
126
|
-
|
|
127
|
-
/** Default max tilt in degrees */
|
|
128
108
|
const DEFAULT_TILT_DEG = 10
|
|
129
|
-
/** Default normalization factor (~30° of device rotation = full tilt) */
|
|
130
109
|
const DEFAULT_NORM_FACTOR = Math.PI / 6
|
|
131
110
|
|
|
132
111
|
export interface HolographicCardProps {
|
|
133
|
-
/** Card art — `require()` asset or `{ uri }`. Omitted = gradient-only foil surface. */
|
|
134
112
|
source?: Parameters<typeof useImage>[0]
|
|
135
|
-
/** Card width (dp). Defaults to 300. */
|
|
136
113
|
width?: number
|
|
137
|
-
/** Card height (dp). Defaults to `width * 1.4` (trading-card ratio). */
|
|
138
114
|
height?: number
|
|
139
|
-
/** Corner radius (dp). Defaults to `RADIUS.md`. */
|
|
140
115
|
borderRadius?: number
|
|
141
|
-
/** React to device motion (gyroscope) for parallax tilt + sheen. Defaults to true. */
|
|
142
116
|
enableTilt?: boolean
|
|
143
|
-
/** Strength of the foil sheen, 0–1. Defaults to 1. */
|
|
144
117
|
intensity?: number
|
|
145
|
-
/** Called when the card is pressed. */
|
|
146
118
|
onPress?: () => void
|
|
147
119
|
style?: ViewStyle
|
|
148
|
-
|
|
149
|
-
// ─── New Customization Props ────────────────────────────────────────────────
|
|
150
|
-
|
|
151
|
-
/** Foil color preset. Defaults to 'rainbow'. Ignored if `foilColors` is provided. */
|
|
152
120
|
foilPreset?: FoilPreset
|
|
153
|
-
/** Custom foil gradient colors (array of RGBA strings). Overrides `foilPreset`. */
|
|
154
121
|
foilColors?: string[]
|
|
155
|
-
/** Maximum tilt angle in degrees (0–45). Defaults to 10. */
|
|
156
122
|
maxTiltDegrees?: number
|
|
157
|
-
/** Sensitivity of tilt to device motion (0.1–2). Higher = more responsive. Defaults to 1. */
|
|
158
123
|
tiltSensitivity?: number
|
|
159
|
-
/** How far the sheen moves relative to tilt (0–1). Defaults to 0.6. */
|
|
160
124
|
sheenSpread?: number
|
|
161
|
-
/** Animation duration for tilt smoothing in ms. Defaults to 80. */
|
|
162
125
|
tiltAnimationDuration?: number
|
|
163
|
-
/** Perspective depth for 3D effect (200–2000). Defaults to 800. */
|
|
164
126
|
perspective?: number
|
|
165
|
-
/** Blend mode for the foil overlay. Defaults to 'plus'. */
|
|
166
127
|
blendMode?: 'plus' | 'screen' | 'overlay' | 'softLight' | 'hardLight'
|
|
167
128
|
}
|
|
168
129
|
|
|
169
|
-
/**
|
|
170
|
-
* Holographic / foil trading-card surface (Pokémon-TCG style). Renders the art
|
|
171
|
-
* on a Skia canvas with an animated rainbow sheen, and tilts in 3D toward device
|
|
172
|
-
* motion. The sheen position tracks the tilt so the foil "catches the light".
|
|
173
|
-
*
|
|
174
|
-
* Deep-import only — keeps Skia out of the main bundle:
|
|
175
|
-
* `import { HolographicCard } from '@retray-dev/ui-kit/HolographicCard'`
|
|
176
|
-
*
|
|
177
|
-
* Requires the optional peers `@shopify/react-native-skia` and (for tilt)
|
|
178
|
-
* `expo-sensors`. Without `expo-sensors` the card renders with a static sheen.
|
|
179
|
-
*/
|
|
180
130
|
export function HolographicCard({
|
|
181
131
|
source,
|
|
182
132
|
width = 300,
|
|
@@ -186,7 +136,6 @@ export function HolographicCard({
|
|
|
186
136
|
intensity = 1,
|
|
187
137
|
onPress,
|
|
188
138
|
style,
|
|
189
|
-
// New customization props
|
|
190
139
|
foilPreset = 'rainbow',
|
|
191
140
|
foilColors,
|
|
192
141
|
maxTiltDegrees = DEFAULT_TILT_DEG,
|
|
@@ -197,25 +146,20 @@ export function HolographicCard({
|
|
|
197
146
|
blendMode = 'plus',
|
|
198
147
|
}: HolographicCardProps) {
|
|
199
148
|
const h = height ?? width * 1.4
|
|
200
|
-
// Called unconditionally (rules of hooks); useImage returns null for a nullish source.
|
|
201
149
|
const image = useImage((source ?? null) as Parameters<typeof useImage>[0])
|
|
202
150
|
|
|
203
|
-
// Clamp and compute values
|
|
204
151
|
const clampedTilt = Math.max(0, Math.min(45, maxTiltDegrees))
|
|
205
152
|
const clampedSensitivity = Math.max(0.1, Math.min(2, tiltSensitivity))
|
|
206
153
|
const clampedSpread = Math.max(0, Math.min(1, sheenSpread))
|
|
207
154
|
const clampedPerspective = Math.max(200, Math.min(2000, perspective))
|
|
208
|
-
|
|
209
|
-
// Resolve foil colors: custom > preset > default
|
|
155
|
+
|
|
210
156
|
const resolvedFoilColors = useMemo(() => {
|
|
211
157
|
if (foilColors && foilColors.length >= 2) return foilColors
|
|
212
158
|
return FOIL_PRESETS[foilPreset] ?? DEFAULT_FOIL_COLORS
|
|
213
159
|
}, [foilColors, foilPreset])
|
|
214
160
|
|
|
215
|
-
// Normalization factor adjusted by sensitivity
|
|
216
161
|
const normFactor = DEFAULT_NORM_FACTOR / clampedSensitivity
|
|
217
162
|
|
|
218
|
-
// Tilt in normalized [-1, 1] on each axis.
|
|
219
163
|
const tiltX = useSharedValue(0)
|
|
220
164
|
const tiltY = useSharedValue(0)
|
|
221
165
|
|
|
@@ -223,7 +167,6 @@ export function HolographicCard({
|
|
|
223
167
|
if (!enableTilt || Platform.OS === 'web') return
|
|
224
168
|
let remove: (() => void) | undefined
|
|
225
169
|
let cancelled = false
|
|
226
|
-
// Dynamic import: expo-sensors is an optional peer. Absence = static sheen.
|
|
227
170
|
import('expo-sensors')
|
|
228
171
|
.then(({ DeviceMotion }) => {
|
|
229
172
|
if (cancelled) return
|
|
@@ -237,21 +180,13 @@ export function HolographicCard({
|
|
|
237
180
|
})
|
|
238
181
|
remove = () => sub.remove()
|
|
239
182
|
})
|
|
240
|
-
.catch(() => {
|
|
241
|
-
// expo-sensors not installed — leave tilt at rest.
|
|
242
|
-
})
|
|
183
|
+
.catch(() => {})
|
|
243
184
|
return () => {
|
|
244
185
|
cancelled = true
|
|
245
186
|
remove?.()
|
|
246
187
|
}
|
|
247
188
|
}, [enableTilt, tiltX, tiltY, normFactor, tiltAnimationDuration])
|
|
248
189
|
|
|
249
|
-
// 3D parallax — perspective tilt of the whole card toward the device motion.
|
|
250
|
-
const { animatedStyle: pressStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
251
|
-
pressScale: PRESS_SCALE.card,
|
|
252
|
-
disabled: !onPress,
|
|
253
|
-
})
|
|
254
|
-
|
|
255
190
|
const tiltStyle = useAnimatedStyle(() => ({
|
|
256
191
|
transform: [
|
|
257
192
|
{ perspective: clampedPerspective },
|
|
@@ -260,7 +195,6 @@ export function HolographicCard({
|
|
|
260
195
|
],
|
|
261
196
|
}))
|
|
262
197
|
|
|
263
|
-
// Sheen sweeps across the card as it tilts.
|
|
264
198
|
const start = useDerivedValue(() => vec(width * (0.5 - tiltX.value * clampedSpread), h * (0.5 - tiltY.value * clampedSpread)))
|
|
265
199
|
const end = useDerivedValue(() => vec(width * (0.5 + tiltX.value * clampedSpread), h * (0.5 + tiltY.value * clampedSpread)))
|
|
266
200
|
|
|
@@ -268,13 +202,11 @@ export function HolographicCard({
|
|
|
268
202
|
|
|
269
203
|
const canvas = (
|
|
270
204
|
<Canvas style={{ width, height: h }}>
|
|
271
|
-
{/* Art clipped to the rounded card. */}
|
|
272
205
|
{image ? (
|
|
273
206
|
<Group clip={{ rect: rrct, rx: borderRadius, ry: borderRadius }}>
|
|
274
207
|
<SkiaImage image={image} x={0} y={0} width={width} height={h} fit="cover" />
|
|
275
208
|
</Group>
|
|
276
209
|
) : null}
|
|
277
|
-
{/* Foil sheen — additive rainbow gradient that tracks the tilt. */}
|
|
278
210
|
<RoundedRect x={0} y={0} width={width} height={h} r={borderRadius} opacity={intensity} blendMode={blendMode}>
|
|
279
211
|
<LinearGradient start={start} end={end} colors={resolvedFoilColors} />
|
|
280
212
|
</RoundedRect>
|
|
@@ -288,28 +220,15 @@ export function HolographicCard({
|
|
|
288
220
|
if (!onPress) return card
|
|
289
221
|
|
|
290
222
|
return (
|
|
291
|
-
<
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
accessibilityRole="imagebutton"
|
|
302
|
-
{...hoverHandlers}
|
|
303
|
-
style={styles.touch}
|
|
304
|
-
>
|
|
305
|
-
{card}
|
|
306
|
-
</TouchableOpacity>
|
|
307
|
-
</Animated.View>
|
|
223
|
+
<PressableCard
|
|
224
|
+
onPress={() => { impactLight(); onPress() }}
|
|
225
|
+
enabled
|
|
226
|
+
rippleColor="transparent"
|
|
227
|
+
touchSoundDisabled
|
|
228
|
+
accessibilityRole="imagebutton"
|
|
229
|
+
style={{ alignSelf: 'flex-start' }}
|
|
230
|
+
>
|
|
231
|
+
{card}
|
|
232
|
+
</PressableCard>
|
|
308
233
|
)
|
|
309
234
|
}
|
|
310
|
-
|
|
311
|
-
const styles = StyleSheet.create({
|
|
312
|
-
touch: {
|
|
313
|
-
alignSelf: 'flex-start',
|
|
314
|
-
},
|
|
315
|
-
})
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { impactLight } from '../../utils/haptics'
|
|
10
10
|
import { useTheme } from '../../theme'
|
|
11
11
|
import { s, ms } from '../../utils/scaling'
|
|
12
|
-
import {
|
|
12
|
+
import { Icon } from '../../utils/icons'
|
|
13
13
|
import { PressableButton } from '../../utils/pressable'
|
|
14
14
|
|
|
15
15
|
// primary: filled primary
|
|
@@ -92,7 +92,7 @@ function IconButtonBase({
|
|
|
92
92
|
const { container: containerSize, icon: iconSize } = sizeMap[size]
|
|
93
93
|
|
|
94
94
|
const resolvedIcon: React.ReactNode = iconName
|
|
95
|
-
?
|
|
95
|
+
? <Icon name={iconName} size={iconSize} color={iconColor ?? defaultIconColor} />
|
|
96
96
|
: icon
|
|
97
97
|
|
|
98
98
|
// Badge rendering
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
} from '@gorhom/bottom-sheet'
|
|
9
9
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
10
10
|
import { useTheme } from '../../theme'
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { Icon } from '../../utils/icons'
|
|
12
|
+
import { getCuratedCategories, getAllCuratedIcons } from '../../utils/curatedIcons'
|
|
13
13
|
import { selectionAsync as hapticSelection, impactMedium } from '../../utils/haptics'
|
|
14
14
|
import { s, vs, ms } from '../../utils/scaling'
|
|
15
15
|
import { RADIUS } from '../../tokens'
|
|
@@ -54,7 +54,7 @@ function IconCell({ name, selected, size, onPress }: { name: string; selected: b
|
|
|
54
54
|
accessibilityLabel={name}
|
|
55
55
|
style={[styles.cell, { width: size, height: size, backgroundColor: bg }]}
|
|
56
56
|
>
|
|
57
|
-
{
|
|
57
|
+
<Icon name={name} size={ms(20)} color={iconColor} />
|
|
58
58
|
</TouchableOpacity>
|
|
59
59
|
)
|
|
60
60
|
}
|
|
@@ -83,10 +83,11 @@ export function IconPicker({
|
|
|
83
83
|
const sheetName = useId()
|
|
84
84
|
|
|
85
85
|
const activeIcons = useMemo(() => {
|
|
86
|
+
const allIcons = getAllCuratedIcons()
|
|
86
87
|
if (activeCategory) {
|
|
87
|
-
return
|
|
88
|
+
return getCuratedCategories().find((c) => c.name === activeCategory)?.icons ?? allIcons
|
|
88
89
|
}
|
|
89
|
-
return
|
|
90
|
+
return allIcons
|
|
90
91
|
}, [activeCategory])
|
|
91
92
|
|
|
92
93
|
const gapPx = s(gap)
|
|
@@ -129,7 +130,7 @@ export function IconPicker({
|
|
|
129
130
|
[],
|
|
130
131
|
)
|
|
131
132
|
|
|
132
|
-
const selectedIcon = value ?
|
|
133
|
+
const selectedIcon = value ? <Icon name={value} size={ms(28)} color={colors.foreground} /> : null
|
|
133
134
|
|
|
134
135
|
return (
|
|
135
136
|
<View style={[styles.triggerContainer, style]}>
|
|
@@ -157,7 +158,7 @@ export function IconPicker({
|
|
|
157
158
|
disabled && styles.triggerDisabled,
|
|
158
159
|
]}
|
|
159
160
|
>
|
|
160
|
-
{selectedIcon ??
|
|
161
|
+
{selectedIcon ?? <Icon name="plus" size={ms(24)} color={colors.foregroundMuted} />}
|
|
161
162
|
</TouchableOpacity>
|
|
162
163
|
{error ? (
|
|
163
164
|
<Text
|
|
@@ -223,7 +224,7 @@ export function IconPicker({
|
|
|
223
224
|
activeOpacity={0.7}
|
|
224
225
|
touchSoundDisabled={true}
|
|
225
226
|
accessibilityRole="button"
|
|
226
|
-
accessibilityLabel="
|
|
227
|
+
accessibilityLabel="Todas"
|
|
227
228
|
accessibilityState={{ selected: activeCategory === null }}
|
|
228
229
|
style={[
|
|
229
230
|
styles.categoryChip,
|
|
@@ -234,7 +235,7 @@ export function IconPicker({
|
|
|
234
235
|
]}
|
|
235
236
|
>
|
|
236
237
|
<View style={styles.categoryChipInner}>
|
|
237
|
-
|
|
238
|
+
<Icon name="grid" size={ms(14)} color={activeCategory === null ? colors.primaryForeground : colors.foregroundSubtle} />
|
|
238
239
|
<Text
|
|
239
240
|
style={[
|
|
240
241
|
styles.categoryChipText,
|
|
@@ -243,11 +244,11 @@ export function IconPicker({
|
|
|
243
244
|
allowFontScaling={true}
|
|
244
245
|
numberOfLines={1}
|
|
245
246
|
>
|
|
246
|
-
|
|
247
|
+
Todas
|
|
247
248
|
</Text>
|
|
248
249
|
</View>
|
|
249
250
|
</TouchableOpacity>
|
|
250
|
-
{
|
|
251
|
+
{getCuratedCategories().map((cat) => (
|
|
251
252
|
<TouchableOpacity
|
|
252
253
|
key={cat.name}
|
|
253
254
|
onPress={() => setActiveCategory(cat.name)}
|
|
@@ -265,7 +266,7 @@ export function IconPicker({
|
|
|
265
266
|
]}
|
|
266
267
|
>
|
|
267
268
|
<View style={styles.categoryChipInner}>
|
|
268
|
-
{
|
|
269
|
+
<Icon name={cat.categoryIcon} size={ms(14)} color={activeCategory === cat.name ? colors.primaryForeground : colors.foregroundSubtle} />
|
|
269
270
|
<Text
|
|
270
271
|
style={[
|
|
271
272
|
styles.categoryChipText,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { Image } from 'expo-image'
|
|
3
|
+
import { View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
4
|
import { Feather } from '@expo/vector-icons'
|
|
4
5
|
import { impactLight } from '../../utils/haptics'
|
|
5
6
|
import { useTheme } from '../../theme'
|
|
@@ -27,65 +28,58 @@ export interface ImageUploadProps {
|
|
|
27
28
|
borderRadius?: number
|
|
28
29
|
/** Aspect ratio for the selected image. Defaults to 'cover'. */
|
|
29
30
|
resizeMode?: 'cover' | 'contain' | 'stretch'
|
|
31
|
+
/** Whether to allow the user to crop the image after selecting. Defaults to true. */
|
|
32
|
+
allowsEditing?: boolean
|
|
30
33
|
disabled?: boolean
|
|
31
34
|
style?: ViewStyle
|
|
32
35
|
accessibilityLabel?: string
|
|
36
|
+
/** Called synchronously when user taps the upload area, before dynamic import and permission request. */
|
|
37
|
+
onPickerStarting?: () => void
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
export function ImageUpload({
|
|
36
41
|
value,
|
|
37
42
|
onChange,
|
|
38
43
|
loading = false,
|
|
39
|
-
placeholder = '
|
|
44
|
+
placeholder = 'Toca para añadir imagen',
|
|
40
45
|
showPlaceholderText = true,
|
|
41
46
|
width,
|
|
42
47
|
height = 200,
|
|
43
48
|
borderRadius = RADIUS.lg,
|
|
44
49
|
resizeMode = 'cover',
|
|
50
|
+
allowsEditing = true,
|
|
45
51
|
disabled = false,
|
|
46
52
|
style,
|
|
47
53
|
accessibilityLabel,
|
|
54
|
+
onPickerStarting,
|
|
48
55
|
}: ImageUploadProps) {
|
|
49
56
|
const { colors } = useTheme()
|
|
57
|
+
const [imageLoaded, setImageLoaded] = useState(false)
|
|
50
58
|
|
|
51
59
|
const handlePress = async () => {
|
|
52
60
|
if (disabled || loading) return
|
|
53
61
|
impactLight()
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// avoid expo-image-picker's top-level createPermissionHook dependency.
|
|
63
|
+
onPickerStarting?.()
|
|
64
|
+
|
|
58
65
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
66
|
let picker: any
|
|
60
67
|
try {
|
|
61
|
-
|
|
62
|
-
picker = (
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
69
|
+
picker = require('expo-image-picker')
|
|
63
70
|
} catch {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
picker = await import('expo-image-picker')
|
|
67
|
-
} catch {
|
|
68
|
-
if (__DEV__) console.warn('[ImageUpload] expo-image-picker not installed.')
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (Platform.OS !== 'web') {
|
|
74
|
-
try {
|
|
75
|
-
const { status } = await picker.requestMediaLibraryPermissionsAsync()
|
|
76
|
-
if (status !== 'granted') return
|
|
77
|
-
} catch {
|
|
78
|
-
// Permission check failed — try picker anyway
|
|
79
|
-
}
|
|
71
|
+
if (__DEV__) console.warn('[ImageUpload] expo-image-picker not installed.')
|
|
72
|
+
return
|
|
80
73
|
}
|
|
81
74
|
|
|
82
75
|
const result = await picker.launchImageLibraryAsync({
|
|
83
76
|
mediaTypes: ['images'],
|
|
84
|
-
allowsEditing
|
|
77
|
+
allowsEditing,
|
|
85
78
|
quality: 0.8,
|
|
86
79
|
})
|
|
87
80
|
|
|
88
81
|
if (!result.canceled && result.assets?.[0]) {
|
|
82
|
+
setImageLoaded(false)
|
|
89
83
|
onChange?.(result.assets[0].uri)
|
|
90
84
|
}
|
|
91
85
|
}
|
|
@@ -97,7 +91,7 @@ export function ImageUpload({
|
|
|
97
91
|
borderWidth: value ? 0 : 1,
|
|
98
92
|
borderStyle: 'dashed',
|
|
99
93
|
borderColor: colors.border,
|
|
100
|
-
backgroundColor: value ? 'transparent' : colors.surface,
|
|
94
|
+
backgroundColor: (value && imageLoaded) ? 'transparent' : colors.surface,
|
|
101
95
|
overflow: 'hidden',
|
|
102
96
|
}
|
|
103
97
|
|
|
@@ -108,7 +102,7 @@ export function ImageUpload({
|
|
|
108
102
|
rippleColor="transparent"
|
|
109
103
|
touchSoundDisabled
|
|
110
104
|
accessibilityRole="button"
|
|
111
|
-
accessibilityLabel={accessibilityLabel ?? (value ? '
|
|
105
|
+
accessibilityLabel={accessibilityLabel ?? (value ? 'Cambiar imagen' : placeholder)}
|
|
112
106
|
accessibilityState={{ disabled: disabled || loading }}
|
|
113
107
|
style={[containerStyle, style]}
|
|
114
108
|
>
|
|
@@ -116,7 +110,9 @@ export function ImageUpload({
|
|
|
116
110
|
<Image
|
|
117
111
|
source={{ uri: value }}
|
|
118
112
|
style={[StyleSheet.absoluteFillObject, { borderRadius }]}
|
|
119
|
-
|
|
113
|
+
contentFit={resizeMode === 'stretch' ? 'fill' : resizeMode}
|
|
114
|
+
onLoad={() => setImageLoaded(true)}
|
|
115
|
+
onError={() => setImageLoaded(true)}
|
|
120
116
|
/>
|
|
121
117
|
) : (
|
|
122
118
|
<View style={styles.placeholder}>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useState, useCallback } from 'react'
|
|
2
|
+
import { Image } from 'expo-image'
|
|
2
3
|
import {
|
|
3
4
|
Modal,
|
|
4
5
|
View,
|
|
5
|
-
Image,
|
|
6
6
|
Dimensions,
|
|
7
7
|
StyleSheet,
|
|
8
8
|
useWindowDimensions,
|
|
@@ -105,7 +105,7 @@ function ZoomableImage({ source, width, height, onZoomChange }: ZoomableImagePro
|
|
|
105
105
|
<GestureDetector gesture={composed}>
|
|
106
106
|
<View style={[{ width, height }, styles.imageWrap]} collapsable={false}>
|
|
107
107
|
<Animated.View style={[{ width, height }, animatedStyle]}>
|
|
108
|
-
<Image source={source} style={{ width, height }}
|
|
108
|
+
<Image source={source} style={{ width, height }} contentFit="contain" />
|
|
109
109
|
</Animated.View>
|
|
110
110
|
</View>
|
|
111
111
|
</GestureDetector>
|
|
@@ -235,7 +235,7 @@ export function ImageViewer({ images, visible, onClose, initialIndex = 0 }: Imag
|
|
|
235
235
|
style={{ backgroundColor: 'rgba(255,255,255,0.18)' }}
|
|
236
236
|
iconColor="#fff"
|
|
237
237
|
onPress={onClose}
|
|
238
|
-
accessibilityLabel="
|
|
238
|
+
accessibilityLabel="Cerrar"
|
|
239
239
|
/>
|
|
240
240
|
</View>
|
|
241
241
|
|
|
@@ -5,7 +5,7 @@ import { EaseView } from 'react-native-ease'
|
|
|
5
5
|
import { AntDesign } from '@expo/vector-icons'
|
|
6
6
|
import { useTheme } from '../../theme'
|
|
7
7
|
import { s, vs, ms } from '../../utils/scaling'
|
|
8
|
-
import {
|
|
8
|
+
import { Icon } from '../../utils/icons'
|
|
9
9
|
import { COLOR_TRANSITION } from '../../utils/animations'
|
|
10
10
|
|
|
11
11
|
const webInputResetStyle: Record<string, unknown> =
|
|
@@ -33,7 +33,7 @@ export interface InputProps extends TextInputProps {
|
|
|
33
33
|
sheetMode?: boolean
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = 'text', containerStyle, inputWrapperStyle, sheetMode = false, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }: InputProps) {
|
|
36
|
+
export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = 'text', containerStyle, inputWrapperStyle, sheetMode = false, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, autoCapitalize, autoCorrect, ...props }: InputProps) {
|
|
37
37
|
const { colors } = useTheme()
|
|
38
38
|
const [focused, setFocused] = useState(false)
|
|
39
39
|
const [showPassword, setShowPassword] = useState(false)
|
|
@@ -41,9 +41,11 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
41
41
|
const isDisabled = disabled || editable === false
|
|
42
42
|
const isPassword = type === 'password'
|
|
43
43
|
const effectiveSecure = isPassword ? !showPassword : secureTextEntry
|
|
44
|
+
const effectiveAutoCapitalize = isPassword ? 'none' : autoCapitalize
|
|
45
|
+
const effectiveAutoCorrect = isPassword ? false : autoCorrect
|
|
44
46
|
|
|
45
47
|
const effectivePrefix: React.ReactNode = prefixIcon
|
|
46
|
-
?
|
|
48
|
+
? <Icon name={prefixIcon} size={20} color={prefixIconColor ?? colors.foregroundMuted} />
|
|
47
49
|
: prefix
|
|
48
50
|
|
|
49
51
|
const effectiveSuffix: React.ReactNode = isPassword && !suffix && !suffixIcon ? (
|
|
@@ -54,12 +56,12 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
54
56
|
style={styles.passwordToggle}
|
|
55
57
|
activeOpacity={0.6}
|
|
56
58
|
accessibilityRole="button"
|
|
57
|
-
accessibilityLabel={showPassword ? '
|
|
59
|
+
accessibilityLabel={showPassword ? 'Ocultar contraseña' : 'Mostrar contraseña'}
|
|
58
60
|
>
|
|
59
61
|
<AntDesign name={showPassword ? 'eye' : 'eye-invisible'} size={20} color={colors.foregroundMuted} />
|
|
60
62
|
</TouchableOpacity>
|
|
61
63
|
) : suffixIcon
|
|
62
|
-
?
|
|
64
|
+
? <Icon name={suffixIcon} size={20} color={suffixIconColor ?? colors.foregroundMuted} />
|
|
63
65
|
: suffix
|
|
64
66
|
|
|
65
67
|
// Border color animated via EaseView. Width is static (1px normal, 2px error)
|
|
@@ -109,6 +111,8 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
109
111
|
secureTextEntry={effectiveSecure}
|
|
110
112
|
editable={isDisabled ? false : editable}
|
|
111
113
|
accessibilityLabel={accessibilityLabel ?? label}
|
|
114
|
+
autoCapitalize={effectiveAutoCapitalize}
|
|
115
|
+
autoCorrect={effectiveAutoCorrect}
|
|
112
116
|
{...props}
|
|
113
117
|
/>
|
|
114
118
|
) : (
|
|
@@ -132,6 +136,8 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
|
|
|
132
136
|
secureTextEntry={effectiveSecure}
|
|
133
137
|
editable={isDisabled ? false : editable}
|
|
134
138
|
accessibilityLabel={accessibilityLabel ?? label}
|
|
139
|
+
autoCapitalize={effectiveAutoCapitalize}
|
|
140
|
+
autoCorrect={effectiveAutoCorrect}
|
|
135
141
|
{...props}
|
|
136
142
|
/>
|
|
137
143
|
)}
|
|
@@ -2,7 +2,7 @@ import React from 'react'
|
|
|
2
2
|
import { View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
3
|
import { useTheme } from '../../theme'
|
|
4
4
|
import { s, ms, mvs } from '../../utils/scaling'
|
|
5
|
-
import {
|
|
5
|
+
import { Icon } from '../../utils/icons'
|
|
6
6
|
|
|
7
7
|
export interface LabelValueProps {
|
|
8
8
|
label: string
|
|
@@ -18,7 +18,7 @@ function LabelValueBase({ label, value, iconName, iconColor, style }: LabelValue
|
|
|
18
18
|
const { colors } = useTheme()
|
|
19
19
|
|
|
20
20
|
const resolvedIcon = iconName
|
|
21
|
-
?
|
|
21
|
+
? <Icon name={iconName} size={ms(14)} color={iconColor ?? colors.foregroundMuted} />
|
|
22
22
|
: null
|
|
23
23
|
|
|
24
24
|
return (
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import { Image } from 'expo-image'
|
|
2
3
|
import {
|
|
3
4
|
View,
|
|
4
5
|
Text,
|
|
5
6
|
StyleSheet,
|
|
6
7
|
ViewStyle,
|
|
7
8
|
TextStyle,
|
|
8
|
-
Image,
|
|
9
9
|
ImageSourcePropType,
|
|
10
10
|
} from 'react-native'
|
|
11
11
|
import { Entypo } from '@expo/vector-icons'
|
|
12
12
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
13
13
|
import { useTheme } from '../../theme'
|
|
14
14
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
15
|
-
import {
|
|
15
|
+
import { Icon } from '../../utils/icons'
|
|
16
16
|
import { RADIUS } from '../../tokens'
|
|
17
17
|
import { PressableRow } from '../../utils/pressable'
|
|
18
18
|
|
|
@@ -122,7 +122,7 @@ function ListItemBase({
|
|
|
122
122
|
const effectiveLeft: React.ReactNode = imageSource
|
|
123
123
|
? <Image source={imageSource} style={styles.image} />
|
|
124
124
|
: leftIcon
|
|
125
|
-
?
|
|
125
|
+
? <Icon name={leftIcon} size={24} color={leftIconColor ?? colors.foreground} />
|
|
126
126
|
: leftRender
|
|
127
127
|
|
|
128
128
|
const hasRightContent = !!(rightIcon || (rightActions && rightActions.length > 0) || rightRender !== undefined || showChevron)
|
|
@@ -181,7 +181,7 @@ function ListItemBase({
|
|
|
181
181
|
{hasRightContent ? (
|
|
182
182
|
rightIcon ? (
|
|
183
183
|
<View style={styles.rightContainer}>
|
|
184
|
-
{
|
|
184
|
+
<Icon name={rightIcon} size={24} color={rightIconColor ?? colors.foregroundMuted} />
|
|
185
185
|
</View>
|
|
186
186
|
) : rightActions && rightActions.length > 0 ? (
|
|
187
187
|
<View style={styles.rightActionsContainer}>
|