@retray-dev/ui-kit 6.2.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 +444 -10
- 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 -873
- package/dist/index.d.ts +94 -873
- package/dist/index.js +751 -357
- package/dist/index.mjs +50 -3895
- 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 +3 -3
- 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 +10 -11
- package/src/components/ButtonGroup/ButtonGroup.tsx +13 -10
- package/src/components/Card/Card.tsx +17 -34
- package/src/components/CategoryStrip/CategoryStrip.tsx +24 -21
- package/src/components/Checkbox/Checkbox.tsx +11 -6
- package/src/components/Chip/Chip.tsx +17 -15
- 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 +4 -2
- package/src/components/Input/Input.tsx +27 -31
- package/src/components/LabelValue/LabelValue.tsx +6 -4
- package/src/components/ListGroup/ListGroup.tsx +145 -0
- package/src/components/ListGroup/index.ts +1 -0
- package/src/components/ListItem/ListItem.tsx +9 -10
- package/src/components/MediaCard/MediaCard.tsx +7 -5
- package/src/components/MenuGroup/MenuGroup.tsx +145 -0
- package/src/components/MenuGroup/index.ts +1 -0
- package/src/components/MenuItem/MenuItem.tsx +7 -9
- package/src/components/MonthPicker/MonthPicker.tsx +2 -2
- package/src/components/RadioGroup/RadioGroup.tsx +11 -14
- package/src/components/Select/Select.tsx +6 -6
- package/src/components/Separator/Separator.tsx +1 -3
- package/src/components/Sheet/Sheet.tsx +81 -17
- package/src/components/Skeleton/Skeleton.tsx +1 -1
- package/src/components/Slider/Slider.tsx +2 -2
- package/src/components/Spinner/Spinner.tsx +1 -1
- package/src/components/Switch/Switch.tsx +28 -5
- package/src/components/Tabs/Tabs.tsx +22 -18
- package/src/components/Text/Text.tsx +3 -1
- package/src/components/Textarea/Textarea.tsx +18 -14
- package/src/components/Toast/Toast.tsx +6 -6
- package/src/components/Toggle/Toggle.tsx +47 -23
- 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/icons.ts +47 -20
- package/src/utils/usePressScale.ts +2 -0
- package/src/assets/fonts/Poppins-Black.ttf +0 -0
- package/src/assets/fonts/Poppins-BlackItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Bold.ttf +0 -0
- package/src/assets/fonts/Poppins-BoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBold.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLight.ttf +0 -0
- package/src/assets/fonts/Poppins-ExtraLightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Italic.ttf +0 -0
- package/src/assets/fonts/Poppins-Light.ttf +0 -0
- package/src/assets/fonts/Poppins-LightItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Medium.ttf +0 -0
- package/src/assets/fonts/Poppins-MediumItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Regular.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
- package/src/assets/fonts/Poppins-SemiBoldItalic.ttf +0 -0
- package/src/assets/fonts/Poppins-Thin.ttf +0 -0
- package/src/assets/fonts/Poppins-ThinItalic.ttf +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
|
+
import { useTheme } from '../../theme'
|
|
4
|
+
import { s, vs } from '../../utils/scaling'
|
|
5
|
+
import { RADIUS } from '../../tokens'
|
|
6
|
+
|
|
7
|
+
export type ListGroupVariant = 'plain' | 'card'
|
|
8
|
+
|
|
9
|
+
export interface ListGroupProps {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
/**
|
|
12
|
+
* - `plain` (default): no background, plain ListItems inside.
|
|
13
|
+
* - `card`: card surface with background + border wrapping plain ListItems.
|
|
14
|
+
*/
|
|
15
|
+
variant?: ListGroupVariant
|
|
16
|
+
style?: ViewStyle
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ListGroupHeaderProps {
|
|
20
|
+
children: React.ReactNode
|
|
21
|
+
style?: ViewStyle
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ListGroupFooterProps {
|
|
25
|
+
children: React.ReactNode
|
|
26
|
+
style?: ViewStyle
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ListGroup wraps multiple ListItems and auto-adds separators between them.
|
|
31
|
+
* Use variant="card" for a standalone surface or "plain" for items inside another container.
|
|
32
|
+
*/
|
|
33
|
+
export function ListGroup({ children, variant = 'plain', style }: ListGroupProps) {
|
|
34
|
+
const { colors } = useTheme()
|
|
35
|
+
|
|
36
|
+
// Auto-inject showSeparator={true} to all ListItem children except the last
|
|
37
|
+
const processedChildren = React.Children.map(children, (child, index) => {
|
|
38
|
+
if (!React.isValidElement(child)) return child
|
|
39
|
+
|
|
40
|
+
// Skip ListGroup.Header and ListGroup.Footer
|
|
41
|
+
if (child.type === ListGroupHeader || child.type === ListGroupFooter) {
|
|
42
|
+
return child
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check if it's a ListItem (has title prop as a heuristic)
|
|
46
|
+
const childProps = child.props as Record<string, unknown>
|
|
47
|
+
const isListItem = 'title' in childProps
|
|
48
|
+
if (!isListItem) return child
|
|
49
|
+
|
|
50
|
+
const isLast = index === React.Children.count(children) - 1
|
|
51
|
+
|
|
52
|
+
// Only add separator if not already explicitly set and not last item
|
|
53
|
+
if (childProps['showSeparator'] === undefined && !isLast) {
|
|
54
|
+
return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {
|
|
55
|
+
showSeparator: true,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return child
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const cardStyle: ViewStyle =
|
|
63
|
+
variant === 'card'
|
|
64
|
+
? {
|
|
65
|
+
backgroundColor: colors.card,
|
|
66
|
+
borderRadius: RADIUS.md,
|
|
67
|
+
borderWidth: 1,
|
|
68
|
+
borderColor: colors.border,
|
|
69
|
+
shadowColor: '#000',
|
|
70
|
+
shadowOffset: { width: 0, height: 2 },
|
|
71
|
+
shadowOpacity: 0.06,
|
|
72
|
+
shadowRadius: 6,
|
|
73
|
+
elevation: 2,
|
|
74
|
+
paddingVertical: vs(4),
|
|
75
|
+
}
|
|
76
|
+
: {}
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<View style={[styles.container, cardStyle, style]}>
|
|
80
|
+
{processedChildren}
|
|
81
|
+
</View>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function ListGroupHeader({ children, style }: ListGroupHeaderProps) {
|
|
86
|
+
const { colors } = useTheme()
|
|
87
|
+
|
|
88
|
+
if (typeof children === 'string') {
|
|
89
|
+
return (
|
|
90
|
+
<View style={[styles.header, { borderBottomColor: colors.separator }, style]}>
|
|
91
|
+
<Text style={[styles.headerText, { color: colors.foregroundMuted }]} allowFontScaling={true}>
|
|
92
|
+
{children}
|
|
93
|
+
</Text>
|
|
94
|
+
</View>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return <View style={[styles.header, { borderBottomColor: colors.separator }, style]}>{children}</View>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function ListGroupFooter({ children, style }: ListGroupFooterProps) {
|
|
102
|
+
const { colors } = useTheme()
|
|
103
|
+
|
|
104
|
+
if (typeof children === 'string') {
|
|
105
|
+
return (
|
|
106
|
+
<View style={[styles.footer, style]}>
|
|
107
|
+
<Text style={[styles.footerText, { color: colors.foregroundMuted }]} allowFontScaling={true}>
|
|
108
|
+
{children}
|
|
109
|
+
</Text>
|
|
110
|
+
</View>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return <View style={[styles.footer, style]}>{children}</View>
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
ListGroup.Header = ListGroupHeader
|
|
118
|
+
ListGroup.Footer = ListGroupFooter
|
|
119
|
+
|
|
120
|
+
const styles = StyleSheet.create({
|
|
121
|
+
container: {
|
|
122
|
+
overflow: 'hidden',
|
|
123
|
+
},
|
|
124
|
+
header: {
|
|
125
|
+
paddingHorizontal: s(16),
|
|
126
|
+
paddingTop: vs(12),
|
|
127
|
+
paddingBottom: vs(8),
|
|
128
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
129
|
+
},
|
|
130
|
+
headerText: {
|
|
131
|
+
fontFamily: 'Sohne-SemiBold',
|
|
132
|
+
fontSize: 13,
|
|
133
|
+
letterSpacing: 0.32,
|
|
134
|
+
textTransform: 'uppercase',
|
|
135
|
+
},
|
|
136
|
+
footer: {
|
|
137
|
+
paddingHorizontal: s(16),
|
|
138
|
+
paddingTop: vs(8),
|
|
139
|
+
paddingBottom: vs(12),
|
|
140
|
+
},
|
|
141
|
+
footerText: {
|
|
142
|
+
fontFamily: 'Sohne-Regular',
|
|
143
|
+
fontSize: 12,
|
|
144
|
+
},
|
|
145
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ListGroup'
|
|
@@ -81,7 +81,7 @@ export interface ListItemProps {
|
|
|
81
81
|
accessibilityLabel?: string
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
function ListItemBase({
|
|
85
85
|
leftRender,
|
|
86
86
|
rightRender,
|
|
87
87
|
trailing,
|
|
@@ -210,10 +210,7 @@ export function ListItem({
|
|
|
210
210
|
<View
|
|
211
211
|
style={[
|
|
212
212
|
styles.separator,
|
|
213
|
-
{
|
|
214
|
-
backgroundColor: colors.border,
|
|
215
|
-
marginLeft: effectiveLeft ? s(44) + s(12) : 0
|
|
216
|
-
},
|
|
213
|
+
{ backgroundColor: colors.separator },
|
|
217
214
|
]}
|
|
218
215
|
/>
|
|
219
216
|
) : null}
|
|
@@ -221,11 +218,13 @@ export function ListItem({
|
|
|
221
218
|
)
|
|
222
219
|
}
|
|
223
220
|
|
|
221
|
+
export const ListItem = React.memo(ListItemBase)
|
|
222
|
+
|
|
224
223
|
const styles = StyleSheet.create({
|
|
225
224
|
container: {
|
|
226
225
|
flexDirection: 'row',
|
|
227
226
|
alignItems: 'center',
|
|
228
|
-
paddingHorizontal:
|
|
227
|
+
paddingHorizontal: s(16),
|
|
229
228
|
paddingVertical: vs(10),
|
|
230
229
|
gap: s(12),
|
|
231
230
|
},
|
|
@@ -241,17 +240,17 @@ const styles = StyleSheet.create({
|
|
|
241
240
|
gap: vs(4),
|
|
242
241
|
},
|
|
243
242
|
title: {
|
|
244
|
-
fontFamily: '
|
|
243
|
+
fontFamily: 'Sohne-Medium',
|
|
245
244
|
fontSize: ms(15),
|
|
246
245
|
lineHeight: mvs(22),
|
|
247
246
|
},
|
|
248
247
|
subtitle: {
|
|
249
|
-
fontFamily: '
|
|
248
|
+
fontFamily: 'Sohne-Regular',
|
|
250
249
|
fontSize: ms(13),
|
|
251
250
|
lineHeight: mvs(18),
|
|
252
251
|
},
|
|
253
252
|
caption: {
|
|
254
|
-
fontFamily: '
|
|
253
|
+
fontFamily: 'Sohne-Regular',
|
|
255
254
|
fontSize: ms(12),
|
|
256
255
|
lineHeight: mvs(16),
|
|
257
256
|
opacity: 0.7,
|
|
@@ -263,7 +262,7 @@ const styles = StyleSheet.create({
|
|
|
263
262
|
maxWidth: s(160),
|
|
264
263
|
},
|
|
265
264
|
rightText: {
|
|
266
|
-
fontFamily: '
|
|
265
|
+
fontFamily: 'Sohne-Regular',
|
|
267
266
|
fontSize: ms(14),
|
|
268
267
|
},
|
|
269
268
|
separator: {
|
|
@@ -61,7 +61,7 @@ export interface MediaCardProps {
|
|
|
61
61
|
accessibilityLabel?: string
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
function MediaCardBase({
|
|
65
65
|
imageSource,
|
|
66
66
|
aspectRatio = '4:3',
|
|
67
67
|
badge,
|
|
@@ -112,7 +112,7 @@ export function MediaCard({
|
|
|
112
112
|
{...(Platform.OS === 'web' ? hoverHandlers : {})}
|
|
113
113
|
>
|
|
114
114
|
<View style={[styles.imageContainer, imageStyle]}>
|
|
115
|
-
<View style={{ paddingTop: `${ratio * 100}%` as
|
|
115
|
+
<View style={{ paddingTop: `${ratio * 100}%` as `${number}%` }}>
|
|
116
116
|
<View style={StyleSheet.absoluteFill}>
|
|
117
117
|
{imageSource ? (
|
|
118
118
|
<Image
|
|
@@ -191,6 +191,8 @@ export function MediaCard({
|
|
|
191
191
|
return cardContent
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
export const MediaCard = React.memo(MediaCardBase)
|
|
195
|
+
|
|
194
196
|
const styles = StyleSheet.create({
|
|
195
197
|
card: {
|
|
196
198
|
borderRadius: RADIUS.md,
|
|
@@ -233,17 +235,17 @@ const styles = StyleSheet.create({
|
|
|
233
235
|
gap: vs(2),
|
|
234
236
|
},
|
|
235
237
|
title: {
|
|
236
|
-
fontFamily: '
|
|
238
|
+
fontFamily: 'Sohne-SemiBold',
|
|
237
239
|
fontSize: ms(14),
|
|
238
240
|
lineHeight: mvs(20),
|
|
239
241
|
},
|
|
240
242
|
subtitle: {
|
|
241
|
-
fontFamily: '
|
|
243
|
+
fontFamily: 'Sohne-Regular',
|
|
242
244
|
fontSize: ms(13),
|
|
243
245
|
lineHeight: mvs(18),
|
|
244
246
|
},
|
|
245
247
|
caption: {
|
|
246
|
-
fontFamily: '
|
|
248
|
+
fontFamily: 'Sohne-Regular',
|
|
247
249
|
fontSize: ms(12),
|
|
248
250
|
lineHeight: mvs(16),
|
|
249
251
|
},
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { View, Text, StyleSheet, ViewStyle } from 'react-native'
|
|
3
|
+
import { useTheme } from '../../theme'
|
|
4
|
+
import { s, vs } from '../../utils/scaling'
|
|
5
|
+
import { RADIUS } from '../../tokens'
|
|
6
|
+
|
|
7
|
+
export type MenuGroupVariant = 'plain' | 'card'
|
|
8
|
+
|
|
9
|
+
export interface MenuGroupProps {
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
/**
|
|
12
|
+
* - `plain` (default): no background, plain MenuItems inside.
|
|
13
|
+
* - `card`: card surface with background + border wrapping plain MenuItems.
|
|
14
|
+
*/
|
|
15
|
+
variant?: MenuGroupVariant
|
|
16
|
+
style?: ViewStyle
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface MenuGroupHeaderProps {
|
|
20
|
+
children: React.ReactNode
|
|
21
|
+
style?: ViewStyle
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface MenuGroupFooterProps {
|
|
25
|
+
children: React.ReactNode
|
|
26
|
+
style?: ViewStyle
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* MenuGroup wraps multiple MenuItems and auto-adds separators between them.
|
|
31
|
+
* Use variant="card" for a standalone surface or "plain" for items inside another container.
|
|
32
|
+
*/
|
|
33
|
+
export function MenuGroup({ children, variant = 'plain', style }: MenuGroupProps) {
|
|
34
|
+
const { colors } = useTheme()
|
|
35
|
+
|
|
36
|
+
// Auto-inject showSeparator={true} to all MenuItem children except the last
|
|
37
|
+
const processedChildren = React.Children.map(children, (child, index) => {
|
|
38
|
+
if (!React.isValidElement(child)) return child
|
|
39
|
+
|
|
40
|
+
// Skip MenuGroup.Header and MenuGroup.Footer
|
|
41
|
+
if (child.type === MenuGroupHeader || child.type === MenuGroupFooter) {
|
|
42
|
+
return child
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check if it's a MenuItem (has onPress prop as a heuristic)
|
|
46
|
+
const childProps = child.props as Record<string, unknown>
|
|
47
|
+
const isMenuItem = 'onPress' in childProps
|
|
48
|
+
if (!isMenuItem) return child
|
|
49
|
+
|
|
50
|
+
const isLast = index === React.Children.count(children) - 1
|
|
51
|
+
|
|
52
|
+
// Only add separator if not already explicitly set and not last item
|
|
53
|
+
if (childProps['showSeparator'] === undefined && !isLast) {
|
|
54
|
+
return React.cloneElement(child as React.ReactElement<Record<string, unknown>>, {
|
|
55
|
+
showSeparator: true,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return child
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const cardStyle: ViewStyle =
|
|
63
|
+
variant === 'card'
|
|
64
|
+
? {
|
|
65
|
+
backgroundColor: colors.card,
|
|
66
|
+
borderRadius: RADIUS.md,
|
|
67
|
+
borderWidth: 1,
|
|
68
|
+
borderColor: colors.border,
|
|
69
|
+
shadowColor: '#000',
|
|
70
|
+
shadowOffset: { width: 0, height: 2 },
|
|
71
|
+
shadowOpacity: 0.06,
|
|
72
|
+
shadowRadius: 6,
|
|
73
|
+
elevation: 2,
|
|
74
|
+
paddingVertical: vs(4),
|
|
75
|
+
}
|
|
76
|
+
: {}
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<View style={[styles.container, cardStyle, style]}>
|
|
80
|
+
{processedChildren}
|
|
81
|
+
</View>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function MenuGroupHeader({ children, style }: MenuGroupHeaderProps) {
|
|
86
|
+
const { colors } = useTheme()
|
|
87
|
+
|
|
88
|
+
if (typeof children === 'string') {
|
|
89
|
+
return (
|
|
90
|
+
<View style={[styles.header, { borderBottomColor: colors.separator }, style]}>
|
|
91
|
+
<Text style={[styles.headerText, { color: colors.foregroundMuted }]} allowFontScaling={true}>
|
|
92
|
+
{children}
|
|
93
|
+
</Text>
|
|
94
|
+
</View>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return <View style={[styles.header, { borderBottomColor: colors.separator }, style]}>{children}</View>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function MenuGroupFooter({ children, style }: MenuGroupFooterProps) {
|
|
102
|
+
const { colors } = useTheme()
|
|
103
|
+
|
|
104
|
+
if (typeof children === 'string') {
|
|
105
|
+
return (
|
|
106
|
+
<View style={[styles.footer, style]}>
|
|
107
|
+
<Text style={[styles.footerText, { color: colors.foregroundMuted }]} allowFontScaling={true}>
|
|
108
|
+
{children}
|
|
109
|
+
</Text>
|
|
110
|
+
</View>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return <View style={[styles.footer, style]}>{children}</View>
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
MenuGroup.Header = MenuGroupHeader
|
|
118
|
+
MenuGroup.Footer = MenuGroupFooter
|
|
119
|
+
|
|
120
|
+
const styles = StyleSheet.create({
|
|
121
|
+
container: {
|
|
122
|
+
overflow: 'hidden',
|
|
123
|
+
},
|
|
124
|
+
header: {
|
|
125
|
+
paddingHorizontal: s(16),
|
|
126
|
+
paddingTop: vs(12),
|
|
127
|
+
paddingBottom: vs(8),
|
|
128
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
129
|
+
},
|
|
130
|
+
headerText: {
|
|
131
|
+
fontFamily: 'Sohne-SemiBold',
|
|
132
|
+
fontSize: 13,
|
|
133
|
+
letterSpacing: 0.32,
|
|
134
|
+
textTransform: 'uppercase',
|
|
135
|
+
},
|
|
136
|
+
footer: {
|
|
137
|
+
paddingHorizontal: s(16),
|
|
138
|
+
paddingTop: vs(8),
|
|
139
|
+
paddingBottom: vs(12),
|
|
140
|
+
},
|
|
141
|
+
footerText: {
|
|
142
|
+
fontFamily: 'Sohne-Regular',
|
|
143
|
+
fontSize: 12,
|
|
144
|
+
},
|
|
145
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './MenuGroup'
|
|
@@ -60,7 +60,7 @@ export interface MenuItemProps {
|
|
|
60
60
|
accessibilityLabel?: string
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
function MenuItemBase({
|
|
64
64
|
label,
|
|
65
65
|
subtitle,
|
|
66
66
|
iconName,
|
|
@@ -164,11 +164,7 @@ export function MenuItem({
|
|
|
164
164
|
<View
|
|
165
165
|
style={[
|
|
166
166
|
styles.separator,
|
|
167
|
-
{
|
|
168
|
-
backgroundColor: colors.border,
|
|
169
|
-
marginLeft: resolvedIcon ? s(22) + s(12) : 0,
|
|
170
|
-
opacity: 0.6,
|
|
171
|
-
},
|
|
167
|
+
{ backgroundColor: colors.separator },
|
|
172
168
|
]}
|
|
173
169
|
/>
|
|
174
170
|
) : null}
|
|
@@ -176,11 +172,13 @@ export function MenuItem({
|
|
|
176
172
|
)
|
|
177
173
|
}
|
|
178
174
|
|
|
175
|
+
export const MenuItem = React.memo(MenuItemBase)
|
|
176
|
+
|
|
179
177
|
const styles = StyleSheet.create({
|
|
180
178
|
container: {
|
|
181
179
|
flexDirection: 'row',
|
|
182
180
|
alignItems: 'center',
|
|
183
|
-
paddingHorizontal:
|
|
181
|
+
paddingHorizontal: s(16),
|
|
184
182
|
paddingVertical: vs(16),
|
|
185
183
|
minHeight: vs(54),
|
|
186
184
|
gap: s(12),
|
|
@@ -196,11 +194,11 @@ const styles = StyleSheet.create({
|
|
|
196
194
|
justifyContent: 'center',
|
|
197
195
|
},
|
|
198
196
|
label: {
|
|
199
|
-
fontFamily: '
|
|
197
|
+
fontFamily: 'Sohne-Medium',
|
|
200
198
|
fontSize: ms(15),
|
|
201
199
|
},
|
|
202
200
|
subtitle: {
|
|
203
|
-
fontFamily: '
|
|
201
|
+
fontFamily: 'Sohne-Regular',
|
|
204
202
|
fontSize: ms(12),
|
|
205
203
|
marginTop: vs(1),
|
|
206
204
|
},
|
|
@@ -3,7 +3,7 @@ import { View, Text, TouchableOpacity, StyleSheet, ViewStyle } from 'react-nativ
|
|
|
3
3
|
import { Entypo } from '@expo/vector-icons'
|
|
4
4
|
import { selectionAsync as hapticSelection } from '../../utils/haptics'
|
|
5
5
|
import { useTheme } from '../../theme'
|
|
6
|
-
import { s,
|
|
6
|
+
import { s, ms, mvs } from '../../utils/scaling'
|
|
7
7
|
|
|
8
8
|
const MONTH_NAMES: Record<string, string[]> = {
|
|
9
9
|
en: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
@@ -103,7 +103,7 @@ const styles = StyleSheet.create({
|
|
|
103
103
|
justifyContent: 'center',
|
|
104
104
|
},
|
|
105
105
|
label: {
|
|
106
|
-
fontFamily: '
|
|
106
|
+
fontFamily: 'Sohne-Medium',
|
|
107
107
|
fontSize: ms(17),
|
|
108
108
|
lineHeight: mvs(24),
|
|
109
109
|
textAlign: 'center',
|
|
@@ -45,7 +45,6 @@ function RadioItem({
|
|
|
45
45
|
})
|
|
46
46
|
const colorProgress = useColorTransition(selected)
|
|
47
47
|
|
|
48
|
-
// Pop-in animation for the inner dot
|
|
49
48
|
const dotScale = useSharedValue(selected ? 1 : 0)
|
|
50
49
|
useEffect(() => {
|
|
51
50
|
dotScale.value = withSpring(selected ? 1 : 0, SPRINGS.elastic)
|
|
@@ -61,8 +60,11 @@ function RadioItem({
|
|
|
61
60
|
}))
|
|
62
61
|
|
|
63
62
|
return (
|
|
63
|
+
// AUDIT FIX: opacity was applied only to the radio circle, leaving the label
|
|
64
|
+
// at full opacity when disabled. The whole row now dims uniformly so users
|
|
65
|
+
// get a single, consistent disabled signal across the entire item.
|
|
64
66
|
<TouchableOpacity
|
|
65
|
-
style={styles.row}
|
|
67
|
+
style={[styles.row, option.disabled && styles.rowDisabled]}
|
|
66
68
|
onPress={() => {
|
|
67
69
|
if (!option.disabled) {
|
|
68
70
|
hapticSelection()
|
|
@@ -79,21 +81,12 @@ function RadioItem({
|
|
|
79
81
|
accessibilityState={{ checked: selected, disabled: !!option.disabled }}
|
|
80
82
|
>
|
|
81
83
|
<Animated.View style={scaleStyle}>
|
|
82
|
-
<Animated.View
|
|
83
|
-
style={[
|
|
84
|
-
styles.radio,
|
|
85
|
-
{ opacity: option.disabled ? 0.45 : 1 },
|
|
86
|
-
radioStyle,
|
|
87
|
-
]}
|
|
88
|
-
>
|
|
84
|
+
<Animated.View style={[styles.radio, radioStyle]}>
|
|
89
85
|
<Animated.View style={[styles.dot, { backgroundColor: colors.primary }, dotStyle]} />
|
|
90
86
|
</Animated.View>
|
|
91
87
|
</Animated.View>
|
|
92
88
|
<Text
|
|
93
|
-
style={[
|
|
94
|
-
styles.label,
|
|
95
|
-
{ color: option.disabled ? colors.foregroundMuted : colors.foreground },
|
|
96
|
-
]}
|
|
89
|
+
style={[styles.label, { color: colors.foreground }]}
|
|
97
90
|
allowFontScaling={true}
|
|
98
91
|
>
|
|
99
92
|
{option.label}
|
|
@@ -141,6 +134,10 @@ const styles = StyleSheet.create({
|
|
|
141
134
|
alignItems: 'center',
|
|
142
135
|
gap: s(12),
|
|
143
136
|
},
|
|
137
|
+
// AUDIT FIX: was opacity on the inner circle only
|
|
138
|
+
rowDisabled: {
|
|
139
|
+
opacity: 0.45,
|
|
140
|
+
},
|
|
144
141
|
radio: {
|
|
145
142
|
width: s(24),
|
|
146
143
|
height: s(24),
|
|
@@ -155,7 +152,7 @@ const styles = StyleSheet.create({
|
|
|
155
152
|
borderRadius: s(5),
|
|
156
153
|
},
|
|
157
154
|
label: {
|
|
158
|
-
fontFamily: '
|
|
155
|
+
fontFamily: 'Sohne-Regular',
|
|
159
156
|
fontSize: ms(14),
|
|
160
157
|
lineHeight: mvs(20),
|
|
161
158
|
},
|
|
@@ -60,7 +60,7 @@ export function Select({
|
|
|
60
60
|
setPendingValue(value)
|
|
61
61
|
setPickerVisible(true)
|
|
62
62
|
} else if (isAndroid) {
|
|
63
|
-
;(pickerRef.current as
|
|
63
|
+
;(pickerRef.current as { focus?: () => void })?.focus?.()
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -234,7 +234,7 @@ const styles = StyleSheet.create({
|
|
|
234
234
|
gap: vs(8),
|
|
235
235
|
},
|
|
236
236
|
label: {
|
|
237
|
-
fontFamily: '
|
|
237
|
+
fontFamily: 'Sohne-Medium',
|
|
238
238
|
fontSize: ms(13),
|
|
239
239
|
},
|
|
240
240
|
trigger: {
|
|
@@ -247,7 +247,7 @@ const styles = StyleSheet.create({
|
|
|
247
247
|
paddingVertical: vs(11),
|
|
248
248
|
},
|
|
249
249
|
triggerText: {
|
|
250
|
-
fontFamily: '
|
|
250
|
+
fontFamily: 'Sohne-Regular',
|
|
251
251
|
fontSize: ms(15),
|
|
252
252
|
flex: 1,
|
|
253
253
|
},
|
|
@@ -255,7 +255,7 @@ const styles = StyleSheet.create({
|
|
|
255
255
|
marginLeft: s(8),
|
|
256
256
|
},
|
|
257
257
|
helperText: {
|
|
258
|
-
fontFamily: '
|
|
258
|
+
fontFamily: 'Sohne-Regular',
|
|
259
259
|
fontSize: ms(13),
|
|
260
260
|
},
|
|
261
261
|
iosBackdrop: {
|
|
@@ -276,14 +276,14 @@ const styles = StyleSheet.create({
|
|
|
276
276
|
borderBottomWidth: 1,
|
|
277
277
|
},
|
|
278
278
|
iosToolbarTitle: {
|
|
279
|
-
fontFamily: '
|
|
279
|
+
fontFamily: 'Sohne-SemiBold',
|
|
280
280
|
fontSize: ms(17),
|
|
281
281
|
},
|
|
282
282
|
iosDoneBtn: {
|
|
283
283
|
padding: s(4),
|
|
284
284
|
},
|
|
285
285
|
iosDoneBtnText: {
|
|
286
|
-
fontFamily: '
|
|
286
|
+
fontFamily: 'Sohne-SemiBold',
|
|
287
287
|
fontSize: ms(17),
|
|
288
288
|
},
|
|
289
289
|
androidHiddenPicker: {
|
|
@@ -14,7 +14,7 @@ export function Separator({ orientation = 'horizontal', style }: SeparatorProps)
|
|
|
14
14
|
<View
|
|
15
15
|
style={[
|
|
16
16
|
orientation === 'horizontal' ? styles.horizontal : styles.vertical,
|
|
17
|
-
{ backgroundColor: colors.
|
|
17
|
+
{ backgroundColor: colors.separator },
|
|
18
18
|
style,
|
|
19
19
|
]}
|
|
20
20
|
/>
|
|
@@ -25,11 +25,9 @@ const styles = StyleSheet.create({
|
|
|
25
25
|
horizontal: {
|
|
26
26
|
height: 1,
|
|
27
27
|
width: '100%',
|
|
28
|
-
opacity: 0.7,
|
|
29
28
|
},
|
|
30
29
|
vertical: {
|
|
31
30
|
width: 1,
|
|
32
31
|
height: '100%',
|
|
33
|
-
opacity: 0.7,
|
|
34
32
|
},
|
|
35
33
|
})
|