@retray-dev/ui-kit 6.1.0 → 7.0.1
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 +447 -13
- package/EXAMPLES.md +248 -0
- package/README.md +11 -10
- package/dist/Accordion.d.mts +28 -0
- package/dist/Accordion.d.ts +28 -0
- package/dist/Accordion.js +340 -0
- package/dist/Accordion.mjs +6 -0
- package/dist/AlertBanner.d.mts +16 -0
- package/dist/AlertBanner.d.ts +16 -0
- package/dist/AlertBanner.js +247 -0
- package/dist/AlertBanner.mjs +5 -0
- package/dist/Avatar.d.mts +20 -0
- package/dist/Avatar.d.ts +20 -0
- package/dist/Avatar.js +234 -0
- package/dist/Avatar.mjs +3 -0
- package/dist/Badge.d.mts +26 -0
- package/dist/Badge.d.ts +26 -0
- package/dist/Badge.js +247 -0
- package/dist/Badge.mjs +4 -0
- package/dist/Button.d.mts +25 -0
- package/dist/Button.d.ts +25 -0
- package/dist/Button.js +414 -0
- package/dist/Button.mjs +8 -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 +2 -0
- package/dist/Card.d.mts +39 -0
- package/dist/Card.d.ts +39 -0
- package/dist/Card.js +329 -0
- package/dist/Card.mjs +7 -0
- package/dist/CategoryStrip.d.mts +26 -0
- package/dist/CategoryStrip.d.ts +26 -0
- package/dist/CategoryStrip.js +396 -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 +304 -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 +370 -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 +530 -0
- package/dist/ConfirmDialog.mjs +9 -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 +3 -0
- package/dist/CurrencyInput.d.mts +26 -0
- package/dist/CurrencyInput.d.ts +26 -0
- package/dist/CurrencyInput.js +404 -0
- package/dist/CurrencyInput.mjs +7 -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 +4 -0
- package/dist/EmptyState.d.mts +27 -0
- package/dist/EmptyState.d.ts +27 -0
- package/dist/EmptyState.js +503 -0
- package/dist/EmptyState.mjs +9 -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 +3 -0
- package/dist/IconButton.d.mts +22 -0
- package/dist/IconButton.d.ts +22 -0
- package/dist/IconButton.js +383 -0
- package/dist/IconButton.mjs +7 -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 +6 -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 +4 -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 +4 -0
- package/dist/ListItem.d.mts +64 -0
- package/dist/ListItem.d.ts +64 -0
- package/dist/ListItem.js +430 -0
- package/dist/ListItem.mjs +8 -0
- package/dist/MediaCard.d.mts +39 -0
- package/dist/MediaCard.d.ts +39 -0
- package/dist/MediaCard.js +427 -0
- package/dist/MediaCard.mjs +8 -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 +4 -0
- package/dist/MenuItem.d.mts +48 -0
- package/dist/MenuItem.d.ts +48 -0
- package/dist/MenuItem.js +403 -0
- package/dist/MenuItem.mjs +8 -0
- package/dist/MonthPicker.d.mts +20 -0
- package/dist/MonthPicker.d.ts +20 -0
- package/dist/MonthPicker.js +234 -0
- package/dist/MonthPicker.mjs +4 -0
- package/dist/Pressable.d.mts +34 -0
- package/dist/Pressable.d.ts +34 -0
- package/dist/Pressable.js +132 -0
- package/dist/Pressable.mjs +4 -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 +4 -0
- package/dist/RadioGroup.d.mts +19 -0
- package/dist/RadioGroup.d.ts +19 -0
- package/dist/RadioGroup.js +341 -0
- package/dist/RadioGroup.mjs +7 -0
- package/dist/Select.d.mts +22 -0
- package/dist/Select.d.ts +22 -0
- package/dist/Select.js +441 -0
- package/dist/Select.mjs +6 -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 +2 -0
- package/dist/Sheet.d.mts +81 -0
- package/dist/Sheet.d.ts +81 -0
- package/dist/Sheet.js +340 -0
- package/dist/Sheet.mjs +4 -0
- package/dist/Skeleton.d.mts +17 -0
- package/dist/Skeleton.d.ts +17 -0
- package/dist/Skeleton.js +205 -0
- package/dist/Skeleton.mjs +4 -0
- package/dist/Slider.d.mts +20 -0
- package/dist/Slider.d.ts +20 -0
- package/dist/Slider.js +232 -0
- package/dist/Slider.mjs +4 -0
- package/dist/Spinner.d.mts +12 -0
- package/dist/Spinner.d.ts +12 -0
- package/dist/Spinner.js +172 -0
- package/dist/Spinner.mjs +3 -0
- package/dist/Switch.d.mts +13 -0
- package/dist/Switch.d.ts +13 -0
- package/dist/Switch.js +261 -0
- package/dist/Switch.mjs +5 -0
- package/dist/Tabs.d.mts +27 -0
- package/dist/Tabs.d.ts +27 -0
- package/dist/Tabs.js +389 -0
- package/dist/Tabs.mjs +6 -0
- package/dist/Text.d.mts +12 -0
- package/dist/Text.d.ts +12 -0
- package/dist/Text.js +311 -0
- package/dist/Text.mjs +4 -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 +6 -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 +3 -0
- package/dist/Toggle.d.mts +33 -0
- package/dist/Toggle.d.ts +33 -0
- package/dist/Toggle.js +397 -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 +1 -0
- package/dist/chunk-2CE3TQVY.mjs +11 -0
- package/dist/chunk-2UYENBLV.mjs +49 -0
- package/dist/chunk-3BBOZ3OQ.mjs +41 -0
- package/dist/chunk-5IKW3VNC.mjs +43 -0
- package/dist/chunk-63357L2X.mjs +51 -0
- package/dist/chunk-6LQYY7HC.mjs +127 -0
- package/dist/chunk-6Q64UFIA.mjs +71 -0
- package/dist/chunk-76PFOSM2.mjs +41 -0
- package/dist/chunk-7H2OR44A.mjs +14 -0
- package/dist/chunk-A4MDAP7G.mjs +42 -0
- package/dist/chunk-AU2VDY4P.mjs +190 -0
- package/dist/chunk-BRKYVJVV.mjs +60 -0
- package/dist/chunk-CRYBX2CM.mjs +146 -0
- package/dist/chunk-DITNP6PL.mjs +106 -0
- package/dist/chunk-FTLJOUOQ.mjs +97 -0
- package/dist/chunk-GCWOGZYL.mjs +104 -0
- package/dist/chunk-GNGLDL6Z.mjs +60 -0
- package/dist/chunk-GPOUINK5.mjs +148 -0
- package/dist/chunk-HSPSMN6U.mjs +115 -0
- package/dist/chunk-IRRY3CRZ.mjs +82 -0
- package/dist/chunk-JB67UOB5.mjs +92 -0
- package/dist/chunk-JBLL7U3U.mjs +64 -0
- package/dist/chunk-KWCPOM6W.mjs +136 -0
- package/dist/chunk-KZJRQOIU.mjs +64 -0
- package/dist/chunk-L7E7TVEZ.mjs +145 -0
- package/dist/chunk-LG4DO3DK.mjs +174 -0
- package/dist/chunk-LWG526VX.mjs +139 -0
- package/dist/chunk-MN7OG7IY.mjs +96 -0
- package/dist/chunk-MX6HRKMI.mjs +29 -0
- package/dist/chunk-NC5ZTR2Y.mjs +32 -0
- package/dist/chunk-NQGVLMWG.mjs +90 -0
- package/dist/chunk-QCNARS3X.mjs +46 -0
- package/dist/chunk-QXGYKWI7.mjs +134 -0
- package/dist/chunk-QY3X2UYR.mjs +191 -0
- package/dist/chunk-RKLHUDZS.mjs +92 -0
- package/dist/chunk-RMMK64W5.mjs +54 -0
- package/dist/chunk-RR2VQLKE.mjs +190 -0
- package/dist/chunk-RTC3CFXF.mjs +29 -0
- package/dist/chunk-SBZYEV4S.mjs +61 -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-TAJ2PQ2O.mjs +163 -0
- package/dist/chunk-U4N7WF4Z.mjs +108 -0
- package/dist/chunk-URDE3EUU.mjs +132 -0
- package/dist/chunk-URLL5JBR.mjs +245 -0
- package/dist/chunk-XDMN67KV.mjs +59 -0
- package/dist/chunk-Y6MXOREN.mjs +120 -0
- package/dist/chunk-YZJAFS4P.mjs +131 -0
- package/dist/index.d.mts +94 -852
- package/dist/index.d.ts +94 -852
- package/dist/index.js +1387 -942
- package/dist/index.mjs +50 -3844
- package/package.json +23 -14
- 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 +13 -15
- package/src/components/AlertBanner/AlertBanner.tsx +33 -12
- package/src/components/Avatar/Avatar.tsx +4 -2
- package/src/components/Badge/Badge.tsx +4 -2
- package/src/components/Button/Button.tsx +30 -29
- package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
- package/src/components/Card/Card.tsx +36 -65
- package/src/components/CategoryStrip/CategoryStrip.tsx +68 -58
- package/src/components/Checkbox/Checkbox.tsx +41 -55
- package/src/components/Chip/Chip.tsx +49 -84
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +2 -2
- package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +4 -2
- package/src/components/CurrencyInput/CurrencyInput.tsx +2 -2
- package/src/components/DetailRow/DetailRow.tsx +9 -7
- package/src/components/EmptyState/EmptyState.tsx +2 -2
- package/src/components/Form/Form.tsx +149 -0
- package/src/components/Form/index.ts +1 -0
- package/src/components/IconButton/IconButton.tsx +24 -20
- package/src/components/Input/Input.tsx +63 -50
- 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 +30 -43
- package/src/components/MediaCard/MediaCard.tsx +31 -29
- package/src/components/MenuGroup/MenuGroup.tsx +145 -0
- package/src/components/MenuGroup/index.ts +1 -0
- package/src/components/MenuItem/MenuItem.tsx +29 -40
- package/src/components/MonthPicker/MonthPicker.tsx +14 -4
- package/src/components/Pressable/Pressable.tsx +27 -46
- package/src/components/Progress/Progress.tsx +21 -12
- package/src/components/RadioGroup/RadioGroup.tsx +55 -32
- package/src/components/Select/Select.tsx +23 -21
- package/src/components/Separator/Separator.tsx +1 -3
- package/src/components/Sheet/Sheet.tsx +85 -18
- package/src/components/Skeleton/Skeleton.tsx +25 -14
- package/src/components/Slider/Slider.tsx +13 -3
- package/src/components/Spinner/Spinner.tsx +1 -1
- package/src/components/Switch/Switch.tsx +70 -52
- package/src/components/Tabs/Tabs.tsx +59 -47
- package/src/components/Text/Text.tsx +3 -1
- package/src/components/Textarea/Textarea.tsx +44 -23
- package/src/components/Toast/Toast.tsx +6 -6
- package/src/components/Toggle/Toggle.tsx +86 -68
- package/src/components/VirtualList/VirtualList.tsx +60 -0
- package/src/components/VirtualList/index.ts +1 -0
- package/src/fonts.ts +38 -20
- package/src/index.ts +5 -1
- 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 +58 -0
- package/src/utils/icons.ts +47 -20
- package/src/utils/useColorTransition.ts +40 -0
- package/src/utils/usePressScale.ts +75 -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
|
@@ -1,73 +1,37 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { View, Text, TouchableOpacity,
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, TouchableOpacity, StyleSheet, ViewStyle, TextStyle } from 'react-native'
|
|
3
|
+
import Animated from 'react-native-reanimated'
|
|
3
4
|
import { impactLight } from '../../utils/haptics'
|
|
4
5
|
import { useTheme } from '../../theme'
|
|
5
6
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
6
7
|
import { RADIUS } from '../../tokens'
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
import { usePressScale } from '../../utils/usePressScale'
|
|
9
|
+
import { SPRINGS, PRESS_SCALE } from '../../utils/animations'
|
|
9
10
|
|
|
10
11
|
export type CardVariant = 'elevated' | 'outlined' | 'filled'
|
|
11
12
|
|
|
12
13
|
export interface CardProps {
|
|
13
14
|
children: React.ReactNode
|
|
14
|
-
/** Visual style variant. `'elevated'` (default) has shadow, `'outlined'` has border only, `'filled'` uses accent background. */
|
|
15
15
|
variant?: CardVariant
|
|
16
|
-
/** Makes the card tappable. Adds press animation and haptic feedback. */
|
|
17
16
|
onPress?: () => void
|
|
18
17
|
style?: ViewStyle
|
|
18
|
+
accessibilityLabel?: string
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export interface CardHeaderProps {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface CardTitleProps {
|
|
27
|
-
children: React.ReactNode
|
|
28
|
-
style?: TextStyle
|
|
29
|
-
}
|
|
21
|
+
export interface CardHeaderProps { children: React.ReactNode; style?: ViewStyle }
|
|
22
|
+
export interface CardTitleProps { children: React.ReactNode; style?: TextStyle }
|
|
23
|
+
export interface CardDescriptionProps { children: React.ReactNode; style?: TextStyle }
|
|
24
|
+
export interface CardContentProps { children: React.ReactNode; style?: ViewStyle }
|
|
25
|
+
export interface CardFooterProps { children: React.ReactNode; style?: ViewStyle }
|
|
30
26
|
|
|
31
|
-
export
|
|
32
|
-
children: React.ReactNode
|
|
33
|
-
style?: TextStyle
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface CardContentProps {
|
|
37
|
-
children: React.ReactNode
|
|
38
|
-
style?: ViewStyle
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface CardFooterProps {
|
|
42
|
-
children: React.ReactNode
|
|
43
|
-
style?: ViewStyle
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function Card({ children, variant = 'elevated', onPress, style }: CardProps) {
|
|
27
|
+
export function Card({ children, variant = 'elevated', onPress, style, accessibilityLabel }: CardProps) {
|
|
47
28
|
const { colors } = useTheme()
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
useNativeDriver: nativeDriver,
|
|
55
|
-
stiffness: 400,
|
|
56
|
-
damping: 30,
|
|
57
|
-
mass: 1.0,
|
|
58
|
-
}).start()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const handlePressOut = () => {
|
|
62
|
-
if (!onPress) return
|
|
63
|
-
Animated.spring(scale, {
|
|
64
|
-
toValue: 1,
|
|
65
|
-
useNativeDriver: nativeDriver,
|
|
66
|
-
stiffness: 250,
|
|
67
|
-
damping: 24,
|
|
68
|
-
mass: 1.0,
|
|
69
|
-
}).start()
|
|
70
|
-
}
|
|
29
|
+
const { animatedStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
30
|
+
pressScale: PRESS_SCALE.card,
|
|
31
|
+
pressInSpring: SPRINGS.surfacePressIn,
|
|
32
|
+
pressOutSpring: SPRINGS.surfacePressOut,
|
|
33
|
+
disabled: !onPress,
|
|
34
|
+
})
|
|
71
35
|
|
|
72
36
|
const handlePress = () => {
|
|
73
37
|
if (!onPress) return
|
|
@@ -78,11 +42,14 @@ export function Card({ children, variant = 'elevated', onPress, style }: CardPro
|
|
|
78
42
|
const variantStyle: ViewStyle = {
|
|
79
43
|
elevated: {
|
|
80
44
|
backgroundColor: colors.card,
|
|
81
|
-
|
|
45
|
+
// AUDIT FIX: removed borderColor — shadow is the depth signal; a border on
|
|
46
|
+
// top of a shadow creates redundant double-framing that reads as "heavy"
|
|
47
|
+
// rather than "elevated". borderWidth: 0 overrides the base style's borderWidth: 1.
|
|
48
|
+
borderWidth: 0,
|
|
82
49
|
shadowColor: '#000',
|
|
83
|
-
shadowOffset: { width: 0, height:
|
|
84
|
-
shadowOpacity: 0.
|
|
85
|
-
shadowRadius:
|
|
50
|
+
shadowOffset: { width: 0, height: 4 },
|
|
51
|
+
shadowOpacity: 0.09,
|
|
52
|
+
shadowRadius: 14,
|
|
86
53
|
elevation: 4,
|
|
87
54
|
},
|
|
88
55
|
outlined: {
|
|
@@ -107,13 +74,15 @@ export function Card({ children, variant = 'elevated', onPress, style }: CardPro
|
|
|
107
74
|
|
|
108
75
|
if (onPress) {
|
|
109
76
|
return (
|
|
110
|
-
<Animated.View style={
|
|
77
|
+
<Animated.View style={animatedStyle} {...hoverHandlers}>
|
|
111
78
|
<TouchableOpacity
|
|
112
79
|
onPress={handlePress}
|
|
113
|
-
onPressIn={
|
|
114
|
-
onPressOut={
|
|
80
|
+
onPressIn={onPressIn}
|
|
81
|
+
onPressOut={onPressOut}
|
|
115
82
|
activeOpacity={1}
|
|
116
83
|
touchSoundDisabled={true}
|
|
84
|
+
accessibilityRole="button"
|
|
85
|
+
accessibilityLabel={accessibilityLabel}
|
|
117
86
|
>
|
|
118
87
|
{cardContent}
|
|
119
88
|
</TouchableOpacity>
|
|
@@ -136,7 +105,7 @@ export function CardTitle({ children, style }: CardTitleProps) {
|
|
|
136
105
|
export function CardDescription({ children, style }: CardDescriptionProps) {
|
|
137
106
|
const { colors } = useTheme()
|
|
138
107
|
return (
|
|
139
|
-
<Text style={[styles.description, { color: colors.
|
|
108
|
+
<Text style={[styles.description, { color: colors.foregroundSubtle }, style]} allowFontScaling={true}>{children}</Text>
|
|
140
109
|
)
|
|
141
110
|
}
|
|
142
111
|
|
|
@@ -150,7 +119,7 @@ export function CardFooter({ children, style }: CardFooterProps) {
|
|
|
150
119
|
|
|
151
120
|
const styles = StyleSheet.create({
|
|
152
121
|
card: {
|
|
153
|
-
borderRadius: RADIUS.md,
|
|
122
|
+
borderRadius: RADIUS.md,
|
|
154
123
|
borderWidth: 1,
|
|
155
124
|
},
|
|
156
125
|
header: {
|
|
@@ -159,12 +128,14 @@ const styles = StyleSheet.create({
|
|
|
159
128
|
gap: vs(4),
|
|
160
129
|
},
|
|
161
130
|
title: {
|
|
162
|
-
fontFamily: '
|
|
131
|
+
fontFamily: 'Sohne-SemiBold',
|
|
163
132
|
fontSize: ms(16),
|
|
164
133
|
lineHeight: mvs(22),
|
|
165
134
|
},
|
|
135
|
+
// AUDIT FIX: was foregroundMuted (2.2:1 fail) — description text now uses
|
|
136
|
+
// foregroundSubtle (5.9:1 ✓) which is readable while still visually secondary.
|
|
166
137
|
description: {
|
|
167
|
-
fontFamily: '
|
|
138
|
+
fontFamily: 'Sohne-Regular',
|
|
168
139
|
fontSize: ms(13),
|
|
169
140
|
lineHeight: mvs(18),
|
|
170
141
|
},
|
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useCallback } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
ScrollView,
|
|
4
4
|
TouchableOpacity,
|
|
5
|
-
Animated,
|
|
6
5
|
Text,
|
|
7
6
|
View,
|
|
8
7
|
StyleSheet,
|
|
9
8
|
ViewStyle,
|
|
10
|
-
Platform,
|
|
11
9
|
} from 'react-native'
|
|
10
|
+
import Animated, {
|
|
11
|
+
useAnimatedStyle,
|
|
12
|
+
interpolateColor,
|
|
13
|
+
} from 'react-native-reanimated'
|
|
12
14
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
13
15
|
import { useTheme } from '../../theme'
|
|
14
16
|
import { s, vs, ms } from '../../utils/scaling'
|
|
15
17
|
import { renderIcon } from '../../utils/icons'
|
|
18
|
+
import { usePressScale } from '../../utils/usePressScale'
|
|
19
|
+
import { useColorTransition } from '../../utils/useColorTransition'
|
|
20
|
+
import { PRESS_SCALE } from '../../utils/animations'
|
|
16
21
|
import { RADIUS } from '../../tokens'
|
|
17
22
|
|
|
18
|
-
const nativeDriver = Platform.OS !== 'web'
|
|
19
|
-
|
|
20
23
|
export interface CategoryItem {
|
|
21
24
|
label: string
|
|
22
25
|
value: string
|
|
@@ -36,68 +39,69 @@ export interface CategoryStripProps {
|
|
|
36
39
|
style?: ViewStyle
|
|
37
40
|
/** Style applied to each pill item. */
|
|
38
41
|
itemStyle?: ViewStyle
|
|
42
|
+
accessibilityLabel?: string
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
function CategoryChip({
|
|
45
|
+
const CategoryChip = React.memo(function CategoryChip({
|
|
42
46
|
item,
|
|
43
47
|
selected,
|
|
44
|
-
|
|
48
|
+
onSelect,
|
|
45
49
|
}: {
|
|
46
50
|
item: CategoryItem
|
|
47
51
|
selected: boolean
|
|
48
|
-
|
|
52
|
+
onSelect: (value: string) => void
|
|
49
53
|
}) {
|
|
50
54
|
const { colors } = useTheme()
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
55
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut, hoverHandlers } = usePressScale({
|
|
56
|
+
pressScale: PRESS_SCALE.chip,
|
|
57
|
+
})
|
|
58
|
+
const progress = useColorTransition(selected)
|
|
56
59
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
const surfaceStyle = useAnimatedStyle(() => ({
|
|
61
|
+
backgroundColor: interpolateColor(progress.value, [0, 1], [colors.surface, colors.primary]),
|
|
62
|
+
borderColor: interpolateColor(progress.value, [0, 1], [colors.border, colors.primary]),
|
|
63
|
+
}))
|
|
60
64
|
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
const textColorStyle = useAnimatedStyle(() => ({
|
|
66
|
+
color: interpolateColor(progress.value, [0, 1], [colors.foregroundSubtle, colors.primaryForeground]),
|
|
67
|
+
}))
|
|
64
68
|
|
|
69
|
+
// Static color for icon — icon families take a static color prop, not animated.
|
|
70
|
+
const iconColor = selected ? colors.primaryForeground : colors.foregroundSubtle
|
|
65
71
|
const resolvedIcon =
|
|
66
72
|
typeof item.icon === 'string'
|
|
67
|
-
? renderIcon(item.icon, 16,
|
|
73
|
+
? renderIcon(item.icon, 16, iconColor)
|
|
68
74
|
: item.icon ?? null
|
|
69
75
|
|
|
70
76
|
return (
|
|
71
|
-
<Animated.View style={
|
|
77
|
+
<Animated.View style={scaleStyle} {...hoverHandlers}>
|
|
72
78
|
<TouchableOpacity
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
backgroundColor: bgColor,
|
|
77
|
-
borderColor,
|
|
78
|
-
},
|
|
79
|
-
]}
|
|
80
|
-
onPress={onPress}
|
|
81
|
-
onPressIn={handlePressIn}
|
|
82
|
-
onPressOut={handlePressOut}
|
|
79
|
+
onPress={() => onSelect(item.value)}
|
|
80
|
+
onPressIn={onPressIn}
|
|
81
|
+
onPressOut={onPressOut}
|
|
83
82
|
activeOpacity={1}
|
|
84
83
|
touchSoundDisabled={true}
|
|
84
|
+
accessibilityRole="button"
|
|
85
|
+
accessibilityLabel={item.label}
|
|
86
|
+
accessibilityState={{ selected }}
|
|
85
87
|
>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<
|
|
93
|
-
{
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
<Animated.View style={[styles.chip, surfaceStyle]}>
|
|
89
|
+
{resolvedIcon && <View style={styles.chipIcon}>{resolvedIcon}</View>}
|
|
90
|
+
<Animated.Text style={[styles.chipLabel, textColorStyle]} allowFontScaling={true}>
|
|
91
|
+
{item.label}
|
|
92
|
+
</Animated.Text>
|
|
93
|
+
{item.badge !== undefined && item.badge > 0 && (
|
|
94
|
+
<View style={[styles.chipBadge, { backgroundColor: colors.primary }]}>
|
|
95
|
+
<Text style={[styles.chipBadgeText, { color: colors.primaryForeground }]}>
|
|
96
|
+
{Math.min(item.badge, 99)}
|
|
97
|
+
</Text>
|
|
98
|
+
</View>
|
|
99
|
+
)}
|
|
100
|
+
</Animated.View>
|
|
97
101
|
</TouchableOpacity>
|
|
98
102
|
</Animated.View>
|
|
99
103
|
)
|
|
100
|
-
}
|
|
104
|
+
})
|
|
101
105
|
|
|
102
106
|
export function CategoryStrip({
|
|
103
107
|
categories,
|
|
@@ -106,21 +110,25 @@ export function CategoryStrip({
|
|
|
106
110
|
multiSelect = false,
|
|
107
111
|
style,
|
|
108
112
|
itemStyle,
|
|
113
|
+
accessibilityLabel,
|
|
109
114
|
}: CategoryStripProps) {
|
|
110
115
|
const selected = Array.isArray(value) ? value : value ? [value] : []
|
|
111
116
|
|
|
112
|
-
const handlePress = (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
const handlePress = useCallback(
|
|
118
|
+
(v: string) => {
|
|
119
|
+
hapticSelection()
|
|
120
|
+
if (multiSelect) {
|
|
121
|
+
const current = Array.isArray(value) ? value : value ? [value] : []
|
|
122
|
+
const next = current.includes(v)
|
|
123
|
+
? current.filter((x) => x !== v)
|
|
124
|
+
: [...current, v]
|
|
125
|
+
onValueChange?.(next)
|
|
126
|
+
} else {
|
|
127
|
+
onValueChange?.(v === value ? '' : v)
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
[multiSelect, value, onValueChange],
|
|
131
|
+
)
|
|
124
132
|
|
|
125
133
|
return (
|
|
126
134
|
<ScrollView
|
|
@@ -128,13 +136,15 @@ export function CategoryStrip({
|
|
|
128
136
|
showsHorizontalScrollIndicator={false}
|
|
129
137
|
contentContainerStyle={[styles.container, style]}
|
|
130
138
|
style={styles.scroll}
|
|
139
|
+
accessibilityRole={multiSelect ? undefined : 'radiogroup'}
|
|
140
|
+
accessibilityLabel={accessibilityLabel}
|
|
131
141
|
>
|
|
132
142
|
{categories.map((cat) => (
|
|
133
143
|
<View key={cat.value} style={itemStyle}>
|
|
134
144
|
<CategoryChip
|
|
135
145
|
item={cat}
|
|
136
146
|
selected={selected.includes(cat.value)}
|
|
137
|
-
|
|
147
|
+
onSelect={handlePress}
|
|
138
148
|
/>
|
|
139
149
|
</View>
|
|
140
150
|
))}
|
|
@@ -166,7 +176,7 @@ const styles = StyleSheet.create({
|
|
|
166
176
|
justifyContent: 'center',
|
|
167
177
|
},
|
|
168
178
|
chipLabel: {
|
|
169
|
-
fontFamily: '
|
|
179
|
+
fontFamily: 'Sohne-Medium',
|
|
170
180
|
fontSize: ms(13),
|
|
171
181
|
},
|
|
172
182
|
chipBadge: {
|
|
@@ -178,7 +188,7 @@ const styles = StyleSheet.create({
|
|
|
178
188
|
justifyContent: 'center',
|
|
179
189
|
},
|
|
180
190
|
chipBadgeText: {
|
|
181
|
-
fontFamily: '
|
|
191
|
+
fontFamily: 'Sohne-Bold',
|
|
182
192
|
fontSize: ms(9),
|
|
183
193
|
lineHeight: 14,
|
|
184
194
|
},
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { TouchableOpacity,
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { TouchableOpacity, View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
|
+
import Animated, {
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
interpolateColor,
|
|
6
|
+
withTiming,
|
|
7
|
+
} from 'react-native-reanimated'
|
|
3
8
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
4
|
-
|
|
5
|
-
const nativeDriver = Platform.OS !== 'web'
|
|
6
9
|
import { useTheme } from '../../theme'
|
|
7
10
|
import { s, vs, ms, mvs } from '../../utils/scaling'
|
|
11
|
+
import { usePressScale } from '../../utils/usePressScale'
|
|
12
|
+
import { useColorTransition } from '../../utils/useColorTransition'
|
|
13
|
+
import { PRESS_SCALE, TIMINGS, EASINGS } from '../../utils/animations'
|
|
8
14
|
|
|
9
15
|
export interface CheckboxProps {
|
|
10
16
|
checked?: boolean
|
|
@@ -12,6 +18,7 @@ export interface CheckboxProps {
|
|
|
12
18
|
label?: string
|
|
13
19
|
disabled?: boolean
|
|
14
20
|
style?: ViewStyle
|
|
21
|
+
accessibilityLabel?: string
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
export function Checkbox({
|
|
@@ -20,78 +27,53 @@ export function Checkbox({
|
|
|
20
27
|
label,
|
|
21
28
|
disabled,
|
|
22
29
|
style,
|
|
30
|
+
accessibilityLabel,
|
|
23
31
|
}: CheckboxProps) {
|
|
24
32
|
const { colors } = useTheme()
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
Animated.parallel([
|
|
31
|
-
Animated.timing(bgOpacity, {
|
|
32
|
-
toValue: checked ? 1 : 0,
|
|
33
|
-
duration: 150,
|
|
34
|
-
useNativeDriver: false,
|
|
35
|
-
}),
|
|
36
|
-
Animated.timing(checkOpacity, {
|
|
37
|
-
toValue: checked ? 1 : 0,
|
|
38
|
-
duration: 120,
|
|
39
|
-
useNativeDriver: false,
|
|
40
|
-
}),
|
|
41
|
-
]).start()
|
|
42
|
-
}, [checked, bgOpacity, checkOpacity])
|
|
43
|
-
|
|
44
|
-
const borderColor = bgOpacity.interpolate({
|
|
45
|
-
inputRange: [0, 1],
|
|
46
|
-
outputRange: [colors.border, colors.primary],
|
|
33
|
+
const { animatedStyle: scaleStyle, onPressIn, onPressOut } = usePressScale({
|
|
34
|
+
pressScale: PRESS_SCALE.button,
|
|
35
|
+
disabled,
|
|
47
36
|
})
|
|
37
|
+
const progress = useColorTransition(checked)
|
|
48
38
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
})
|
|
39
|
+
const boxStyle = useAnimatedStyle(() => ({
|
|
40
|
+
borderColor: interpolateColor(progress.value, [0, 1], [colors.border, colors.primary]),
|
|
41
|
+
backgroundColor: interpolateColor(progress.value, [0, 1], ['transparent', colors.primary]),
|
|
42
|
+
}))
|
|
53
43
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const handlePressOut = () => {
|
|
60
|
-
Animated.spring(scale, { toValue: 1, useNativeDriver: nativeDriver, speed: 40, bounciness: 0 }).start()
|
|
61
|
-
}
|
|
44
|
+
const checkStyle = useAnimatedStyle(() => ({
|
|
45
|
+
opacity: withTiming(checked ? 1 : 0, { duration: TIMINGS.state.duration, easing: EASINGS.standard }),
|
|
46
|
+
}))
|
|
62
47
|
|
|
63
48
|
return (
|
|
49
|
+
// AUDIT FIX: opacity was applied only to the box, leaving the label at full
|
|
50
|
+
// opacity when disabled — a contradictory visual signal. Now the entire row
|
|
51
|
+
// dims uniformly so label and control communicate the same disabled state.
|
|
64
52
|
<TouchableOpacity
|
|
65
|
-
style={[styles.row, style]}
|
|
53
|
+
style={[styles.row, disabled && styles.rowDisabled, style]}
|
|
66
54
|
onPress={() => {
|
|
67
55
|
hapticSelection()
|
|
68
56
|
onCheckedChange?.(!checked)
|
|
69
57
|
}}
|
|
70
|
-
onPressIn={
|
|
71
|
-
onPressOut={
|
|
58
|
+
onPressIn={onPressIn}
|
|
59
|
+
onPressOut={onPressOut}
|
|
72
60
|
disabled={disabled}
|
|
73
61
|
activeOpacity={1}
|
|
74
62
|
touchSoundDisabled={true}
|
|
63
|
+
accessibilityRole="checkbox"
|
|
64
|
+
accessibilityLabel={accessibilityLabel ?? label}
|
|
65
|
+
accessibilityState={{ checked, disabled: !!disabled }}
|
|
75
66
|
>
|
|
76
|
-
<Animated.View style={
|
|
77
|
-
<Animated.View
|
|
78
|
-
style={
|
|
79
|
-
styles.box,
|
|
80
|
-
{
|
|
81
|
-
borderColor,
|
|
82
|
-
backgroundColor,
|
|
83
|
-
opacity: disabled ? 0.45 : 1,
|
|
84
|
-
},
|
|
85
|
-
]}
|
|
86
|
-
>
|
|
87
|
-
<Animated.View style={{ opacity: checkOpacity }}>
|
|
67
|
+
<Animated.View style={scaleStyle}>
|
|
68
|
+
<Animated.View style={[styles.box, boxStyle]}>
|
|
69
|
+
<Animated.View style={checkStyle}>
|
|
88
70
|
<View style={[styles.checkmark, { borderColor: colors.primaryForeground }]} />
|
|
89
71
|
</Animated.View>
|
|
90
72
|
</Animated.View>
|
|
91
73
|
</Animated.View>
|
|
92
74
|
{label ? (
|
|
93
75
|
<Text
|
|
94
|
-
style={[styles.label, { color:
|
|
76
|
+
style={[styles.label, { color: colors.foreground }]}
|
|
95
77
|
allowFontScaling={true}
|
|
96
78
|
>
|
|
97
79
|
{label}
|
|
@@ -107,6 +89,10 @@ const styles = StyleSheet.create({
|
|
|
107
89
|
alignItems: 'center',
|
|
108
90
|
gap: s(12),
|
|
109
91
|
},
|
|
92
|
+
// AUDIT FIX: was inline opacity on the box only
|
|
93
|
+
rowDisabled: {
|
|
94
|
+
opacity: 0.45,
|
|
95
|
+
},
|
|
110
96
|
box: {
|
|
111
97
|
width: s(24),
|
|
112
98
|
height: s(24),
|
|
@@ -123,7 +109,7 @@ const styles = StyleSheet.create({
|
|
|
123
109
|
transform: [{ rotate: '-45deg' }, { translateY: -1 }],
|
|
124
110
|
},
|
|
125
111
|
label: {
|
|
126
|
-
fontFamily: '
|
|
112
|
+
fontFamily: 'Sohne-Regular',
|
|
127
113
|
fontSize: ms(14),
|
|
128
114
|
lineHeight: mvs(20),
|
|
129
115
|
},
|