@retray-dev/ui-kit 12.2.0 → 13.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/CONSUMER.md +26 -11
- package/DESIGN.md +2 -2
- package/README.md +15 -11
- package/{COMPONENTS.md → SKILL.md} +374 -996
- package/dist/Accordion.d.mts +2 -0
- package/dist/Accordion.d.ts +2 -0
- package/dist/Accordion.js +49 -210
- package/dist/Accordion.mjs +6 -6
- package/dist/AlertBanner.js +29 -153
- package/dist/AlertBanner.mjs +3 -4
- package/dist/AppHeader.d.mts +5 -2
- package/dist/AppHeader.d.ts +5 -2
- package/dist/AppHeader.js +45 -239
- package/dist/AppHeader.mjs +6 -8
- package/dist/Avatar.d.mts +17 -1
- package/dist/Avatar.d.ts +17 -1
- package/dist/Avatar.js +80 -115
- package/dist/Avatar.mjs +2 -3
- package/dist/Badge.js +24 -149
- package/dist/Badge.mjs +3 -4
- package/dist/Button.js +79 -267
- package/dist/Button.mjs +6 -7
- package/dist/ButtonGroup.mjs +0 -1
- package/dist/Card.js +15 -200
- package/dist/Card.mjs +4 -6
- package/dist/CategoryStrip.d.mts +0 -5
- package/dist/CategoryStrip.d.ts +0 -5
- package/dist/CategoryStrip.js +47 -265
- package/dist/CategoryStrip.mjs +6 -7
- package/dist/Checkbox.d.mts +2 -1
- package/dist/Checkbox.d.ts +2 -1
- package/dist/Checkbox.js +18 -201
- package/dist/Checkbox.mjs +5 -6
- package/dist/Chip.js +44 -236
- package/dist/Chip.mjs +7 -7
- package/dist/ConfirmDialog.d.mts +2 -1
- package/dist/ConfirmDialog.d.ts +2 -1
- package/dist/ConfirmDialog.js +110 -300
- package/dist/ConfirmDialog.mjs +7 -8
- package/dist/CurrencyDisplay.js +1 -114
- package/dist/CurrencyDisplay.mjs +2 -3
- package/dist/CurrencyInput.js +35 -162
- package/dist/CurrencyInput.mjs +5 -6
- package/dist/DetailRow.js +25 -150
- package/dist/DetailRow.mjs +3 -4
- package/dist/EmptyState.js +80 -268
- package/dist/EmptyState.mjs +7 -8
- package/dist/ErrorBoundary.js +32 -199
- package/dist/ErrorBoundary.mjs +4 -5
- package/dist/Form.js +1 -114
- package/dist/Form.mjs +2 -3
- 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 -33
- package/dist/IconButton.js +36 -234
- package/dist/IconButton.mjs +5 -7
- package/dist/IconPicker.js +222 -929
- package/dist/IconPicker.mjs +5 -6
- package/dist/ImageUpload.d.mts +3 -3
- package/dist/ImageUpload.d.ts +3 -3
- package/dist/ImageUpload.js +49 -238
- package/dist/ImageUpload.mjs +5 -7
- package/dist/ImageViewer.js +75 -266
- package/dist/ImageViewer.mjs +8 -9
- package/dist/Input.d.mts +1 -1
- package/dist/Input.d.ts +1 -1
- package/dist/Input.js +35 -162
- package/dist/Input.mjs +4 -5
- package/dist/LabelValue.js +24 -149
- package/dist/LabelValue.mjs +3 -4
- package/dist/ListGroup.js +1 -114
- package/dist/ListGroup.mjs +2 -3
- package/dist/ListItem.d.mts +2 -1
- package/dist/ListItem.d.ts +2 -1
- package/dist/ListItem.js +41 -236
- package/dist/ListItem.mjs +5 -7
- package/dist/MediaCard.d.mts +0 -14
- package/dist/MediaCard.d.ts +0 -14
- package/dist/MediaCard.js +69 -315
- package/dist/MediaCard.mjs +5 -7
- package/dist/MenuGroup.js +1 -114
- package/dist/MenuGroup.mjs +2 -3
- package/dist/MenuItem.d.mts +2 -1
- package/dist/MenuItem.d.ts +2 -1
- package/dist/MenuItem.js +39 -235
- package/dist/MenuItem.mjs +5 -7
- package/dist/MonthPicker.js +8 -163
- package/dist/MonthPicker.mjs +3 -4
- package/dist/NumberStepper.d.mts +2 -1
- package/dist/NumberStepper.d.ts +2 -1
- package/dist/NumberStepper.js +44 -239
- package/dist/NumberStepper.mjs +5 -7
- package/dist/PagerDots.d.mts +1 -1
- package/dist/PagerDots.d.ts +1 -1
- package/dist/PagerDots.js +69 -224
- package/dist/PagerDots.mjs +6 -6
- package/dist/Pressable.js +14 -85
- package/dist/Pressable.mjs +4 -5
- package/dist/PricingCard.js +87 -272
- package/dist/PricingCard.mjs +8 -9
- package/dist/Progress.js +3 -123
- package/dist/Progress.mjs +3 -4
- package/dist/RadioGroup.js +52 -265
- package/dist/RadioGroup.mjs +5 -6
- package/dist/RetrayProvider.js +3 -6
- package/dist/RetrayProvider.mjs +3 -4
- package/dist/Select.d.mts +3 -1
- package/dist/Select.d.ts +3 -1
- package/dist/Select.js +27 -233
- package/dist/Select.mjs +4 -6
- package/dist/SelectableCard.js +33 -209
- package/dist/SelectableCard.mjs +5 -6
- package/dist/SelectableGrid.d.mts +0 -21
- package/dist/SelectableGrid.d.ts +0 -21
- package/dist/SelectableGrid.js +49 -272
- package/dist/SelectableGrid.mjs +5 -7
- package/dist/Separator.js +1 -114
- package/dist/Separator.mjs +2 -3
- package/dist/Sheet.d.mts +1 -1
- package/dist/Sheet.d.ts +1 -1
- package/dist/Sheet.js +33 -175
- package/dist/Sheet.mjs +3 -4
- package/dist/SheetSelect.js +39 -236
- package/dist/SheetSelect.mjs +6 -7
- package/dist/Skeleton.js +4 -124
- package/dist/Skeleton.mjs +3 -4
- package/dist/Slider.d.mts +2 -1
- package/dist/Slider.d.ts +2 -1
- package/dist/Slider.js +8 -161
- package/dist/Slider.mjs +3 -4
- package/dist/Spinner.js +3 -116
- package/dist/Spinner.mjs +2 -3
- package/dist/Stats.js +36 -234
- package/dist/Stats.mjs +5 -7
- package/dist/Switch.d.mts +2 -1
- package/dist/Switch.d.ts +2 -1
- package/dist/Switch.js +26 -176
- package/dist/Switch.mjs +5 -5
- package/dist/TabBar.js +43 -200
- package/dist/TabBar.mjs +5 -5
- package/dist/Tabs.js +15 -199
- package/dist/Tabs.mjs +5 -6
- package/dist/Text.js +9 -130
- package/dist/Text.mjs +2 -3
- package/dist/Textarea.d.mts +2 -1
- package/dist/Textarea.d.ts +2 -1
- package/dist/Textarea.js +71 -219
- package/dist/Textarea.mjs +4 -5
- package/dist/Toast.d.mts +12 -10
- package/dist/Toast.d.ts +12 -10
- package/dist/Toast.js +1 -114
- package/dist/Toast.mjs +2 -3
- package/dist/Toggle.js +39 -236
- package/dist/Toggle.mjs +6 -7
- package/dist/{chunk-ELGEOM7I.mjs → chunk-2QXJDRVU.mjs} +13 -10
- package/dist/{chunk-LIS6I5UP.mjs → chunk-2VIDP72N.mjs} +3 -3
- package/dist/{chunk-NHDI3VQB.mjs → chunk-422IVD3H.mjs} +16 -12
- package/dist/{chunk-DF7JA72E.mjs → chunk-4NQFTHN3.mjs} +13 -7
- package/dist/{chunk-3XCFYSX4.mjs → chunk-5MYNAAFE.mjs} +13 -17
- package/dist/{chunk-E7NEHHXV.mjs → chunk-62BBSSUF.mjs} +3 -3
- package/dist/{chunk-UBUXUMER.mjs → chunk-77UOVFIS.mjs} +7 -5
- package/dist/{chunk-M3C7XM2M.mjs → chunk-7BZJRB77.mjs} +28 -18
- package/dist/chunk-ARONDO7M.mjs +40 -0
- package/dist/{chunk-GH67YXG6.mjs → chunk-AZV7KNJI.mjs} +3 -3
- package/dist/{chunk-2P2CB235.mjs → chunk-BULKGOIZ.mjs} +7 -8
- package/dist/{chunk-RJNLAH76.mjs → chunk-C5ZRMR2E.mjs} +4 -2
- package/dist/chunk-CM2DG4MR.mjs +142 -0
- package/dist/{chunk-UQ4742ET.mjs → chunk-COA2YZOX.mjs} +8 -6
- package/dist/{chunk-EDLCGYIO.mjs → chunk-CZN6L2QU.mjs} +11 -8
- package/dist/{chunk-TS7DGUIR.mjs → chunk-DBHSUUKU.mjs} +2 -2
- package/dist/{chunk-57V2LXCK.mjs → chunk-DE25XTVQ.mjs} +3 -3
- package/dist/{chunk-RMRS44MQ.mjs → chunk-E2PONRJG.mjs} +13 -9
- package/dist/{chunk-GUTDFUNF.mjs → chunk-EHGBHFMH.mjs} +9 -17
- package/dist/{chunk-ZIMY2QUM.mjs → chunk-ERWJPVX7.mjs} +2 -2
- package/dist/{chunk-NLZY4TXU.mjs → chunk-ESQDPO5E.mjs} +7 -7
- package/dist/{chunk-VJBUCITV.mjs → chunk-EW2FIDSM.mjs} +1 -1
- package/dist/{chunk-HC4VVCWY.mjs → chunk-FTTI6T5Q.mjs} +4 -4
- package/dist/{chunk-MVMGPZN6.mjs → chunk-H6MQL7PS.mjs} +12 -7
- package/dist/{chunk-CF27NBXO.mjs → chunk-HHOOFDBA.mjs} +38 -41
- package/dist/{chunk-2HFD4IHU.mjs → chunk-HUSSF6TF.mjs} +1 -1
- package/dist/{chunk-HEDQPK4I.mjs → chunk-IDVUZIVY.mjs} +16 -22
- package/dist/chunk-IFYMBOEN.mjs +14 -0
- package/dist/{chunk-QOLWA2PW.mjs → chunk-IGU223UM.mjs} +80 -4
- package/dist/chunk-IJCMPVW5.mjs +121 -0
- package/dist/{chunk-AENAVIKT.mjs → chunk-ITG4JQM3.mjs} +4 -4
- package/dist/{chunk-E5UKLSJZ.mjs → chunk-K3QX2M26.mjs} +11 -8
- package/dist/{chunk-4OORJ2DY.mjs → chunk-K7TKID3V.mjs} +8 -7
- package/dist/{chunk-2LG326TT.mjs → chunk-KAGADD2O.mjs} +4 -4
- package/dist/{chunk-IVSRW4HS.mjs → chunk-KC5QDYGZ.mjs} +4 -4
- package/dist/{chunk-7AFZWSCI.mjs → chunk-KPTY7UYQ.mjs} +1 -1
- package/dist/{chunk-YTXRIXNZ.mjs → chunk-KSSVIFYR.mjs} +9 -12
- package/dist/chunk-L3YKPTJQ.mjs +119 -0
- package/dist/chunk-M53LC4Q7.mjs +35 -0
- package/dist/chunk-MZ6WRTD2.mjs +40 -0
- package/dist/chunk-NGEN2EES.mjs +581 -0
- package/dist/{chunk-ZR6HSEAB.mjs → chunk-NPCBNGNE.mjs} +17 -26
- package/dist/{chunk-C43HRKXH.mjs → chunk-OBV72JD4.mjs} +1 -1
- package/dist/{chunk-LPV4NJJK.mjs → chunk-PGQ6FMXS.mjs} +6 -5
- package/dist/{chunk-MEPSKGBO.mjs → chunk-PI6RULJX.mjs} +1 -1
- package/dist/{chunk-F3YTWO3T.mjs → chunk-RA6SAAFE.mjs} +9 -8
- package/dist/{chunk-UNNRUJTM.mjs → chunk-RRKM4MKB.mjs} +7 -7
- package/dist/{chunk-ULGNQPNE.mjs → chunk-S2VGME7X.mjs} +1 -1
- package/dist/{chunk-OLVJFKXS.mjs → chunk-S44XWTTC.mjs} +35 -25
- package/dist/{chunk-YMYIEVZP.mjs → chunk-SZEKQAOY.mjs} +1 -1
- package/dist/{chunk-BXF4AMHY.mjs → chunk-TMH263OK.mjs} +5 -4
- package/dist/{chunk-NJG7DHVF.mjs → chunk-U6DEBYU5.mjs} +10 -9
- package/dist/{chunk-QXDGGOLC.mjs → chunk-UMZTPUB3.mjs} +33 -21
- package/dist/{chunk-KSUWPU2F.mjs → chunk-WIPEDNSD.mjs} +7 -7
- package/dist/{chunk-QDAZGZUF.mjs → chunk-XCIG6HT2.mjs} +3 -3
- package/dist/{chunk-4J2PXL36.mjs → chunk-Y6YS33GM.mjs} +40 -38
- package/dist/{chunk-4XOB5TTD.mjs → chunk-ZKDKKQCE.mjs} +5 -5
- package/dist/{chunk-LOBLCFMN.mjs → chunk-ZTPYUU5C.mjs} +5 -5
- package/dist/fonts.mjs +0 -2
- package/dist/index.d.mts +13 -73
- package/dist/index.d.ts +13 -73
- package/dist/index.js +1149 -1892
- package/dist/index.mjs +81 -86
- package/package.json +20 -20
- package/src/components/Accordion/Accordion.tsx +15 -9
- package/src/components/AlertBanner/AlertBanner.tsx +7 -6
- package/src/components/AppHeader/AppHeader.tsx +25 -10
- 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 +50 -46
- package/src/components/Card/Card.tsx +1 -0
- package/src/components/CategoryStrip/CategoryStrip.tsx +36 -49
- package/src/components/Checkbox/Checkbox.tsx +3 -0
- package/src/components/Chip/Chip.tsx +5 -4
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +33 -17
- 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 +43 -46
- 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 +7 -4
- package/src/components/MediaCard/MediaCard.tsx +21 -59
- package/src/components/MenuItem/MenuItem.tsx +5 -2
- package/src/components/MonthPicker/MonthPicker.tsx +2 -2
- package/src/components/NumberStepper/NumberStepper.tsx +10 -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 +35 -39
- package/src/components/SelectableCard/SelectableCard.tsx +4 -6
- package/src/components/SelectableGrid/SelectableGrid.tsx +37 -72
- package/src/components/Sheet/Sheet.tsx +28 -15
- package/src/components/Sheet/index.ts +2 -2
- package/src/components/SheetSelect/SheetSelect.tsx +3 -3
- package/src/components/Skeleton/Skeleton.tsx +1 -1
- package/src/components/Slider/Slider.tsx +3 -0
- package/src/components/Spinner/Spinner.tsx +2 -2
- package/src/components/Stats/Stats.tsx +2 -2
- package/src/components/Switch/Switch.tsx +12 -7
- package/src/components/TabBar/TabBar.tsx +9 -8
- package/src/components/Text/Text.tsx +13 -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 +3 -4
- package/src/theme/ThemeProvider.tsx +1 -4
- package/src/theme/colorUtils.ts +1 -72
- package/src/theme/colors.ts +40 -1
- package/src/theme/types.ts +2 -2
- 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-2BA3JMKK.mjs +0 -136
- package/dist/chunk-3DKJ2GIC.mjs +0 -30
- package/dist/chunk-7ELGZ66G.mjs +0 -164
- package/dist/chunk-DVK4G2GT.mjs +0 -59
- package/dist/chunk-EJ7ZPXOH.mjs +0 -163
- package/dist/chunk-KA7LTET3.mjs +0 -71
- package/dist/chunk-LNPKGWBG.mjs +0 -134
- package/dist/chunk-NC5ZTR2Y.mjs +0 -32
- package/dist/chunk-SAWUXP3A.mjs +0 -1114
- package/dist/chunk-Y6FXYEAI.mjs +0 -8
- 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,13 +1,11 @@
|
|
|
1
1
|
import React, { useRef, useState } from 'react'
|
|
2
2
|
import { View, Text, TouchableOpacity, Modal, StyleSheet, ViewStyle, Platform } from 'react-native'
|
|
3
|
-
import Animated from 'react-native-reanimated'
|
|
4
3
|
import { Picker } from '@react-native-picker/picker'
|
|
5
4
|
import { Entypo } from '@expo/vector-icons'
|
|
6
5
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
7
6
|
import { useTheme } from '../../theme'
|
|
8
7
|
import { s, vs, ms } from '../../utils/scaling'
|
|
9
|
-
import {
|
|
10
|
-
import { PRESS_SCALE } from '../../utils/animations'
|
|
8
|
+
import { PressableButton } from '../../utils/pressable'
|
|
11
9
|
|
|
12
10
|
const isIOS = Platform.OS === 'ios'
|
|
13
11
|
const isAndroid = Platform.OS === 'android'
|
|
@@ -25,10 +23,12 @@ export interface SelectProps {
|
|
|
25
23
|
onValueChange?: (value: string) => void
|
|
26
24
|
placeholder?: string
|
|
27
25
|
label?: string
|
|
26
|
+
hint?: string
|
|
28
27
|
error?: string
|
|
29
28
|
disabled?: boolean
|
|
30
29
|
style?: ViewStyle
|
|
31
30
|
accessibilityLabel?: string
|
|
31
|
+
accessibilityHint?: string
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export function Select({
|
|
@@ -37,16 +37,14 @@ export function Select({
|
|
|
37
37
|
onValueChange,
|
|
38
38
|
placeholder = 'Select an option',
|
|
39
39
|
label,
|
|
40
|
+
hint,
|
|
40
41
|
error,
|
|
41
42
|
disabled,
|
|
42
43
|
style,
|
|
43
44
|
accessibilityLabel,
|
|
45
|
+
accessibilityHint,
|
|
44
46
|
}: SelectProps) {
|
|
45
47
|
const { colors } = useTheme()
|
|
46
|
-
const { animatedStyle, onPressIn, onPressOut } = usePressScale({
|
|
47
|
-
pressScale: PRESS_SCALE.button,
|
|
48
|
-
disabled,
|
|
49
|
-
})
|
|
50
48
|
const [pickerVisible, setPickerVisible] = useState(false)
|
|
51
49
|
const [pendingValue, setPendingValue] = useState<string | undefined>(value)
|
|
52
50
|
const pickerRef = useRef<React.ElementRef<typeof Picker>>(null)
|
|
@@ -82,38 +80,37 @@ export function Select({
|
|
|
82
80
|
|
|
83
81
|
{/* Trigger button — shown on iOS and Android only */}
|
|
84
82
|
{!isWeb ? (
|
|
85
|
-
<
|
|
86
|
-
|
|
83
|
+
<PressableButton
|
|
84
|
+
style={[
|
|
85
|
+
styles.trigger,
|
|
86
|
+
{
|
|
87
|
+
borderColor: error ? colors.destructive : colors.border,
|
|
88
|
+
backgroundColor: colors.background,
|
|
89
|
+
},
|
|
90
|
+
disabled && { opacity: 0.45 },
|
|
91
|
+
]}
|
|
92
|
+
onPress={handleOpen}
|
|
93
|
+
enabled={!disabled}
|
|
94
|
+
rippleColor="transparent"
|
|
95
|
+
touchSoundDisabled
|
|
96
|
+
accessibilityRole="combobox"
|
|
97
|
+
accessibilityLabel={accessibilityLabel ?? label}
|
|
98
|
+
accessibilityHint={accessibilityHint}
|
|
99
|
+
accessibilityValue={{ text: selected?.label ?? placeholder }}
|
|
100
|
+
accessibilityState={{ disabled: !!disabled, expanded: pickerVisible }}
|
|
101
|
+
>
|
|
102
|
+
<Text
|
|
87
103
|
style={[
|
|
88
|
-
styles.
|
|
89
|
-
{
|
|
90
|
-
borderColor: error ? colors.destructive : colors.border,
|
|
91
|
-
backgroundColor: colors.background,
|
|
92
|
-
},
|
|
104
|
+
styles.triggerText,
|
|
105
|
+
{ color: selected ? colors.foreground : colors.foregroundMuted },
|
|
93
106
|
]}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
onPressOut={onPressOut}
|
|
97
|
-
activeOpacity={1}
|
|
98
|
-
touchSoundDisabled={true}
|
|
99
|
-
accessibilityRole="combobox"
|
|
100
|
-
accessibilityLabel={accessibilityLabel ?? label}
|
|
101
|
-
accessibilityValue={{ text: selected?.label ?? placeholder }}
|
|
102
|
-
accessibilityState={{ disabled: !!disabled, expanded: pickerVisible }}
|
|
107
|
+
numberOfLines={1}
|
|
108
|
+
allowFontScaling={true}
|
|
103
109
|
>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
]}
|
|
109
|
-
numberOfLines={1}
|
|
110
|
-
allowFontScaling={true}
|
|
111
|
-
>
|
|
112
|
-
{selected?.label ?? placeholder}
|
|
113
|
-
</Text>
|
|
114
|
-
<Entypo name="chevron-down" size={20} color={colors.foregroundMuted} />
|
|
115
|
-
</TouchableOpacity>
|
|
116
|
-
</Animated.View>
|
|
110
|
+
{selected?.label ?? placeholder}
|
|
111
|
+
</Text>
|
|
112
|
+
<Entypo name="chevron-down" size={20} color={colors.foregroundMuted} />
|
|
113
|
+
</PressableButton>
|
|
117
114
|
) : null}
|
|
118
115
|
|
|
119
116
|
{/* iOS: Modal with wheel Picker */}
|
|
@@ -224,6 +221,8 @@ export function Select({
|
|
|
224
221
|
|
|
225
222
|
{error ? (
|
|
226
223
|
<Text style={[styles.helperText, { color: colors.destructive }]} allowFontScaling={true}>{error}</Text>
|
|
224
|
+
) : !error && hint ? (
|
|
225
|
+
<Text style={[styles.helperText, { color: colors.foregroundMuted }]} allowFontScaling={true}>{hint}</Text>
|
|
227
226
|
) : null}
|
|
228
227
|
</View>
|
|
229
228
|
)
|
|
@@ -251,9 +250,6 @@ const styles = StyleSheet.create({
|
|
|
251
250
|
fontSize: ms(15),
|
|
252
251
|
flex: 1,
|
|
253
252
|
},
|
|
254
|
-
chevron: {
|
|
255
|
-
marginLeft: s(8),
|
|
256
|
-
},
|
|
257
253
|
helperText: {
|
|
258
254
|
fontFamily: 'Sohne-Regular',
|
|
259
255
|
fontSize: ms(13),
|
|
@@ -5,7 +5,7 @@ import { impactLight } from '../../utils/haptics'
|
|
|
5
5
|
import { useTheme } from '../../theme'
|
|
6
6
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
7
7
|
import { RADIUS } from '../../tokens'
|
|
8
|
-
import {
|
|
8
|
+
import { Icon } from '../../utils/icons'
|
|
9
9
|
import { COLOR_TRANSITION, OPACITY_TRANSITION, SPRING_ELASTIC } from '../../utils/animations'
|
|
10
10
|
|
|
11
11
|
type SelectType = 'radio' | 'checkbox'
|
|
@@ -146,20 +146,18 @@ export function SelectableCard({
|
|
|
146
146
|
})()
|
|
147
147
|
|
|
148
148
|
const resolvedIcon = iconName
|
|
149
|
-
?
|
|
149
|
+
? <Icon name={iconName} size={ms(22)} color={disabled ? colors.foregroundMuted : colors.foregroundMuted} />
|
|
150
150
|
: icon
|
|
151
151
|
|
|
152
152
|
const resolvedIconElement = resolvedIcon ? (
|
|
153
153
|
<View style={[styles.iconWrapper, disabled && { opacity: 0.45 }]}>{resolvedIcon}</View>
|
|
154
154
|
) : null
|
|
155
155
|
|
|
156
|
-
const selectorAccessibilityRole = type === 'radio' ? 'radio' : 'checkbox'
|
|
157
|
-
|
|
158
156
|
return (
|
|
159
157
|
<Pressable
|
|
160
158
|
onPress={handlePress}
|
|
161
159
|
disabled={disabled}
|
|
162
|
-
accessibilityRole=
|
|
160
|
+
accessibilityRole={type === 'radio' ? 'radio' : 'checkbox'}
|
|
163
161
|
accessibilityLabel={`${title}${description ? `, ${description}` : ''}`}
|
|
164
162
|
accessibilityState={{ selected: isSelected, disabled }}
|
|
165
163
|
style={[
|
|
@@ -171,7 +169,7 @@ export function SelectableCard({
|
|
|
171
169
|
>
|
|
172
170
|
<View style={styles.row}>
|
|
173
171
|
{/* Selection indicator */}
|
|
174
|
-
<View style={styles.selectorContainer}
|
|
172
|
+
<View style={styles.selectorContainer}>
|
|
175
173
|
{type === 'radio' ? (
|
|
176
174
|
<EaseView
|
|
177
175
|
style={styles.radioCircle}
|
|
@@ -1,38 +1,27 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
|
-
import { View, Text,
|
|
3
|
-
import Animated from 'react-native-reanimated'
|
|
2
|
+
import { View, Text, StyleSheet, ViewStyle, ScrollView } from 'react-native'
|
|
4
3
|
import { useTheme } from '../../theme'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { Icon } from '../../utils/icons'
|
|
5
|
+
import { PressableChip } from '../../utils/pressable'
|
|
7
6
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
8
|
-
import { PRESS_SCALE } from '../../utils/animations'
|
|
9
7
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
10
8
|
import { RADIUS } from '../../tokens'
|
|
11
9
|
|
|
12
10
|
export interface SelectableGridItem<T extends string | number = string> {
|
|
13
|
-
/** Unique value emitted on selection. */
|
|
14
11
|
value: T
|
|
15
|
-
/** Label rendered under the icon. */
|
|
16
12
|
label?: string
|
|
17
|
-
/** Icon name resolved via the icon registry. */
|
|
18
13
|
iconName?: string
|
|
19
|
-
/** Custom icon node — overrides `iconName`. */
|
|
20
14
|
icon?: React.ReactNode
|
|
21
15
|
disabled?: boolean
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
export interface SelectableGridProps<T extends string | number = string> {
|
|
25
19
|
items: SelectableGridItem<T>[]
|
|
26
|
-
/** Selected value(s). Array when `multiple`. */
|
|
27
20
|
value: T | T[] | null
|
|
28
21
|
onChange: (value: T) => void
|
|
29
|
-
/** Allow multiple selections. `value` should be an array. Defaults to false. */
|
|
30
22
|
multiple?: boolean
|
|
31
|
-
/** Columns per row. Defaults to 4. Ignored when `orientation='horizontal'`. */
|
|
32
23
|
numColumns?: number
|
|
33
|
-
/** Gap between cells (dp). Defaults to 12. */
|
|
34
24
|
gap?: number
|
|
35
|
-
/** Layout orientation. 'grid' (default) wraps into rows. 'horizontal' creates a single scrollable row. */
|
|
36
25
|
orientation?: 'grid' | 'horizontal'
|
|
37
26
|
style?: ViewStyle
|
|
38
27
|
}
|
|
@@ -51,63 +40,43 @@ interface CellProps<T extends string | number> {
|
|
|
51
40
|
|
|
52
41
|
function Cell<T extends string | number>({ item, selected, width, onPress }: CellProps<T>) {
|
|
53
42
|
const { colors } = useTheme()
|
|
54
|
-
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
55
|
-
pressScale: PRESS_SCALE.chip,
|
|
56
|
-
disabled: item.disabled,
|
|
57
|
-
})
|
|
58
43
|
|
|
59
44
|
const iconColor = selected ? colors.primary : colors.foregroundSubtle
|
|
60
|
-
const iconNode = item.icon ?? (item.iconName ?
|
|
45
|
+
const iconNode = item.icon ?? (item.iconName ? <Icon name={item.iconName} size={ms(24)} color={iconColor} /> : null)
|
|
61
46
|
|
|
62
47
|
return (
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
</Text>
|
|
93
|
-
) : null}
|
|
94
|
-
</TouchableOpacity>
|
|
95
|
-
</Animated.View>
|
|
48
|
+
<PressableChip
|
|
49
|
+
onPress={onPress}
|
|
50
|
+
enabled={!item.disabled}
|
|
51
|
+
rippleColor="transparent"
|
|
52
|
+
touchSoundDisabled
|
|
53
|
+
activateOnHover
|
|
54
|
+
accessibilityRole="button"
|
|
55
|
+
accessibilityState={{ selected, disabled: item.disabled }}
|
|
56
|
+
accessibilityLabel={item.label ?? String(item.value)}
|
|
57
|
+
style={[
|
|
58
|
+
{ width },
|
|
59
|
+
styles.cell,
|
|
60
|
+
{
|
|
61
|
+
borderColor: selected ? colors.primary : 'transparent',
|
|
62
|
+
},
|
|
63
|
+
item.disabled && styles.cellDisabled,
|
|
64
|
+
]}
|
|
65
|
+
>
|
|
66
|
+
{iconNode}
|
|
67
|
+
{item.label ? (
|
|
68
|
+
<Text
|
|
69
|
+
style={[styles.label, { color: selected ? colors.primary : colors.foreground }]}
|
|
70
|
+
numberOfLines={1}
|
|
71
|
+
allowFontScaling={true}
|
|
72
|
+
>
|
|
73
|
+
{item.label}
|
|
74
|
+
</Text>
|
|
75
|
+
) : null}
|
|
76
|
+
</PressableChip>
|
|
96
77
|
)
|
|
97
78
|
}
|
|
98
79
|
|
|
99
|
-
/**
|
|
100
|
-
* Grid of selectable cells (icon + label) — for store / category / emoji pickers
|
|
101
|
-
* where a list would be the wrong shape. Single or multi select.
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* <SelectableGrid
|
|
105
|
-
* items={categories}
|
|
106
|
-
* value={selected}
|
|
107
|
-
* onChange={setSelected}
|
|
108
|
-
* numColumns={4}
|
|
109
|
-
* />
|
|
110
|
-
*/
|
|
111
80
|
export function SelectableGrid<T extends string | number = string>({
|
|
112
81
|
items,
|
|
113
82
|
value,
|
|
@@ -120,10 +89,7 @@ export function SelectableGrid<T extends string | number = string>({
|
|
|
120
89
|
}: SelectableGridProps<T>) {
|
|
121
90
|
const [containerWidth, setContainerWidth] = useState(0)
|
|
122
91
|
const gapPx = s(gap)
|
|
123
|
-
// Compute exact cell width so `numColumns` always fits — percentage widths + gap
|
|
124
|
-
// overflow and wrap one short. -0.5 guards against sub-pixel rounding overflow.
|
|
125
92
|
const cellWidth = containerWidth > 0 ? (containerWidth - gapPx * (numColumns - 1)) / numColumns - 0.5 : 0
|
|
126
|
-
// Horizontal mode: fixed 72dp cell width (same scale as grid cells)
|
|
127
93
|
const horizCellWidth = s(72)
|
|
128
94
|
|
|
129
95
|
const handlePress = (item: SelectableGridItem<T>) => {
|
|
@@ -184,22 +150,21 @@ const styles = StyleSheet.create({
|
|
|
184
150
|
paddingHorizontal: s(4),
|
|
185
151
|
},
|
|
186
152
|
cell: {
|
|
187
|
-
flex: 1,
|
|
188
153
|
borderRadius: RADIUS.md,
|
|
189
154
|
borderWidth: 2,
|
|
190
155
|
alignItems: 'center',
|
|
191
156
|
justifyContent: 'center',
|
|
192
157
|
gap: vs(4),
|
|
193
|
-
paddingHorizontal: s(
|
|
194
|
-
paddingVertical: vs(
|
|
158
|
+
paddingHorizontal: s(8),
|
|
159
|
+
paddingVertical: vs(10),
|
|
195
160
|
},
|
|
196
161
|
cellDisabled: {
|
|
197
162
|
opacity: 0.4,
|
|
198
163
|
},
|
|
199
164
|
label: {
|
|
200
165
|
fontFamily: 'Sohne-Medium',
|
|
201
|
-
fontSize: ms(
|
|
202
|
-
lineHeight: mvs(
|
|
166
|
+
fontSize: ms(11),
|
|
167
|
+
lineHeight: mvs(14),
|
|
203
168
|
textAlign: 'center',
|
|
204
169
|
},
|
|
205
170
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useId } from 'react'
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState, useId } from 'react'
|
|
2
2
|
import { View, Text, TouchableOpacity, StyleSheet, ViewStyle } from 'react-native'
|
|
3
3
|
import {
|
|
4
4
|
BottomSheetModal,
|
|
@@ -95,28 +95,41 @@ export function Sheet({
|
|
|
95
95
|
footer,
|
|
96
96
|
snapPoints,
|
|
97
97
|
}: SheetProps) {
|
|
98
|
+
type SheetState = 'idle' | 'presenting' | 'presented' | 'dismissing'
|
|
99
|
+
|
|
98
100
|
const { colors } = useTheme()
|
|
99
101
|
const insets = useSafeAreaInsets()
|
|
100
102
|
const ref = useRef<BottomSheetModal>(null)
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
+
const sheetState = useRef<SheetState>('idle')
|
|
104
|
+
const onCloseRef = useRef(onClose)
|
|
103
105
|
const name = useId()
|
|
106
|
+
const [tick, setTick] = useState(0)
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
onClose?.()
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
onCloseRef.current = onClose
|
|
108
110
|
}, [onClose])
|
|
109
111
|
|
|
112
|
+
const handleDismiss = useCallback(() => {
|
|
113
|
+
sheetState.current = 'idle'
|
|
114
|
+
onCloseRef.current?.()
|
|
115
|
+
setTick((t) => t + 1)
|
|
116
|
+
}, [])
|
|
117
|
+
|
|
110
118
|
useEffect(() => {
|
|
111
|
-
if (open
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
if (open) {
|
|
120
|
+
if (sheetState.current === 'idle') {
|
|
121
|
+
sheetState.current = 'presenting'
|
|
122
|
+
impactMedium()
|
|
123
|
+
ref.current?.present()
|
|
124
|
+
sheetState.current = 'presented'
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
if (sheetState.current === 'presented' || sheetState.current === 'presenting') {
|
|
128
|
+
sheetState.current = 'dismissing'
|
|
129
|
+
ref.current?.dismiss()
|
|
130
|
+
}
|
|
118
131
|
}
|
|
119
|
-
}, [open])
|
|
132
|
+
}, [open, tick])
|
|
120
133
|
|
|
121
134
|
const renderBackdrop = useCallback(
|
|
122
135
|
(props: BottomSheetBackdropProps) => (
|
|
@@ -163,7 +176,7 @@ export function Sheet({
|
|
|
163
176
|
activeOpacity={0.6}
|
|
164
177
|
touchSoundDisabled={true}
|
|
165
178
|
accessibilityRole="button"
|
|
166
|
-
accessibilityLabel="
|
|
179
|
+
accessibilityLabel="Cerrar"
|
|
167
180
|
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
|
|
168
181
|
>
|
|
169
182
|
<AntDesign name="close" size={ms(18)} color={colors.foregroundMuted} />
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { Sheet, BottomSheetModalProvider, SheetTextInput } from './Sheet'
|
|
2
|
-
export type { SheetProps } from './Sheet'
|
|
1
|
+
export { Sheet, SheetHeader, SheetContent, SheetFooter, BottomSheetModalProvider, SheetTextInput } from './Sheet'
|
|
2
|
+
export type { SheetProps, SheetHeaderProps, SheetContentProps, SheetFooterProps } from './Sheet'
|
|
@@ -4,7 +4,7 @@ import { EaseView } from 'react-native-ease'
|
|
|
4
4
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
5
5
|
import { useTheme } from '../../theme'
|
|
6
6
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
7
|
-
import {
|
|
7
|
+
import { Icon } from '../../utils/icons'
|
|
8
8
|
import { COLOR_TRANSITION } from '../../utils/animations'
|
|
9
9
|
import { PressableChip } from '../../utils/pressable'
|
|
10
10
|
import { RADIUS } from '../../tokens'
|
|
@@ -47,7 +47,7 @@ function SheetSelectChip({
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const iconColor = selected ? colors.primaryForeground : colors.foreground
|
|
50
|
-
const resolvedIcon = option.iconName ?
|
|
50
|
+
const resolvedIcon = option.iconName ? <Icon name={option.iconName} size={ms(13)} color={iconColor} /> : null
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
53
|
<PressableChip
|
|
@@ -55,7 +55,7 @@ function SheetSelectChip({
|
|
|
55
55
|
rippleColor="transparent"
|
|
56
56
|
touchSoundDisabled
|
|
57
57
|
accessibilityRole="button"
|
|
58
|
-
accessibilityLabel={option.disabled ? `${option.label},
|
|
58
|
+
accessibilityLabel={option.disabled ? `${option.label}, no disponible` : option.label}
|
|
59
59
|
accessibilityState={{ selected, disabled: option.disabled }}
|
|
60
60
|
>
|
|
61
61
|
<EaseView
|
|
@@ -83,7 +83,7 @@ export function Skeleton({
|
|
|
83
83
|
]}
|
|
84
84
|
onLayout={(e) => setContainerWidth(e.nativeEvent.layout.width)}
|
|
85
85
|
accessibilityRole="progressbar"
|
|
86
|
-
accessibilityLabel="
|
|
86
|
+
accessibilityLabel="Cargando"
|
|
87
87
|
accessibilityState={{ busy: true }}
|
|
88
88
|
>
|
|
89
89
|
<Animated.View style={[StyleSheet.absoluteFill, shimmerStyle]}>
|
|
@@ -16,6 +16,7 @@ export interface SliderProps {
|
|
|
16
16
|
showValue?: boolean
|
|
17
17
|
formatValue?: (value: number) => string
|
|
18
18
|
accessibilityLabel?: string
|
|
19
|
+
accessibilityHint?: string
|
|
19
20
|
disabled?: boolean
|
|
20
21
|
style?: ViewStyle
|
|
21
22
|
}
|
|
@@ -31,6 +32,7 @@ export function Slider({
|
|
|
31
32
|
showValue = false,
|
|
32
33
|
formatValue = (v: number) => v.toFixed(2),
|
|
33
34
|
accessibilityLabel,
|
|
35
|
+
accessibilityHint,
|
|
34
36
|
disabled,
|
|
35
37
|
style,
|
|
36
38
|
}: SliderProps) {
|
|
@@ -50,6 +52,7 @@ export function Slider({
|
|
|
50
52
|
style={[styles.wrapper, style]}
|
|
51
53
|
accessibilityRole="adjustable"
|
|
52
54
|
accessibilityLabel={accessibilityLabel ?? label}
|
|
55
|
+
accessibilityHint={accessibilityHint}
|
|
53
56
|
accessibilityValue={{
|
|
54
57
|
min: minimumValue,
|
|
55
58
|
max: maximumValue,
|
|
@@ -13,7 +13,7 @@ export interface SpinnerProps extends Omit<ActivityIndicatorProps, 'size'> {
|
|
|
13
13
|
|
|
14
14
|
const sizeMap: Record<SpinnerSize, 'small' | 'large'> = {
|
|
15
15
|
sm: 'small',
|
|
16
|
-
md: '
|
|
16
|
+
md: 'large',
|
|
17
17
|
lg: 'large',
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -25,7 +25,7 @@ const labelFontSize: Record<SpinnerSize, number> = {
|
|
|
25
25
|
|
|
26
26
|
export function Spinner({ size = 'md', color, label, ...props }: SpinnerProps) {
|
|
27
27
|
const { colors } = useTheme()
|
|
28
|
-
const a11yLabel = label || '
|
|
28
|
+
const a11yLabel = label || 'Cargando'
|
|
29
29
|
|
|
30
30
|
if (label) {
|
|
31
31
|
return (
|
|
@@ -4,7 +4,7 @@ import { impactLight } from '../../utils/haptics'
|
|
|
4
4
|
import { useTheme } from '../../theme'
|
|
5
5
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
6
6
|
import { RADIUS } from '../../tokens'
|
|
7
|
-
import {
|
|
7
|
+
import { Icon } from '../../utils/icons'
|
|
8
8
|
import { PressableCard } from '../../utils/pressable'
|
|
9
9
|
|
|
10
10
|
export type StatsVariant = 'elevated' | 'outlined' | 'filled'
|
|
@@ -114,7 +114,7 @@ function StatsComponent({
|
|
|
114
114
|
|
|
115
115
|
const iconColorResolved = iconColor ?? colors.primary
|
|
116
116
|
|
|
117
|
-
const resolvedIcon = iconName ?
|
|
117
|
+
const resolvedIcon = iconName ? <Icon name={iconName} size={sizeStyles.iconSize} color={iconColorResolved} /> : icon
|
|
118
118
|
|
|
119
119
|
const iconElement = resolvedIcon ? (
|
|
120
120
|
<View style={styles.iconWrapper}>{resolvedIcon}</View>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { StyleSheet, ViewStyle, View } from 'react-native'
|
|
3
3
|
import { EaseView } from 'react-native-ease'
|
|
4
4
|
import { Feather } from '@expo/vector-icons'
|
|
5
5
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
6
6
|
import { useTheme } from '../../theme'
|
|
7
7
|
import { s } from '../../utils/scaling'
|
|
8
8
|
import { COLOR_TRANSITION, OPACITY_TRANSITION, SPRING_ELASTIC } from '../../utils/animations'
|
|
9
|
+
import { PressableButton } from '../../utils/pressable'
|
|
9
10
|
|
|
10
11
|
const TRACK_WIDTH = s(52)
|
|
11
12
|
const TRACK_HEIGHT = s(30)
|
|
@@ -22,24 +23,26 @@ export interface SwitchProps {
|
|
|
22
23
|
disabled?: boolean
|
|
23
24
|
style?: ViewStyle
|
|
24
25
|
accessibilityLabel?: string
|
|
26
|
+
accessibilityHint?: string
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
export function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel }: SwitchProps) {
|
|
29
|
+
export function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel, accessibilityHint }: SwitchProps) {
|
|
28
30
|
const { colors } = useTheme()
|
|
29
31
|
const isDisabled = !!disabled
|
|
30
32
|
|
|
31
33
|
return (
|
|
32
34
|
<View style={[{ alignSelf: 'flex-start' }, style]}>
|
|
33
|
-
<
|
|
35
|
+
<PressableButton
|
|
34
36
|
onPress={() => {
|
|
35
37
|
hapticSelection()
|
|
36
38
|
onCheckedChange?.(!checked)
|
|
37
39
|
}}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
touchSoundDisabled
|
|
40
|
+
enabled={!disabled}
|
|
41
|
+
rippleColor="transparent"
|
|
42
|
+
touchSoundDisabled
|
|
41
43
|
accessibilityRole="switch"
|
|
42
44
|
accessibilityLabel={accessibilityLabel}
|
|
45
|
+
accessibilityHint={accessibilityHint}
|
|
43
46
|
accessibilityState={{ checked, disabled: isDisabled }}
|
|
44
47
|
style={styles.touchable}
|
|
45
48
|
>
|
|
@@ -76,7 +79,7 @@ export function Switch({ checked = false, onCheckedChange, disabled, style, acce
|
|
|
76
79
|
</EaseView>
|
|
77
80
|
</EaseView>
|
|
78
81
|
</View>
|
|
79
|
-
</
|
|
82
|
+
</PressableButton>
|
|
80
83
|
</View>
|
|
81
84
|
)
|
|
82
85
|
}
|
|
@@ -84,6 +87,8 @@ export function Switch({ checked = false, onCheckedChange, disabled, style, acce
|
|
|
84
87
|
const styles = StyleSheet.create({
|
|
85
88
|
touchable: {
|
|
86
89
|
alignSelf: 'flex-start',
|
|
90
|
+
minHeight: 44,
|
|
91
|
+
justifyContent: 'center',
|
|
87
92
|
},
|
|
88
93
|
trackContainer: {
|
|
89
94
|
position: 'relative',
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { View, Text,
|
|
2
|
+
import { View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
4
4
|
import { useTheme } from '../../theme'
|
|
5
|
-
import {
|
|
5
|
+
import { Icon } from '../../utils/icons'
|
|
6
6
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
7
7
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
8
|
+
import { PressableTab } from '../../utils/pressable'
|
|
8
9
|
|
|
9
10
|
export interface TabBarItem {
|
|
10
11
|
/** Unique key for the tab. */
|
|
@@ -74,23 +75,23 @@ export function TabBar({
|
|
|
74
75
|
{items.map((item) => {
|
|
75
76
|
const active = item.key === activeKey
|
|
76
77
|
const tint = active ? resolvedActive : resolvedInactive
|
|
77
|
-
const iconNode = item.icon ?? (item.iconName ?
|
|
78
|
+
const iconNode = item.icon ?? (item.iconName ? <Icon name={item.iconName} size={ms(24)} color={tint} /> : null)
|
|
78
79
|
const showBadge = item.badge !== undefined && item.badge !== false
|
|
79
80
|
const badgeCount = typeof item.badge === 'number' ? item.badge : undefined
|
|
80
81
|
|
|
81
82
|
return (
|
|
82
|
-
<
|
|
83
|
+
<PressableTab
|
|
83
84
|
key={item.key}
|
|
84
|
-
style={styles.tab}
|
|
85
85
|
onPress={() => {
|
|
86
86
|
if (!active) hapticSelection()
|
|
87
87
|
onTabPress(item.key)
|
|
88
88
|
}}
|
|
89
|
-
|
|
90
|
-
touchSoundDisabled
|
|
89
|
+
rippleColor="transparent"
|
|
90
|
+
touchSoundDisabled
|
|
91
91
|
accessibilityRole="tab"
|
|
92
92
|
accessibilityState={{ selected: active }}
|
|
93
93
|
accessibilityLabel={item.label ?? item.key}
|
|
94
|
+
style={styles.tab}
|
|
94
95
|
>
|
|
95
96
|
<View>
|
|
96
97
|
{iconNode}
|
|
@@ -115,7 +116,7 @@ export function TabBar({
|
|
|
115
116
|
{item.label}
|
|
116
117
|
</Text>
|
|
117
118
|
) : null}
|
|
118
|
-
</
|
|
119
|
+
</PressableTab>
|
|
119
120
|
)
|
|
120
121
|
})}
|
|
121
122
|
</View>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { Text as RNText, TextProps as RNTextProps, TextStyle } from 'react-native'
|
|
3
|
+
|
|
4
|
+
declare const __DEV__: boolean | undefined
|
|
3
5
|
import { useTheme } from '../../theme'
|
|
4
6
|
import { TYPOGRAPHY } from '../../tokens'
|
|
5
7
|
import { ms, mvs } from '../../utils/scaling'
|
|
6
|
-
import {
|
|
8
|
+
import { isLoaded as expoFontIsLoaded } from 'expo-font'
|
|
7
9
|
|
|
8
10
|
export type TextVariant =
|
|
9
11
|
| 'display-hero'
|
|
@@ -70,6 +72,16 @@ const defaultColorVariant: Partial<Record<TextVariant, 'foreground' | 'foregroun
|
|
|
70
72
|
'button-sm': 'foreground',
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
let fontWarned = false
|
|
76
|
+
function warnIfFontsMissing(): void {
|
|
77
|
+
if (fontWarned || typeof __DEV__ === 'undefined' || !__DEV__) return
|
|
78
|
+
fontWarned = true
|
|
79
|
+
if (!expoFontIsLoaded('Sohne-Regular')) {
|
|
80
|
+
// eslint-disable-next-line no-console
|
|
81
|
+
console.warn('[retray-ui-kit] Sohne fonts not loaded — text falls back to system font.')
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
function TextBase({ variant = 'body-md', color, style, uppercase, children, ...props }: TextProps) {
|
|
74
86
|
warnIfFontsMissing()
|
|
75
87
|
const { colors } = useTheme()
|